/* ============================================================
   Self-hosted type. Both families are variable fonts under the SIL Open
   Font License, and Google serves one byte-identical file per family and
   subset across every weight, so one @font-face per subset covers 400-700.
   Self-hosted so the page doesn't depend on a third party staying up (or
   watching who reads it).
   ============================================================ */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('../fonts/Inter-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('../fonts/Inter-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Space Grotesk'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('../fonts/SpaceGrotesk-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Space Grotesk'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('../fonts/SpaceGrotesk-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

/* ============================================================
   Mirraya — "Pulse" design system
   A network of points reading and connecting, like a body being
   measured. Predominantly dark, bold turquoise + coral accents,
   one bright "Snow" section per page as a contrast beat.
   No gradients anywhere — depth comes from solid fills, glow
   (box-shadow), and the live particle-network canvas behind everything.
   ============================================================ */

:root {
  --black-1: #181818;   /* Carbon Black */
  --black-2: #292929;   /* Graphite */
  --black-3: #181818;   /* Carbon again — the palette has two darks, not three */
  --turquoise:  #00F5DC;   /* Accent 1 */
  --cyan-soft:  #00F5DC;
  --coral:      #FB6376;   /* Accent 2 — Bubblegum Pink */
  --snow:       #F3EFE6;   /* Soft Linen */
  --white:      #FFFFFF;
  /* The on-paper accents. Verdigris is the palette's Primary and takes
     over from the old #006B60; the palette carries no dark pink, so
     Accent 2 is used as-is. Both are well under AA as body text on
     Linen (2.6:1 and 2.5:1) — see the note above .stat__n. */
  --turquoise-deep: #00A898;   /* Verdigris — Primary */
  --coral-deep:     #FB6376;   /* Bubblegum Pink — Accent 2 */

  /* White-alpha (on dark surfaces) */
  --w-06:  rgba(255, 255, 255, .06);
  --w-08:  rgba(255, 255, 255, .08);
  --w-12:  rgba(255, 255, 255, .12);
  --w-20:  rgba(255, 255, 255, .20);
  --w-35:  rgba(255, 255, 255, .35);
  --w-50:  rgba(255, 255, 255, .50);
  --w-70:  rgba(255, 255, 255, .70);

  /* Black-alpha (on the one light "Snow" surface) */
  --b-08:  rgba(24, 24, 24, .08);
  --b-14:  rgba(24, 24, 24, .14);
  --b-25:  rgba(24, 24, 24, .25);
  --b-45:  rgba(24, 24, 24, .45);
  --b-60:  rgba(24, 24, 24, .60);

  --radius-sm: 8px;
  --radius-md: 14px;
  --radius-lg: 20px;
  --radius-xl: 28px;

  --ease: cubic-bezier(.16,1,.3,1);
  --ease-soft: cubic-bezier(.25,.8,.25,1);

  --nav-h: 84px;
  --nav-h-scrolled: 64px;

  --mono: ui-monospace, Menlo, Monaco, "Cascadia Code", monospace;
  --display: "Space Grotesk", "Inter", system-ui, sans-serif;
  --body: "Inter", system-ui, -apple-system, sans-serif;

  /* ---- Paper: warm off-white, deliberately not the cool --snow.
     Every reference site sits on a warm ground (#fcfcf7, #f8f7f5, #fafaee);
     a blue-cast white reads clinical at full-page scale. --snow keeps its
     job as the TEXT colour on the inverted beat. ---- */
  --paper:   #F3EFE6;
  --paper-2: #FFFFFF;   /* the palette's second ground is White, not a darker cream */
  --ink:     #181818;
  --turquoise-bright: #00F5DC;  /* large fills only, never text on paper */

  /* ---- Tracking. Negative tracking applied system-wide is the single
     most consistent trait across the reference set, and it tightens
     further as display size grows. ---- */
  --track-display: -.045em;
  --track-title:   -.03em;
  --track-body:    -.011em;
  --track-label:   .14em;   /* mono labels open up — the counterpoint */

  /* ---- Type scale. Replaces the hand-picked 13.5/14/14.5/15px values
     that were scattered through the component blocks. ---- */
  --step-6: clamp(46px, 7.4vw, 104px);
  --step-5: clamp(34px, 5vw, 58px);
  --step-4: clamp(26px, 3.4vw, 40px);
  --step-3: clamp(20px, 2.2vw, 26px);
  --step-2: clamp(17px, 1.5vw, 20px);
  /* The bottom three were flat px and set too small — reading copy in the
     supporting sections was sitting at 13px, a caption size doing a body
     job. These now grow with the viewport like everything above them, and
     the sections that carry real sentences were moved up to --step-1;
     --step--1 is back to meaning a caption. */
  --step-1: clamp(16px, 1.1vw, 18px);
  --step-0: clamp(15px, .95vw, 16.5px);
  --step--1: 13.5px;
  --step--2: 11.5px;
  /* Mono markers that head a block — the outro keys, and the numbers on the
     two step lists. They were sharing --step--2 with the eyebrows, but an
     eyebrow names a whole section from a distance while these sit directly
     on top of the text they belong to and have to be read with it. */
  --step-marker: 13.5px;

  /* ---- Spacing. Fluid like the type; the big section gaps are most of
     what separates an editorial page from a stack of blocks. ---- */
  --space-s:   clamp(16px, 2vw, 24px);
  --space-m:   clamp(28px, 3.5vw, 44px);
  --space-l:   clamp(44px, 5.5vw, 72px);
  --space-xl:  clamp(64px, 8vw, 104px);
  --space-2xl: clamp(88px, 11vw, 150px);
  --space-3xl: clamp(112px, 14vw, 200px);

  --gutter: clamp(20px, 6vw, 104px);
  --col-gap: clamp(16px, 2vw, 32px);
}

/* ============================================================
   Light theme — scoped to <html data-theme="light">, so index can
   flip while product/about/contact keep running on the dark tokens
   until they're converted.

   The whole stylesheet is already written in terms of --white,
   --w-* and --turquoise, so redefining those four families here
   flips the page without touching the component blocks. Only the
   things that must NOT invert (a bright fill, a real hairline)
   get an explicit rule.
   ============================================================ */
:root[data-theme="light"] {
  --white:   #181818;          /* "white" now means ink */
  --black-1: var(--paper);
  --black-2: var(--paper-2);
  --black-3: var(--paper-2);
  --snow:    var(--paper);

  --turquoise:  #00A898;       /* Verdigris, the Primary */
  --cyan-soft:  #00F5DC;
  --coral:      #FB6376;       /* Accent 2 — the problem, and only the problem */

  --w-06: rgba(24,24,24,.05);
  --w-08: rgba(24,24,24,.10);
  --w-12: rgba(24,24,24,.14);
  --w-20: rgba(24,24,24,.20);
  --w-35: rgba(24,24,24,.32);
  --w-50: rgba(24,24,24,.52);
  --w-70: rgba(24,24,24,.72);

  /* Shape is split by job, and the split is the whole system:

     CONTAINERS ARE SQUARE. Zeroing the radius tokens squares every panel,
     card, table and field at once, and scopes it to the converted page —
     product/about/contact keep their radii until they come across. Square
     is what makes the grid read as a grid.

     CONTROLS ARE PILLS. Anything you click is fully round-ended, which is the
     mark's own geometry: both ribbon strokes terminate in a half-round cap,
     and the opening panel arrives as one before it grows into the page.

     Matching the widget's 14px trigger instead was tried, on the argument that
     the site's buttons should be the product's button. It is a good argument
     and it lost to looking at it: the page went quiet and generic, and the
     square/round contrast that carries the whole layout went with it. The site
     is not the widget — the widget wears the RETAILER's shape by design, which
     is exactly why it can't also carry ours.

     Because the split is by job rather than by taste, it also tells a reader
     what is pressable before they read a word of it. */
  --control-radius: 999px;
  --radius-sm: 0; --radius-md: 0; --radius-lg: 0; --radius-xl: 0;
}

/* The controls. Listed rather than blanket-applied to `button`, because the
   widget and dashboard mocks further down are portraits of real product
   surfaces — their shapes belong to those products, not to this page. */
:root[data-theme="light"] .btn-primary,
:root[data-theme="light"] .btn-ghost,
:root[data-theme="light"] .btn-cta,
:root[data-theme="light"] .nav-link,
:root[data-theme="light"] .nav__indicator {
  border-radius: var(--control-radius);
}
/* Round ends eat their own side padding: on a 52px-tall button the cap is a
   26px radius, so the base 30px left the text 4px clear of the curve and it
   read as crowded. These add back roughly the cap. */
:root[data-theme="light"] .btn-primary,
:root[data-theme="light"] .btn-ghost { padding: 16px 36px; }
:root[data-theme="light"] .btn-cta { padding: 11px 24px; }

/* The pill stops at the edge of the widget mock, and inside it the radius is
   the REAL widget's: w.js derives its inner controls from
   `rIn = max(8, radius - 4)` = 10px. Continue / Get my size / Back / Start
   again stand in for those, so they take 10 — a depiction of the product must
   not claim a shape the product doesn't have. */
:root[data-theme="light"] .widget .btn-primary,
:root[data-theme="light"] .widget .btn-ghost {
  border-radius: 10px;
}

/* Nav on paper. The mark is a turquoise-filled SVG loaded as an <img>, so
   it can't be recoloured by `color` and invert() would send it to its
   complement (red). brightness(0) flattens any source fill to ink, which
   is what it should be beside an ink wordmark. The footer stays dark, so
   the mark is left alone there. */
:root[data-theme="light"] .nav {
  /* Tied to --paper via color-mix so it can't drift out of sync with the
     ground again; the blur behind it needs the alpha. */
  background: color-mix(in srgb, var(--paper) 72%, transparent);
  border-bottom: 1px solid var(--w-08);
  color: var(--ink);
}
:root[data-theme="light"] .nav.is-scrolled {
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  box-shadow: none;
}
:root[data-theme="light"] .nav__brand img { filter: brightness(0); }

/* The walkthrough mock on paper. Its placeholder greys are hardcoded
   (they were picked to sit on the old near-black), so they read as heavy blocks
   against off-white and need light values of their own. */
:root[data-theme="light"] .hiw-step { opacity: .5; }
:root[data-theme="light"] .hiw-step:hover { opacity: .8; }
:root[data-theme="light"] .hiw-step[aria-selected="true"] { opacity: 1; }
:root[data-theme="light"] .nav-overlay { background: var(--paper); }

/* The one inverted beat. Flipping the tokens back on the element itself
   means everything inside it — borders, muted text, the accent — returns
   to its dark-surface values with no per-child overrides. */
/* The footer is a dark panel too, and it was missed when the page went
   light: it kept its dark background while --white and the --w-* alphas
   flipped to ink underneath it, so every word in it was ink on Graphite.
   It takes the same flip as the inverted section rather than a set of
   per-child overrides. */
:root[data-theme="light"] .section--snow,
:root[data-theme="light"] .site-footer {
  /* Graphite, not Carbon: the palette lists Graphite as a background and
     keeps Carbon for text, and the softer dark sits better against Linen. */
  background: #292929;
  color: var(--snow-text, #FFFFFF);

  --white:   #FFFFFF;
  --black-1: #181818;   /* Carbon Black */
  --black-2: #292929;   /* Graphite */
  --black-3: #181818;   /* Carbon again — the palette has two darks, not three */

  --turquoise: #00F5DC;
  --coral:     #FB6376;

  --w-06: rgba(255,255,255,.06);
  --w-08: rgba(255,255,255,.08);
  --w-12: rgba(255,255,255,.12);
  --w-20: rgba(255,255,255,.20);
  --w-35: rgba(255,255,255,.35);
  --w-50: rgba(255,255,255,.50);
  --w-70: rgba(255,255,255,.70);
}

* { box-sizing: border-box; }
html { scroll-behavior: auto; } /* Lenis owns smooth scrolling when it loads */

body {
  margin: 0;
  background: var(--black-1);
  color: var(--white);
  font-family: var(--body);
  letter-spacing: var(--track-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

/* Faint film-grain — texture, not a gradient. Kills the flat template feel. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 5;
  opacity: .025;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 200px 200px;
}

a { text-decoration: none; color: inherit; }
button { font: inherit; }
::selection { background: var(--turquoise); color: var(--black-1); }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-thumb { background: var(--w-20); border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: var(--w-35); }

/* Ink sits a little heavier on paper than on a dark ground. */
:root[data-theme="light"] body::after { opacity: .05; }

/* ============================================================
   Keyframes
   ============================================================ */
@keyframes fadeup { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
@keyframes hiw-scanline { from { top: 0; } to { top: 100%; } }
@keyframes menu-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }

/* ============================================================
   Nav — floating glass bar
   ============================================================ */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 200;
  height: var(--nav-h);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 clamp(20px, 4vw, 48px);
  background: rgba(16,16,16,.5);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border-bottom: 1px solid var(--w-08);
  color: var(--white);
  transition: height .4s var(--ease), background .4s var(--ease), box-shadow .4s var(--ease);
}
.nav.is-scrolled {
  height: var(--nav-h-scrolled);
  background: rgba(12,12,12,.86);
  box-shadow: 0 20px 50px -30px rgba(0,0,0,.7);
}
.nav__brand { display: flex; align-items: center; gap: 11px; z-index: 2; }
.nav__brand img { height: 26px; width: auto; display: block; color: var(--turquoise); }
.nav__wordmark { font-family: var(--display); font-weight: 600; font-size: 19px; letter-spacing: -.01em; }

.nav__links { position: relative; display: flex; align-items: center; gap: 4px; list-style: none; margin: 0; padding: 0; }
.nav-link {
  position: relative; display: block; padding: 9px 16px;
  font-size: 12.5px; letter-spacing: .07em; text-transform: uppercase; font-weight: 600;
  color: var(--w-70); border-radius: 20px; transition: color .25s;
}
.nav-link:hover { color: var(--white); }
.nav-link[aria-current="page"] { color: var(--white); }
.nav__indicator {
  position: absolute; top: 4px; height: calc(100% - 8px);
  background: var(--w-08); border-radius: 20px;
  transition: transform .45s var(--ease), width .45s var(--ease), opacity .25s;
  opacity: 0; pointer-events: none;
}
.nav__links:hover .nav__indicator, .nav__indicator.is-ready { opacity: 1; }

.nav__actions { display: flex; align-items: center; gap: 14px; z-index: 2; }
.nav-toggle {
  display: none; width: 42px; height: 42px; border-radius: 50%; border: 1px solid var(--w-12);
  background: transparent; color: var(--white); cursor: pointer;
  align-items: center; justify-content: center; position: relative;
}
.nav-toggle__bar, .nav-toggle__bar::before, .nav-toggle__bar::after {
  content: ""; position: absolute; width: 16px; height: 1.5px; background: currentColor;
  transition: transform .3s var(--ease), opacity .2s;
}
.nav-toggle__bar::before { transform: translateY(-5px); }
.nav-toggle__bar::after { transform: translateY(5px); }
body.nav-open .nav-toggle__bar { background: transparent; }
body.nav-open .nav-toggle__bar::before { transform: rotate(45deg); }
body.nav-open .nav-toggle__bar::after { transform: rotate(-45deg); }

.nav-overlay {
  position: fixed; inset: 0; z-index: 190; background: var(--black-1);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 28px;
  opacity: 0; pointer-events: none; transform: translateY(-8px);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
body.nav-open .nav-overlay { opacity: 1; pointer-events: auto; transform: translateY(0); }
.nav-overlay__link {
  font-family: var(--display); font-size: clamp(30px, 8vw, 46px); font-weight: 600;
  color: var(--w-70); opacity: 0; transform: translateY(14px);
}
body.nav-open .nav-overlay__link { animation: menu-in .5s var(--ease) both; }
.nav-overlay__link:nth-child(1) { animation-delay: .06s; }
.nav-overlay__link:nth-child(2) { animation-delay: .12s; }
.nav-overlay__link:nth-child(3) { animation-delay: .18s; }
.nav-overlay__link:nth-child(4) { animation-delay: .24s; }
.nav-overlay__link[aria-current="page"], .nav-overlay__link:hover { color: var(--turquoise); }
.nav-overlay .btn-primary { margin-top: 10px; opacity: 0; animation: menu-in .5s var(--ease) both; animation-delay: .32s; }

@media (max-width: 900px) {
  .nav__links, .nav__actions .btn-cta-nav { display: none; }
  .nav-toggle { display: flex; }
}

/* ============================================================
   Layout / sections — predominantly dark, canvas visible through
   ============================================================ */
.main { padding-top: var(--nav-h); position: relative; z-index: 1; }

/* Sections are a 12-column grid. Children default to full width; the two
   that carry the section's voice are placed asymmetrically — title on the
   left six, lede on the right five, sharing a row. That single placement
   is what stops the page reading as a stack of centred blocks, and it
   needs no wrapper markup. */
.section {
  padding: var(--space-3xl) var(--gutter);
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
  align-content: start;
}
.section > * { grid-column: 1 / -1; min-width: 0; }
.section > .sec-title { grid-column: 1 / span 6; margin-bottom: 0; }
.section > .lede      { grid-column: 8 / -1; align-self: end; padding-bottom: .35em; }

.section--dark  { background: rgba(24,24,24,.85); color: var(--white); }
.section--dark2 { background: rgba(32,32,32,.85); color: var(--white); }
.section--deep  { background: rgba(16,16,16,.86); color: var(--white); }
.section--snow  { background: var(--snow); color: var(--black-1); }

/* A section that OPENS a colour band sits close to the edge that announced
   it — the change of paper is the section break, so a full --space-3xl on
   top of it reads as drift rather than rhythm. Sections that continue a
   band keep the full gap. */
.section--lead { padding-top: var(--space-l); }

/* The last section runs into the footer, and when both are dark there is no
   colour change to absorb the gap — a full --space-3xl below the last row
   plus the footer's own top padding read as the page having stopped early.
   The footer carries the separation instead, with a rule. */
.main > .section:last-child { padding-bottom: var(--space-l); }


/* Those four backgrounds are literals (they were semi-transparent to let
   the old canvas through), so they need explicit light values. */
:root[data-theme="light"] .section--dark,
:root[data-theme="light"] .section--deep  { background: var(--paper); color: var(--ink); }
:root[data-theme="light"] .section--dark2 { background: var(--paper-2); color: var(--ink); }

/* No rule between paper sections: --paper and --paper-2 are now far enough
   apart to read as a tonal step on their own, and a hairline on top of a
   visible step is one device too many. */

@media (max-width: 1080px) {
  .section > .sec-title, .section > .lede {
    grid-column: 1 / -1; align-self: auto; padding-bottom: 0;
  }
  .section > .sec-title { margin-bottom: var(--space-s); }
}

.reveal { opacity: 0; transform: translateY(20px); transition: opacity .8s var(--ease), transform .8s var(--ease); will-change: opacity, transform; }
.reveal.reveal--in { opacity: 1; transform: none; }

/* Mono is the second voice: every eyebrow, figure label and citation.
   It's what lets the page say "instrument" without looking like a
   dashboard, and it's the one place tracking opens up instead of tightening. */
.eyebrow {
  font-family: var(--mono); font-size: var(--step--2);
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--w-50); margin: 0 0 var(--space-m);
  display: flex; align-items: center; gap: 10px;
}
.eyebrow::before {
  content: ""; width: 22px; height: 1px; background: currentColor; opacity: .6; flex: none;
}

/* Display type is set at regular weight, not bold. None of the reference
   sites use a heavy headline — the scale and the tracking carry it, and
   weight 600 at 100px is what made this page read as a slide. */
h1.hero-title {
  font-family: var(--display); font-weight: 400;
  font-size: var(--step-6); line-height: .94;
  letter-spacing: var(--track-display); margin: 0 0 var(--space-m);
}
h1.hero-title em, h2.sec-title em { font-style: normal; color: var(--turquoise); }
h2.sec-title {
  font-family: var(--display); font-weight: 400;
  font-size: var(--step-5); line-height: 1.0;
  letter-spacing: var(--track-title); margin: 0 0 var(--space-m); max-width: 18ch;
}
.lede {
  font-size: var(--step-2); line-height: 1.5; max-width: 46ch;
  color: var(--w-70); overflow-wrap: break-word; margin: 0;
}

/* ============================================================
   Buttons — solid fills only, no gradients
   ============================================================ */
.btn-primary {
  background: var(--turquoise); color: var(--black-1); font-weight: 600;
  padding: 16px 30px; border-radius: 0; font-size: var(--step-0);
  letter-spacing: var(--track-body);
  display: inline-flex; align-items: center; gap: 8px;
  transition: background .25s var(--ease), color .25s var(--ease);
  border: none; cursor: pointer;
}
.btn-primary:hover { background: var(--cyan-soft); }
.btn-ghost {
  background: transparent; border: 1px solid var(--w-35); color: var(--white); font-weight: 500;
  padding: 16px 30px; border-radius: 0; font-size: var(--step-0);
  letter-spacing: var(--track-body); transition: border-color .2s, color .2s, background .2s;
}
.btn-ghost:hover { border-color: currentColor; background: var(--w-06); }

/* Bright turquoise is a fill, never text: it fails contrast on paper but
   carries perfectly as a block with ink on top. This is the one place the
   light theme keeps the electric value. */
:root[data-theme="light"] .btn-primary,
:root[data-theme="light"] .btn-cta { background: var(--turquoise-bright); color: var(--ink); }
:root[data-theme="light"] .btn-primary:hover,
:root[data-theme="light"] .btn-cta:hover { background: var(--ink); color: var(--paper); }

.btn-cta {
  display: inline-flex; align-items: center; gap: 8px; background: var(--turquoise); color: var(--black-1);
  font-weight: 600; font-size: var(--step--1); padding: 11px 20px; border-radius: 0; transition: background .2s, color .2s;
}
.btn-cta:hover { background: var(--cyan-soft); }
[data-magnetic] { display: inline-block; will-change: transform; }

/* ============================================================
   Hero
   ============================================================ */
.hero {
  /* No px cap. It used to be min(92vh, 900px), which meant the hero stopped
     growing while the viewport kept going — so on a tall window the next
     section crept toward the fold (74px of clearance at 1080 tall, ~0 beyond).
     Any cap just moves that cliff to a taller screen. Tracking the viewport
     outright keeps the clearance constant at every height, which is what buys
     the room to tighten .whofor's top padding without the section peeking. */
  position: relative; min-height: 92vh;
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap); align-items: center;
  padding: var(--space-l) var(--gutter);
  background: transparent; z-index: 1;
}
/* display:contents dissolves the wrapper so the copy sits directly on the
   hero's 12 columns. Rows are explicit rather than auto-placed: the right-hand
   band spans two of them, which leaves gaps auto-flow would happily reflow
   copy into — the support note lands beside the headline instead of under the
   band, and only at some widths, which is the worst kind of bug. */
.hero__inner { display: contents; }
.hero .eyebrow { grid-column: 1 / -1; }
.hero-title { grid-column: 1 / span 7; grid-row: 1; }
.hero .lede { grid-column: 1 / span 6; grid-row: 2; max-width: none; align-self: start; }
.hero__support {
  grid-column: 8 / -1; grid-row: 3; align-self: start; margin: 0;
  font-size: var(--step-1); line-height: 1.65; color: var(--w-50);
  padding-top: var(--space-s); border-top: 1px solid var(--w-08);
}
.hero__cta-row {
  grid-column: 1 / span 6; grid-row: 4; display: flex; gap: 12px;
  margin-top: var(--space-l); flex-wrap: wrap;
}
@media (max-width: 1080px) {
  .hero { min-height: 0; padding-top: var(--space-xl); }
  /* Rows go back to auto — the explicit ones above only exist to keep the
     right-hand band's two-row span from reflowing copy, and nothing spans
     two rows here. */
  .hero-title, .hero .lede, .hero__support, .hero__cta-row {
    grid-column: 1 / -1; grid-row: auto;
  }
  .hero .lede { max-width: 46ch; }
  .hero__support { margin-top: var(--space-m); max-width: 52ch; }
}

/* ============================================================
   The solution — a ruled list, not cards. Three equal rounded
   boxes side by side is the single most template-looking thing a
   page can do; hairlines and a wide left label read as editorial
   and cost nothing to render.
   ============================================================ */

.pitch-row { position: relative; margin-top: var(--space-xl); }
.pitch-card {
  position: relative;
  display: grid; grid-template-columns: 4fr 7fr; gap: var(--col-gap);
  padding: var(--space-m) 0;
}
/* The hairlines are drawn as pseudo-elements rather than borders so they can
   be animated — a border cannot be swept, a scaled 1px box can. One above
   every row, and the closing line belongs to the last row rather than to the
   container, so that row owns both of its own edges and can draw them
   together. */
.pitch-card::before,
.pitch-card:last-child::after {
  content: ""; position: absolute; left: 0; right: 0; height: 1px;
  background: var(--w-08);
}
.pitch-card::before { top: 0; }
.pitch-card:last-child::after { bottom: 0; }

.pitch-card__k {
  font-family: var(--display); font-weight: 400; font-size: var(--step-3);
  letter-spacing: var(--track-title); display: block; color: var(--turquoise);
}
.pitch-card p { font-size: var(--step-1); line-height: 1.6; color: var(--w-70); margin: 0; max-width: 54ch; }

/* ---- The rules draw themselves ----
   The hairlines ARE the design of this section, so they are what animates:
   the line is drawn across in turquoise, the label and copy are wiped in
   behind that same edge, and only then does the line settle back to a
   hairline. Nothing fades.

   Every row runs this on its own, when it reaches the fold — the timing
   lives here, but WHICH row and WHEN is one observer per row, in initPitch.
   A single staggered run off the first row meant that on a slow scroll rows
   two and three had already finished by the time you got to them, so only
   the top one ever appeared to animate.

   The first version swept the hairline at its resting 8% grey and was
   invisible — a 1px line at that value has nothing to see moving. The colour
   is what makes the gesture legible; it is temporary, so the section still
   ends up exactly as drawn.

   Hidden state is scoped to .pitch-anim, which JS adds per row — with no JS,
   no IntersectionObserver, or reduced motion, the section is simply static
   and fully visible. */
.pitch-card.pitch-anim::before,
.pitch-card.pitch-anim:last-child::after {
  transform: scaleX(0); transform-origin: left center;
  background: var(--turquoise);
  /* Transform is composited; the colour is a 1px-tall box, so repainting it
     costs nothing even on an old laptop. The second delay is the colour
     settling back — it starts .4s into the sweep, so the line is turquoise
     where it is being drawn and grey where it has already passed. */
  transition: transform 1s var(--ease), background-color .55s linear;
  transition-delay: 0s, .4s;
}
/* The last row draws both of its edges, the closing one a beat later so the
   row is boxed in rather than bracketed at once. */
.pitch-card.pitch-anim:last-child::after { transition-delay: .3s, .7s; }

/* Label AND copy are both wiped in behind the line rather than faded — same
   direction, same edge, so the rule reads as drawing the whole row rather
   than as decoration next to it. Each is wiped from its own left edge, not
   the row's, so the two clear together despite starting in different
   columns. */
.pitch-card.pitch-anim .pitch-card__k,
.pitch-card.pitch-anim p {
  clip-path: inset(0 100% 0 0);
  transition: clip-path .9s var(--ease);
}
.pitch-card.pitch-anim .pitch-card__k { transition-delay: .1s; }
.pitch-card.pitch-anim p { transition-delay: .22s; }

.pitch-card.is-drawn::before,
.pitch-card.is-drawn:last-child::after { transform: none; background: var(--w-08); }
.pitch-card.is-drawn .pitch-card__k,
.pitch-card.is-drawn p { clip-path: inset(0 0 0 0); }

@media (max-width: 720px) {
  .pitch-card { grid-template-columns: 1fr; gap: var(--space-s); }
}


/* Four ruled columns rather than four boxes: one shared top hairline,
   dividers between, nothing floating. */
/* Five items now, so the flush/last-in-row rules are keyed to the column
   count rather than to :first-child — otherwise the fifth card wraps and
   lands indented, with no rule above it. */
.privacy-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  margin-top: var(--space-xl); border-top: 1px solid var(--w-12);
}
.privacy-card { padding: var(--space-m) var(--space-s) var(--space-l); border-right: 1px solid var(--w-08); }
.privacy-card:nth-child(3n+1) { padding-left: 0; }
.privacy-card:nth-child(3n) { border-right: none; padding-right: 0; }
.privacy-card:last-child { border-right: none; }
.privacy-card__icon { color: var(--turquoise); margin-bottom: var(--space-m); display: block; }
.privacy-card__icon svg { width: 22px; height: 22px; display: block; }
.privacy-card h3 {
  font-family: var(--display); font-weight: 400; font-size: var(--step-3);
  letter-spacing: var(--track-title); line-height: 1.15; margin: 0 0 12px;
}
.privacy-card p { font-size: var(--step-1); line-height: 1.6; color: var(--w-70); margin: 0; }
.privacy-cta { display: flex; gap: 12px; margin-top: var(--space-xl); flex-wrap: wrap; }

@media (max-width: 720px) {
  .privacy-grid { grid-template-columns: 1fr; }
  .privacy-card:nth-child(n) {
    border-right: none; padding-left: 0; padding-right: 0;
    border-bottom: 1px solid var(--w-08);
  }
  .privacy-card:last-child { border-bottom: none; }
}

/* ============================================================
   Trailing notes under the widget. The pinned walkthrough and its
   parallel .flow mock are gone — there is one widget demo now, the
   real one, so the two can no longer drift apart.
   ============================================================ */
/* These are the widget's own footnotes, so they share its paper rather than
   arriving on a new colour: #try and .hiw-outro are one band, and the join
   carries no padding of its own. Previously the band changed at the widget's
   bottom edge and then ran ~190px of empty paper before the first key, which
   read as an orphaned section rather than a continuation. */
#try { padding-bottom: var(--space-xl); }
.hiw-outro { padding-top: 0; }

.hiw-features {
  display: grid; grid-template-columns: repeat(4, 1fr);
  margin-top: var(--space-l); border-top: 1px solid var(--w-12);
}
.hiw-feature { padding: var(--space-m); border-right: 1px solid var(--w-08); }
.hiw-feature:first-child { padding-left: 0; }
.hiw-feature:last-child { border-right: none; padding-right: 0; }
.hiw-feature__k { font-family: var(--mono); font-size: var(--step-marker); letter-spacing: var(--track-label); text-transform: uppercase; color: var(--turquoise); font-weight: 400; }
.hiw-feature__v { font-size: var(--step-1); color: var(--w-70); margin-top: 10px; line-height: 1.6; }
.hiw-note { margin-top: var(--space-m); font-size: var(--step-1); line-height: 1.7; color: var(--w-50); max-width: 70ch; }

@media (max-width: 720px) {
  .hiw-features { grid-template-columns: repeat(2, 1fr); }
  .hiw-feature:nth-child(2) { border-right: none; }
  .hiw-feature:nth-child(1), .hiw-feature:nth-child(2) { border-bottom: 1px solid var(--w-08); }
}

@media (max-width: 1080px) { .mv-grid { grid-template-columns: 1fr; } }


/* ============================================================
   Who it's for: a strip, but on the same rails as a section.
   Horizontal padding, eyebrow and type scale all come from the
   system (.section / .eyebrow / .pitch-card) so it can't drift.
   ============================================================ */
/* A short band, so it takes the section rails but not the full section gap. */
/* First section after the hero, so its top gap is smaller than a section-to-
   section one: the hero already pays its own bottom padding, and a full
   --space-2xl on top of that left ~250px of nothing between the CTA row and
   "Who it's for". The bottom stays generous — the gap DOWN to the next
   section is a real section break, the gap UP is a double-count. */
.whofor { padding-bottom: var(--space-2xl); }
.whofor__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--w-12);
}
.whofor__item { padding: var(--space-m) var(--space-m) 0; border-right: 1px solid var(--w-08); }
.whofor__item:first-child { padding-left: 0; }
.whofor__item:last-child { border-right: none; padding-right: 0; }
.whofor__item b {
  display: block; font-family: var(--display); font-weight: 400; font-size: var(--step-3);
  letter-spacing: var(--track-title); line-height: 1.15; color: var(--turquoise); margin-bottom: 12px;
}
.whofor__item span { display: block; font-size: var(--step-1); line-height: 1.6; color: var(--w-70); }

/* ============================================================
   The problem, in three borrowed numbers. Every one carries its
   source in the markup, because a claim without one is decoration.
   ============================================================ */
/* A hairline table, not three cards. Coral is spent here and nowhere
   else on the page — it is the colour of the problem. */

.stats__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  margin-top: var(--space-xl); border-top: 1px solid var(--w-12);
}
/* The bottom padding was sized around a third line — the source credit — that
   the cells no longer carry, and without it the dividers ran on past the text
   into nothing. */
.stat { padding: var(--space-m) var(--space-m) var(--space-m); border-right: 1px solid var(--w-08); }
.stat:first-child { padding-left: 0; }
.stat:last-child { border-right: none; padding-right: 0; }
.stat__n {
  font-family: var(--display); font-weight: 400;
  font-size: clamp(52px, 7vw, 96px); line-height: .92;
  letter-spacing: var(--track-display); color: var(--coral);
}
.stat__n i { font-style: normal; font-size: .34em; margin-left: 4px; letter-spacing: 0; }
/* A joining word rather than a unit: "bn" and "%" hang off the end of a number
   and only need a hair of air on the left, "in" sits BETWEEN two numerals and
   has to read as a gap. In em on the <i>, so it tracks the clamped display
   size instead of collapsing to a hair on a phone. */
.stat__n i.j { margin-left: .55em; margin-right: .55em; }
/* No max-width: the cell is already a third of the container and carries 44px
   of side padding, so a measure cap on top of that was a third limit. It held
   the caption to 293px inside a 441px cell, wrapping every one to two lines
   with ~150px of the cell left empty — which is what read as compressed. */
.stat__v { font-size: var(--step-1); line-height: 1.5; margin: var(--space-s) 0 0; color: var(--w-70); }
.stats__foot {
  margin-top: var(--space-l); font-size: var(--step-1); line-height: 1.65;
  color: var(--w-70); max-width: 82ch;
}

/* 1080 is the page's own breakpoint (.hiw__grid, .privacy-grid stack there). */
@media (max-width: 1080px) {
  .whofor__grid, .stats__grid { grid-template-columns: 1fr; }
  .whofor__item, .stat {
    border-right: none; border-bottom: 1px solid var(--w-08);
    padding-left: 0; padding-right: 0;
  }
  .whofor__item:last-child, .stat:last-child { border-bottom: none; }
}

/* ============================================================
   About — mission/vision, team
   ============================================================ */
.about-intro__copy { max-width: 74ch; }
.mv-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; margin-top: 56px; }
.mv-card { border: 1px solid var(--w-08); border-radius: var(--radius-xl); padding: 32px; background: var(--black-2); }
.mv-card:hover { border-color: var(--turquoise); }
.mv-card__k { font-family: var(--mono); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--turquoise); display: block; margin-bottom: 16px; }
.mv-card p { font-family: var(--display); font-weight: 500; font-size: clamp(19px, 2vw, 23px); line-height: 1.45; margin: 0; }

.team-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 48px; }
.team-card { margin: 0; }
.team-card__photo {
  position: relative; aspect-ratio: 4 / 5; border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--w-08); background: var(--black-3); display: flex; align-items: center; justify-content: center;
}
.team-card__initials { font-family: var(--display); font-weight: 700; font-size: 46px; color: var(--w-35); letter-spacing: .01em; }
.team-card figcaption { margin-top: 18px; }
.team-card__name { font-family: var(--display); font-weight: 600; font-size: 19px; }
.team-card__role { font-size: 13px; color: var(--turquoise-deep); margin-top: 4px; letter-spacing: .02em; }
.team-contact { margin-top: 44px; font-size: 15px; opacity: .8; }
.team-contact a { color: var(--turquoise-deep); font-weight: 600; border-bottom: 2px solid rgba(0,107,96,.4); }

@media (max-width: 720px) { .team-grid { grid-template-columns: 1fr; max-width: 320px; } }

/* ============================================================
   Contact — book a demo form
   ============================================================ */
/* Vertically centred inside 92vh, so with no padding the form sits against
   the footer whenever the content is tall enough to fill it. */
.contact-wrap { position: relative; overflow: hidden; min-height: 92vh; display: flex; align-items: center; padding: var(--space-l) 8vw; background: rgba(24,24,24,.82); }
.contact-inner { position: relative; z-index: 2; max-width: 640px; min-width: 0; }
.demo-form { margin-top: 36px; display: flex; flex-direction: column; gap: 16px; max-width: 460px; }
.demo-form input, .demo-form textarea {
  font-family: var(--body); font-size: 15px; padding: 15px 18px; border-radius: var(--radius-md);
  border: 1px solid var(--w-20); background: var(--black-2); color: var(--white);
}
.demo-form input::placeholder, .demo-form textarea::placeholder { color: var(--w-50); }
.demo-form input:focus, .demo-form textarea:focus { outline: 2px solid var(--turquoise); outline-offset: 1px; }
.demo-form textarea { resize: vertical; min-height: 96px; }
.demo-form button { background: var(--turquoise); color: var(--black-1); font-weight: 700; font-size: 15px; padding: 17px; border-radius: var(--radius-md); border: none; cursor: pointer; transition: background .2s, transform .15s; }
.demo-form button:hover { background: var(--cyan-soft); transform: translateY(-1px); }
.form-sent { margin-top: 26px; font-size: 17px; font-weight: 600; font-family: var(--display); display: none; }
.form-sent.show { display: block; }
.contact-methods { display: flex; gap: 40px; flex-wrap: wrap; margin-top: 48px; }
.contact-methods a { font-weight: 600; border-bottom: 2px solid var(--w-35); padding-bottom: 2px; }

/* ============================================================
   The widget demo — a mock of a RETAILER's product page, carrying the
   real w.js. There is no mock of the widget itself any more: the page
   used to hand-build its four screens in HTML and CSS here, which is a
   second implementation of the product with nothing keeping it honest.
   Everything below styles the page AROUND the widget; the widget styles
   itself, inside its own shadow root, exactly as it does on a customer's
   store. That boundary is the point — nothing here can restyle it into
   looking better than it really does.
   ============================================================ */
.pdp-demo {
  margin-top: var(--space-l);
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--col-gap); align-items: start;
  border: 1px solid var(--w-12); background: var(--paper);
}
.pdp-demo__art { background: #f0ece3; align-self: stretch; }
.pdp-demo__art img { display: block; width: 100%; height: 100%; object-fit: cover; }
.pdp-demo__info { padding: var(--space-m) var(--space-m) var(--space-l) 0; }

.pdp-demo__cat {
  font-family: var(--mono); font-size: var(--step--2); letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--w-50); margin: 0 0 10px;
}
.pdp-demo__name {
  font-family: var(--display); font-weight: 400; font-size: var(--step-4);
  letter-spacing: var(--track-title); line-height: 1.1; margin: 0;
}
.pdp-demo__price { font-size: var(--step-2); margin: 8px 0 0; }
.pdp-demo__desc { font-size: var(--step-1); line-height: 1.6; color: var(--w-70); margin: 16px 0 0; max-width: 46ch; }

.pdp-demo__label {
  display: block; font-family: var(--mono); font-size: var(--step--2);
  letter-spacing: var(--track-label); text-transform: uppercase; color: var(--w-50);
}
.pdp-demo__opt { margin-top: var(--space-m); }
.pdp-demo__swatches { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
/* The retailer's own size control — the thing the widget is there to replace.
   Square, because a storefront's controls are not ours to make pills of. */
.pdp-demo .sw input { position: absolute; opacity: 0; pointer-events: none; }
.pdp-demo .sw span {
  display: inline-block; min-width: 46px; text-align: center;
  padding: 10px 12px; border: 1px solid var(--w-12);
  font-size: var(--step-0); cursor: pointer; transition: border-color .15s, background .15s;
}
.pdp-demo .sw input:checked + span { border-color: var(--ink); background: var(--ink); color: var(--paper); }
.pdp-demo .sw input:focus-visible + span { outline: 2px solid var(--turquoise); outline-offset: 2px; }
/* The moment the widget hands the size back. Brief and once — the swatch is
   already selected by then, so this only has to make the change noticeable,
   not argue for it. */
.pdp-demo .sw.is-picked span { animation: sw-picked 1.4s var(--ease) 1; }
@keyframes sw-picked {
  0%   { box-shadow: 0 0 0 0 rgba(0, 245, 220, .9); }
  60%  { box-shadow: 0 0 0 9px rgba(0, 245, 220, 0); }
  100% { box-shadow: 0 0 0 0 rgba(0, 245, 220, 0); }
}

/* stretch, not center: the stepper takes its height FROM the widget's trigger
   rather than guessing at it. The trigger is sized by w.js's own padding, so
   any hard number here drifts the moment that changes — and the two sitting at
   different heights in the same row is the first thing the eye catches. */
.pdp-demo__row { display: flex; align-items: stretch; gap: 12px; margin-top: var(--space-m); flex-wrap: wrap; }
/* min-height for the wrapped case: on a narrow screen the trigger drops to
   its own line, and with nothing left to stretch against the stepper
   collapsed to 24px. */
.pdp-demo__qty { display: flex; align-items: stretch; min-height: 48px; border: 1px solid var(--w-12); }
.pdp-demo__qty button {
  width: 40px; border: 0; background: none; cursor: pointer;
  font-size: 17px; color: inherit; font-family: var(--body);
}
.pdp-demo__qty input {
  width: 46px; border: 0; border-left: 1px solid var(--w-12); border-right: 1px solid var(--w-12);
  background: none; text-align: center; font-family: var(--body); font-size: var(--step-0); color: inherit;
  -moz-appearance: textfield;
}
.pdp-demo__qty input::-webkit-outer-spin-button,
.pdp-demo__qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pdp-demo__fit { flex: 1 1 240px; min-width: 0; display: flex; }
.pdp-demo__fit > div { flex: 1; min-width: 0; }

.pdp-demo__buy {
  display: block; width: 100%; margin-top: 12px; padding: 15px 20px;
  border: 0; background: var(--ink); color: var(--paper);
  font-family: var(--body); font-size: var(--step-0); font-weight: 600; cursor: pointer;
}

/* The "click me" pulse: the box itself breathes, rather than radiating rings
   out of it. Drawn by the WRAPPER, never by w.js — a shadow host renders no
   pseudo-elements of its own, and the production widget is not getting a
   marketing animation compiled into it for one page.

   THE TRAP, and why the animation stops while the sheet is open: a transform
   on an ancestor makes position:fixed descendants resolve against THAT
   element instead of the viewport. The widget's overlay is fixed and lives
   inside this wrapper, so an always-on transform would peg the modal to a
   240px box in the buy row. `animation: none` restores transform:none, which
   is why it is switched off rather than paused. Nothing is lost visually —
   the trigger is behind a full-screen scrim by then. */
.demo-pulse { position: relative; animation: demo-pulse 2.2s var(--ease) infinite; }
@keyframes demo-pulse {
  0%, 100% { transform: scale(1);     box-shadow: 0 0 0 0 rgba(0, 245, 220, 0); }
  50%      { transform: scale(1.022); box-shadow: 0 6px 26px -6px rgba(0, 245, 220, .75); }
}
:root.widget-open .demo-pulse { animation: none; }

/* While the sheet is open, the nav drops below the page.

   .section and .main both set `position: relative; z-index: 1`, and each of
   those is a stacking context. The widget's overlay asks for z-index
   2147483000, but that number is only compared INSIDE #try — so the whole
   modal was being resolved at the section's z-index of 1, under a nav sitting
   at 200. The visible symptom was the sheet's top edge, its progress bar and
   its close button disappearing behind the nav bar.

   Raising the section instead would put the section's own content over the
   nav on every scroll, which is worse. Lowering the nav for the duration is
   what a full-screen modal wants anyway. The class is put on <html> by
   widget-demo.js, which watches the overlay. */
:root.widget-open .nav { z-index: 0; }

.pdp-demo__note {
  margin: var(--space-m) 0 0; max-width: 74ch;
  font-size: var(--step--1); line-height: 1.65; color: var(--w-50);
}

@media (max-width: 900px) {
  .pdp-demo { grid-template-columns: 1fr; }
  .pdp-demo__art img { height: auto; aspect-ratio: 4 / 5; }
  .pdp-demo__info { padding: var(--space-m); }
}

/* ============================================================
   Retailer dashboard, reproduced

   A portrait of dashboard/public/index.html, so it carries that file's
   own tokens rather than the site's — its light theme, its 236px sidebar,
   its 14px card radius, its Space Grotesk figures. Everything is scoped
   under .dm and prefixed, because the dashboard's class names (.card,
   .metric, .row, .pill) are generic enough to collide with the site's.

   The values below are copied from the dashboard's
   :root[data-theme="light"] block. If they drift there, they are wrong
   here.
   ============================================================ */
.dm {
  --dm-bg: #f4f5f6;
  --dm-panel: #ffffff;
  --dm-panel2: #f2f3f4;
  --dm-panel3: #e8eaeb;
  --dm-side: #ffffff;
  --dm-line: rgba(16,16,20,.09);
  --dm-line2: rgba(16,16,20,.15);
  --dm-ink: #16181b;
  --dm-mut: rgba(16,16,20,.58);
  --dm-mut2: rgba(16,16,20,.40);
  --dm-acc: #06B6A4;
  --dm-acc-soft: #00D6C2;
  --dm-acc-ink: #ffffff;
  --dm-acc-text: #068C7E;
  --dm-acc-fill: rgba(6,182,164,.12);
  --dm-warn: #C98A21;
  --dm-radius: 14px;

  margin-top: 48px;
  border: 1px solid var(--w-12);
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: var(--dm-bg);
  color: var(--dm-ink);
  font-size: 15px;
  line-height: 1.55;
  box-shadow: 0 40px 90px -55px rgba(24,24,24,.45);
}

/* Browser chrome — the site's framing device, not the dashboard's. */
.dm__chrome { display: flex; align-items: center; gap: 8px; padding: 13px 18px; background: var(--dm-panel2); border-bottom: 1px solid var(--dm-line); }
.dm__dot { width: 10px; height: 10px; border-radius: 50%; background: var(--dm-line2); }
.dm__url { margin-left: 14px; font-family: var(--mono); font-size: 11.5px; color: var(--dm-mut2); }

/* ── app layout: sidebar + content ───────────────────────────── */
.dm__app { display: grid; grid-template-columns: 210px 1fr; min-height: 460px; }
.dm__side { display: flex; flex-direction: column; gap: 8px; padding: 20px 14px; background: var(--dm-side); border-right: 1px solid var(--dm-line); }
.dm__brand { display: inline-flex; align-items: center; gap: 9px; padding: 2px 8px 16px; }
.dm__mark { width: 21px; height: 18px; flex: none; background: var(--dm-acc); -webkit-mask: url("../img/mark.svg") no-repeat center/contain; mask: url("../img/mark.svg") no-repeat center/contain; }
.dm__brandword { font-family: var(--display); font-weight: 700; font-size: 17px; letter-spacing: -.4px; }

.dm__nav { display: flex; flex-direction: column; gap: 3px; }
.dm-tab { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: 1px solid transparent; border-radius: 10px;
  color: var(--dm-mut); font-family: var(--body); font-size: 13.5px; font-weight: 500; padding: 9px 11px;
  transition: color .15s, background .15s; }
.dm-tab:hover { color: var(--dm-ink); background: var(--dm-panel2); }
.dm-tab.on { color: var(--dm-ink); background: var(--dm-acc-fill); }
.dm-tab.on .dm-ic { background: var(--dm-acc); }
.dm-ic { width: 16px; height: 16px; flex: none; background: var(--dm-mut);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain; }

.dm__sidefoot { margin-top: auto; }
.dm-store { background: var(--dm-panel2); border: 1px solid var(--dm-line); border-radius: 12px; padding: 11px; }
.dm-store__n { font-weight: 600; font-size: 13.5px; display: flex; align-items: center; gap: 7px; }
.dm-store__s { font-weight: 400; font-size: 11px; color: var(--dm-acc-text); }
.dm-store__id { font-family: var(--mono); font-size: 10.5px; color: var(--dm-mut2); margin-top: 3px; }
.dm-store__e { font-size: 11px; color: var(--dm-mut); margin-top: 4px; }

.dm__content { padding: 22px clamp(16px, 2.4vw, 28px) 30px; min-width: 0; }
.dm__top { display: flex; align-items: baseline; gap: 12px; margin-bottom: 18px; }
.dm__top h3 { font-family: var(--display); font-weight: 600; font-size: 22px; margin: 0; letter-spacing: -.6px; }
.dm__sub { color: var(--dm-mut); font-size: 12.5px; }

/* ── cards / grid ────────────────────────────────────────────── */
.dm-card { background: var(--dm-panel); border: 1px solid var(--dm-line); border-radius: var(--dm-radius); padding: 18px; }
.dm-card > b { font-family: var(--display); font-weight: 600; font-size: 14.5px; letter-spacing: -.1px; }
.dm-grid { display: grid; gap: 12px; }
.dm-g4 { grid-template-columns: repeat(4, 1fr); }
.dm-g2 { grid-template-columns: 1fr 1fr; }
.dm-sp { height: 12px; }
.dm-row { display: flex; gap: 9px; align-items: center; }
.dm-right { margin-left: auto; }
.dm-muted { color: var(--dm-mut); }
.dm-mono { font-family: var(--mono); font-size: 12.5px; }
.dm-sub { color: var(--dm-mut); font-size: 12px; margin: 3px 0 14px; }
.dm-cardhead { display: flex; align-items: center; gap: 9px; }
.dm-cardhead b { font-family: var(--display); font-weight: 600; font-size: 14.5px; }
/* The site's commentary on the screen, deliberately outside the device —
   inside it, it would read as copy the dashboard itself shows. */
.dash-note { font-size: var(--step--1); color: var(--w-50); line-height: 1.6; margin: 18px 0 0; max-width: 76ch; }

/* ── metric cards ────────────────────────────────────────────── */
.dm-metric__l { color: var(--dm-mut); font-size: 10.5px; text-transform: uppercase; letter-spacing: 1.2px; font-weight: 600; }
.dm-metric__n { font-family: var(--display); font-size: 30px; font-weight: 700; line-height: 1.05; margin-top: 7px; letter-spacing: -1px; }
.dm-metric__s { color: var(--dm-mut); font-size: 12px; margin-top: 3px; }
.dm-bar { height: 6px; border-radius: 4px; background: var(--dm-panel3); margin-top: 13px; overflow: hidden; }
.dm-bar > i { display: block; height: 100%; background: var(--dm-acc); border-radius: 4px; }

/* ── trend chart ─────────────────────────────────────────────── */
.dm-chart svg { display: block; width: 100%; height: 110px; overflow: visible; }

/* ── distribution rows / top list / gauge ────────────────────── */
.dm-dist { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; font-size: 12.5px; }
.dm-dist__k { width: 58px; flex: none; font-weight: 600; }
.dm-dist__t { flex: 1; height: 20px; background: var(--dm-panel2); border-radius: 6px; overflow: hidden; }
.dm-dist__t > i { display: block; height: 100%; border-radius: 6px; min-width: 2px;
  background: linear-gradient(90deg, var(--dm-acc), var(--dm-acc-soft)); }
.dm-dist__v { width: 64px; flex: none; text-align: right; color: var(--dm-mut); font-variant-numeric: tabular-nums; }

.dm-top { list-style: none; margin: 0; padding: 0; }
.dm-top li { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--dm-line); font-size: 13px; }
.dm-top li:last-child { border-bottom: none; }
.dm-top__r { width: 18px; color: var(--dm-mut2); font-family: var(--display); font-weight: 700; }
.dm-top__n { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dm-top__c { color: var(--dm-acc-text); font-weight: 600; font-variant-numeric: tabular-nums; }

.dm-gauge { display: flex; align-items: center; gap: 16px; }
.dm-ring { --p: 0; position: relative; width: 86px; height: 86px; flex: none; border-radius: 50%;
  background: conic-gradient(var(--dm-acc) calc(var(--p) * 1%), var(--dm-panel3) 0);
  display: grid; place-items: center; }
.dm-ring::before { content: ""; width: 66px; height: 66px; border-radius: 50%; background: var(--dm-panel); position: absolute; }
.dm-ring b { position: relative; font-family: var(--display); font-size: 20px; font-weight: 700; }
.dm-gauge__m { font-size: 12.5px; color: var(--dm-mut); line-height: 1.7; }
.dm-gauge__m b { color: var(--dm-ink); }

/* ── tables ──────────────────────────────────────────────────── */
.dm-tablewrap { overflow-x: auto; }
.dm-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.dm-table th, .dm-table td { text-align: left; padding: 10px 9px; border-bottom: 1px solid var(--dm-line); }
.dm-table th { color: var(--dm-mut); font-weight: 600; font-size: 10.5px; text-transform: uppercase; letter-spacing: .6px; white-space: nowrap; }
.dm-table tbody tr:last-child td { border-bottom: none; }
.dm-table--list tbody tr { cursor: pointer; }
.dm-table--list tbody tr.on { background: var(--dm-acc-fill); }

.dm-pill { display: inline-block; padding: 2px 9px; border-radius: 20px; font-size: 11.5px; border: 1px solid var(--dm-line2); white-space: nowrap; }
.dm-pill.size { background: var(--dm-acc-fill); border-color: transparent; color: var(--dm-acc-text); font-weight: 600; }
.dm-pill.flag { background: rgba(201,138,33,.16); border-color: transparent; color: var(--dm-warn); }

.dm-pager { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: 12.5px; }

/* ── controls. Inert on a marketing page, so the inputs are rendered
      as blocks rather than real fields: a focusable box that does
      nothing is worse than a picture of one. ─────────────────── */
.dm-btn { font: inherit; font-size: 12px; cursor: pointer; border: 1px solid var(--dm-line2);
  background: var(--dm-panel2); color: var(--dm-ink); padding: 6px 12px; border-radius: 9px;
  font-family: var(--body); transition: border-color .15s, background .15s; }
.dm-btn:hover { border-color: var(--dm-acc); }
.dm-btn--primary { background: var(--dm-acc); border-color: var(--dm-acc); color: var(--dm-acc-ink); font-weight: 600; }
.dm-btn--primary:hover { background: var(--dm-acc-soft); border-color: var(--dm-acc-soft); }
.dm-lab { display: block; font-size: 11.5px; color: var(--dm-mut); margin: 0 0 5px; }
.dm-input { background: var(--dm-panel); border: 1px solid var(--dm-line2); border-radius: 9px; padding: 9px 11px; font-size: 13px; line-height: 1.5; }
.dm-input--sm { flex: 1; max-width: 260px; padding: 7px 11px; }
.dm-code { background: var(--dm-panel2); border: 1px solid var(--dm-line); border-radius: 9px;
  padding: 12px; font-family: var(--mono); font-size: 11.5px; line-height: 1.6; margin: 0;
  white-space: pre; overflow-x: auto; color: var(--dm-ink); }
.dm-keyrow { display: flex; align-items: center; gap: 10px; padding: 11px 0; border-bottom: 1px solid var(--dm-line); font-size: 12.5px; flex-wrap: wrap; }

/* ── reflow. The sidebar becomes a strip, as it does in the real
      dashboard at 860px. ──────────────────────────────────────── */
@media (max-width: 1080px) {
  .dm-g4 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 860px) {
  .dm__app { grid-template-columns: 1fr; }
  .dm__side { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 6px;
    border-right: none; border-bottom: 1px solid var(--dm-line); padding: 11px 14px; }
  .dm__brand { padding: 0 6px 0 0; }
  .dm__nav { flex-direction: row; flex-wrap: wrap; }
  .dm-tab { width: auto; padding: 7px 10px; font-size: 12.5px; }
  .dm__sidefoot { display: none; }
  .dm-g4, .dm-g2 { grid-template-columns: 1fr; }
}

.faq { max-width: 780px; margin-top: 36px; }
.faq-item { border-top: 1px solid var(--b-14); }
.section--dark .faq-item, .section--dark2 .faq-item, .section--deep .faq-item { border-top: 1px solid var(--w-08); }
.faq-item:last-child { border-bottom: 1px solid var(--w-08); }
.faq-q { width: 100%; text-align: left; background: none; border: none; cursor: pointer; color: inherit; font-family: var(--display); font-weight: 600; font-size: 19px; padding: 24px 0; display: flex; justify-content: space-between; align-items: center; gap: 20px; }
.faq-q__icon { color: var(--turquoise); font-size: 22px; transition: transform .3s var(--ease); flex-shrink: 0; }
/* The + is the only thing that says a row opens, so it has to clear 3:1 as a
   non-text control. Verdigris on white lands at 2.98, just under. */
:root[data-theme="light"] .section--dark2 .faq-q__icon { color: #006B60; }

/* ============================================================
   About and Contact on paper

   Both pages ride the same token flip as the home page, so most of this
   comes for free: --black-* resolve to paper, --white to ink, the --w-*
   alphas to ink alphas. These are the literals the flip cannot reach.
   ============================================================ */

/* The contact panel's ground is a hardcoded near-black, so it stayed dark
   under a light nav and a light footer. */
:root[data-theme="light"] .contact-wrap { background: var(--paper); }

/* Inputs: --black-2 resolves to White, which is right, but the border and
   the placeholder were picked to sit on near-black. A form is the one place
   on either page where a shopper has to see the edge of a control. */
:root[data-theme="light"] .demo-form input,
:root[data-theme="light"] .demo-form textarea {
  background: var(--paper-2);
  border-color: var(--w-20);
  color: var(--ink);
}
:root[data-theme="light"] .demo-form input::placeholder,
:root[data-theme="light"] .demo-form textarea::placeholder { color: rgba(24,24,24,.45); }

/* The mission/vision labels sit on White inside the card, not on cream, and
   Verdigris there is 2.98:1 at 12px. Same darker teal the FAQ marker takes. */
:root[data-theme="light"] .mv-card__k { color: #006B60; }

/* The submit button was turquoise-fill with --black-1 text, and --black-1 is
   cream on this theme: cream on Verdigris is 2.59:1. It takes the same
   treatment as every other primary button on paper, which is the bright fill
   with ink on top. */
/* Shape by job: on paper --radius-md is 0, which is right for the fields
   (they are containers) and wrong for the button, which is a control and
   should be the pill every other button on the site is. */
:root[data-theme="light"] .demo-form button { background: var(--turquoise-bright); color: var(--ink); border-radius: 999px; }
:root[data-theme="light"] .demo-form button:hover { background: var(--ink); color: var(--paper); }

/* The team block keeps inverting with Snow, so anything inside it is back on
   a dark ground and takes the bright accent rather than Verdigris. */
:root[data-theme="light"] .section--snow .team-card__role { color: var(--turquoise); }
:root[data-theme="light"] .section--snow .team-contact a {
  color: var(--turquoise);
  border-bottom-color: rgba(0,245,220,.4);
}
.faq-item.open .faq-q__icon { transform: rotate(45deg); }
.faq-a { max-height: 0; overflow: hidden; transition: max-height .35s var(--ease), padding .35s var(--ease); font-size: 15px; line-height: 1.6; opacity: .78; }
.faq-item.open .faq-a { padding-bottom: 24px; }

.toast { position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%) translateY(20px); background: var(--black-2); color: var(--white); padding: 14px 22px; border-radius: 100px; border: 1px solid var(--w-08); font-size: 14px; opacity: 0; pointer-events: none; transition: opacity .3s var(--ease), transform .3s var(--ease); z-index: 400; }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }


/* ============================================================
   Weave — the fabric answer to "we need texture but own no
   photography". A plain weave is over-under warp and weft, which
   is a thing to generate rather than license: no bytes, no model
   release, no attribution, and it is literally what the product
   is about. It is also a halftone by construction, so it speaks
   the same language as the hero rather than adding a second one.

   Used as a GROUND, not as a divider strip. A 16px band of it read
   as a placeholder or a selection marquee — texture needs area to
   register as material rather than as a pattern.
   ============================================================ */
/* As a ground: the closer sits on cloth, fading out so the type
   never has to fight it. */
.closer { position: relative; overflow: hidden; }
.closer::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='9' height='9'><rect width='9' height='9' fill='%23181818' opacity='.22'/><g fill='%23181818' opacity='.62'><rect x='0' y='0' width='3' height='3'/><rect x='3' y='3' width='3' height='3'/><rect x='6' y='6' width='3' height='3'/></g><g fill='%23181818' opacity='.30'><rect x='2.7' y='0' width='.5' height='9'/><rect x='5.7' y='0' width='.5' height='9'/></g></svg>");
  background-size: 9px 9px;
  opacity: .085;
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,1), rgba(0,0,0,0) 78%);
  mask-image: linear-gradient(180deg, rgba(0,0,0,1), rgba(0,0,0,0) 78%);
}
.closer > * { position: relative; }

/* ============================================================
   What a pilot looks like — a real sequence, so the numbering
   carries information rather than decorating the section.
   ============================================================ */
.pilot__steps {
  list-style: none; margin: var(--space-xl) 0 0; padding: 0;
  grid-column: 1 / -1;
  display: grid; grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--w-12);
}
.pilot-step { padding: var(--space-m); border-right: 1px solid var(--w-08); }
.pilot-step:first-child { padding-left: 0; }
.pilot-step:last-child { border-right: none; padding-right: 0; }
.pilot-step__n {
  font-family: var(--mono); font-size: var(--step-marker);
  letter-spacing: var(--track-label); color: var(--turquoise);
  display: block; margin-bottom: var(--space-m);
}
.pilot-step h3 {
  font-family: var(--display); font-weight: 400; font-size: var(--step-3);
  letter-spacing: var(--track-title); line-height: 1.15; margin: 0 0 12px;
}
.pilot-step p { font-size: var(--step-1); line-height: 1.6; color: var(--w-70); margin: 0; }

@media (max-width: 1080px) {
  /* Three into two leaves an orphan, so the row becomes a stack: the rules
     move from vertical to horizontal and the last one is dropped. */
  .pilot__steps { grid-template-columns: 1fr; }
  .pilot-step { border-right: none; padding-left: 0; padding-right: 0;
    border-bottom: 1px solid var(--w-08); }
  .pilot-step:last-child { border-bottom: none; padding-bottom: 0; }
}
@media (max-width: 720px) {
  .pilot__steps { grid-template-columns: 1fr; }
  .pilot-step { border-right: none; padding-left: 0; padding-right: 0; border-bottom: 1px solid var(--w-08); }
  .pilot-step:last-child { border-bottom: none; }
}

/* ============================================================
   The closing ask — the page used to just stop.
   ============================================================ */
.closer { padding-top: var(--space-2xl); padding-bottom: var(--space-2xl); }
.closer__h {
  grid-column: 1 / span 9;
  font-family: var(--display); font-weight: 400; font-size: var(--step-5);
  line-height: 1.0; letter-spacing: var(--track-title); margin: 0;
  max-width: 20ch;
}
.closer__cta { display: flex; gap: 12px; margin-top: var(--space-l); flex-wrap: wrap; }
@media (max-width: 1080px) { .closer__h { grid-column: 1 / -1; } }

/* ============================================================
   Widget + dashboard on paper. Both were built for a dark page and
   moved here when product.html was folded into the home page. The
   token remap carries most of it; these are the literals it can't
   reach, chiefly the fake browser chrome, which is Graphite in the
   markup while the tab labels flipped to ink and disappeared into it.
   ============================================================ */


/* ============================================================
   Site footer
   ============================================================ */
.site-footer { background: #292929; color: var(--white); padding: var(--space-l) 8vw 32px; border-top: 1px solid var(--w-12); position: relative; z-index: 1; }
.footer__grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 40px; padding-bottom: 56px; border-bottom: 1px solid var(--w-08); }
.footer__brand { display: flex; align-items: center; gap: 11px; margin-bottom: 18px; }
.footer__brand img { height: 28px; width: auto; }
.footer__brand span { font-family: var(--display); font-weight: 600; font-size: 20px; }
.footer__tagline { font-size: 13.5px; line-height: 1.6; color: var(--w-50); max-width: 30ch; }
.footer__col-title { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--w-50); margin-bottom: 18px; }
.footer__links { display: flex; flex-direction: column; gap: 12px; list-style: none; margin: 0; padding: 0; }
.footer__links a { font-size: 14px; color: var(--w-70); transition: color .2s; }
.footer__links a:hover { color: var(--turquoise); }
.footer__bottom { display: flex; justify-content: space-between; align-items: center; padding-top: 28px; flex-wrap: wrap; gap: 12px; }
.footer__copy { font-size: 12.5px; color: var(--w-50); }

@media (max-width: 1080px) { .footer__grid { grid-template-columns: 1fr 1fr; row-gap: 40px; } }
@media (max-width: 560px) { .footer__grid { grid-template-columns: 1fr; } }

/* ============================================================
   Responsive — general
   ============================================================ */
/* .section padding is fluid now (--space-3xl / --gutter), so it no longer
   needs a breakpoint of its own. */

/* ============================================================
   Reduced motion
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
  html { scroll-behavior: auto; }
  .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  /* initPitch already bails under reduced motion, so this only matters when the
     setting is changed after load — reduceMotion is read once and the class
     would otherwise stay on. */
  .pitch-card.pitch-anim::before,
  .pitch-card.pitch-anim::after,
  .pitch-card.pitch-anim .pitch-card__k,
  .pitch-card.pitch-anim p {
    opacity: 1 !important; transform: none !important; transition: none !important;
    clip-path: none !important; background-color: var(--w-08) !important;
  }
  .mv-grid:hover > .mv-card:not(:hover),
  .team-grid:hover > .team-card:not(:hover) {
    transform: none; opacity: .6;
  }
}

/* ============================================================
   The opening — the site arrives as the thing it sells.

   A pill the size of the widget's own trigger opens into a panel,
   and the panel becomes the page. One continuous object: its mark
   and wordmark travel to exactly where the nav's sit, so the
   overlay can fade out with no seam behind it.

   Cost: one fixed element changing its own width and height.
   Nothing under it is in flow, so nothing reflows — and the
   page beneath is fully rendered the whole time. It is covered,
   never gated: no JS, or a script that fails, means a normal
   site rather than a blank screen.

   Armed by an inline script in <head> (not here) so it covers
   before first paint instead of flashing the page first.
   ============================================================ */
.intro { display: none; }
/* Reserving the gutter while scrolling is locked keeps the document the
   same width as it will be once the scrollbar comes back. Without it the
   page — and the box centred over it — jump sideways by the scrollbar's
   width at the exact moment of the handover. */
:root.intro-lock { overflow: hidden; scrollbar-gutter: stable; }

:root.intro-armed .intro {
  display: block; position: fixed; inset: 0; z-index: 900;
  background: var(--paper); cursor: pointer;
  transition: opacity .38s linear;
}
.intro.is-gone { opacity: 0; pointer-events: none; }

/* The panel. Width is tight to its contents, so "left-aligned" and
   "centred" are the same thing here — which is what lets it widen
   into a nav bar without the brand ever jumping alignment.

   It starts on --control-radius, the same corner as every button on the
   page, then squares off as it grows. So the sequence reads as one Mirraya
   control opening into the page, and the shape it lands on is the square
   the rest of the layout is built from. */
.intro__box {
  position: absolute; left: 50%; top: 50%;
  width: 235px; height: 88px; border-radius: var(--control-radius);
  transform: translate(-50%, -50%) translateY(12px);
  /* It is a large fill, so it takes the bright mark rather than the
     deep teal that accent TEXT uses on paper. It bleeds back to paper as it
     grows — a full-viewport #00F5DC would be a flashbang, and the panel has
     to arrive as the page's own ground anyway. */
  background: var(--turquoise-bright);
  box-shadow: 0 24px 50px -28px rgba(24, 24, 24, .55);
  opacity: 0; overflow: hidden;
  transition: width 0.85s var(--ease) .26s, height 0.85s var(--ease) .26s,
              background .18s linear, border-radius .26s var(--ease-soft),
              box-shadow .5s linear .26s, opacity .5s var(--ease),
              transform .62s var(--ease);
}
.intro.is-in .intro__box { opacity: 1; transform: translate(-50%, -50%) translateY(0); }
.intro:hover .intro__box { box-shadow: 0 28px 56px -26px rgba(24, 24, 24, .62); }
.intro.is-open .intro__box {
  /* 100% of the overlay, not 100vw — vw includes the scrollbar. */
  width: 100%; height: 100%; border-radius: 0;
  background: var(--paper); box-shadow: none;
}

/* Ends on the nav's own geometry — same height, same gutter, same
   mark and wordmark sizes. If the nav changes, this must follow. */
.intro__bar {
  display: flex; align-items: center; gap: 9px;
  height: 88px; padding: 0 34px;
  border-bottom: 1px solid transparent;
  transition: height 0.85s var(--ease) .26s, padding 0.85s var(--ease) .26s,
              gap 0.85s var(--ease) .26s, border-color .3s linear .75s;
}
.intro.is-open .intro__bar {
  height: var(--nav-h); padding: 0 clamp(20px, 4vw, 48px); gap: 11px;
  border-bottom-color: var(--w-08);
}
.intro__bar img {
  height: 36px; width: auto; display: block; filter: brightness(0);
  transition: height 0.85s var(--ease) .26s;
}
.intro.is-open .intro__bar img { height: 26px; }
.intro__wordmark {
  font-family: var(--display); font-weight: 600; font-size: 32px;
  letter-spacing: -.015em; color: var(--ink); white-space: nowrap;
  transition: font-size 0.85s var(--ease) .26s, letter-spacing 0.85s var(--ease) .26s;
}
.intro.is-open .intro__wordmark { font-size: 19px; letter-spacing: -.01em; }

.intro__hint {
  position: absolute; left: 0; right: 0; top: calc(50% + 66px);
  margin: 0; text-align: center;
  font-family: var(--mono); font-size: var(--step--2);
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--w-50);
  opacity: 0; transition: opacity .5s linear .25s;
}
.intro.is-in .intro__hint { opacity: 1; }
.intro.is-open .intro__hint { opacity: 0; transition-delay: 0s; transition-duration: .2s; }

.intro__skip {
  position: absolute; right: clamp(16px, 4vw, 40px); bottom: clamp(16px, 4vw, 32px);
  background: none; border: 0; padding: 8px 10px; cursor: pointer;
  font-family: var(--mono); font-size: var(--step--2);
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--w-50); opacity: 0; transition: opacity .5s linear .5s, color .2s;
}
.intro.is-in .intro__skip { opacity: 1; }
.intro__skip:hover { color: var(--ink); }
.intro.is-open .intro__skip { opacity: 0; transition-delay: 0s; transition-duration: .2s; }

/* A click means "get on with it" — same choreography, compressed. */
.intro.is-fast, .intro.is-fast * { transition-duration: .34s !important; transition-delay: 0s !important; }

@media (prefers-reduced-motion: reduce) {
  .intro { display: none !important; }
  :root.intro-lock { overflow: visible; }
}

/* ============================================================
   The headline sets itself, a word at a time.

   Each word rides up out of a mask on a stagger, arriving as the
   opening clears. The mask needs room for descenders: the line is
   set at .94 leading, so an unpadded overflow:hidden would shave
   the tails off "apparel page you sell".

   The hidden state is applied by JS (.is-words), never by this
   stylesheet on its own — if the script never runs, the headline
   is simply a headline. Transform and opacity only, so it costs a
   composite per word and nothing on the main thread.
   ============================================================ */
.hero-title .w {
  display: inline-block; overflow: hidden; vertical-align: top;
  padding-bottom: .2em; margin-bottom: -.2em;
}
.hero-title .w > i { display: inline-block; font-style: inherit; }
.hero-title.is-words .w > i { transform: translateY(1.15em); opacity: 0; }
.hero-title.is-words.is-set .w > i {
  transform: none; opacity: 1;
  transition: transform .72s var(--ease), opacity .45s linear;
}
@media (prefers-reduced-motion: reduce) {
  .hero-title.is-words .w > i { transform: none; opacity: 1; transition: none; }
}

/* The rest of the hero waits for the sentence to finish. Held by the
   script (.hero-hold is only ever added by JS), so if it never runs the
   copy and the buttons are simply there. */
.hero-hold { opacity: 0; transform: translateY(16px); }
.hero-hold.is-in {
  opacity: 1; transform: none;
  transition: opacity .55s linear, transform .7s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .hero-hold { opacity: 1; transform: none; transition: none; }
}
