/* ==========================================================================
   TR1N1TY — ASCENSION (Variant 4)
   Obsidian, monochrome glass, and a photographic garment scroll film.
   Unbounded display · Figtree body · Chivo Mono labels.
   ========================================================================== */

@font-face {
  font-family: "Unbounded";
  src: url("../assets/fonts/unbounded/Unbounded-Variable.ttf") format("truetype");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: "Figtree";
  src: url("../assets/fonts/figtree/Figtree-Variable.ttf") format("truetype");
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
}

@font-face {
  font-family: "Chivo Mono";
  src: url("../assets/fonts/chivo-mono/ChivoMono-Variable.ttf") format("truetype");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

/* ---------- theme tokens ----------
   Dark is the origin design and stays the default. Light is a full
   re-theme layered on top via :root[data-theme="light"] below — every
   themeable colour resolves through one of these tokens, so the override
   block is the single place light mode is defined.

   Two categories deliberately do NOT theme:
   1. Ink printed ON the white garment (the chest print-demo, the brand
      mark's cross). That fabric is white in both themes, so its ink stays
      dark — theming it would make it vanish against the garment.
   2. Anything inside .xp, the hero film. See the dark-island block below. */
:root {
  --void: #07070b;
  --void-2: #0b0b12;
  --glass: rgba(255, 255, 255, 0.045);
  --glass-2: rgba(255, 255, 255, 0.08);
  --stroke: rgba(255, 255, 255, 0.1);
  --stroke-2: rgba(255, 255, 255, 0.18);
  --text: #f4f4fa;
  --dim: #a2a2b5;
  --faint: #63636f;
  --teal: #e8ebf1;   /* silver — the single accent (legacy token name kept) */
  --on-accent: #0b0b10;
  --tile: #ffffff;

  /* surfaces that were hardcoded before light mode existed */
  --header-bg: rgba(10, 10, 16, 0.55);
  --header-bg-scrolled: rgba(10, 10, 16, 0.82);
  --header-shadow: 0 14px 44px rgba(0, 0, 0, 0.5);
  --panel: rgba(10, 10, 16, 0.6);
  --panel-strong: rgba(10, 10, 16, 0.85);
  --footer-bg: rgba(5, 5, 9, 0.75);
  --accent-text: #ffffff;
  --accent-glow: rgba(255, 255, 255, 0.35);
  --scrim: #07070b;            /* text-shadow halo behind hero copy */
  --checker-bg: #121219;       /* transparency-grid backdrop */
  --tile-edge: transparent;    /* white tiles need no edge on dark */
  /* iOS paints its own grey box over anything tapped. Toned to the surface
     rather than set to transparent: killing it outright would leave taps with
     no feedback at all, since these controls carry :hover states, not :active. */
  --tap-highlight: rgba(255, 255, 255, 0.1);

  /* Chips that sit over PHOTOGRAPHY or the transparency grid rather than
     over the page ground. What's behind them isn't theme-controlled, so
     these stay a dark scrim with light text in BOTH themes — theming them
     would flip the text dark over a still-dark scrim. Deliberately absent
     from the light override block below. */
  --chip-bg: rgba(10, 10, 16, 0.72);
  --chip-text: #f4f4fa;

  --font-d: "Unbounded", "Arial Black", sans-serif;
  --font-b: "Figtree", "Helvetica Neue", sans-serif;
  --font-m: "Chivo Mono", "Courier New", monospace;

  --r: 18px;
  --r-s: 12px;
  --pad: clamp(1.25rem, 4vw, 3.5rem);
  --max: 1320px;
  --ease: cubic-bezier(0.25, 1, 0.35, 1);

  /* Header geometry as tokens, because the hero's framing has to know where
     the header ends before it can place the garment under it. --nav-h is
     enforced as a min-height on .nav rather than left to whatever the tallest
     control happens to be, so --hdr-bottom is a fact rather than a guess —
     the hit-area work below deliberately grows targets with pseudo-elements,
     which cost no layout height and so cannot invalidate this. */
  --hdr-top: max(0.9rem, env(safe-area-inset-top));
  /* 3.8rem clears the tallest thing the bar ever holds — the desktop Store
     button, whose content box comes to 59.9px — so .nav lands on exactly this
     height at every breakpoint and --hdr-bottom is arithmetic rather than an
     estimate. At 3.6rem the button won on desktop and the token ran 2.3px
     short of the real header. */
  --nav-h: 3.8rem;
  --hdr-bottom: calc(var(--hdr-top) + var(--nav-h) + 2px); /* +2px: the header's hairline */
}

/* Set by theme.js for one frame around a theme swap — see the comment in
   that file for why this is required and not just a polish detail. */
:root.theme-switching,
:root.theme-switching *,
:root.theme-switching *::before,
:root.theme-switching *::after {
  transition: none !important;
}

/* ---------- theme toggle ----------
   Shows the icon of the theme it will switch TO, which is the convention
   users read fastest: a sun while dark (click for light), a moon while
   light (click for dark). */
.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  border: 1px solid var(--stroke-2);
  color: var(--text);
  background: var(--glass);
  flex: none;
  transition: border-color .2s, background .2s, color .2s;
}
.theme-toggle:hover { border-color: var(--text); background: var(--glass-2); }
.theme-toggle svg { width: 17px; height: 17px; display: block; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }

/* White surfaces need a hairline in light mode or they dissolve into the
   page ground. --tile-edge is transparent in dark, where the contrast
   against #07070b already defines the shape. */
.card-media,
.story-fig,
.gallery-main,
.gallery-thumbs button { box-shadow: inset 0 0 0 1px var(--tile-edge); }

/* ---------- light theme ----------
   Not a naive inversion. The page ground is a soft off-white rather than
   pure #fff so the white product tiles and the white brand patch still
   read as objects sitting on a surface instead of dissolving into it —
   and --tile-edge gives them a hairline for the same reason. The silver
   accent has to become near-black here: #e8ebf1 on a light ground is
   ~1.1:1, invisible. */
:root[data-theme="light"] {
  --void: #f4f4f7;
  --void-2: #ffffff;
  --glass: rgba(11, 11, 18, 0.035);
  --glass-2: rgba(11, 11, 18, 0.07);
  --stroke: rgba(11, 11, 18, 0.12);
  --stroke-2: rgba(11, 11, 18, 0.22);
  --text: #101015;
  --dim: #4c4c5a;
  /* Measured, not guessed: #75757f gave 4.42:1 on the footer ground and
     4.21:1 on the slightly darker card ground — both under the 4.5 AA
     floor. #66666f clears both (≈4.8 on cards, ≈5.5 on the footer). */
  --faint: #66666f;
  --teal: #14141a;
  --on-accent: #ffffff;
  --tile: #ffffff;

  --header-bg: rgba(255, 255, 255, 0.72);
  --header-bg-scrolled: rgba(255, 255, 255, 0.9);
  --header-shadow: 0 10px 30px rgba(11, 11, 18, 0.1);
  --panel: rgba(255, 255, 255, 0.78);
  --panel-strong: rgba(255, 255, 255, 0.93);
  --footer-bg: rgba(255, 255, 255, 0.66);
  --accent-text: #05050a;
  --accent-glow: rgba(11, 11, 18, 0.13);
  --scrim: #07070b;            /* still dark: it haloes copy over the dark hero */
  --checker-bg: #ececef;
  --tile-edge: rgba(11, 11, 18, 0.1);
  --tap-highlight: rgba(11, 11, 18, 0.08);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  font-family: var(--font-b);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--text);
  background: var(--void);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* aurora atmosphere */
.aurora {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.aurora::before, .aurora::after { content: none; }

::selection { background: var(--teal); color: var(--void); }

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; }

/* ---------- type helpers ---------- */
.display {
  font-family: var(--font-d);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.01em;
}

/* The heading accent. In dark it's pure white against near-white body copy —
   brighter than its surroundings is what makes it read as emphasis. That
   inverts in light mode: it has to be DARKER than body copy instead, or it
   would be white-on-white and vanish. */
.grad-text { color: var(--accent-text); text-shadow: 0 0 26px var(--accent-glow); }

.mono {
  font-family: var(--font-m);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.mono-dim { color: var(--dim); }

/* ---------- layout ---------- */
.wrap {
  max-width: var(--max);
  margin: 0 auto;
  padding-left: max(var(--pad), env(safe-area-inset-left));
  padding-right: max(var(--pad), env(safe-area-inset-right));
}

.section { padding: clamp(4rem, 8vw, 7rem) 0; position: relative; }

.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: clamp(1.8rem, 4vw, 3rem);
}
.section-head .mono { color: var(--teal); display: block; margin-bottom: 0.7rem; }
.section-head h2 { font-family: var(--font-d); font-weight: 700; font-size: clamp(1.5rem, 3.6vw, 2.4rem); line-height: 1.1; }
.section-head .side a {
  font-family: var(--font-m);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  border-bottom: 1px solid var(--stroke-2);
  padding-bottom: 2px;
  white-space: nowrap;
  transition: color .2s, border-color .2s;
}
.section-head .side a:hover { color: var(--teal); border-color: var(--teal); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.95rem 1.9rem;
  font-family: var(--font-m);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  background: var(--glass);
  border: 1px solid var(--stroke-2);
  border-radius: 999px;
  backdrop-filter: blur(10px);
  transition: background 0.25s, border-color 0.25s, color 0.25s, transform 0.15s, box-shadow 0.3s;
}
.btn:hover { background: var(--glass-2); border-color: rgba(255, 255, 255, 0.35); transform: translateY(-1px); }
.btn:active { transform: translateY(1px); }

.btn-teal { background: var(--teal); border-color: var(--teal); color: var(--on-accent); font-weight: 700; }
.btn-teal:hover { background: #ffffff; border-color: #ffffff; box-shadow: 0 8px 34px rgba(255, 255, 255, 0.22); }

.btn-block { width: 100%; }

/* ==========================================================================
   HEADER — floating glass bar
   ========================================================================== */
.site-header {
  position: fixed;
  top: var(--hdr-top);
  left: 50%;
  transform: translateX(-50%);
  width: min(
    var(--max),
    calc(100% - 2rem - env(safe-area-inset-left) - env(safe-area-inset-right))
  );
  z-index: 900;
  border-radius: 999px;
  background: var(--header-bg);
  border: 1px solid var(--stroke);
  backdrop-filter: blur(18px);
  transition: background 0.3s, box-shadow 0.3s;
}
body.scrolled .site-header { background: var(--header-bg-scrolled); box-shadow: var(--header-shadow); }

.nav {
  display: flex;
  align-items: center;
  gap: 1.8rem;
  min-height: var(--nav-h);
  padding: 0.7rem 1.4rem;
}

.brand { display: flex; align-items: center; gap: 0.7rem; margin-right: auto; }
/* The mark is the garment: a white patch with a black cross, the same
   thing the hero presses onto the chest.

   The cross is drawn rather than typed. The markup carries a † for the
   no-CSS case, but a dagger glyph is a different shape in every fallback
   font — tapered, off-centre, and never the flat-footed Latin cross on the
   hoodie. Two bars give the real proportions: 11x19 in a 32 badge, matching
   the garment's 32x56 chest cross, with the arm 36% down from the top on
   both. font-size:0 suppresses the glyph; the span is aria-hidden, and the
   brand link is labelled, so nothing is lost to a screen reader. */
.brand-mark {
  position: relative;
  width: 32px; height: 32px;
  border-radius: 10px;
  background: #ffffff;
  /* The inset hairline is what keeps this white patch from dissolving into
     a light header; --tile-edge is transparent in dark mode, where the drop
     shadow alone already separates it. */
  box-shadow: 0 1px 10px rgba(0, 0, 0, 0.45), inset 0 0 0 1px var(--tile-edge);
  font-size: 0;
  flex: none;
}
.brand-mark::before,
.brand-mark::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background: #0b0b10;
}
.brand-mark::before {          /* upright */
  width: 3.5px;
  height: 19px;
  transform: translate(-50%, -50%);
}
.brand-mark::after {           /* arm, raised off centre to sit Latin */
  width: 11px;
  height: 3.5px;
  transform: translate(-50%, calc(-50% - 2.7px));
}
.brand-text {
  font-family: var(--font-d);
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
}
.brand-text .one { color: var(--teal); }

.nav-links { display: flex; gap: 1.5rem; }
.nav-dropdown { position: relative; }
.nav-dropdown::after {
  content: "";
  position: absolute;
  top: 100%;
  left: -0.5rem;
  right: -0.5rem;
  height: 0.7rem;
}
.nav-dropdown-trigger { display: inline-flex; align-items: center; gap: 0.35rem; }
.nav-dropdown-chevron { color: var(--teal); font-size: 0.95em; line-height: 1; transform: translateY(-0.08em); }
.nav-dropdown-menu {
  position: absolute;
  top: calc(100% + 0.7rem);
  left: 50%;
  min-width: 14.5rem;
  transform: translate(-50%, -0.45rem);
  padding: 0.45rem;
  background: var(--void-2);
  border: 1px solid var(--stroke);
  border-radius: var(--r-s);
  box-shadow: 0 16px 38px rgba(0, 0, 0, 0.42);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.2s, visibility 0.2s, transform 0.2s var(--ease);
  z-index: 10;
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translate(-50%, 0);
}
.nav-dropdown-menu a {
  display: block;
  padding: 0.65rem 0.75rem;
  border-radius: calc(var(--r-s) - 2px);
  color: var(--dim);
  font-size: 0.78rem;
  line-height: 1.35;
  white-space: nowrap;
}
.nav-dropdown-menu a:hover,
.nav-dropdown-menu a:focus-visible { color: var(--text); background: var(--glass-strong); }
.nav-links a {
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--dim);
  position: relative;
  padding: 0.3rem 0;
  transition: color 0.2s;
}
.nav-links a:hover, .nav-links a[aria-current="page"] { color: var(--text); }
.nav-links a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 50%; bottom: -3px;
  transform: translateX(-50%);
  width: 16px; height: 2px;
  border-radius: 2px;
  background: var(--teal);
}

.nav-cta { display: flex; align-items: center; gap: 0.9rem; }
.nav-cta .btn { padding: 0.55rem 1.15rem; }

.nav-burger { display: none; flex-direction: column; gap: 5px; padding: 0.5rem; }
.nav-burger span { width: 22px; height: 2px; border-radius: 2px; background: var(--text); transition: transform .3s, opacity .3s; }
body.nav-open .nav-burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
body.nav-open .nav-burger span:nth-child(2) { opacity: 0; }
body.nav-open .nav-burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ==========================================================================
   THE EXPERIENCE — pinned 3D scroll film
   ========================================================================== */
/* Scroll length of the cinematic hero. 280vh so the rotation can finish
   early (see ROTATION_ENDS_AT) and the closing chapters still get a long,
   unhurried hold on the settled front-facing frame. */
/* ---------- the hero is a dark island in both themes ----------
   The garment in the frame sequence is a WHITE hoodie on transparency.
   On a light ground it would be white-on-white — the entire film would
   vanish. So the hero keeps the dark palette regardless of theme, and
   paints its own ground rather than relying on body's.

   Redeclaring the tokens here rather than writing .xp-specific rules
   means every descendant — chapters, colorway HUD, progress rail,
   scroll hint, the print demo — inherits the dark values automatically
   and needs no light-mode special-casing of its own. */
.xp {
  --void: #07070b;
  --void-2: #0b0b12;
  --glass: rgba(255, 255, 255, 0.045);
  --glass-2: rgba(255, 255, 255, 0.08);
  --stroke: rgba(255, 255, 255, 0.1);
  --stroke-2: rgba(255, 255, 255, 0.18);
  --text: #f4f4fa;
  --dim: #a2a2b5;
  --faint: #63636f;
  --teal: #e8ebf1;
  --on-accent: #0b0b10;
  --panel: rgba(10, 10, 16, 0.6);
  --panel-strong: rgba(10, 10, 16, 0.85);
  --checker-bg: #121219;
  --accent-text: #ffffff;
  --accent-glow: rgba(255, 255, 255, 0.35);
  --tap-highlight: rgba(255, 255, 255, 0.1);

  position: relative;
  height: 280vh;
  background: var(--void);
  color: var(--text);
}

.xp-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}

/* The canvas always covers the whole stage. How much of it the garment is
   allowed to occupy is set by these four variables, applied as `inset` on
   .xp-fit. Canvas is a replaced element, so JS has to do its contain-fit in
   the draw call — but it measures .xp-fit rather than re-deriving the box
   from these values, which matters for two reasons:

     1. One box, not two. The poster used to mirror the inset via `padding`,
        and percentage padding resolves against WIDTH on all four sides while
        the JS resolved top/bottom against HEIGHT. At 375x635 that put the
        poster's hoodie 50.7px below the canvas's, so the garment visibly
        jumped the instant the sequence took over.
     2. Any unit works. Measuring an element means these can be rem, px,
        svh, calc() or env() — which is what lets --fit-top below be stated
        as "clear the header", the one thing a percentage cannot express. */
/* Every frame carries transparent headroom above the garment — 8.5% of the
   square at its tallest, measured across all 49 frames of the phone set — so
   the hood already sits below the top of the fit box on its own. --fit-top
   only has to make up whatever that headroom leaves short of the header.
   The svh term restates that headroom against viewport height: on a tall
   screen it covers the whole gap and max() picks the plain 2%, while on a
   short laptop (1366x768 was clipping the hood by half a pixel, 1440x720 by
   five) it insets exactly the shortfall instead of a flat, wasteful margin. */
.xp-stage {
  --fit-top: max(2%, calc(var(--hdr-bottom) + 0.5rem - 6svh));
  --fit-right: 4%;
  --fit-bottom: 9%;
  --fit-left: 4%;
}
#hero-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 2;
}
.xp-fit {
  position: absolute;
  inset: var(--fit-top) var(--fit-right) var(--fit-bottom) var(--fit-left);
}

/* --- depth treatment -------------------------------------------------
   The garment frames are transparent, so the sense of a real object
   floating in the studio comes from CSS underneath and behind it:
   an ambient glow behind, a soft contact shadow below. Neither touches
   the source frames. */
.hero-glow {
  position: absolute;
  left: 50%;
  top: 46%;
  width: min(78vmin, 780px);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(255, 255, 255, 0.085) 0%,
    rgba(255, 255, 255, 0.035) 42%,
    transparent 68%
  );
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.8s var(--ease);
}
body.hero-ready .hero-glow,
body.hero-static .hero-glow { opacity: 1; }

/* --- responsive framing ----------------------------------------------
   Desktop has room for the garment and side-anchored copy. Tablet and
   phone shrink the canvas box and move every chapter into the lower
   band, so text never sits on top of the hood, sleeves or waistband. */
@media (max-width: 1100px) {
  .xp-stage { --fit-top: max(1%, calc(var(--hdr-bottom) + 0.5rem - 6svh)); --fit-right: 4%; --fit-bottom: 13%; --fit-left: 4%; }
  .hero-glow { top: 43%; width: min(84vmin, 620px); }
  .hero-shadow { bottom: 14%; width: min(50vmin, 360px); }
}

/* Phone and tablet put the copy in a reserved lower band, which makes the box
   short enough that the garment is height-constrained — there is no letterbox
   slack left to absorb the header, so --fit-top states the clearance outright
   rather than going through the max() the wider breakpoints use. */
@media (max-width: 900px) {
  .xp-stage { --fit-top: calc(var(--hdr-bottom) + 0.6rem); --fit-right: 4%; --fit-bottom: 35%; --fit-left: 4%; }
  .hero-glow { top: 33%; width: min(88vmin, 520px); }
  .hero-shadow { bottom: 35%; width: min(54vmin, 300px); height: min(6vmin, 42px); }

  /* all copy drops into the lower band, below the garment */
  .xp-stage .chapter {
    top: auto;
    bottom: max(6svh, calc(env(safe-area-inset-bottom) + 0.75rem));
    left: max(var(--pad), env(safe-area-inset-left));
    right: max(var(--pad), env(safe-area-inset-right));
    max-width: none;
    text-align: left;
    transform: none;
  }
  .xp-stage .chapter p { margin-left: 0; max-width: none; }
  .xp-stage .ch-4 {
    left: max(var(--pad), env(safe-area-inset-left));
    right: max(var(--pad), env(safe-area-inset-right));
    top: auto;
    bottom: max(6svh, calc(env(safe-area-inset-bottom) + 0.75rem));
    width: auto;
    max-width: none;
    text-align: left;
  }
  .xp-stage .ch-4 p { margin-left: 0; margin-right: 0; }
  .xp-stage .ch-4 .actions { justify-content: flex-start; }
  /* The intro copy already says "Keep scrolling" and the progress rail stays
     visible. Removing the duplicate hint keeps it off compact-phone copy. */
  .xp-stage .scroll-hint { display: none; }
}

@media (max-width: 640px) {
  /* Same choreography — every chapter window is a fraction of the section —
     just less absolute thumb-scrolling to get through it. */
  .xp { height: 240vh; }
  /* 38% rather than 39%: with the header clearance now taken off the top, the
     bottom reserve is what keeps the waistband clear of chapter copy. Checked
     against a 375x635 stage — a real iPhone's small viewport height, which is
     ~180px shorter than the 812 a desktop emulator reports — where the tallest
     chapter leaves the least room. */
  .xp-stage { --fit-top: calc(var(--hdr-bottom) + 0.6rem); --fit-right: 2%; --fit-bottom: 38%; --fit-left: 2%; }
  /* The verse makes the closing card taller; tighten it here so the card
     stays in the lower band instead of climbing over the waistband. */
  .xp-stage .ch-4 { padding: 1rem 1.1rem; }
  .xp-stage .ch-4 .ch-sub { font-size: 1.02rem; margin-top: 0.55rem; }
  .xp-stage .ch-4 .ch-verse { font-size: 0.85rem; line-height: 1.45; margin-top: 0.4rem; }
  .xp-stage .ch-4 .ch-ref { margin-top: 0.4rem; font-size: 0.63rem; }
  .hero-glow { top: 30%; }
  .hero-shadow { bottom: 39%; }
  .xp-stage .chapter,
  .xp-stage .ch-4 { bottom: max(4svh, calc(env(safe-area-inset-bottom) + 0.75rem)); }
}

.hero-shadow {
  position: absolute;
  left: 50%;
  bottom: 9%;
  width: min(46vmin, 430px);
  height: min(7vmin, 62px);
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(
    ellipse at center,
    rgba(0, 0, 0, 0.62) 0%,
    rgba(0, 0, 0, 0.34) 45%,
    transparent 72%
  );
  filter: blur(11px);
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.8s var(--ease);
}
body.hero-ready .hero-shadow,
body.hero-static .hero-shadow { opacity: 1; }

/* --- "your text here" print demo -------------------------------------
   Chapter 03 claims companies can put their own artwork on our blanks.
   This shows it: a placement box types itself onto the chest, just under
   the cross, while the settled front-facing frame holds.

   It is positioned from --art-x/y/w/h — the real drawn rect of the frame
   sequence, published by hero-sequence.js on every resize. Percentages of
   that rect are what weld it to the chest at every viewport, instead of
   percentages of the stage, which would drift off the garment whenever
   the contain-fit letterboxing changed.

   Measured against the source frames: the cross ends at 38.5% of frame
   height and the kangaroo pocket starts near 59%, so the box centres at
   45% with room either side. Fabric under it is solid and bright
   (lum 211+) across the full span, so multiply reads as ink, not sticker. */
.print-demo {
  position: absolute;
  z-index: 4;
  left: calc(var(--art-x, 0px) + var(--art-w, 0px) * 0.5);
  top: calc(var(--art-y, 0px) + var(--art-h, 0px) * 0.45);
  width: calc(var(--art-w, 0px) * 0.34);
  transform: translate(-50%, -50%) scale(0.94);
  opacity: 0;
  pointer-events: none;
  /* Multiply belongs here, not on .print-box: the transform above makes
     this element a stacking context, so a blend mode on a child would be
     isolated inside it and quietly do nothing. From here it blends against
     the canvas, letting the fleece shading fall across the ink. */
  mix-blend-mode: multiply;
  transition: opacity 0.45s var(--ease), transform 0.55s var(--ease);
}
body.hero-ready .print-demo.on {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

.print-box {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(var(--art-h, 0px) * 0.075);
  padding: 0.4em 0.75em;
  border: max(1px, calc(var(--art-w, 0px) * 0.0016)) dashed rgba(14, 14, 20, 0.34);
  border-radius: 3px;
}
.print-text {
  font-family: var(--font-d);
  font-weight: 700;
  font-size: max(9px, calc(var(--art-w, 0px) * 0.0285));
  line-height: 1;
  letter-spacing: 0.015em;
  color: #14141a;
  white-space: nowrap;
}
.print-caret {
  display: inline-block;
  width: 0.08em;
  height: 0.92em;
  margin-left: 0.1em;
  background: #14141a;
  vertical-align: -0.08em;
  animation: print-blink 1.05s steps(1, end) infinite;
}
@keyframes print-blink { 0%, 52% { opacity: 1; } 53%, 100% { opacity: 0; } }

/* Smaller garment, slightly larger relative print, so the demo stays
   readable on a phone without looking like an oversized press. */
@media (max-width: 900px) {
  .print-demo { width: calc(var(--art-w, 0px) * 0.4); }
  .print-text { font-size: max(9px, calc(var(--art-w, 0px) * 0.034)); }
}

@media (prefers-reduced-motion: reduce) {
  .print-caret { animation: none; }
  .print-demo { transition: none; }
}

.xp-poster {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--void);
  opacity: 1;
  transition: opacity 0.3s var(--ease);
  pointer-events: none;
}
.xp-poster img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
body.hero-ready .xp-poster {
  opacity: 0;
}

/* Fallback layouts hand the poster its own box, so the fit inset is dropped
   and the image fills that box instead. The canvas is display:none in all
   three, so nothing is reading .xp-fit's rect here. */
body.hero-static .xp-fit,
body.no3d .xp-fit,
html.no-js .xp-fit { position: static; inset: auto; display: block; height: 100%; }

/* Loading state — a designed brand moment, not a bare spinner on black.
   This is the hero's first paint, so it has to look intentional. */
.xp-loading {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 0.9rem;
  z-index: 0;
  transition: opacity 0.6s var(--ease);
}
body.has3d .xp-loading,
body.hero-ready .xp-loading,
body.hero-static .xp-loading,
body.no3d .xp-loading { opacity: 0; pointer-events: none; }

/* Reduced motion: the poster is the hero. No canvas, no sequence, no
   scroll scrubbing — every heading, button and link stays exactly as is. */
body.hero-static .xp { height: auto; }
body.hero-static .xp-stage {
  position: relative;
  height: auto;
  min-height: 88vh;
  padding: 7rem 0 3rem;
}
body.hero-static #hero-canvas,
body.hero-static .print-demo,
body.hero-static .rail,
body.hero-static .hud,
body.hero-static .scroll-hint { display: none; }
body.hero-static .xp-poster {
  position: relative;
  opacity: 1;
  height: min(62vh, 560px);
}
body.hero-static .chapter {
  position: static;
  opacity: 1 !important;
  transform: none !important;
  pointer-events: auto !important;
  max-width: 40rem;
  margin: 1.5rem auto 0;
  text-align: center;
  padding: 0 var(--pad);
}
body.hero-static .chapter:not(.ch-0):not(.ch-4) { display: none; }
body.hero-static .chapter .actions { justify-content: center; }

.loading-mark {
  font-size: 1.6rem;
  color: var(--teal);
  opacity: 0.9;
  animation: breathe 2.4s ease-in-out infinite;
}
.loading-word {
  font-family: var(--font-d);
  font-weight: 700;
  font-size: clamp(1.3rem, 3vw, 1.9rem);
  letter-spacing: 0.16em;
  color: var(--text);
}
.loading-word .one { color: var(--teal); }
.loading-note {
  font-family: var(--font-m);
  font-size: 0.58rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--faint);
}
.loading-bar {
  width: min(210px, 42vw);
  height: 2px;
  border-radius: 2px;
  background: var(--stroke);
  overflow: hidden;
  margin-top: 0.3rem;
}
.loading-bar i {
  display: block;
  width: 42%;
  height: 100%;
  border-radius: 2px;
  background: var(--teal);
  animation: sweep 1.5s var(--ease) infinite;
}
@keyframes breathe { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }
@keyframes sweep { 0% { transform: translateX(-110%); } 100% { transform: translateX(260%); } }

/* chapter overlays */
.chapter {
  position: absolute;
  z-index: 5;
  max-width: 30rem;
  opacity: 0;
  pointer-events: none;
}
.chapter .mono {
  color: var(--teal);
  display: block;
  margin-bottom: 0.9rem;
  text-shadow: 0 1px 5px #07070b, 0 0 16px #07070b;
}
.chapter h1, .chapter h2 {
  font-family: var(--font-d);
  font-weight: 700;
  font-size: clamp(1.8rem, 4.6vw, 3.4rem);
  line-height: 1.06;
  letter-spacing: -0.01em;
  text-shadow: 0 2px 7px #07070b, 0 0 22px #07070b;
}
.chapter p {
  color: #eeeeF4;
  margin-top: 1rem;
  font-size: 1.02rem;
  max-width: 26rem;
  text-shadow: 0 1px 4px #07070b, 0 0 12px #07070b, 0 0 28px #07070b;
}
.chapter .actions { display: flex; flex-wrap: wrap; gap: 0.9rem; margin-top: 1.8rem; }

.ch-0 { left: var(--pad); top: 22vh; }
.ch-0 h1 { font-size: clamp(2.2rem, 5.6vw, 4.2rem); }
.ch-1 { right: var(--pad); top: 24vh; text-align: right; }
.ch-1 p { margin-left: auto; }
.ch-2 { left: var(--pad); bottom: 20vh; }
.ch-3 { right: var(--pad); bottom: 24vh; text-align: right; }
.ch-3 p { margin-left: auto; }
.ch-4 {
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  width: min(36rem, calc(100vw - 2.5rem));
  max-width: 36rem;
  padding: clamp(1.25rem, 3vw, 2rem);
  background: rgba(7, 7, 11, 0.62);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  backdrop-filter: blur(8px);
}
.ch-4 p { margin-left: auto; margin-right: auto; }
.ch-4 .actions { justify-content: center; }

/* Closing card: the headline, then the verse it comes from. Ephesians 4:24
   runs as one continuous quotation across two lines — the phrase carries the
   emphasis at display size and the rest follows quieter beneath it. Nothing
   divides them: no rule between, a small gap, and both upright rather than
   half the sentence in italic, which would read as two voices.

   Scoped to .ch-4 rather than written as bare classes: both of these are
   <p> elements inside .chapter, and `.chapter p` (0,1,1) would otherwise
   out-specify a lone `.ch-sub` (0,1,0) and hand them all back the same
   body size and colour. */
.ch-4 .ch-sub {
  font-family: var(--font-d);
  font-weight: 600;
  font-size: clamp(1.05rem, 2.2vw, 1.45rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text);
  margin-top: 0.85rem;
  text-shadow: 0 2px 7px #07070b, 0 0 20px #07070b;
}
.ch-4 .ch-verse {
  margin-top: 0.45rem;
  font-size: 0.94rem;
  line-height: 1.5;
  color: var(--dim);
  max-width: 24rem;
}
/* Sets the mono face itself instead of carrying the .mono class, and states
   no colour. Both deliberate: .grad-text (0,1,0) is what glows this line the
   way "Tr1n1ty" and "new self" glow, and it loses to anything more specific.
   `.chapter .mono` (0,2,0) would have repainted it silver, and a colour
   declared here (0,2,0) would have killed the glow just as quietly. */
.ch-4 .ch-ref {
  display: block;
  margin-top: 0.55rem;
  font-family: var(--font-m);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* colorway HUD */
.hud {
  position: absolute;
  left: 50%;
  bottom: 7vh;
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  background: var(--panel);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  padding: 0.55rem 1.1rem;
  backdrop-filter: blur(12px);
  opacity: 0;
  pointer-events: none;
}
.hud .dot { width: 1rem; height: 1rem; border-radius: 50%; border: 1px solid var(--stroke-2); background: #181818; }
.hud .name { font-family: var(--font-m); font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; }
.hud .lbl { font-family: var(--font-m); font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); }

/* progress rail */
.rail {
  position: absolute;
  right: 1.6rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
}
.rail-track { position: relative; width: 2px; height: 26vh; background: var(--stroke); border-radius: 2px; overflow: hidden; }
.rail-fill { position: absolute; inset: 0; background: var(--teal); transform-origin: top; transform: scaleY(0); }
.rail-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--stroke-2); transition: background 0.3s, box-shadow 0.3s; }
.rail-dot.on { background: var(--teal); box-shadow: 0 0 10px rgba(255, 255, 255, 0.6); }

/* scroll hint */
.scroll-hint {
  position: absolute;
  left: 50%;
  bottom: 3vh;
  transform: translateX(-50%);
  z-index: 6;
  display: grid;
  justify-items: center;
  gap: 0.4rem;
  color: var(--dim);
  pointer-events: none;
}
.scroll-hint .chev {
  width: 18px; height: 18px;
  border-right: 2px solid var(--teal);
  border-bottom: 2px solid var(--teal);
  transform: rotate(45deg);
  animation: chev 1.6s ease-in-out infinite;
}
@keyframes chev { 0%, 100% { transform: translateY(0) rotate(45deg); opacity: 1; } 50% { transform: translateY(7px) rotate(45deg); opacity: 0.4; } }

/* 3D fallback (no WebGL / module failed) */
/* No sequence (module failed, WebP unsupported, or JS off): the poster IS the
   hero. It is already preloaded and discovered as plain HTML, so it is
   guaranteed to be on screen — no extra download, and nothing to lazy-load.
   An earlier separate fallback JPEG never appeared here, because loading="lazy"
   does not fire for an element that only becomes visible via a state class. */
body.no3d .xp,
html.no-js .xp { height: auto; }
body.no3d .xp-stage,
html.no-js .xp-stage { position: relative; height: auto; padding: 8.5rem 0 3rem; overflow: visible; }
body.no3d .xp-poster,
html.no-js .xp-poster {
  position: relative;
  opacity: 1;
  height: min(58vh, 520px);
  padding: 0;
  margin-bottom: 2rem;
}
body.no3d #hero-canvas,
body.no3d .hero-glow,
body.no3d .hero-shadow,
body.no3d .print-demo,
body.no3d .rail,
body.no3d .hud,
body.no3d .scroll-hint,
html.no-js #hero-canvas,
html.no-js .hero-glow,
html.no-js .hero-shadow,
html.no-js .print-demo,
html.no-js .xp-loading,
html.no-js .rail,
html.no-js .hud,
html.no-js .scroll-hint { display: none; }
body.no3d .chapter,
html.no-js .chapter {
  position: static;
  opacity: 1 !important;
  transform: none !important;
  pointer-events: auto !important;
  max-width: 40rem;
  margin: 0 auto 3rem;
  text-align: center;
  padding: 0 var(--pad);
}
body.no3d .chapter p,
html.no-js .chapter p { margin-left: auto; margin-right: auto; }
body.no3d .chapter .actions,
html.no-js .chapter .actions { justify-content: center; }
body.no3d .xp-fallback,
html.no-js .xp-fallback {
  display: block;
  max-width: 26rem;
  margin: 0 auto 3rem;
  border-radius: var(--r);
  overflow: hidden;
  border: 1px solid var(--stroke);
}
body.no3d .xp-fallback img,
html.no-js .xp-fallback img { width: 100%; }

/* ==========================================================================
   PRODUCT CARDS — glass
   ========================================================================== */
.grid-products {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(0.9rem, 1.8vw, 1.4rem);
}

.card {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  backdrop-filter: blur(10px);
  transition: transform 0.3s var(--ease), border-color 0.3s, box-shadow 0.35s var(--ease);
}
.card:hover {
  transform: translateY(-4px);
  border-color: rgba(255, 255, 255, 0.4);
  box-shadow: 0 22px 50px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.18), 0 10px 40px rgba(255, 255, 255, 0.06);
}

.card-media {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--tile);
}
.card-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;   /* the whole garment, always */
  padding: 5%;
  transition: opacity 0.4s var(--ease), transform 0.55s var(--ease);
}
.card-img.b { opacity: 0; }
.card:hover .card-img.b { opacity: 1; }
.card:hover .card-img.a { opacity: 0; }
.card:hover .card-img { transform: scale(1.02); }

.card-flag {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 2;
  font-family: var(--font-m);
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  background: var(--teal);
  color: var(--on-accent);
  font-weight: 700;
  padding: 0.28rem 0.55rem;
  border-radius: 999px;
}
.card-cat {
  position: absolute;
  bottom: 0.75rem;
  right: 0.75rem;
  z-index: 2;
  font-family: var(--font-m);
  font-size: 0.56rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  background: var(--chip-bg);
  color: var(--chip-text);
  padding: 0.26rem 0.55rem;
  border-radius: 999px;
  backdrop-filter: blur(6px);
}

.card-meta { padding: 1rem 1.1rem 1.15rem; display: grid; gap: 0.3rem; }
.card-name { font-weight: 700; font-size: 0.95rem; line-height: 1.35; }
.card-line { font-family: var(--font-m); font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); }
.card-price { margin-top: 0.35rem; font-size: 0.92rem; display: flex; align-items: baseline; gap: 0.55rem; }
.card-price s { color: var(--faint); font-weight: 400; }
.card-price b { font-weight: 700; }
.card-price .go { margin-left: auto; color: var(--teal); transition: transform 0.2s var(--ease); }
.card:hover .card-price .go { transform: translateX(4px); }

/* ==========================================================================
   VERSE BAND
   ========================================================================== */
.verse-band { text-align: center; }
.verse-band blockquote {
  font-family: var(--font-d);
  font-weight: 700;
  font-size: clamp(1.5rem, 4vw, 2.7rem);
  line-height: 1.2;
  max-width: 54rem;
  margin: 0 auto;
}
.verse-band .ref { display: inline-block; margin-top: 1.5rem; color: var(--dim); }

/* ==========================================================================
   STORY SPLIT
   ========================================================================== */
.story-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}
.story-fig {
  border-radius: var(--r);
  overflow: hidden;
  border: 1px solid var(--stroke);
  background: var(--tile);
  position: relative;
}
.story-fig img { width: 100%; aspect-ratio: 3 / 4; object-fit: contain; padding: 4%; }
.story-fig .plate {
  position: absolute;
  left: 1rem; bottom: 1rem;
  background: var(--chip-bg);
  border: 1px solid var(--stroke);
  color: var(--chip-text);
  border-radius: 999px;
  padding: 0.5rem 1rem;
  font-family: var(--font-m);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  backdrop-filter: blur(8px);
}
.story-copy h2 { font-family: var(--font-d); font-weight: 700; font-size: clamp(1.6rem, 3.8vw, 2.5rem); line-height: 1.12; margin: 0.9rem 0 1.2rem; }
.story-copy p { color: var(--dim); max-width: 36rem; }
.story-copy p + p { margin-top: 1rem; }
.story-facts { display: flex; gap: 2.4rem; margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid var(--stroke); }
.fact b { display: block; font-family: var(--font-d); font-weight: 700; font-size: 1.5rem; }
.fact b.grad-text { display: inline-block; }
.fact span { font-family: var(--font-m); font-size: 0.58rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); display: block; }

/* ==========================================================================
   CTA BAND
   ========================================================================== */
.cta-band { text-align: center; position: relative; overflow: hidden; }
.cta-glass {
  max-width: 56rem;
  margin: 0 auto;
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: calc(var(--r) * 1.6);
  padding: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 4vw, 3rem);
  backdrop-filter: blur(14px);
  position: relative;
  overflow: hidden;
}
.cta-glass::before { content: none; }
.cta-glass h2 { font-family: var(--font-d); font-weight: 700; font-size: clamp(1.7rem, 4.4vw, 3rem); line-height: 1.1; position: relative; }
.cta-glass p { color: var(--dim); margin: 1rem auto 2rem; max-width: 30rem; position: relative; }
.cta-glass .actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 1rem; position: relative; }

/* ==========================================================================
   FOOTER
   ========================================================================== */
.site-footer { border-top: 1px solid var(--stroke); background: var(--footer-bg); }
.footer-main {
  display: grid;
  grid-template-columns: 1.7fr 1fr 1fr 1.2fr;
  gap: clamp(2rem, 4vw, 4rem);
  padding: clamp(3rem, 6vw, 4.5rem) 0 2.5rem;
}
.footer-brand p { color: var(--dim); font-size: 0.94rem; margin-top: 1rem; max-width: 22rem; }
.footer-col h4 { font-family: var(--font-m); font-size: 0.6rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--faint); margin-bottom: 1rem; }
.footer-col ul { list-style: none; display: grid; gap: 0.5rem; }
.footer-col a { color: var(--dim); font-size: 0.94rem; transition: color .2s; }
.footer-col a:hover { color: var(--teal); }
.footer-col li { color: var(--dim); font-size: 0.94rem; }
.footer-bottom {
  border-top: 1px solid var(--stroke);
  padding: 1.3rem 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.8rem;
  font-family: var(--font-m);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
.footer-bottom .t { color: var(--teal); }
.footer-bottom .scripture-credit {
  flex: 1 0 100%;
  max-width: 72rem;
  line-height: 1.5;
  letter-spacing: 0.02em;
  text-transform: none;
}

/* ==========================================================================
   INNER PAGES
   ========================================================================== */
.page-head { padding-top: clamp(8.5rem, 16vh, 11rem); padding-bottom: clamp(1.6rem, 3vw, 2.4rem); }
.page-head .mono { color: var(--teal); display: block; margin-bottom: 1rem; }
.page-title { font-size: clamp(2.1rem, 5.4vw, 3.8rem); }
.page-sub { margin-top: 1.1rem; color: var(--dim); max-width: 42rem; font-size: 1.02rem; }

.catalog-bar {
  position: sticky;
  /* Derived from the header rather than hardcoded. The two hardcoded values
     this replaces (84px here, 76px at the 900px breakpoint) were measured
     against an older header; the mobile one already sat 6.8px behind it. */
  top: calc(var(--hdr-bottom) + 0.5rem);
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 0.7rem 1rem;
  margin-bottom: clamp(1.8rem, 3.5vw, 2.6rem);
  background: var(--panel);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  backdrop-filter: blur(14px);
}
.filters { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.filter-btn {
  padding: 0.5rem 1.05rem;
  font-family: var(--font-m);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
  border: 1px solid transparent;
  border-radius: 999px;
  transition: all 0.2s;
}
.filter-btn:hover { color: var(--text); border-color: var(--stroke-2); }
.filter-btn.active { background: var(--teal); color: var(--on-accent); font-weight: 700; }
.catalog-count { font-family: var(--font-m); font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); padding-right: 0.6rem; }

/* product page */
.product-layout {
  display: grid;
  grid-template-columns: 1.02fr 0.98fr;
  gap: clamp(2rem, 4.5vw, 4.5rem);
  padding-top: clamp(8rem, 15vh, 10.5rem);
  align-items: start;
}
.crumbs { display: flex; flex-wrap: wrap; gap: 0.5rem; font-family: var(--font-m); font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); margin-bottom: 1.2rem; }
.crumbs a:hover { color: var(--teal); }

.gallery { position: sticky; top: 7.5rem; }
.gallery-main {
  position: relative;
  border-radius: var(--r);
  border: 1px solid var(--stroke);
  background: var(--tile);
  aspect-ratio: 1;
  overflow: hidden;
}
.gallery-main img { width: 100%; height: 100%; object-fit: contain; padding: 4%; }
.gallery-main .card-flag { top: 1rem; left: 1rem; }
.gallery-thumbs { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0.5rem; margin-top: 0.6rem; }
.gallery-thumbs button {
  aspect-ratio: 1;
  border-radius: var(--r-s);
  border: 1px solid var(--stroke);
  background: var(--tile);
  padding: 0;
  overflow: hidden;
  transition: border-color .2s, box-shadow .2s;
}
.gallery-thumbs button.active, .gallery-thumbs button:hover { border-color: var(--teal); }
.gallery-thumbs button.active { box-shadow: 0 0 0 1px var(--teal), 0 0 16px rgba(255, 255, 255, 0.28); }
.gallery-thumbs img { width: 100%; height: 100%; object-fit: contain; padding: 8%; }

.pd-name { font-size: clamp(1.6rem, 3.4vw, 2.4rem); margin-top: 0.3rem; }
.pd-line { color: var(--dim); margin-top: 0.6rem; }

.pd-price { display: flex; align-items: baseline; gap: 0.9rem; margin: 1.2rem 0 0.4rem; }
.pd-price .now { font-family: var(--font-d); font-weight: 700; font-size: 1.7rem; }
.pd-price s { color: var(--faint); }
.pd-price .save { font-family: var(--font-m); font-size: 0.56rem; letter-spacing: 0.1em; text-transform: uppercase; background: var(--teal); color: var(--on-accent); font-weight: 700; padding: 0.26rem 0.6rem; border-radius: 999px; }

.pd-verse {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-left: 3px solid var(--teal);
  border-radius: var(--r-s);
  padding: 0.95rem 1.15rem;
  margin: 1.1rem 0 1.2rem;
}
.pd-verse .v { color: var(--text); font-style: italic; }
.pd-verse .r { font-family: var(--font-m); font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--teal); display: block; margin-top: 0.45rem; }

.pd-desc { color: var(--dim); }

.opt-group { margin-top: 1.5rem; }
.opt-label { display: flex; justify-content: space-between; font-family: var(--font-m); font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: 0.6rem; color: var(--dim); }
.opt-label .picked { color: var(--teal); }
.opt-values { display: flex; flex-wrap: wrap; gap: 0.45rem; }

.chip {
  border: 1px solid var(--stroke-2);
  background: var(--glass);
  color: var(--text);
  border-radius: 999px;
  padding: 0.45rem 0.85rem 0.45rem 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
  font-weight: 500;
  transition: border-color .2s, box-shadow .2s, background .2s;
}
.chip:hover { border-color: rgba(255, 255, 255, 0.4); }
.chip.active { border-color: var(--teal); box-shadow: 0 0 0 1px var(--teal), 0 0 14px rgba(255, 255, 255, 0.22); }
.chip .dot { width: 1.05rem; height: 1.05rem; border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.35); display: inline-block; flex: none; }
.chip.no-dot { padding: 0.45rem 0.95rem; }

.pd-ctas { display: grid; grid-template-columns: 1.2fr 0.8fr; gap: 0.8rem; margin-top: 1.8rem; }
.pd-note { margin-top: 1rem; font-size: 0.82rem; color: var(--faint); }

.acc { margin-top: 2rem; border-top: 1px solid var(--stroke-2); }
.acc details { border-bottom: 1px solid var(--stroke); }
.acc summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; align-items: center; padding: 1rem 0; font-family: var(--font-m); font-size: 0.64rem; letter-spacing: 0.14em; text-transform: uppercase; }
.acc summary::-webkit-details-marker { display: none; }
.acc summary::after { content: "+"; font-size: 1rem; color: var(--teal); transition: transform .25s; }
.acc details[open] summary::after { transform: rotate(45deg); }
.acc .acc-body { padding: 0 0 1.1rem; color: var(--dim); font-size: 0.92rem; }
.acc .acc-body ul { padding-left: 1.1rem; display: grid; gap: 0.4rem; }
.acc .acc-body a { color: var(--teal); }

.size-table { width: 100%; border-collapse: collapse; font-size: 0.84rem; margin-top: 0.3rem; }
.size-table th, .size-table td { border: 1px solid var(--stroke); padding: 0.45rem 0.65rem; text-align: center; color: var(--dim); }
.size-table th { font-family: var(--font-m); font-size: 0.56rem; letter-spacing: 0.1em; text-transform: uppercase; background: var(--glass); color: var(--dim); }
.size-table td:first-child { text-align: left; font-weight: 600; color: var(--text); }

.related { padding-bottom: clamp(4rem, 8vw, 6.5rem); }

/* about cards */
.pillars { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(0.9rem, 1.8vw, 1.4rem); }
.pillar {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  padding: clamp(1.5rem, 3vw, 2.2rem);
  backdrop-filter: blur(10px);
  transition: border-color .3s, transform .3s var(--ease);
}
.pillar:hover { border-color: rgba(255, 255, 255, 0.35); transform: translateY(-3px); }
.pillar .mono { color: var(--teal); display: block; margin-bottom: 0.6rem; }
.pillar h3 { font-family: var(--font-d); font-weight: 700; font-size: 1.15rem; margin-bottom: 0.5rem; }
.pillar p { color: var(--dim); font-size: 0.93rem; }

/* contact */
.contact-grid { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
.contact-card {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  padding: 1.4rem 1.6rem;
  backdrop-filter: blur(10px);
}
.contact-card + .contact-card { margin-top: 1rem; }
.contact-card .mono { display: block; margin-bottom: 0.35rem; color: var(--teal); }
.contact-card a.big, .contact-card p.big { font-family: var(--font-d); font-weight: 700; font-size: clamp(0.95rem, 2.1vw, 1.2rem); word-break: break-word; transition: color .2s; }
.contact-card a.big:hover { color: var(--teal); }

.form-panel {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: calc(var(--r) * 1.2);
  padding: clamp(1.6rem, 3.5vw, 2.6rem);
  backdrop-filter: blur(12px);
}
.form-panel h3 { font-family: var(--font-d); font-weight: 700; font-size: 1.35rem; margin-bottom: 0.4rem; }
.form-panel .lead { color: var(--dim); font-size: 0.92rem; margin-bottom: 1.4rem; }
.custom-design-form { margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--stroke); }
.upload-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.upload-card {
  display: flex; align-items: center; gap: 0.8rem; width: 100%; min-height: 4.2rem;
  padding: 0.7rem 0.8rem; border: 1px dashed var(--stroke-2); border-radius: var(--r-s);
  background: rgba(255, 255, 255, 0.035); cursor: pointer; transition: border-color .2s, background .2s, transform .2s;
}
.upload-card:hover, .upload-card:focus-within { border-color: var(--teal); background: rgba(63, 219, 197, 0.07); transform: translateY(-1px); }
.upload-icon { display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: 50%; background: var(--teal); color: var(--void); font-size: 1.4rem; line-height: 1; }
.upload-copy { display: grid; gap: 0.2rem; flex: 1; }
.upload-copy strong { font-size: 0.86rem; }
.upload-copy small { color: var(--dim); font-size: 0.72rem; }
.upload-action { padding: 0.45rem 0.7rem; border: 1px solid var(--stroke-2); border-radius: var(--r-s); color: var(--text); font-size: 0.72rem; font-weight: 600; }
.upload-preview { display: flex; align-items: center; gap: 0.65rem; margin-top: 0.6rem; color: var(--dim); font-size: 0.78rem; }
.upload-preview img { width: 2.4rem; height: 2.4rem; object-fit: contain; padding: 0.2rem; border: 1px solid var(--stroke-2); border-radius: 0.35rem; background: var(--void-2); }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.form-grid .full { grid-column: 1 / -1; }
.field label { display: block; font-family: var(--font-m); font-size: 0.58rem; letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: 0.45rem; color: var(--dim); }
.field input, .field textarea, .field select {
  width: 100%;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--stroke-2);
  border-radius: var(--r-s);
  padding: 0.85rem 1rem;
  font: inherit;
  font-size: 0.95rem;
  color: var(--text);
  transition: border-color .2s, box-shadow .2s;
}
.field select { appearance: none; }
.field option { background: var(--void-2); color: var(--text); }
.field textarea { min-height: 8rem; resize: vertical; }
.field input::placeholder, .field textarea::placeholder { color: var(--faint); }
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: var(--teal); box-shadow: 0 0 0 1px var(--teal); }

.faq details { border: 1px solid var(--stroke); border-radius: var(--r-s); background: var(--glass); margin-bottom: 0.7rem; overflow: hidden; backdrop-filter: blur(8px); }
.faq summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; gap: 1rem; align-items: center; padding: 1rem 1.2rem; font-weight: 600; font-size: 0.94rem; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--teal); font-size: 1.15rem; transition: transform .25s; }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq .faq-body { padding: 0 1.2rem 1.1rem; color: var(--dim); font-size: 0.92rem; }

/* ---------- homepage Design Center teaser ---------- */
.teaser-fig { position: relative; }
.teaser-zone {
  position: absolute;
  left: 34.5%; top: 30%;
  width: 31%; height: 34%;
  border: 2px dashed rgba(20, 20, 24, 0.45);
  border-radius: 4px;
  display: grid;
  place-items: center;
}
.teaser-zone i {
  font-style: normal;
  font-family: var(--font-m);
  font-size: 0.54rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(20, 20, 24, 0.6);
  text-align: center;
}
.teaser-list {
  list-style: none;
  display: grid;
  gap: 0.55rem;
  margin-top: 1.3rem;
}
.teaser-list li {
  position: relative;
  padding-left: 1.4rem;
  color: var(--dim);
  font-size: 0.94rem;
}
.teaser-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--teal);
}

/* ==========================================================================
   DESIGN CENTER (studio.html)
   ========================================================================== */
.studio-head { padding-bottom: clamp(1.2rem, 2.5vw, 2rem); }

.studio-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(300px, 0.65fr);
  gap: clamp(1.2rem, 2.6vw, 2.2rem);
  align-items: start;
  padding-bottom: clamp(3.5rem, 7vw, 6rem);
}

/* ---------- stage ---------- */
.studio-stage {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: calc(var(--r) * 1.1);
  padding: clamp(0.8rem, 1.6vw, 1.2rem);
  backdrop-filter: blur(12px);
  position: sticky;
  top: 6.5rem;
}

.stage-wrap {
  position: relative;
  aspect-ratio: 1 / 1;
  max-height: 70vh;
  border-radius: var(--r-s);
  overflow: hidden;
  background: var(--checker-bg) url("../assets/img/site/transparency-grid.png") 0 0 / 26px 26px;
  touch-action: pan-y;
}
.stage-wrap.is-touch-editing { touch-action: none; }
#studio-canvas { position: absolute; inset: 0; width: 100%; height: 100%; cursor: grab; }
#studio-canvas:active { cursor: grabbing; }

.drop-hint {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-m);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--chip-text);
  background: var(--chip-bg);
  border: 2px dashed var(--stroke-2);
  border-radius: var(--r-s);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}
.stage-wrap.dropping .drop-hint { opacity: 1; }

.stage-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  padding-top: 0.9rem;
}
.stage-meta {
  display: grid;
  grid-template-columns: auto auto;
  gap: 0.2rem 0.7rem;
  font-size: 0.82rem;
  align-items: baseline;
}
.stage-meta .mono-k {
  font-family: var(--font-m);
  font-size: 0.56rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
.stage-meta span:not(.mono-k) { color: var(--text); font-weight: 500; }
.stage-tools {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.55rem;
}

/* Front / Back switch — a segmented control rather than two loose buttons,
   so it reads as "pick one side" instead of two independent actions. */
.view-switch {
  display: inline-flex;
  padding: 3px;
  gap: 3px;
  border: 1px solid var(--stroke-2);
  border-radius: 999px;
  background: var(--glass);
}
.view-btn {
  font-family: var(--font-m);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
  padding: 0.38rem 0.85rem;
  border-radius: 999px;
  transition: color .2s, background .2s;
}
.view-btn:hover { color: var(--text); }
.view-btn.active { background: var(--teal); color: var(--on-accent); }

.ghost-toggle {
  font-family: var(--font-m);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text);
  border: 1px solid var(--stroke-2);
  border-radius: 999px;
  padding: 0.45rem 0.9rem;
  transition: color .2s, border-color .2s, opacity .2s;
}
.ghost-toggle:hover { border-color: rgba(255, 255, 255, 0.4); }
.ghost-toggle.off { opacity: 0.45; }
.ghost-toggle:disabled { cursor: not-allowed; opacity: 0.35; }
#btn-touch-edit { display: none; }

@media (pointer: coarse) {
  #btn-touch-edit { display: inline-flex; }
}

.warn {
  margin-top: 0.7rem;
  font-size: 0.82rem;
  color: var(--text);
  background: var(--glass-2);
  border: 1px solid var(--stroke-2);
  border-radius: var(--r-s);
  padding: 0.6rem 0.85rem;
}
.stage-note { margin-top: 0.7rem; font-size: 0.78rem; color: var(--faint); }

/* ---------- control rail ---------- */
.studio-rail { display: grid; gap: clamp(0.8rem, 1.6vw, 1.1rem); }

.rail-card {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  padding: clamp(1.1rem, 2.2vw, 1.5rem);
  backdrop-filter: blur(10px);
}
.rail-title {
  font-family: var(--font-m);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 0.9rem;
}
.rail-hint { font-size: 0.78rem; color: var(--faint); margin-top: 0.7rem; line-height: 1.55; }
.rail-hint b { color: var(--dim); }
.rail-link {
  display: inline-block;
  margin-top: 0.9rem;
  font-family: var(--font-m);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
  border-bottom: 1px solid var(--stroke-2);
  padding-bottom: 2px;
  transition: color .2s, border-color .2s;
}
.rail-link:hover { color: var(--text); border-color: var(--text); }

/* garment chips */
.garment-rail { display: grid; gap: 0.45rem; }
.garment-chip {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--stroke);
  border-radius: var(--r-s);
  background: rgba(255, 255, 255, 0.02);
  transition: border-color .2s, background .2s, box-shadow .2s;
}
.garment-chip:hover { border-color: var(--stroke-2); background: rgba(255, 255, 255, 0.05); }
.garment-chip.active { border-color: var(--teal); box-shadow: 0 0 0 1px var(--teal); }
.garment-chip .sw {
  width: 1.5rem; height: 1.5rem;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  flex: none;
}
.garment-chip .gt { display: grid; line-height: 1.25; min-width: 0; }
.garment-chip .gt b { font-size: 0.82rem; font-weight: 600; }
.garment-chip .gt i {
  font-style: normal;
  font-family: var(--font-m);
  font-size: 0.56rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Base-garment colorways. The visible color name stays beside the swatches so
   the choice never depends on color perception alone. */
.colorway-picker {
  min-width: 0;
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--stroke);
}
.colorway-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.65rem;
}
.colorway-head .fld-label { margin: 0; }
.colorway-head strong {
  font-family: var(--font-m);
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text);
}
.colorway-rail {
  display: grid;
  grid-template-columns: repeat(auto-fill, 2rem);
  align-items: center;
  justify-content: start;
  gap: 0.55rem;
  width: 100%;
  max-width: 100%;
}
.colorway-chip {
  appearance: none;
  display: grid;
  place-items: center;
  position: relative;
  width: 2rem;
  min-width: 2rem;
  max-width: 2rem;
  height: 2rem;
  min-height: 2rem;
  max-height: 2rem;
  line-height: 0;
  padding: 3px;
  border: 1px solid var(--stroke-2);
  border-radius: 50%;
  background: transparent;
  transition: border-color .2s, box-shadow .2s, transform .2s;
}
.colorway-chip::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: inherit;
  background: var(--swatch);
}
.colorway-chip:hover { transform: translateY(-1px); border-color: var(--text); }
.colorway-chip.active {
  border-color: var(--teal);
  box-shadow: 0 0 0 2px rgba(45, 212, 191, 0.28);
}
.colorway-chip:focus-visible { outline: 2px solid var(--teal); outline-offset: 3px; }

@media (max-width: 420px) {
  .colorway-rail {
    grid-template-columns: repeat(auto-fill, 1.85rem);
    gap: 0.48rem;
  }
  .colorway-chip {
    width: 1.85rem;
    min-width: 1.85rem;
    max-width: 1.85rem;
    height: 1.85rem;
    min-height: 1.85rem;
    max-height: 1.85rem;
  }
}

/* fields */
.fld-label {
  display: block;
  font-family: var(--font-m);
  font-size: 0.56rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 1rem 0 0.4rem;
}
.rail-card .fld-label:first-of-type { margin-top: 0.4rem; }

.studio-rail input[type="range"] {
  width: 100%;
  appearance: none;
  height: 3px;
  border-radius: 3px;
  background: var(--stroke-2);
  outline: none;
}
.studio-rail input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--teal);
  border: 0;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}
.studio-rail input[type="range"]::-moz-range-thumb {
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--teal);
  border: 0;
  cursor: pointer;
}
.studio-rail input[type="range"]:disabled { opacity: 0.35; }
.studio-rail input[type="range"]:disabled::-webkit-slider-thumb { cursor: not-allowed; }

.studio-rail select,
.studio-rail textarea {
  width: 100%;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--stroke-2);
  border-radius: var(--r-s);
  padding: 0.65rem 0.8rem;
  font: inherit;
  font-size: 0.86rem;
  color: var(--text);
  transition: border-color .2s, box-shadow .2s;
}
.studio-rail select { appearance: none; }
.studio-rail select option { background: var(--void-2); color: var(--text); }
.studio-rail textarea { resize: vertical; min-height: 4.4rem; }
.studio-rail select:focus, .studio-rail textarea:focus {
  outline: none; border-color: var(--teal); box-shadow: 0 0 0 1px var(--teal);
}
.studio-rail select:disabled { opacity: 0.4; }

.text-tool { margin-top: 1.1rem; padding-top: 1.1rem; border-top: 1px solid var(--stroke); }
.text-row { display: flex; gap: 0.5rem; margin-top: 0.5rem; align-items: stretch; }
.text-row select { flex: 1; min-width: 0; }
.text-row input[type="color"] {
  width: 2.6rem;
  padding: 0;
  border: 1px solid var(--stroke-2);
  border-radius: var(--r-s);
  background: transparent;
  cursor: pointer;
  flex: none;
}
.text-row .btn { padding: 0.5rem 1rem; flex: none; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.1rem; }
.btn-row .btn { flex: 1; min-width: 5.5rem; padding: 0.65rem 0.9rem; }
.studio-rail .btn:disabled { opacity: 0.4; cursor: not-allowed; }
.studio-rail .btn:disabled:hover { background: var(--glass); border-color: var(--stroke-2); transform: none; }
.studio-rail .btn-teal:disabled:hover { background: var(--teal); border-color: var(--teal); }

@media (max-width: 980px) {
  .studio-layout { grid-template-columns: 1fr; }
  .studio-stage { position: static; }
  .stage-wrap { max-height: none; }
}

/* NOT pinning the stage on mobile, having measured it: one column puts the
   controls below the garment, so dragging a slider scrolls the preview off
   screen. Pinning .studio-stage does not fix that. It is a grid item, so
   sticky is confined to its own grid row and barely travels; and even forced
   to travel, the card is 547px tall on a 375x635 screen — the 292px canvas
   plus a 175px readout bar — which leaves the controls -20px of room.
   Making this work means pinning the canvas alone and relocating the
   readout, i.e. restructuring the Design Center's mobile layout, which is
   more than a framing pass should quietly do. */

/* ---------- skip link ---------- */
.skip-link {
  position: absolute;
  left: 1rem;
  top: -3.5rem;
  z-index: 1100;
  /* 44px tall like every other control. It only ever appears on focus, so
     this is invisible to anyone not driving the page from a keyboard or
     switch — which is exactly who needs it to be a comfortable target. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  background: var(--teal);
  color: var(--on-accent);
  font-weight: 700;
  padding: 0.7rem 1.2rem;
  font-family: var(--font-m);
  font-size: 0.64rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border-radius: 999px;
  transition: top 0.2s;
}
.skip-link:focus { top: 1rem; }

/* ---------- toast ---------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: 2rem;
  transform: translate(-50%, 200%);
  background: var(--panel-strong);
  border: 1px solid var(--stroke-2);
  color: var(--text);
  font-family: var(--font-m);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.85rem 1.5rem;
  border-radius: 999px;
  backdrop-filter: blur(12px);
  z-index: 1200;
  transition: transform 0.4s var(--ease);
}
.toast.show { transform: translate(-50%, 0); }

/* ---------- reveal (JS-gated so no-JS users see everything) ---------- */
html.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); transition-delay: var(--d, 0ms); }
html.js .reveal.in { opacity: 1; transform: none; }

html.js .rise { opacity: 0; transform: translateY(24px); animation: rise 0.8s var(--ease) forwards; animation-delay: var(--d, 0ms); }
@keyframes rise { to { opacity: 1; transform: none; } }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */
@media (max-width: 1100px) {
  .grid-products { grid-template-columns: repeat(3, 1fr); }
  .footer-main { grid-template-columns: 1fr 1fr; }
  .pillars { grid-template-columns: 1fr; }
}

@media (max-width: 900px) {
  html.nav-open,
  body.nav-open { overflow: hidden; }
  .nav-links {
    position: absolute;
    top: calc(100% + 0.55rem);
    left: 0;
    right: 0;
    padding: 2rem 1.5rem;
    background: var(--void);
    backdrop-filter: blur(18px);
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 2rem;
    border: 1px solid var(--stroke);
    border-radius: var(--r);
    box-shadow: 0 18px 48px rgba(0, 0, 0, 0.58);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-0.75rem);
    transition: opacity 0.25s, visibility 0.25s, transform 0.35s var(--ease);
    z-index: 4;
  }
  body.nav-open .nav-links {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
  }
  .nav-dropdown { width: 100%; text-align: center; }
  .nav-dropdown-trigger { justify-content: center; }
  .nav-dropdown-menu {
    position: static;
    min-width: 0;
    margin-top: 0.35rem;
    padding: 0.25rem 0;
    transform: none;
    background: transparent;
    border: 0;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }
  .nav-dropdown-menu a { padding: 0.45rem 0; font-size: 0.92rem; }
  .nav-links a { font-size: 1.15rem; }
  .nav-burger { display: flex; z-index: 5; }
  .nav-cta .btn { display: none; }
  html.no-js .site-header { border-radius: var(--r); }
  html.no-js .nav { flex-wrap: wrap; }
  html.no-js .nav-links {
    position: static;
    width: 100%;
    padding: 0.65rem 0 0.2rem;
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    flex-flow: row wrap;
    gap: 0.65rem 1.2rem;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
  }
  html.no-js .nav-links a { font-size: 0.86rem; }
  html.no-js .nav-burger { display: none; }

  .story-grid, .contact-grid { grid-template-columns: 1fr; }
  .product-layout { grid-template-columns: 1fr; }
  .gallery { position: static; }
  .rail { right: 0.9rem; }
  .chapter { max-width: min(30rem, calc(100vw - 2.5rem)); }
  .ch-1, .ch-3 { text-align: left; }
  .ch-1 p, .ch-3 p { margin-left: 0; }
}

@media (max-width: 640px) {
  .grid-products { grid-template-columns: repeat(2, 1fr); }
  .section-head { flex-direction: column; align-items: flex-start; gap: 0.9rem; }
  .catalog-bar {
    gap: 0.45rem;
    padding: 0.55rem;
    background: var(--panel-strong);
    border-radius: var(--r-s);
  }
  .filters {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.2rem;
  }
  .filter-btn { width: 100%; padding: 0.5rem 0.2rem; }
  .catalog-count { width: 100%; padding: 0 0.35rem; color: var(--dim); text-align: right; }
  .card-line { display: none; }
  .pd-ctas { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .footer-main { grid-template-columns: 1fr; }
  .story-facts { gap: 1.5rem; }
  .chapter h1, .chapter h2 { font-size: clamp(1.5rem, 7.4vw, 2.2rem); }
  .ch-0 { top: 16vh; }
  .ch-1 { top: 18vh; }
  .hud .lbl { display: none; }
}

/* Short phone landscape needs a side-by-side composition; there is not
   enough vertical room for the portrait-only garment-over-copy stack. */
@media (max-width: 900px) and (max-height: 520px) and (orientation: landscape) {
  .xp-stage {
    --fit-top: 16%;
    --fit-right: 1%;
    --fit-bottom: 2%;
    --fit-left: 52%;
  }
  .hero-glow { left: 75%; top: 52%; width: min(78svh, 360px); }
  .hero-shadow { left: 75%; bottom: 4%; width: min(40svh, 260px); }
  .xp-stage .chapter,
  .xp-stage .ch-4 {
    top: max(5.5rem, 24svh);
    bottom: auto;
    left: max(var(--pad), env(safe-area-inset-left));
    right: auto;
    width: min(46vw, 28rem);
    max-width: 28rem;
  }
  .xp-stage .chapter h1,
  .xp-stage .chapter h2 { font-size: clamp(1.45rem, 4.4vw, 2.2rem); }
  .xp-stage .chapter p { margin-top: 0.7rem; font-size: 0.9rem; line-height: 1.5; }
  .xp-stage .chapter .mono { margin-bottom: 0.55rem; }
  .xp-stage .ch-4 { top: max(5rem, 20svh); padding: 1rem; }
  .xp-stage .ch-4 .actions { gap: 0.55rem; margin-top: 0.9rem; }
  .xp-stage .ch-4 .btn { padding: 0.7rem 1.1rem; }
}

/* ==========================================================================
   TOUCH ERGONOMICS
   Keyed on (pointer: coarse), not on width: a narrow desktop window is still
   driven by a mouse and needs none of this, while an iPad at 1024px does.

   Two different techniques, chosen per control rather than uniformly:

   - Where the control's SIZE IS THE DESIGN — the theme toggle's circle, the
     burger, the colorway dots — the hit area is grown with a pseudo-element
     so the target reaches 44px while the artwork stays exactly as drawn.
   - Where the control is a pill or a row that can simply be bigger, it is
     given min-height and the layout absorbs it.

   The footer is the one place a pseudo-element would have been wrong: its
   links sit on a ~26px pitch, so 44px overlays would have overlapped their
   neighbours and put half of every target on top of the link above. That
   needs real spacing, so those rows genuinely grow.
   ========================================================================== */
@media (pointer: coarse) {
  a, button, input, select, textarea, summary,
  [role="button"] { -webkit-tap-highlight-color: var(--tap-highlight); }

  /* --- header controls: hit area only, artwork untouched ---
     The brand is here rather than on min-height for a reason beyond looks:
     it is the tallest thing in the bar, so a min-height on it grew .nav past
     --nav-h and made --hdr-bottom wrong by 5.6px — which in turn slid the
     header over the shop's sticky filter bar. An overlay costs no layout. */
  .brand,
  .theme-toggle,
  .nav-burger { position: relative; }
  .brand::after,
  .theme-toggle::after,
  .nav-burger::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: max(44px, 100%);
    height: max(44px, 100%);
    transform: translate(-50%, -50%);
  }

  /* --- pills that can just be taller --- */
  .filter-btn,
  .view-btn,
  .chip,
  .ghost-toggle { min-height: 44px; }
  /* Colour wells state no height and sit in a stretch row, but the UA gives
     input[type=color] an intrinsic box that wins: 27px in the text tool,
     41.6px in the admin editor. Both need it said outright. */
  .text-row input[type="color"],
  .admin-fields input[type="color"] { min-height: 44px; min-width: 44px; }
  .chip { padding-top: 0.5rem; padding-bottom: 0.5rem; }
  .filter-btn,
  .view-btn { display: inline-flex; align-items: center; justify-content: center; }

  /* The open burger menu is the primary way around the site on a phone and
     its links were 40px. It stacks on a 2rem gap, so growing them is free. */
  .nav-links a { display: flex; align-items: center; min-height: 44px; }

  /* Secondary navigation and section links. inline-flex rather than padding
     so the row grows once instead of each link gaining a detached box, and
     because .crumbs wraps — 44px overlays on a wrapped 23.8px pitch would
     have overlapped the row above. */
  .crumbs a,
  .section-head .side a,
  a[href^="mailto:"],
  a[href^="tel:"] { display: inline-flex; align-items: center; min-height: 44px; }

  /* --- colorway dots: 2rem circle, 44px target --- */
  .colorway-chip::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
    border-radius: 50%;
  }
  /* The rail packs the dots at a 2rem + 0.55rem pitch — tighter than 44px —
     so without this the overlays would fight each other exactly the way the
     footer's would. 2rem + 0.9rem puts the pitch at 46.4px in both axes,
     clearing the overlay each dot now carries.

     Both the column size AND the dot size are restated because the 420px
     breakpoint shrinks dots to 1.85rem: leaving that in place held the
     COLUMN pitch at 46.4 but dropped the ROW pitch to exactly 44.0, so the
     overlays met edge to edge with no slack at all. auto-fill just lays out
     fewer per row, so widening these cannot overflow the card. */
  .colorway-rail { grid-template-columns: repeat(auto-fill, 2rem); gap: 0.9rem; }
  .colorway-chip {
    width: 2rem; min-width: 2rem; max-width: 2rem;
    height: 2rem; min-height: 2rem; max-height: 2rem;
  }

  /* --- footer: real rows, not overlays --- */
  .footer-col ul { gap: 0; }
  .footer-col a { display: block; padding: 0.68rem 0; }

  /* .rail-link draws its own underline with padding-bottom + border-bottom,
     so padding here would have pushed the rule away from the text. It sits
     alone at the foot of a card with 0.9rem of clearance above, which is
     more than the 12.6px an overlay extends, so it takes the overlay. */
  .rail-link { position: relative; }
  .rail-link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }

  /* --- iOS zooms the whole page when a focused field is under 16px, and
         does not zoom back out afterwards. Every one of these was under it:
         the contact form at 15.2px, the Design Center's text tool at 13.76,
         the admin fields at 14.4. --- */
  .field input,
  .field textarea,
  .field select,
  .studio-rail select,
  .studio-rail textarea,
  .admin-fields input[type="text"],
  .admin-fields input[type="number"],
  .admin-fields select,
  .admin-fields textarea,
  .admin-gate-form input[type="password"] { font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
  html { scroll-behavior: auto; }
  html.js .reveal, html.js .rise { opacity: 1; transform: none; }
  .scroll-hint .chev { animation: none; }
}

/* ==========================================================================
   ADMIN DASHBOARD — password-gated Design Center editor (admin.html).
   Reuses the site's existing tokens and component shapes (.btn, the
   contact form's input styling, .rail-card-style panels, .toast) rather
   than inventing a second visual system for one internal page.
   ========================================================================== */
.admin-body { min-height: 100vh; }
.admin-eyebrow { margin-left: 0.5rem; color: var(--faint); }
.admin-main { max-width: var(--max); margin: 0 auto; padding: 7.5rem var(--pad) 5rem; }

/* ---- password gate ---- */
.admin-gate { display: grid; place-items: center; min-height: 60vh; text-align: center; }
.admin-gate-form {
  width: min(24rem, 100%);
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  padding: clamp(1.6rem, 4vw, 2.2rem);
  backdrop-filter: blur(12px);
}
.admin-gate-form h1 { margin: 0.5rem 0 1.4rem; font-size: clamp(1.6rem, 4vw, 2rem); }
.admin-gate-form .fld-label { text-align: left; margin-top: 0; }
.admin-gate-form input[type="password"] {
  width: 100%;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--stroke-2);
  border-radius: var(--r-s);
  padding: 0.85rem 1rem;
  font: inherit;
  font-size: 0.95rem;
  color: var(--text);
  transition: border-color .2s, box-shadow .2s;
}
.admin-gate-form input[type="password"]:focus { outline: none; border-color: var(--teal); box-shadow: 0 0 0 1px var(--teal); }
.admin-gate-form .btn { margin-top: 1.2rem; }
.admin-error { margin-top: 1rem; font-size: 0.82rem; color: #ff9d9d; }

/* ---- dashboard grid ---- */
.admin-toolbar { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; }
.admin-toolbar-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.admin-note { color: var(--faint); font-size: 0.86rem; margin-bottom: 1.8rem; max-width: 42rem; }
.admin-note b { color: var(--dim); }

.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
}
.admin-card {
  display: flex;
  flex-direction: column;
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: var(--r);
  overflow: hidden;
}
.admin-card.is-disabled { opacity: 0.55; }
.admin-card-photo {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--checker-bg) url("../assets/img/site/transparency-grid.png") 0 0 / 26px 26px;
}
.admin-card-photo img { width: 100%; height: 100%; object-fit: contain; }
.admin-card-flag {
  position: absolute; top: 0.5rem; right: 0.5rem;
  font-family: var(--font-m); font-size: 0.56rem; letter-spacing: 0.1em; text-transform: uppercase;
  background: var(--chip-bg);
  border: 1px solid var(--stroke-2);
  border-radius: 999px;
  padding: 0.25rem 0.6rem;
  color: var(--chip-text);
}
.admin-card-body { padding: 0.8rem 0.9rem 0; display: grid; line-height: 1.3; }
.admin-card-body b { font-size: 0.9rem; }
.admin-card-body i { font-style: normal; font-size: 0.76rem; color: var(--faint); }
.admin-card > .btn { margin: 0.8rem; }

.admin-save-bar {
  position: sticky;
  bottom: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: var(--panel-strong);
  border: 1px solid var(--stroke-2);
  border-radius: var(--r);
  padding: 0.9rem 1.1rem;
  backdrop-filter: blur(10px);
}

/* ---- garment editor ---- */
.admin-editor-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.4rem; }
.admin-editor-head h2 { font-family: var(--font-d); font-weight: 700; font-size: 1.4rem; }
.admin-editor-body {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: clamp(1.2rem, 2.6vw, 2.2rem);
  align-items: start;
  padding-bottom: clamp(3rem, 6vw, 5rem);
}

.admin-stage {
  background: var(--glass);
  border: 1px solid var(--stroke);
  border-radius: calc(var(--r) * 1.1);
  padding: clamp(0.8rem, 1.6vw, 1.2rem);
}
.admin-stage-wrap {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-s);
  overflow: hidden;
  background: var(--checker-bg) url("../assets/img/site/transparency-grid.png") 0 0 / 26px 26px;
}
#editor-canvas { position: absolute; inset: 0; width: 100%; height: 100%; cursor: crosshair; touch-action: none; }
.admin-stage-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.8rem; padding-top: 0.9rem; }
.admin-hint { margin-top: 0.7rem; font-size: 0.78rem; color: var(--faint); line-height: 1.5; }
.admin-readout { margin-top: 0.5rem; font-size: 0.66rem; letter-spacing: 0.04em; color: var(--dim); }

.admin-fields { display: grid; }
.admin-fields-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.admin-fields input[type="text"],
.admin-fields input[type="number"],
.admin-fields select,
.admin-fields textarea {
  width: 100%;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--stroke-2);
  border-radius: var(--r-s);
  padding: 0.75rem 0.9rem;
  font: inherit;
  font-size: 0.9rem;
  color: var(--text);
  transition: border-color .2s, box-shadow .2s;
}
.admin-fields select { appearance: none; }
.admin-fields option { background: var(--void-2); color: var(--text); }
.admin-fields textarea { resize: vertical; min-height: 4rem; }
.admin-fields input:focus,
.admin-fields select:focus,
.admin-fields textarea:focus { outline: none; border-color: var(--teal); box-shadow: 0 0 0 1px var(--teal); }
.admin-fields input[type="color"] {
  width: 3.4rem;
  height: 2.6rem;
  padding: 0.2rem;
  border: 1px solid var(--stroke-2);
  border-radius: var(--r-s);
  background: transparent;
  cursor: pointer;
}

.admin-toggle { display: flex; align-items: center; gap: 0.6rem; margin-top: 1.1rem; font-size: 0.86rem; color: var(--dim); }
.admin-toggle input { accent-color: var(--teal); width: 1.05rem; height: 1.05rem; }

.admin-editor-actions { display: flex; justify-content: space-between; gap: 0.8rem; margin-top: 1.6rem; }

.rail-loading { padding: 1rem 0; }

@media (max-width: 900px) {
  .admin-editor-body { grid-template-columns: 1fr; }
  .admin-fields-row { grid-template-columns: 1fr; }
  .admin-save-bar { position: static; }
}
