/* APEX PC Build — shared tokens + public storefront */

/* --- Theme tokens ----------------------------------------------------
   Dark is the base and the default, so the site looks right even if
   JavaScript never runs. Light is applied two ways, matching how the Django
   admin does it:
     [data-theme="light"]            an explicit choice from the toggle
     prefers-color-scheme: light     the OS preference, but only while the
                                     page is on "auto"
   _theme_head.html sets data-theme="dark" on a first visit, so the media
   query below only takes effect for someone carrying "auto" over from the
   admin's own switch. The light values are spelled out twice because CSS
   cannot share one declaration block between a selector and a media query. */

:root {
  /* Shape and type, theme independent */
  --radius: 14px;
  --radius-sm: 9px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;

  /* Dark palette */
  color-scheme: dark;
  --bg-deep: #070a0f;
  --bg: #0a0d13;
  --bg-elev: #121822;
  --bg-elev-2: #182030;
  --line: #232c3d;
  --line-soft: #1a212e;
  --line-strong: #33455f;
  --text: #e8edf7;
  --muted: #8b97ad;
  --muted-2: #7b89a3;
  --accent: #45c8f1;
  --accent-2: #7b6cff;
  --on-accent: #08121c;
  --accent-line: rgba(69, 200, 241, 0.4);
  --accent-tint: rgba(69, 200, 241, 0.07);
  --accent-soft: rgba(69, 200, 241, 0.35);
  --focus: rgba(69, 200, 241, 0.4);
  --pos: #37d07f;
  --pos-line: rgba(55, 208, 127, 0.42);
  --pos-soft: rgba(55, 208, 127, 0.3);
  --neg: #ff6b6b;
  --neg-line: rgba(255, 107, 107, 0.42);
  --neg-soft: rgba(255, 107, 107, 0.3);
  --warn: #ffb340;
  --warn-line: rgba(255, 179, 64, 0.42);
  --header-bg: rgba(10, 13, 19, 0.9);
  --badge-bg: rgba(10, 13, 19, 0.82);
  --placeholder: #3c4a63;
  --chip-text: #b9c4d8;
  /* The ambient wash behind the home-page hero, and the faint ring a card
     lifts on. Kept apart from --accent-tint: these are spread over large
     areas where a hundredth of a point of alpha is the difference between
     "lit" and "smudged". */
  --glow-a: rgba(69, 200, 241, 0.11);
  --glow-b: rgba(123, 108, 255, 0.10);
  --pos-tint: rgba(55, 208, 127, 0.11);
  --shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg-deep: #e9ecf3;
  --bg: #f7f8fc;
  --bg-elev: #ffffff;
  --bg-elev-2: #eef1f7;
  --line: #d7dde9;
  --line-soft: #e9edf4;
  --line-strong: #aeb9cc;
  --text: #131a26;
  --muted: #5b6779;
  --muted-2: #606b7d;
  --accent: #0c7297;
  --accent-2: #5b48d6;
  --on-accent: #ffffff;
  --accent-line: rgba(13, 127, 168, 0.38);
  --accent-tint: rgba(13, 127, 168, 0.08);
  --accent-soft: rgba(13, 127, 168, 0.32);
  --focus: rgba(13, 127, 168, 0.35);
  --pos: #0f7949;
  --pos-line: rgba(16, 128, 77, 0.38);
  --pos-soft: rgba(16, 128, 77, 0.28);
  --neg: #c02b2b;
  --neg-line: rgba(192, 43, 43, 0.34);
  --neg-soft: rgba(192, 43, 43, 0.26);
  --warn: #945e0a;
  --warn-line: rgba(150, 96, 10, 0.38);
  --header-bg: rgba(247, 248, 252, 0.9);
  --badge-bg: rgba(255, 255, 255, 0.88);
  --placeholder: #aab4c6;
  --chip-text: #3f4b60;
  --glow-a: rgba(13, 127, 168, 0.10);
  --glow-b: rgba(91, 72, 214, 0.08);
  --pos-tint: rgba(16, 128, 77, 0.10);
  --shadow: 0 8px 24px rgba(20, 30, 50, 0.09);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --bg-deep: #e9ecf3;
    --bg: #f7f8fc;
    --bg-elev: #ffffff;
    --bg-elev-2: #eef1f7;
    --line: #d7dde9;
    --line-soft: #e9edf4;
    --line-strong: #aeb9cc;
    --text: #131a26;
    --muted: #5b6779;
    --muted-2: #606b7d;
    --accent: #0c7297;
    --accent-2: #5b48d6;
    --on-accent: #ffffff;
    --accent-line: rgba(13, 127, 168, 0.38);
    --accent-tint: rgba(13, 127, 168, 0.08);
    --accent-soft: rgba(13, 127, 168, 0.32);
    --focus: rgba(13, 127, 168, 0.35);
    --pos: #0f7949;
    --pos-line: rgba(16, 128, 77, 0.38);
    --pos-soft: rgba(16, 128, 77, 0.28);
    --neg: #c02b2b;
    --neg-line: rgba(192, 43, 43, 0.34);
    --neg-soft: rgba(192, 43, 43, 0.26);
    --warn: #945e0a;
    --warn-line: rgba(150, 96, 10, 0.38);
    --header-bg: rgba(247, 248, 252, 0.9);
    --badge-bg: rgba(255, 255, 255, 0.88);
    --placeholder: #aab4c6;
    --chip-text: #3f4b60;
    --glow-a: rgba(13, 127, 168, 0.10);
    --glow-b: rgba(91, 72, 214, 0.08);
    --pos-tint: rgba(16, 128, 77, 0.10);
    --shadow: 0 8px 24px rgba(20, 30, 50, 0.09);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap { width: min(1180px, 100% - 2.5rem); margin-inline: auto; }

/* --- Header ---------------------------------------------------------- */

.site-header {
  border-bottom: 1px solid var(--line);
  background: var(--header-bg);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 20;
}
.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 0.9rem 0;
}
.brand {
  display: flex;
  align-items: center;
  gap: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text);
  font-size: 1.05rem;
}
.brand:hover { text-decoration: none; }
/* The logo is a shield crest cut out on transparency, so it gets no frame.
   drop-shadow follows the artwork's real silhouette (box-shadow would draw a
   rectangle around it), giving the crest a faint edge-light on dark headers and
   a little depth on light ones. */
.brand-badge {
  display: grid; place-items: center; flex: none;
  width: 44px; height: 44px;
  transition: transform 0.25s ease;
}
.brand-logo {
  height: 42px; width: auto; max-width: 44px;
  object-fit: contain; display: block;
  filter: drop-shadow(0 0 9px var(--accent-soft)) drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
  transition: filter 0.25s ease;
}
.brand:hover .brand-badge { transform: translateY(-1px) scale(1.05); }
.brand:hover .brand-logo {
  filter: drop-shadow(0 0 15px var(--accent)) drop-shadow(0 3px 5px rgba(0, 0, 0, 0.4));
}

/* Two-line wordmark: the name over a letterspaced descender line. Both halves
   come from SITE_NAME, split on the first space by the context processor. */
.brand-word { display: flex; flex-direction: column; gap: 3px; line-height: 1; }
.brand-word .lead { font-size: 1.1rem; font-weight: 800; letter-spacing: -0.01em; }
.brand-word .sub {
  font-size: 0.6rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.22em; color: var(--accent);
}
.brand .mark {
  width: 30px; height: 30px;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  display: grid; place-items: center;
  font-size: 0.85rem; font-weight: 800; color: var(--on-accent);
}
.site-nav { margin-left: auto; display: flex; align-items: center; gap: 1.1rem; font-size: 0.92rem; }
.site-nav a { color: var(--muted); }
.site-nav a:hover { color: var(--text); text-decoration: none; }
.site-nav .staff-link {
  border: 1px solid var(--line);
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  color: var(--accent);
}

/* The hamburger. Hidden by default and on desktop; shop.js unhides it below
   the breakpoint, so no-JS visitors keep the plain stacked nav instead of a
   button that does nothing. */
.menu-toggle {
  display: none; margin-left: auto;
  width: 44px; height: 44px; padding: 0;
  align-items: center; justify-content: center;
  color: var(--text); background: var(--bg-elev-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  cursor: pointer;
}
.menu-toggle svg {
  width: 22px; height: 22px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round;
}
.menu-toggle .cross { display: none; }
.site-header.is-open .menu-toggle .bars { display: none; }
.site-header.is-open .menu-toggle .cross { display: inline; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Condition of a single component, on the spec sheet. New parts earn a tint;
   everything else stays quiet so the table does not turn into a traffic light. */
.cond {
  display: inline-block; margin-left: 0.45rem;
  font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em;
  padding: 0.1rem 0.42rem; border-radius: 999px; vertical-align: 1px;
  border: 1px solid var(--line); color: var(--muted);
}
.cond.new { color: var(--pos); border-color: var(--pos-line); }
.cond.refurb, .cond.open_box { color: var(--accent); border-color: var(--accent-line); }
.cond.faulty { color: var(--neg); border-color: var(--neg-line); }

/* --- Theme switch ---------------------------------------------------- */

.theme-toggle {
  display: inline-grid; place-items: center; flex: none;
  width: 32px; height: 32px; padding: 0;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--bg-elev-2); color: var(--muted);
  cursor: pointer;
}
.theme-toggle:hover { color: var(--text); border-color: var(--line-strong); }
.theme-toggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.theme-toggle svg {
  width: 16px; height: 16px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
/* The icon shows the theme you are in: moon in the dark, sun in the light. */
.theme-toggle .icon-light { display: none; }
:root[data-theme="light"] .theme-toggle .icon-light { display: block; }
:root[data-theme="light"] .theme-toggle .icon-dark { display: none; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .theme-toggle .icon-light { display: block; }
  :root:not([data-theme="dark"]) .theme-toggle .icon-dark { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .brand-badge, .brand:hover .brand-badge { transition: none; transform: none; }
  .brand-logo { transition: none; }
}

/* --- Hero ------------------------------------------------------------ */
/*
   Asymmetric: the headline runs the full width of the column in two or three
   lines, the paragraph and buttons sit under its left half, and the newest
   machine's photo floats up from the bottom right into the headline's last
   line. Only the public pages use .hero, so nothing here needs scoping.
*/

.hero {
  position: relative; isolation: isolate;
  padding: clamp(2.5rem, 7vw, 6.5rem) 0 clamp(3rem, 7vw, 6rem);
  /* The photo's shadow is drawn outside its box; `clip` stops it widening the
     page without making the hero a scroll container. */
  overflow-x: clip;
}
.hero-copy { min-width: 0; }

/* One cool bloom behind the headline and a violet one to the right. */
.home-hero::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: -20% -10% 0;
  background:
    radial-gradient(38% 52% at 18% 40%, var(--glow-a), transparent 70%),
    radial-gradient(34% 50% at 82% 60%, var(--glow-b), transparent 72%);
}

/* One line of plain fact above the headline, in a small glass pill: where the
   machines are and how they change hands. */
.hero .eyebrow {
  display: inline-flex; align-items: center; gap: 0.6rem;
  margin: 0 0 1.5rem; max-width: none;
  padding: 0.4rem 0.9rem 0.4rem 0.75rem; border-radius: 999px;
  background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.72rem; font-weight: 600; color: var(--muted);
  letter-spacing: 0.14em; text-transform: uppercase;
}
:root[data-theme="light"] .hero .eyebrow { background: rgba(20, 30, 50, 0.04); border-color: rgba(20, 30, 50, 0.08); }
.hero .eyebrow .live {
  width: 8px; height: 8px; flex: none; border-radius: 50%;
  background: var(--pos); box-shadow: 0 0 0 4px var(--pos-tint);
  animation: live-pulse 2.4s ease-in-out infinite;
}
@keyframes live-pulse {
  50% { box-shadow: 0 0 0 7px transparent; }
}

.hero h1 {
  font-family: var(--display, var(--font)); font-weight: 800;
  font-size: clamp(2.4rem, 5.6vw, 5rem);
  line-height: 1.03; letter-spacing: -0.035em;
  margin: 0;
}
/* Keeps descenders inside the painted area: `background-clip: text` shaves
   the tail off a `y` at a tight line height. Padding on an inline box does not
   move the lines, so the layout is unchanged. */
.hero h1 .grad { padding-bottom: 0.08em; }

/* Gradient headline text. Not tied to .hero — the 404 page uses it too. */
.grad {
  background: linear-gradient(100deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero p { color: var(--muted); max-width: 52ch; font-size: 1.08rem; margin: 0; }

/* Copy on the left, a stack of real listings on the right. The flagship
   listing has its own band directly below (.spotlight). */
.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  column-gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
.hero-split .hero-copy { position: relative; z-index: 2; }
/* Two columns leave the headline about 600px; capped so it sets in three
   lines at most rather than four. */
.hero-split h1 { font-size: clamp(2.4rem, 4.8vw, 4.3rem); }
.hero-copy .hero-lede { margin-top: clamp(1.4rem, 2.6vw, 2.2rem); }
.hero-acts { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }

/* --- Primary button with a nested arrow ---------------------------------- */

/* Doubled class: .btn is defined further down and would otherwise win. */
.btn.btn-island {
  display: inline-flex; align-items: center; gap: 0.85rem;
  padding-right: 0.45rem; white-space: nowrap;
}
.btn-island-icon {
  display: grid; place-items: center; flex: none;
  width: 2.1rem; height: 2.1rem; border-radius: 50%;
  background: rgba(8, 18, 28, 0.14);
  transition: transform 0.6s var(--ease-spring, cubic-bezier(0.32, 0.72, 0, 1));
}
.btn-island-icon svg {
  width: 15px; height: 15px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.btn-island:hover .btn-island-icon { transform: translate(2px, -2px) scale(1.06); }
.btn-island:active { transform: scale(0.98); }

/* --- The stack of real machines ------------------------------------------ */
/*
   Up to three listing cards, tilted and overlapping like prints dropped on a
   desk; the first is the front one. Each card is a double bezel: a faint
   glass tray around a solid inner core, so it reads as a physical object. A
   card straightens and comes forward when pointed at.
*/

.hero-stack {
  position: relative;
  height: clamp(26rem, 40vw, 33rem);
}
.stack-card {
  position: absolute; display: block; width: 58%;
  padding: 6px; border-radius: 26px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 50px 90px -50px rgba(0, 0, 0, 0.85), 0 30px 80px -50px var(--accent-soft);
  color: var(--text);
  transition: transform 0.8s cubic-bezier(0.32, 0.72, 0, 1), box-shadow 0.8s cubic-bezier(0.32, 0.72, 0, 1);
}
.stack-card:hover { text-decoration: none; z-index: 4; box-shadow: 0 60px 100px -50px rgba(0, 0, 0, 0.9), 0 40px 90px -40px var(--accent-soft); }
:root[data-theme="light"] .stack-card { background: rgba(20, 30, 50, 0.04); border-color: rgba(20, 30, 50, 0.08); }
.stack-core {
  display: block; overflow: hidden; border-radius: 20px;
  background: var(--bg-elev);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.08);
}
.stack-media { display: block; aspect-ratio: 1 / 1; }
.stack-media img { transition: transform 0.8s cubic-bezier(0.32, 0.72, 0, 1); }
.stack-card:hover .stack-media img { transform: scale(1.04); }
.stack-flag {
  position: absolute; z-index: 2; top: 0.7rem; left: 0.7rem;
  padding: 0.25rem 0.6rem; border-radius: 999px;
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  background: var(--badge-bg); color: var(--muted); border: 1px solid var(--line);
  backdrop-filter: blur(4px);
}
.stack-flag.is-sale { background: var(--pos); color: var(--on-accent); border-color: transparent; }
.stack-tag {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.8rem;
  padding: 0.85rem 1rem 0.95rem;
}
.stack-tag .name {
  min-width: 0; font-size: 0.85rem; font-weight: 600; line-height: 1.3;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
.stack-tag .now {
  font-family: var(--display, var(--font)); font-size: 1.15rem; font-weight: 800;
  letter-spacing: -0.02em; color: var(--accent); white-space: nowrap;
}
.stack-tag .now.is-sale { color: var(--pos); }
.stack-tag .now.is-sold { color: var(--muted); text-decoration: line-through; text-decoration-thickness: 1.5px; }

/* Positions. The front card sits low and left; the others fan out behind. */
.hero-stack .stack-card:nth-child(1) { left: 4%; bottom: 0; z-index: 3; transform: rotate(-3deg); }
.hero-stack .stack-card:nth-child(2) { right: 0; top: 4%; z-index: 2; transform: rotate(5deg); }
.hero-stack .stack-card:nth-child(3) { left: 20%; top: 0; z-index: 1; transform: rotate(-9deg) scale(0.9); }
.hero-stack .stack-card:hover { transform: rotate(0deg) translateY(-8px); }
/* Fewer than three: one centred, or two crossed. */
.hero-stack.count-1 .stack-card:nth-child(1) { left: 21%; bottom: 6%; width: 58%; }
.hero-stack.count-2 .stack-card:nth-child(2) { top: 0; }

/* --- Entrance -------------------------------------------------------------- */
/* The copy and the cards rise into place once on load, one after another. */

.rise { animation: rise 0.9s cubic-bezier(0.32, 0.72, 0, 1) both; }
.hero-copy .rise:nth-child(2) { animation-delay: 0.08s; }
.hero-copy .rise:nth-child(3) { animation-delay: 0.16s; }
.hero-copy .rise:nth-child(4) { animation-delay: 0.24s; }
.hero-stack .stack-card.rise { animation-name: rise-card; animation-duration: 1.1s; }
.hero-stack .stack-card:nth-child(1).rise { animation-delay: 0.3s; }
.hero-stack .stack-card:nth-child(2).rise { animation-delay: 0.42s; }
.hero-stack .stack-card:nth-child(3).rise { animation-delay: 0.54s; }
@keyframes rise {
  from { opacity: 0; transform: translateY(24px); filter: blur(6px); }
}
/* Cards keep their own tilt, so they rise with `translate` rather than
   replacing `transform`. */
@keyframes rise-card {
  from { opacity: 0; translate: 0 48px; }
}

@media (max-width: 900px) {
  .hero-split { grid-template-columns: 1fr; row-gap: 2.4rem; }
  /* No tilt or overlap on a narrower screen: a plain row of cards under the
     copy, each a tap target of its own. */
  .hero-stack {
    height: auto;
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.8rem;
  }
  .hero-stack.count-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero-stack.count-1 { grid-template-columns: minmax(0, 18rem); }
  .hero-stack .stack-card,
  .hero-stack .stack-card:nth-child(n),
  .hero-stack.count-1 .stack-card:nth-child(1) {
    position: relative; inset: auto; width: auto; transform: none;
  }
  .hero-stack .stack-card:hover { transform: translateY(-4px); }
}
@media (max-width: 640px) {
  .hero-stack { gap: 0.5rem; }
  .stack-card { padding: 4px; border-radius: 18px; }
  .stack-core { border-radius: 14px; }
  .stack-tag { flex-direction: column; gap: 0.15rem; padding: 0.55rem 0.6rem 0.65rem; }
  .stack-tag .name { font-size: 0.72rem; }
  .stack-tag .now { font-size: 0.95rem; }
  .stack-flag { top: 0.4rem; left: 0.4rem; font-size: 0.58rem; padding: 0.15rem 0.45rem; }
}

@media (prefers-reduced-motion: reduce) {
  .hero .eyebrow .live, .rise { animation: none; }
  .stack-card, .stack-media img, .btn-island-icon { transition: none; }
  .stack-card:hover .stack-media img, .btn-island:hover .btn-island-icon { transform: none; }
  .hero-stack .stack-card:hover { transform: none; }
}
/* On the desk layout, a pointed-at card keeps its tilt rather than moving. */
@media (prefers-reduced-motion: reduce) and (min-width: 901px) {
  .hero-stack .stack-card:nth-child(1):hover { transform: rotate(-3deg); }
  .hero-stack .stack-card:nth-child(2):hover { transform: rotate(5deg); }
  .hero-stack .stack-card:nth-child(3):hover { transform: rotate(-9deg) scale(0.9); }
}

/* --- Listing spotlight ---------------------------------------------------- */
/*
   The most expensive machine for sale, straight under the hero: its photo on
   the stage at the left, name, key parts and price at the right. Same price
   colours as the cards — green when on sale.
*/

.spotlight { padding-block: 0 clamp(4rem, 8vw, 6.5rem); }
.spot-card {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  border: 1px solid var(--line); border-radius: calc(var(--radius) + 8px);
  background: linear-gradient(135deg, var(--bg-elev), color-mix(in srgb, var(--bg-elev) 55%, var(--bg)));
  box-shadow: 0 40px 90px -50px var(--accent-soft);
  transition: border-color 0.3s ease, box-shadow 0.5s ease;
}
.spot-card:hover { border-color: var(--accent-line); box-shadow: 0 46px 100px -46px var(--accent-soft); }
.spot-card.on-sale { border-color: var(--pos-line); }
.spot-card.on-sale:hover { border-color: var(--pos); }

/* Side by side, the photo takes exactly its column's width and the card's
   full height — at least square, taller when the details run longer. It must
   not carry an aspect-ratio here: stretched to a taller card, the box would
   keep the ratio by growing wider and spill over the text column. */
.spot-media {
  display: block; width: 100%; min-width: 0; height: 100%;
  min-height: clamp(22rem, 40vw, 34rem);
}
/* Laid over the frame rather than sized by it, so a tall photo cannot make
   the card taller than its details need. */
.spot-media.photo-stage img { position: absolute; inset: 0; }
.spot-media img { transition: transform 0.7s ease-out; }
.spot-card:hover .spot-media img { transform: scale(1.04); }
.spot-media .placeholder {
  position: relative; z-index: 1; display: grid; place-items: center; height: 100%;
  color: var(--placeholder); font-size: 2.6rem; font-weight: 800; letter-spacing: 0.1em;
}
.spot-media .flash { z-index: 2; top: 1rem; right: 1rem; font-size: 0.85rem; padding: 0.35rem 0.75rem; }

.spot-body {
  display: flex; flex-direction: column; justify-content: center; gap: 1.1rem;
  padding: clamp(1.8rem, 4vw, 3.4rem);
}
.spot-kicker {
  margin: 0; color: var(--accent);
  font-size: 0.8rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
.spot-body h2 {
  margin: 0; font-weight: 800; line-height: 1.05; letter-spacing: -0.03em;
  font-size: clamp(1.8rem, 3.2vw, 2.8rem); text-wrap: balance;
}
.spot-body h2 a { color: var(--text); }
.spot-body h2 a:hover { color: var(--accent); text-decoration: none; }
.spot-head { margin: 0; color: var(--muted); font-size: 1.05rem; }

.spot-specs {
  margin: 0.3rem 0 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.8rem 1.4rem;
}
.spot-specs div { min-width: 0; padding-top: 0.7rem; border-top: 1px solid var(--line-soft); }
.spot-specs dt {
  margin-bottom: 0.2rem; color: var(--muted);
  font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase;
}
.spot-specs dd { margin: 0; font-size: 0.95rem; font-weight: 600; overflow-wrap: anywhere; }

.spot-price .now { font-size: clamp(2.2rem, 4vw, 3rem); }
.spot-card.on-sale .spot-price .now { color: var(--pos); }
.spot-acts { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 0.3rem; }

@media (max-width: 860px) {
  .spot-card { grid-template-columns: 1fr; }
  /* Stacked, the photo sits above the details: landscape on a tablet so the
     details are not a full screen away, square on a phone (below). */
  .spot-media { height: auto; min-height: 0; aspect-ratio: 4 / 3; }
}
@media (max-width: 640px) {
  .spotlight { padding-bottom: 3rem; }
  .spot-media { aspect-ratio: 1 / 1; }
  .spot-specs { grid-template-columns: 1fr; }
  .spot-acts .btn { flex: 1 1 100%; text-align: center; }
}
@media (prefers-reduced-motion: reduce) {
  .spot-card, .spot-media img { transition: none; }
  .spot-card:hover .spot-media img { transform: none; }
}

/* The custom build page's header: one column, tighter type. */
.request-hero { padding-bottom: clamp(2rem, 4vw, 3rem); }
.request-hero h1 { font-size: clamp(2.2rem, 4.8vw, 4rem); margin-bottom: 1.2rem; }

/* --- Error pages ------------------------------------------------------
   Used by 404.html. The 500 page carries its own copy of these rules inline,
   because it must render even if this stylesheet is part of the problem. */

.errpage { padding: 4rem 0 5rem; max-width: 46rem; }
.errpage-code {
  margin: 0; font-size: clamp(4rem, 16vw, 7rem); font-weight: 800;
  line-height: 0.9; letter-spacing: -0.05em;
  background: linear-gradient(100deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.errpage h1 {
  font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.15;
  letter-spacing: -0.02em; margin: 0.6rem 0 0.7rem;
}
.errpage-lead { color: var(--muted); font-size: 1.02rem; max-width: 46ch; margin: 0; }
.errpage-acts { display: flex; flex-wrap: wrap; gap: 0.7rem; margin-top: 1.8rem; }
.errpage-foot {
  margin: 2.2rem 0 0; padding-top: 1.4rem;
  border-top: 1px solid var(--line-soft);
  font-size: 0.9rem; color: var(--muted);
}
@media (max-width: 600px) {
  .errpage { padding: 2.5rem 0 3.5rem; }
  .errpage-acts .btn { flex: 1 1 100%; text-align: center; }
}

/* --- Filter bar ------------------------------------------------------ */

.filters {
  padding: 0.85rem; margin: 1.5rem 0 2rem;
  background: var(--bg-elev); border: 1px solid var(--line); border-radius: var(--radius);
}
.filter-fields {
  display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center;
}
.filters input[type="search"], .filters select {
  background: var(--bg); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 0.5rem 0.7rem; font: inherit; font-size: 0.9rem;
}
.filters input[type="search"] { flex: 1 1 220px; }
.filters label { font-size: 0.85rem; color: var(--muted); }

/* The bar above the controls: a Filter button on the left and the result count
   on the right. On a desktop only the count shows, since the controls are
   already visible and a button to reveal them would be a lie. */
.filter-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 0.8rem;
}
.filters.js-filters.is-open .filter-bar { margin-bottom: 0.7rem; }
.filter-toggle {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.5rem 0.85rem; min-height: 44px;
  font: inherit; font-size: 0.92rem; font-weight: 600;
  color: var(--text); background: transparent;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  cursor: pointer;
}
.filter-toggle[hidden] { display: none; }
.filter-toggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.filter-toggle svg {
  width: 18px; height: 18px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round;
}
/* A filter is in force: worth a mark, because the count below is not the whole
   catalogue and nothing else on a phone says so. */
.filter-toggle .dot {
  display: inline-block; width: 7px; height: 7px; margin-left: 0.15rem;
  border-radius: 50%; background: var(--accent); vertical-align: middle;
}
.result-count { margin-left: auto; font-size: 0.88rem; color: var(--muted); }

/* --- Pagination ------------------------------------------------------- */

.pager {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.8rem;
  padding: 0.5rem 0 3rem;
}
.pager .btn {
  min-height: 44px; display: inline-flex; align-items: center;
  white-space: nowrap;
}
.pager .is-off { opacity: 0.35; cursor: default; }
.pager-where { font-size: 0.88rem; color: var(--muted); text-align: center; }

.btn {
  display: inline-block; font: inherit; font-size: 0.9rem; font-weight: 600;
  border: 1px solid var(--line); background: var(--bg-elev-2); color: var(--text);
  padding: 0.5rem 0.95rem; border-radius: var(--radius-sm); cursor: pointer;
}
.btn:hover { border-color: var(--accent); text-decoration: none; }
.btn-primary {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: var(--on-accent); border: 0; font-weight: 700;
}
.btn-ghost { background: transparent; color: var(--muted); }
.btn-lg { padding: 0.7rem 1.3rem; font-size: 1rem; }

/* --- Build grid ------------------------------------------------------ */

.grid {
  display: grid; gap: 1.3rem;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  padding-bottom: 3rem;
}
.card {
  position: relative;
  background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  display: flex; flex-direction: column;
  transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
/* The ring is a second, much wider border drawn outside the first one, so a
   hovered card separates from its neighbours by more than a one-pixel colour
   change — which on a phone-sized grid of photos was easy to miss. */
.card:hover {
  transform: translateY(-5px);
  border-color: var(--accent-line);
  box-shadow: var(--shadow), 0 0 0 4px var(--glow-a);
}
/* The photo leads the card, so it gets the lift on hover too. */
.card:hover .card-media img { transform: scale(1.04); }
/* Square tiles. Photos of a tower are portrait (20 of the 24 imported so far,
   median exactly 3:4), so `cover` trims about an eighth off the top and bottom
   to fill the square. That is a fraction of what the old 4:3 frame cut, and the
   whole photo is still there on the listing page, where the gallery uses
   `contain` and crops nothing. */
.card-media {
  aspect-ratio: 1 / 1; background: var(--bg-elev-2);
  position: relative; overflow: hidden;
}
/* A scrim under the two corner labels. The badge has its own backdrop, but a
   bright window or a white case directly behind it still washed the text out;
   this darkens only the top of the photo, where both labels sit. It is over
   the photograph rather than the page, so it stays dark in either theme. */
.card-media::after {
  content: ""; position: absolute; inset: 0 0 auto; height: 38%;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.34), transparent);
  pointer-events: none;
}
.card-media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Cases stand in the middle of the shot, so trim evenly from both ends. */
  object-position: center;
  transition: transform 0.4s ease;
}
.card-media .placeholder {
  width: 100%; height: 100%; display: grid; place-items: center;
  color: var(--placeholder); font-size: 2.4rem; font-weight: 800; letter-spacing: 0.1em;
}
.card-body { padding: 1rem 1.1rem 1.2rem; display: flex; flex-direction: column; gap: 0.55rem; flex: 1; }
.card-body h3 { margin: 0; font-size: 1.05rem; line-height: 1.3; }
.card-body h3 a { color: var(--text); }
.card-head { color: var(--muted); font-size: 0.88rem; margin: 0; }
.spec-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.15rem; }
.chip {
  font-family: var(--mono); font-size: 0.72rem;
  background: var(--bg-elev-2); border: 1px solid var(--line-soft);
  color: var(--chip-text); padding: 0.2rem 0.45rem; border-radius: 6px;
  /* Spec lines copied from a listing can be very long. Clip them so one wordy
     part does not make its card twice the height of the others. */
  max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card-foot {
  margin-top: auto; padding-top: 0.7rem;
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem;
}
/* Price is the thing a buyer scans for, so it gets the accent colour and the
   most weight on the card. A discount shows what it was, struck through. */
.price { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.45rem; }
.price .now {
  font-size: 1.5rem; font-weight: 800; letter-spacing: -0.02em;
  color: var(--accent); line-height: 1.1;
}
.price .was {
  font-size: 0.95rem; font-weight: 600; color: var(--muted);
  text-decoration: line-through; text-decoration-thickness: 1.5px;
}
.price .save {
  font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--pos); border: 1px solid var(--pos-line);
  padding: 0.12rem 0.4rem; border-radius: 999px;
}
.price small {
  flex-basis: 100%;
  font-size: 0.72rem; color: var(--muted); font-weight: 500;
}

/* The corner flash. Opposite the status badge so the two never collide.
   Lifted above .card-media::after, which is the last child of the frame and
   would otherwise be painted straight over both labels. */
.flash {
  position: absolute; z-index: 1; top: 0.7rem; right: 0.7rem;
  font-size: 0.74rem; font-weight: 800; letter-spacing: 0.02em;
  padding: 0.3rem 0.6rem; border-radius: 999px;
  background: var(--pos); color: var(--on-accent);
  box-shadow: 0 4px 12px -4px var(--pos);
}

/* On sale, the price takes the positive colour — the same green as the flash
   and as the detail page, so the three read as one signal. Only ever applied
   to a machine you can still buy: see PCBuild.is_on_sale. */
.card.on-sale { border-color: var(--pos-line); }
.card.on-sale:hover {
  border-color: var(--pos);
  box-shadow: var(--shadow), 0 0 0 4px var(--pos-tint);
}
.card.on-sale .price .now { color: var(--pos); }

@media (prefers-reduced-motion: reduce) {
  .card, .card-media img { transition: none; }
  .card:hover { transform: none; }
  .card:hover .card-media img { transform: none; }
}

.badge {
  position: absolute; z-index: 1; top: 0.7rem; left: 0.7rem;
  font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  padding: 0.25rem 0.55rem; border-radius: 999px;
  background: var(--badge-bg); border: 1px solid var(--line); color: var(--text);
  backdrop-filter: blur(4px);
}
.badge.for_sale { color: var(--pos); border-color: var(--pos-line); }
.badge.reserved { color: var(--warn); border-color: var(--warn-line); }
.badge.sold { color: var(--muted); }

.empty {
  padding: 3rem 1rem; text-align: center; color: var(--muted);
  border: 1px dashed var(--line); border-radius: var(--radius); margin-bottom: 3rem;
}

/* --- Detail page ----------------------------------------------------- */

.detail { display: grid; gap: 2.2rem; grid-template-columns: minmax(0, 1.5fr) minmax(300px, 1fr); padding: 2rem 0 3rem; }
@media (max-width: 900px) { .detail { grid-template-columns: 1fr; } }

.crumbs { color: var(--muted); font-size: 0.85rem; padding-top: 1.2rem; }
.detail h1 { font-size: clamp(1.5rem, 3.5vw, 2.15rem); margin: 0.5rem 0 0.4rem; letter-spacing: -0.02em; }
.detail .lede { color: var(--muted); margin: 0 0 1.3rem; font-size: 1.02rem; }

.gallery { display: grid; gap: 0.6rem; }

/* A fixed square frame, the same 1:1 as the listing cards. Photos arrive in
   different shapes, so each one fills the square (object-fit: cover), trimmed
   evenly from the centre, and the page never jumps as you flick through. The
   full-screen viewer (.lightbox) still shows the whole photo. No max-height:
   capping the height of a full-width square would make it a rectangle again. */
.gallery .frame {
  position: relative; aspect-ratio: 1 / 1; overflow: hidden;
  background: var(--bg-elev-2); border: 1px solid var(--line); border-radius: var(--radius);
}
.gallery .frame img {
  position: absolute; inset: 0; display: none;
  width: 100%; height: 100%; object-fit: cover; object-position: center;
  /* A horizontal swipe belongs to the gallery; a vertical one still scrolls the
     page. Without this the browser claims the drag and no pointer events for it
     ever reach the script. */
  touch-action: pan-y;
  /* Otherwise a swipe that starts on a photo drags a ghost image of it. */
  -webkit-user-drag: none; user-select: none;
}
.gallery .frame img.is-active { display: block; }

.gallery .nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center;
  width: 40px; height: 40px; padding: 0;
  border: 1px solid var(--line); border-radius: 50%;
  background: var(--badge-bg); color: var(--text);
  cursor: pointer; opacity: 0.75; transition: opacity 0.15s ease, border-color 0.15s ease;
}
.gallery .nav:hover { opacity: 1; border-color: var(--accent); }
.gallery .nav:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; opacity: 1; }
.gallery .nav.prev { left: 0.7rem; }
.gallery .nav.next { right: 0.7rem; }
.gallery .nav svg {
  width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

/* The frame is only card-shaped; the photo underneath is usually much bigger.
   The cursor and the corner button both say so, because an image that silently
   does something on click is a guess the visitor has to make. */
.gallery .frame.is-zoomable img { cursor: zoom-in; }
.gallery .expand {
  position: absolute; right: 0.7rem; bottom: 0.7rem;
  display: grid; place-items: center;
  width: 40px; height: 40px; padding: 0;
  border: 1px solid var(--line); border-radius: 50%;
  background: var(--badge-bg); color: var(--text);
  cursor: pointer; opacity: 0.75; transition: opacity 0.15s ease, border-color 0.15s ease;
}
.gallery .expand:hover { opacity: 1; border-color: var(--accent); }
.gallery .expand:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; opacity: 1; }
.gallery .expand svg {
  width: 19px; height: 19px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

/* --- Full-screen photo viewer ----------------------------------------- */
/*
   Built by gallery.js on first use, so it never exists without a way to close
   it. Fixed to the viewport rather than the page, because on a phone the photo
   should get the whole screen — that is the entire point of opening it.
*/

.lightbox {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 3.5rem 1rem;
  background: rgba(3, 5, 9, 0.94);
  backdrop-filter: blur(3px);
}
.lightbox[hidden] { display: none; }
/* The page behind must not scroll under the viewer. */
body.lb-open { overflow: hidden; }

.lightbox .lb-img {
  max-width: 100%; max-height: 100%;
  object-fit: contain; border-radius: var(--radius-sm);
  /* No touch-action here on purpose: the default lets the browser handle
     pinch-to-zoom, which is the reason for opening a photo full screen. The
     inline gallery below sets pan-y because it wants the horizontal swipe;
     this one wants the gesture left alone. */
  -webkit-user-drag: none; user-select: none;
}

.lightbox .lb-close,
.lightbox .lb-nav {
  position: absolute; display: grid; place-items: center;
  width: 46px; height: 46px; padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.22); border-radius: 50%;
  background: rgba(20, 26, 36, 0.8); color: #fff;
  cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
}
.lightbox .lb-close:hover,
.lightbox .lb-nav:hover { border-color: var(--accent); background: rgba(20, 26, 36, 0.95); }
.lightbox .lb-close:focus-visible,
.lightbox .lb-nav:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.lightbox .lb-close { top: 0.9rem; right: 0.9rem; }
.lightbox .lb-nav.prev { left: 0.9rem; }
.lightbox .lb-nav.next { right: 0.9rem; }
.lightbox .lb-nav { top: 50%; transform: translateY(-50%); }
.lightbox .lb-close svg,
.lightbox .lb-nav svg {
  width: 22px; height: 22px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.lightbox .lb-count {
  position: absolute; left: 0; right: 0; bottom: 1rem; margin: 0;
  text-align: center; font-size: 0.85rem; color: rgba(255, 255, 255, 0.72);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  .lightbox { padding: 3.5rem 0.5rem 3rem; }
  /* Arrows sit low so a thumb reaches them, and clear of the photo's middle. */
  .lightbox .lb-nav { top: auto; bottom: 2.6rem; transform: none; }
}

.gallery .thumbs { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.gallery .thumb {
  display: block; line-height: 0; border-radius: var(--radius-sm);
  border: 1px solid var(--line); overflow: hidden; cursor: pointer;
  transition: border-color 0.15s ease, opacity 0.15s ease;
  opacity: 0.65;
}
.gallery .thumb:hover { opacity: 1; border-color: var(--line-strong); }
.gallery .thumb:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.gallery .thumb.is-active { opacity: 1; border-color: var(--accent); }
.gallery .thumb img {
  width: 72px; height: 72px; object-fit: cover; display: block;
  background: var(--bg-elev-2);
}

@media (prefers-reduced-motion: reduce) {
  .gallery .nav, .gallery .thumb { transition: none; }
}

@media (max-width: 520px) {
  .gallery .thumb img { width: 56px; height: 56px; }
}
.gallery .no-photo {
  aspect-ratio: 1 / 1; border: 1px dashed var(--line); border-radius: var(--radius);
  display: grid; place-items: center; color: var(--placeholder); font-weight: 700; letter-spacing: 0.1em;
}

.panel {
  background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.2rem 1.3rem; margin-bottom: 1.3rem;
}
.panel h2 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--muted); margin: 0 0 0.9rem; }

.spec-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.spec-table th {
  text-align: left; font-weight: 600; color: var(--muted); font-size: 0.82rem;
  padding: 0.55rem 1rem 0.55rem 0; vertical-align: top; white-space: nowrap; width: 1%;
}
.spec-table td { padding: 0.55rem 0; border-bottom: 1px solid var(--line-soft); }
.spec-table tr:last-child td, .spec-table tr:last-child th { border-bottom: 0; }
.spec-table .sub { display: block; color: var(--muted); font-size: 0.82rem; font-family: var(--mono); }

.prose p { margin: 0 0 0.9rem; }
.prose p:last-child { margin-bottom: 0; }

.ticks { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.45rem; }
.ticks li { padding-left: 1.4rem; position: relative; font-size: 0.92rem; }
.ticks li::before { content: "✓"; position: absolute; left: 0; color: var(--pos); font-weight: 700; }

.buy-box { position: sticky; top: 5rem; }
.buy-box .amount {
  font-size: 2.2rem; font-weight: 800; letter-spacing: -0.03em; line-height: 1.1;
  color: var(--accent);
}
.buy-box .amount.discounted { color: var(--pos); }
.buy-box .sale-line {
  display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.35rem;
}
.buy-box .sale-line .off {
  font-size: 0.74rem; font-weight: 800; letter-spacing: 0.02em;
  padding: 0.2rem 0.55rem; border-radius: 999px;
  background: var(--pos); color: var(--on-accent);
}
.buy-box .sale-line .was {
  font-size: 1rem; font-weight: 600; color: var(--muted);
  text-decoration: line-through; text-decoration-thickness: 1.5px;
}
.buy-box .saving { margin: 0.25rem 0 0; font-size: 0.85rem; font-weight: 600; color: var(--pos); }
.buy-box .meta { color: var(--muted); font-size: 0.85rem; margin-top: 0.2rem; }
.buy-box .sold-note { color: var(--warn); font-weight: 600; }
.kv { display: flex; justify-content: space-between; gap: 1rem; padding: 0.4rem 0; font-size: 0.9rem; border-bottom: 1px solid var(--line-soft); }
.kv:last-child { border-bottom: 0; }
.kv span:first-child { color: var(--muted); }

/* Where to collect it, and that delivery exists. Two lines, above the buttons,
   because "is this near me" is the question asked before "how do I ask". */
.pickup {
  margin: 0 0 0.9rem; padding: 0.7rem 0.85rem;
  background: var(--bg-elev-2); border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm); font-size: 0.9rem;
}
.pickup p { margin: 0; }
.pickup .dim { color: var(--muted); font-size: 0.85rem; margin-top: 0.2rem; }

/* Contact buttons. Full width and stacked at every size: on a phone they are
   thumb targets, and on a desktop the column is narrow enough that a row would
   squeeze them anyway. */
.contact-acts { display: grid; gap: 0.5rem; }
.contact-acts .btn {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  text-align: center; min-height: 48px;
}
.contact-acts .btn svg { width: 18px; height: 18px; flex: none; fill: currentColor; }
.contact-acts .btn svg.stroke {
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* --- Forms ----------------------------------------------------------- */

form.stack { display: grid; gap: 0.7rem; }
form.stack label { font-size: 0.82rem; color: var(--muted); display: block; margin-bottom: 0.2rem; }
form.stack input, form.stack textarea, form.stack select {
  width: 100%; background: var(--bg); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 0.55rem 0.7rem; font: inherit; font-size: 0.92rem;
}
form.stack input:focus, form.stack textarea:focus { outline: 2px solid var(--focus); outline-offset: 1px; }
form.stack .errorlist { color: var(--neg); font-size: 0.82rem; list-style: none; padding: 0; margin: 0.2rem 0 0; }
form.stack .helptext { color: var(--muted); font-size: 0.78rem; }

.messages { list-style: none; padding: 0; margin: 1rem 0 0; display: grid; gap: 0.5rem; }
.messages li {
  padding: 0.7rem 1rem; border-radius: var(--radius-sm); font-size: 0.92rem;
  border: 1px solid var(--line); background: var(--bg-elev);
}
.messages li.success { border-color: var(--pos-line); color: var(--pos); }
.messages li.error { border-color: var(--neg-line); color: var(--neg); }

/* --- Footer ---------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line); margin-top: 2rem; padding: 2rem 0 3rem;
  color: var(--muted); font-size: 0.88rem;
}
.site-footer .wrap { display: flex; flex-wrap: wrap; gap: 1rem 2rem; justify-content: space-between; }

.section-title { font-size: 1.15rem; margin: 2.5rem 0 1rem; }

/* --- The shopfront on a phone ---------------------------------------- */
/*
   At 375px the brand lockup plus the nav is wider than the content column, so
   the header is allowed to wrap onto a second line rather than push the page
   sideways. Tap targets go to 44px, which is the smallest a thumb reliably hits.
*/

@media (max-width: 640px) {
  /* The header is one row: brand, then a hamburger. Four links and a theme
     toggle will not fit beside a two-line wordmark at 375px, and wrapping them
     onto a second row cost a third of the screen before any content. */
  .site-header .wrap { gap: 0.6rem; padding: 0.6rem 0; }
  .site-header.js-nav .menu-toggle { display: inline-flex; }

  .site-header.js-nav .site-nav {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: 0.4rem 0;
    background: var(--bg-elev); border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow);
  }
  .site-header.js-nav.is-open .site-nav { display: flex; }
  .site-header.js-nav .site-nav a {
    display: flex; align-items: center; min-height: 48px;
    padding: 0 1.1rem; font-size: 1rem; color: var(--text);
    border-bottom: 1px solid var(--line-soft);
  }
  .site-header.js-nav .site-nav .staff-link {
    border: 0; border-bottom: 1px solid var(--line-soft);
    border-radius: 0; color: var(--accent);
  }
  /* The nav is out of flow when collapsed, so its margin-left:auto no longer
     pushes anything right. The theme toggle takes over that job and the menu
     button sits directly beside it. */
  .site-header .theme-toggle {
    margin-left: auto;
    /* It is a header control now rather than a row in a menu, so it gets a
       thumb-sized target like everything else out here. */
    width: 44px; height: 44px;
  }
  .site-header .menu-toggle { margin-left: 0; }
  /* No script: the old stacked nav, which works even if it is not pretty. */
  .site-header:not(.js-nav) .wrap { flex-wrap: wrap; }
  .site-header:not(.js-nav) .site-nav a { display: inline-flex; align-items: center; min-height: 44px; }

  .brand-word .lead { font-size: 1rem; }
  .brand-word .sub { font-size: 0.55rem; letter-spacing: 0.18em; }

  .crumbs a, .site-footer a { display: inline-flex; align-items: center; min-height: 40px; }

  /* Filters collapse behind the button in .filter-bar. */
  .filters { margin: 1rem 0 1.2rem; padding: 0.6rem; }
  .filter-fields { gap: 0.5rem; }
  .filter-fields[hidden] { display: none; }
  .filters input[type="search"], .filters select, .filter-fields .btn {
    width: 100%; min-height: 44px;
  }

  /* The chips repeat the name and the spec sheet a tap away, and cost a whole
     row per card on the one screen where rows are scarce. */
  .spec-chips { display: none; }

  /* Two cards a row. At ~165px wide each, the card keeps only what a buyer
     scans for — photo, name, price — and the type steps down to fit. */
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem; }
  .grid .card:hover { transform: none; }
  .grid .card-body { padding: 0.7rem 0.75rem 0.85rem; gap: 0.3rem; }
  .grid .card-body h3 {
    font-size: 0.86rem; line-height: 1.25;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .grid .card-head { display: none; }
  .grid .card-foot { padding-top: 0.3rem; }
  .grid .price { gap: 0.3rem; }
  .grid .price .now { font-size: 1.12rem; }
  .grid .price .was { font-size: 0.74rem; }
  .grid .price .save { display: none; }
  .grid .price small { font-size: 0.66rem; }
  .grid .card .badge { top: 0.45rem; left: 0.45rem; font-size: 0.56rem; padding: 0.16rem 0.42rem; }
  .grid .card .flash { top: 0.45rem; right: 0.45rem; font-size: 0.62rem; padding: 0.18rem 0.45rem; }

  .pager { gap: 0.5rem; padding-bottom: 2rem; }
  .pager .btn { flex: 1 1 0; justify-content: center; }
  .pager-where { flex: 1 1 100%; order: 3; }
}

/* --- Facebook Marketplace link --------------------------------------- */
/*
   Used twice: as a button under the hero, and as a plain link in the footer.
   The `.btn` classes do the heavy lifting on the hero; these rules only handle
   the mark and the spacing.
*/

.fb-link { display: inline-flex; align-items: center; gap: 0.5rem; }
.fb-link svg { width: 18px; height: 18px; fill: currentColor; flex: none; }

/* The hero button. Marketplace is where the sales actually happen, so it gets
   real prominence rather than being buried in the footer. */
.hero .fb-link {
  background: var(--bg-elev-2); color: var(--text);
  border: 1px solid var(--line-strong);
}
.hero .fb-link:hover {
  border-color: var(--accent); color: var(--accent);
  text-decoration: none;
}
.hero .fb-link svg { width: 20px; height: 20px; }

/* The footer copy. */
.site-footer .fb-link { margin-top: 0.15rem; font-size: 0.9rem; }

/* --- Custom build request -------------------------------------------- */


.request-layout {
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: 1.3rem; align-items: start; padding-bottom: 3rem;
}
@media (max-width: 860px) { .request-layout { grid-template-columns: 1fr; } }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem; }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }

/* A currency mark tucked inside the budget field. */
.prefixed { position: relative; }
.prefixed i {
  position: absolute; left: 0.65rem; top: 50%; transform: translateY(-50%);
  font-style: normal; color: var(--muted);
}
.prefixed input { padding-left: 1.7rem !important; }

/* Also defined in manage.css, but the public pages do not load that file. */
.hint { color: var(--muted); font-size: 0.82rem; margin: 0.3rem 0 0; }

.steps { margin: 0; padding-left: 1.1rem; display: grid; gap: 0.6rem; font-size: 0.92rem; }
.steps li { color: var(--muted); }
.steps b { color: var(--text); font-weight: 600; }

ul.plain { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
ul.plain li { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.92rem; }
ul.plain .dim { color: var(--muted); }

/* =====================================================================
   Shopfront layer
   ---------------------------------------------------------------------
   Everything below is scoped to body.shop, which only base.html sets. The
   back office loads this file too, for the tokens and the buttons, and must
   not change shape when the shopfront does.

   The palette is the one above, untouched. What changes here is type,
   shape, spacing and motion.
   ===================================================================== */

.shop {
  --font: "Satoshi", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --display: "Cabinet Grotesk", "Satoshi", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  /* A soft violet for section headings, lighter on dark and deeper on light. */
  --ink-2: color-mix(in srgb, var(--accent-2) 70%, var(--text));
  /* The gap between chapters of the home page. */
  --section: clamp(5rem, 11vw, 10rem);
  --glass: color-mix(in srgb, var(--bg-elev) 72%, transparent);
  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);

  font-size: 16px;
  /* Two faint blooms at the top of the page, over the flat ground. */
  background:
    radial-gradient(60rem 40rem at 88% -12%, var(--glow-b), transparent 70%),
    radial-gradient(52rem 36rem at -12% 6%, var(--glow-a), transparent 70%),
    var(--bg);
  background-repeat: no-repeat;
}

/* Film grain over everything, so the large dark areas read as a surface and
   not as an empty screen. Under the photo viewer (z-index 100), and never in
   the way of a click. */
.shop::before {
  content: ""; position: fixed; inset: 0; z-index: 90; pointer-events: none;
  opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.shop .page { display: block; overflow-x: clip; }

/* The big headings break into even lines instead of leaving one word on its own. */
.hero h1, .why-head h2, .cta-band h2, .page-hero h1, .shop .detail h1 { text-wrap: balance; }

.shop h1, .shop h2, .shop h3,
.shop .brand-word .lead,
.shop .price .now,
.shop .buy-box .amount,
.shop .errpage-code { font-family: var(--display); }

/* --- Floating pill header -------------------------------------------- */

.shop .site-header {
  position: sticky; top: 0; z-index: 20;
  padding-top: 0.75rem;
  background: none; border: 0; backdrop-filter: none;
}
.shop .site-header .wrap {
  position: relative;
  padding: 0.4rem 0.45rem 0.4rem 0.85rem;
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: 999px;
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  box-shadow: 0 18px 40px -24px rgba(0, 0, 0, 0.7);
}
/* The crest is the brand: it gets the most room the pill can give it. */
.shop .brand-badge { width: 50px; height: 50px; }
.shop .brand-logo { height: 48px; max-width: 50px; }
.shop .site-nav { gap: 0.2rem; }
.shop .site-nav a {
  padding: 0.5rem 0.9rem; border-radius: 999px;
  color: var(--muted); font-weight: 500;
  transition: background 0.25s ease, color 0.25s ease;
}
.shop .site-nav a:hover { background: var(--bg-elev-2); color: var(--text); }
.shop .site-nav .staff-link { border-color: var(--line); }
.shop .theme-toggle { width: 40px; height: 40px; }

/* --- Buttons ---------------------------------------------------------- */

.shop .btn {
  border-radius: 999px; padding: 0.6rem 1.15rem;
  transition: transform 0.35s var(--ease-out), border-color 0.25s ease,
              background 0.25s ease, box-shadow 0.35s ease, color 0.25s ease;
}
.shop .btn:hover { transform: translateY(-2px); }
.shop .btn-lg { padding: 0.85rem 1.5rem; font-size: 1rem; }
.shop .btn-primary { box-shadow: 0 12px 30px -14px var(--accent); }
.shop .btn-primary:hover { box-shadow: 0 18px 40px -14px var(--accent); }
.shop .pager .is-off:hover { transform: none; border-color: var(--line); }
.shop .btn.fb-link { background: var(--bg-elev-2); color: var(--text); border: 1px solid var(--line-strong); }
.shop .btn.fb-link:hover { border-color: var(--accent); color: var(--accent); }
.shop .btn.fb-link svg { width: 19px; height: 19px; }

/* --- Parts ticker ----------------------------------------------------- */

.marquee {
  overflow: hidden;
  padding-block: 1.5rem;
  border-block: 1px solid var(--line-soft);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-track {
  display: flex; width: max-content;
  animation: marquee 52s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-run { display: flex; flex: none; list-style: none; margin: 0; padding: 0; }
.marquee-run li {
  display: flex; align-items: center; gap: 2.6rem; padding-right: 2.6rem;
  font-family: var(--display, var(--font)); font-weight: 700;
  font-size: clamp(1.35rem, 2.8vw, 2.3rem); letter-spacing: -0.02em;
  white-space: nowrap; color: var(--muted);
}
.marquee-run li::after {
  content: ""; flex: none; width: 0.42em; height: 0.42em; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
}
/* Two identical runs, so moving by half the track lands exactly where it began. */
@keyframes marquee { to { transform: translateX(-50%); } }

@media (prefers-reduced-motion: reduce) {
  .marquee { -webkit-mask-image: none; mask-image: none; }
  .marquee-track { animation: none; width: auto; justify-content: center; }
  .marquee-run { flex-wrap: wrap; justify-content: center; row-gap: 0.4rem; }
  .marquee-run[aria-hidden="true"] { display: none; }
}

/* --- Catalogue page ---------------------------------------------------- */
/*
   The listings keep the original grid and cards (the .grid and .card rules
   further up). Only the page heading and the filter bar's shape are new.
*/

.page-hero { padding: clamp(2.5rem, 6vw, 4.5rem) 0 1.6rem; }
.page-hero h1 {
  margin: 0 0 0.7rem; font-weight: 800; line-height: 1;
  font-size: clamp(2.4rem, 5vw, 4rem); letter-spacing: -0.035em;
}
.page-hero p { margin: 0; color: var(--muted); }
.page-hero b { font-family: var(--display); font-size: 1.25rem; font-weight: 800; color: var(--accent); }

.shop .filters {
  margin: 0 0 1.8rem; padding: 0.7rem;
  background: var(--glass); border-color: var(--line);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
.shop .filters input[type="search"],
.shop .filters select {
  border-radius: 999px; padding: 0.6rem 1rem; min-height: 44px;
}
.shop .filters input[type="search"]:focus,
.shop .filters select:focus { outline: 2px solid var(--focus); outline-offset: 1px; }
.shop .filter-bar { padding-inline: 0.3rem; }
.shop .filters.js-filters.is-open .filter-bar { margin-bottom: 0.7rem; }

/* --- Photo stage ------------------------------------------------------- */
/*
   How a build photo sits in a fixed frame — the card square, the spotlight
   and the hero cards: it fills the frame (object-fit: cover), trimmed evenly
   from the centre, under a soft vignette that pulls the eye to the machine.
*/

.photo-stage { position: relative; overflow: hidden; isolation: isolate; background: var(--bg-elev-2); }
.photo-stage img {
  position: relative; z-index: 0; display: block;
  width: 100%; height: 100%; object-fit: cover; object-position: center;
}
.photo-stage::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(80% 75% at 50% 50%, transparent 60%, rgba(0, 0, 0, 0.28));
}
/* The card's corner scrim and labels stay above the photo. */
.card-media.photo-stage::after { z-index: 1; }
.card-media.photo-stage .badge,
.card-media.photo-stage .flash { z-index: 2; }

:root[data-theme="light"] .photo-stage::before { background: radial-gradient(80% 75% at 50% 50%, transparent 65%, rgba(0, 0, 0, 0.1)); }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .photo-stage::before { background: radial-gradient(80% 75% at 50% 50%, transparent 65%, rgba(0, 0, 0, 0.1)); }
}

/* A faint lit ground behind the listing page's gallery, seen only while a
   photo is still loading. */
.shop .gallery .frame {
  background: radial-gradient(70% 60% at 50% 45%, var(--glow-a), transparent 72%), var(--bg-elev-2);
}

/* --- Why buy here -------------------------------------------------------- */
/*
   A centred title and four promises on one lit panel, then three rows that
   alternate copy and picture — the layout of the reference Duc supplied. The
   headings take a soft violet, the brand's second accent.
*/

.why { padding-block: var(--section); }
.why-intro {
  padding: clamp(2.2rem, 4.5vw, 3.4rem) clamp(1.2rem, 3vw, 2.6rem);
  background: linear-gradient(180deg, var(--bg-elev), color-mix(in srgb, var(--bg-elev) 55%, var(--bg)));
  border: 1px solid var(--line-soft); border-radius: var(--radius);
}
.why-head { max-width: 46rem; margin: 0 auto clamp(2rem, 4vw, 3rem); text-align: center; }
.why-head h2 {
  margin: 0 0 0.6rem; font-weight: 800; line-height: 1.05; text-transform: uppercase;
  font-size: clamp(1.7rem, 3.4vw, 2.6rem); letter-spacing: 0.005em;
}
.why-head p {
  margin: 0; color: var(--accent); font-weight: 700;
  font-size: 0.8rem; letter-spacing: 0.08em; text-transform: uppercase;
}

.promises {
  list-style: none; margin: 0; padding: 0; text-align: center;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2rem 1.6rem;
}
.promises svg {
  width: 36px; height: 36px; margin-bottom: 0.85rem;
  fill: none; stroke: var(--text); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
}
.promises h3 {
  margin: 0 0 0.45rem; color: var(--ink-2);
  font-size: 1.1rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
}
.promises p { margin: 0 auto; max-width: 24ch; font-size: 0.9rem; color: var(--muted); }

.features { display: grid; gap: clamp(4rem, 9vw, 8rem); margin-top: clamp(4rem, 9vw, 7rem); }
.feature {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, 6vw, 6rem); align-items: center;
}
.feature.is-flipped .feature-copy { order: 2; }
.feature-copy { justify-self: center; max-width: 34rem; text-align: center; }
.feature-copy h3 {
  margin: 0 0 1rem; color: var(--ink-2); line-height: 1.05; text-transform: uppercase;
  font-size: clamp(1.8rem, 3.4vw, 2.6rem); font-weight: 800; letter-spacing: 0.005em;
}
.feature-copy p { margin: 0; color: var(--muted); line-height: 1.7; }
.feature-copy .btn { margin-top: 1.8rem; }

/* One fixed 4:3 landscape frame for every picture, whatever shape the file
   is: the photo fills it and is trimmed evenly from the centre, so the three
   rows always line up. 4:3 matches the landscape rows and the site's other
   framed media. The accent glow sits outside the frame as a soft shadow. */
.feature-media {
  position: relative; overflow: hidden; isolation: isolate;
  width: 100%; max-width: 560px; aspect-ratio: 4 / 3; justify-self: center;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-elev-2);
  box-shadow: 0 30px 70px -40px var(--accent-soft), 0 20px 50px -35px var(--glow-b);
}
.feature-media img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  transition: transform 0.7s ease-out;
}
/* A faint inner edge so bright photos still sit inside the frame. */
.feature-media::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border-radius: inherit; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.04), inset 0 -60px 80px -60px rgba(0, 0, 0, 0.45);
}
.feature:hover .feature-media img { transform: scale(1.05); }
/* No picture set yet: a quiet framed panel holds the space. */
.feature-media.is-empty {
  background: radial-gradient(60% 60% at 50% 50%, var(--glow-b), transparent 70%), var(--bg-elev);
}

@media (max-width: 860px) {
  .promises { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .feature { grid-template-columns: 1fr; gap: 1.8rem; }
  .feature.is-flipped .feature-copy { order: 0; }
  .feature-media { order: -1; }
}
@media (max-width: 460px) {
  .promises { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .feature-media img { transition: none; }
  .feature:hover .feature-media img { transform: none; }
}

/* --- Closing call to action ------------------------------------------ */

.cta-band {
  position: relative; isolation: isolate; overflow: clip;
  padding-block: var(--section); text-align: center;
  border-top: 1px solid var(--line-soft);
}
.cta-band::before {
  content: ""; position: absolute; inset: 0 -10%; z-index: -1; pointer-events: none;
  background:
    radial-gradient(42% 60% at 42% 55%, var(--glow-a), transparent 70%),
    radial-gradient(30% 46% at 66% 40%, var(--glow-b), transparent 70%);
}
.cta-band h2 {
  margin: 0 auto 1.4rem; max-width: 18ch;
  font-weight: 800; line-height: 0.98;
  font-size: clamp(2.6rem, 7vw, 6.2rem); letter-spacing: -0.045em;
}
.cta-band h2 .grad { padding-bottom: 0.08em; }
.cta-band p { margin: 0 auto 2.4rem; max-width: 48ch; font-size: 1.1rem; color: var(--muted); }
.cta-acts { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.8rem; }

/* --- Footer ------------------------------------------------------------ */

.shop .site-footer { margin-top: 0; padding: 3.5rem 0 3rem; border-top: 1px solid var(--line-soft); }
.site-footer .footer-grid {
  display: grid; gap: 2rem;
  grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr));
}
.footer-crest {
  display: block; width: 72px; height: auto; margin-bottom: 0.9rem;
  filter: drop-shadow(0 0 16px var(--accent-soft));
}
.footer-brand strong {
  font-family: var(--display); font-size: 1.6rem; font-weight: 800;
  letter-spacing: -0.02em; color: var(--text);
}
.footer-brand p { margin: 0.5rem 0 0; max-width: 38ch; }
.footer-col { display: flex; flex-direction: column; align-items: flex-start; gap: 0.55rem; min-width: 0; }
/* A long email address breaks rather than widening the page on a tablet. */
.footer-col a, .footer-col span { max-width: 100%; overflow-wrap: anywhere; }
.footer-col a { color: var(--muted); }
.footer-col a:hover { color: var(--text); text-decoration: none; }
.site-footer .footer-col .fb-link { margin-top: 0; }

/* --- Listing page -------------------------------------------------------- */

.shop .crumbs { padding-top: 2rem; }
.shop .detail h1 { font-size: clamp(2rem, 4vw, 3rem); font-weight: 800; line-height: 1.05; letter-spacing: -0.03em; }
.shop .gallery .frame { border-radius: var(--radius); }
.shop .panel { background: var(--glass); }
.shop .buy-box {
  top: 5.5rem;
  border: 1px solid transparent;
  background:
    linear-gradient(var(--bg-elev), var(--bg-elev)) padding-box,
    linear-gradient(140deg, var(--accent-line), var(--line) 40%, var(--line)) border-box;
  box-shadow: 0 30px 70px -40px var(--accent-soft);
}
.shop .buy-box .amount { font-size: 2.8rem; font-weight: 800; }
.shop .section-title {
  margin: clamp(3rem, 7vw, 5rem) 0 1.4rem;
  font-size: clamp(1.8rem, 3.6vw, 2.8rem); font-weight: 800; letter-spacing: -0.03em;
}
.shop .detail + .section-title + .grid { padding-bottom: var(--section); }

/* --- Policy pages ------------------------------------------------------ */
/*
   Shipping and refund policies: a single readable column of prose. Long, so
   the measure is capped and the headings carry the structure.
*/

.policy { max-width: 46rem; padding: 1.5rem 0 var(--section); }
.policy-head { margin-bottom: 1.6rem; }
.policy-head h1 {
  margin: 0 0 0.5rem; font-weight: 800; line-height: 1.02;
  font-size: clamp(2.2rem, 5vw, 3.4rem); letter-spacing: -0.035em;
}
.policy-date { margin: 0; color: var(--muted); font-size: 0.88rem; }
.policy-lede { margin: 0 0 2.2rem; font-size: 1.1rem; color: var(--text); }
.policy section { padding-top: 1.8rem; margin-top: 1.8rem; border-top: 1px solid var(--line-soft); }
.policy h2 {
  margin: 0 0 0.8rem; color: var(--ink-2);
  font-size: 1.35rem; font-weight: 700; letter-spacing: -0.01em;
}
.policy p, .policy li { color: var(--muted); line-height: 1.7; }
.policy p { margin: 0 0 0.9rem; }
.policy p:last-child { margin-bottom: 0; }
.policy ul, .policy ol { margin: 0 0 0.9rem; padding-left: 1.3rem; display: grid; gap: 0.35rem; }
.policy strong { color: var(--text); }
.policy-note { font-size: 0.9rem; }
.policy-callout {
  padding: 1.4rem 1.5rem; margin-bottom: 0.4rem;
  border: 1px solid var(--accent-line); border-radius: var(--radius);
  background: var(--accent-tint);
}
.policy-callout h2 { color: var(--text); font-size: 1.1rem; }
.policy-callout p { color: var(--text); }
.policy-table { width: 100%; border-collapse: collapse; margin: 0.4rem 0 1rem; font-size: 0.95rem; }
.policy-table th, .policy-table td {
  text-align: left; padding: 0.65rem 0.9rem 0.65rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.policy-table th { color: var(--text); font-weight: 600; font-size: 0.85rem; }
.policy-table td { color: var(--muted); }
.policy-table td:last-child { white-space: nowrap; color: var(--text); }

/* --- Custom build: the four steps as a horizontal accordion -------------- */

.h-accordion {
  list-style: none; margin: 0 0 2.4rem; padding: 0;
  display: flex; gap: 0.7rem; height: 15rem;
}
.slice {
  position: relative; flex: 1 1 0; min-width: 0; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 1.4rem 1.5rem;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: radial-gradient(120% 90% at 0% 100%, var(--glow-a), transparent 60%), var(--bg-elev);
  transition: flex-grow 0.7s var(--ease-out), border-color 0.3s ease;
}
.slice:nth-child(even) {
  background: radial-gradient(120% 90% at 100% 0%, var(--glow-b), transparent 60%), var(--bg-elev);
}
.slice::before {
  content: ""; position: absolute; top: 1.4rem; left: 1.5rem;
  width: 2.4rem; height: 3px; border-radius: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}
.slice:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.slice-title {
  font-family: var(--display); font-weight: 700; line-height: 1.1;
  font-size: 1.35rem; letter-spacing: -0.02em;
}
.slice p {
  margin: 0.6rem 0 0; max-width: 32ch; color: var(--muted); font-size: 0.95rem;
  /* Closed slices give the paragraph no height, so every title sits on the
     same baseline whatever its text would wrap to. */
  max-height: 0; overflow: hidden;
  opacity: 0; transform: translateY(8px);
  transition: max-height 0.6s ease, opacity 0.45s ease 0.1s, transform 0.45s ease 0.1s;
}
/* The first slice is open until the pointer or focus picks another. */
.h-accordion:not(:hover):not(:focus-within) .slice:first-child,
.slice:hover, .slice:focus-within { flex-grow: 2.6; border-color: var(--accent-line); }
.h-accordion:not(:hover):not(:focus-within) .slice:first-child p,
.slice:hover p, .slice:focus-within p { max-height: 8rem; opacity: 1; transform: none; }

@media (max-width: 860px) {
  .h-accordion { flex-direction: column; height: auto; }
  .slice { padding-top: 3rem; }
  .slice p { max-height: none; opacity: 1; transform: none; }
}

/* --- Error page ---------------------------------------------------------- */

.shop .errpage h1 { font-weight: 800; letter-spacing: -0.03em; }

/* --- Phone --------------------------------------------------------------- */

@media (max-width: 640px) {
  .shop { --section: clamp(3.5rem, 14vw, 5rem); }
  .shop .site-header { padding-top: 0.5rem; }
  .shop .site-header .wrap { padding: 0.35rem 0.35rem 0.35rem 0.7rem; }

  /* The open menu drops out of the pill as its own rounded panel. */
  .shop .site-header.js-nav .site-nav {
    top: calc(100% + 0.5rem); padding: 0.4rem;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--bg-elev); overflow: hidden;
  }
  .shop .site-header.js-nav .site-nav a { border-radius: var(--radius-sm); border-bottom: 0; }
  .shop .menu-toggle { border-radius: 999px; }

  /* Get a listing on screen quickly: no paragraph, no floating photo — the
     first card below is the same machine anyway. */
  .hero { padding: 1.8rem 0 2rem; }
  .hero h1 { font-size: clamp(2.1rem, 9vw, 2.6rem); }
  .hero .eyebrow { margin-bottom: 1rem; font-size: 0.62rem; letter-spacing: 0.08em; padding: 0.35rem 0.7rem 0.35rem 0.6rem; }
  .hero-acts { margin-top: 1.4rem; }
  .hero-lede { display: none; }
  .hero-acts .btn { flex: 1 1 auto; justify-content: center; text-align: center; }
  .hero-acts .btn-lg { padding: 0.75rem 1.1rem; font-size: 0.95rem; }

  .marquee { padding-block: 1rem; }
  .shop .filters { padding: 0.5rem; }

  .cta-acts .btn { flex: 1 1 100%; justify-content: center; }
  .site-footer .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-brand { grid-column: 1 / -1; }
}

@media (prefers-reduced-motion: reduce) {
  .shop .btn, .slice, .slice p, .shop .site-nav a { transition: none; }
  .shop .btn:hover { transform: none; }
}
