/* ==========================================================================
   Loquen landing page. Page CSS on top of scrollcraft.css (unmodified).

   The grammar is a STACKED DECK: every act is a full-viewport card, the next
   card slides up over the previous one, and the covered card recedes into the
   page's perspective. The stacking is entirely here, in page CSS: a negative
   top margin of one viewport on every act after the first, ascending z-index,
   and an opaque ground on every stage. site.js writes three variables per act,
   which everything below reads:

     --cover   0..1 while this card is being covered by the next one
     --enter   1..0 while this card is sliding up into view
     --arrive  1..0 across the slide plus the first 0.12 of the pin

   Depth is five things used together, never one: planes at different parallax
   rates, an overlap on every card, offset-and-blur shadows tinted to the
   canvas, a 1 px edge light on every raised surface, and the grain.
   ========================================================================== */

/* ------------------------------------------------------------- tokens --- */
:root {
  --sc-canvas:      #0a0c10;   /* sampled from the app icon ground */
  --sc-surface:     #12151b;
  --sc-ink:         #f3f1ee;
  --sc-ink-soft:    #a7a1a4;   /* warm grey, tinted toward the red */
  --sc-accent:      #ff3347;   /* Loquen red. The CTA, the ribbon, nothing else */
  --sc-accent-ink:  #0a0c10;

  --sc-font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Instrument Sans", system-ui, sans-serif;
  --sc-font-text:    -apple-system, BlinkMacSystemFont, "SF Pro Text", "Instrument Sans", system-ui, sans-serif;
  --sc-font-mono:    ui-monospace, "SF Mono", Menlo, "Geist Mono", monospace;

  --coral: #ff604e;            /* ribbon highlight only */
  --hair: rgba(255, 255, 255, .10);
  --edge: rgba(255, 255, 255, .10);

  /* Literal ink steps. A color-mix() on `color` computes to oklab()/color(srgb)
     in Chrome, which the verification pass cannot read, so every text colour on
     this page is written out. Backgrounds may still mix: those are sampled from
     the render, not parsed. */
  --ink-mid:    #ddd9d8;
  --ink-dim:    #8d888b;
  --ink-dimmer: #7c777a;

  --sc-hairline: var(--hair);
  --sc-shadow-color: 220 45% 1%;

  --bar-h: 56px;
  --pill-space: 176px;         /* every card composes above the pill */
  /* The pill's distance from the bottom edge. site.js writes --pill-bottom
     every frame: on a card with a demo field the capsule docks just under it,
     and everywhere else it eases back to --pill-rest. The easing is in JS, so
     there is deliberately no transition on these two rules. */
  --pill-rest: 24px;
  --pill-bottom: 24px;
  --pill-w: min(760px, 92vw);
}

@media (max-width: 700px) {
  :root { --pill-space: 140px; --pill-w: min(360px, 92vw); --pill-rest: 18px; --pill-bottom: 18px; }
}

html { background: var(--sc-canvas); }

/* Lenis (vendor/lenis.min.js) stamps these classes on <html> while inertial
   scrolling is running. Its own stylesheet is three rules, so they live here
   rather than as a fourth network request. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

body {
  margin: 0;
  background: var(--sc-canvas);
  color: var(--sc-ink);
  font-family: var(--sc-font-text);
  font-size: var(--sc-t-base);
  font-weight: 500;                    /* light on dark: one step up */
  letter-spacing: .002em;
  line-height: var(--sc-leading-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: rgba(255, 51, 71, .38); color: var(--sc-ink); }

:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 3px; border-radius: 4px; }

.skip {
  position: fixed; top: 8px; left: 8px; z-index: 200;
  padding: 10px 14px; border-radius: 10px;
  background: var(--sc-accent); color: var(--sc-accent-ink);
  font: 600 13px/1 var(--sc-font-text); text-decoration: none;
  transform: translateY(-160%);
  transition: transform 160ms var(--sc-ease-out);
}
.skip:focus-visible { transform: none; }

/* NO GRAIN LAYER. The engine's .sc-grain is a fixed, full-viewport SVG
   feTurbulence overlay. Lifted above the deck it has to be re-composited over
   every card on every frame, which on a 2x display is a full-screen blend per
   frame for a texture nobody can name. The element is gone from index.html.
   A body-background tile would be invisible anyway: every stage ground on this
   page is opaque. Depth here comes from the planes, the overlaps, the offset
   shadows and the edge light, which is four of the five it always came from. */

/* The engine's pointer spotlight repaints a 28rem radial gradient across a
   full-viewport stage on every pointermove while the cursor is over it. The
   hero has a live canvas that answers the pointer properly; the close has its
   icon. Neither needs a second full-frame paint. --sc-mx / --sc-my keep being
   published, so the icon still leans. */
[data-sc-spotlight]::after { display: none !important; }

/* -------------------------------------------------------------- type ---- */
.display {
  font-family: var(--sc-font-display);
  font-weight: 640;
  letter-spacing: -.045em;
  line-height: .96;
  margin: 0;
  text-wrap: balance;
}
.display--xl { font-size: var(--sc-t-4xl); }
.display--lg { font-size: var(--sc-t-3xl); }
.display--md { font-size: var(--sc-t-2xl); letter-spacing: -.035em; }

.lede {
  margin: 0;
  max-width: 34ch;
  font-size: var(--sc-t-lg);
  font-weight: 500;
  letter-spacing: .002em;
  line-height: 1.42;
  color: var(--sc-ink);
  text-wrap: pretty;
}
.lede--lg { font-size: var(--sc-t-2xl); line-height: 1.12; letter-spacing: -.03em; font-weight: 600; }

.body { margin: 0; max-width: 56ch; color: var(--sc-ink-soft); text-wrap: pretty; }

.eyebrow {
  margin: 0;
  font-family: var(--sc-font-mono);
  font-size: var(--sc-t-xs);
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.source {
  margin: 0;
  font-family: var(--sc-font-mono);
  font-size: 11px; line-height: 1.55; letter-spacing: 0;
  color: var(--ink-dim);
  max-width: 52ch;
}

.hint {
  margin: 0;
  font-family: var(--sc-font-mono);
  font-size: 11px; letter-spacing: 0;
  color: var(--ink-dim);
}
.hint.is-held { color: var(--sc-ink); }

/* ------------------------------------------------------------ buttons --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 12px 22px;
  border: 0; border-radius: var(--sc-r-pill);
  background: var(--sc-accent);
  color: var(--sc-accent-ink);
  font-family: var(--sc-font-text);
  font-size: var(--sc-t-sm); font-weight: 600;
  letter-spacing: -.005em; line-height: 1;
  white-space: nowrap; text-decoration: none;
  /* Neutral elevation, tinted to the canvas. The only glow on this page is the
     pill's own ribbon. */
  box-shadow: var(--sc-e2);
  transition: background-color 140ms var(--sc-ease-out), transform 120ms var(--sc-ease-out);
}
@media (hover: hover) and (pointer: fine) { .btn:hover { background: var(--coral); } }
.btn:active { transform: translateY(1px); }
.btn--sm { padding: 9px 16px; font-size: var(--sc-t-xs); }
.btn--lg { padding: 15px 28px; font-size: var(--sc-t-base); }
.btn--xl { padding: 19px 38px; font-size: var(--sc-t-lg); }

/* ------------------------------------------------------------ top bar --- */
.topbar {
  position: fixed; inset: 0 0 auto 0; z-index: 60;
  height: var(--bar-h);
  display: flex; align-items: center; justify-content: space-between;
  padding-inline: clamp(1rem, 3vw, 2.25rem);
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: border-color 220ms var(--sc-ease-out), background-color 220ms var(--sc-ease-out);
}
.topbar.is-scrolled {
  border-bottom-color: var(--hair);
  /* Near-solid, not blurred. A backdrop-filter on a fixed bar makes the
     compositor read back the whole strip behind it every frame the page
     scrolls, for the whole life of the page. */
  background: rgba(10, 12, 16, .92);
}
.topbar__mark { display: flex; align-items: center; line-height: 0; }
/* The wordmark carries an ascender and a descender, so its box is taller than
   the old one for the same letter size. Sized to leave the bar real clearance. */
.topbar__mark img { width: 56px; height: auto; display: block; opacity: .94; }

/* ================================================================ deck ===
   The recede is 2D. A page-level `perspective` puts every act into a 3D
   rendering context, which costs a composited layer per card whether or not it
   is on screen, and a rotateX on a full-viewport card re-rasterises the whole
   thing every frame it moves. translateY plus scale plus the opaque dim plate
   read as the same depth for none of that. */
.deck { position: relative; }

.act { position: relative; }
.deck > .act + .act { margin-top: -100vh; margin-top: -100svh; }
/* A flow act is not sticky, so the next act's negative margin would swallow it
   whole. Give it one viewport of its own below the card: the close then starts
   exactly at the card's bottom edge instead of on top of it. */
.act--fit { padding-bottom: 100vh; padding-bottom: 100svh; }

.deck > .act:nth-child(1) { z-index: 1; }
.deck > .act:nth-child(2) { z-index: 2; }
.deck > .act:nth-child(3) { z-index: 3; }
.deck > .act:nth-child(4) { z-index: 4; }
.deck > .act:nth-child(5) { z-index: 5; }
.deck > .act:nth-child(6) { z-index: 6; }
.deck > .act:nth-child(7) { z-index: 7; }
.deck > .act:nth-child(8) { z-index: 8; }
.deck > .act:nth-child(9) { z-index: 9; }
.deck > .act:nth-child(10) { z-index: 10; }
.deck > .act:nth-child(11) { z-index: 11; }
.deck > .act:nth-child(12) { z-index: 12; }
/* site.js also writes each act's z-index from its position, so a card added
   later can never fall below the one before it. The FAQ card did exactly that:
   it became the ninth child, the close lost its stacking order, and the FAQ's
   stage tail painted over the top half of the last screen. */

/* Every stage is opaque, throws a deep shadow onto the card it is covering,
   catches a 1 px lip of light along its top, and rounds its top corners only
   while it is still sliding: a permanent notch at the top of a resting card
   would read as a rendering fault. */
.stage {
  background: var(--card-ground, var(--sc-canvas));
  /* Capped at a 48 px blur. The engine gives every stage `overflow: clip`, so
     a pseudo element's shadow would be clipped away before it ever reached the
     card underneath; the cap is what keeps the sticky stage's paint bounds
     from being inflated by a 120 px feather. The containment that a pseudo
     element would have bought sits on .card below instead. */
  box-shadow: 0 -24px 48px -16px rgba(0, 0, 0, .85);
  border-radius: calc(28px * var(--enter, 0)) calc(28px * var(--enter, 0)) 0 0;
}
.stage::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px; z-index: 40;
  background: var(--edge);
  pointer-events: none;
}

/* The card being covered dims behind an opaque plate rather than a filter: a
   filter on an element this size costs a full-frame pass and would take the
   planes' blend modes with it. */
.recede {
  position: absolute; inset: 0; z-index: 20;
  background: var(--sc-canvas);
  opacity: calc(var(--cover, 0) * .55);
  pointer-events: none;
}

/* The recede and the arrival both live on the inner wrapper, never on the
   sticky stage: a transform on the stage kills the sticky. */
.card {
  position: relative; z-index: 3;
  height: 100%;
  display: flex; flex-direction: column; justify-content: center;
  padding: calc(var(--bar-h) + clamp(1.25rem, 3.5vh, 3rem)) var(--sc-gutter) var(--pill-space);
  transform:
    translateY(calc(var(--cover, 0) * -6%))
    scale(calc(1 + .03 * var(--arrive, 0) - .07 * var(--cover, 0)));
  transform-origin: 50% 30%;
  /* The card is a closed box: nothing inside it affects layout outside it and
     nothing inside it paints outside it. That is what lets the compositor
     re-raster one card instead of the whole deck when this transform moves. */
  contain: layout paint;
}

.act--fit .card {
  min-height: 100svh; height: auto;
  background: var(--card-ground);
  border-radius: calc(28px * var(--enter, 0)) calc(28px * var(--enter, 0)) 0 0;
  box-shadow: 0 -24px 48px -16px rgba(0, 0, 0, .85);
  padding-block: clamp(3rem, 7vh, 4.5rem) var(--pill-space);
  overflow: clip;
}
.act--fit .card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: var(--edge);
}

/* ------------------------------------------------------------- planes --- */
/* Absolutely positioned, transform only, never the thing text is read on. */
.plane { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.plane img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  max-width: none;
  object-fit: cover;
}
/* will-change promotes a layer for the life of the page, so it is only worth
   paying for on a plane that is actually being written to. site.js stamps
   .is-near on the acts within one viewport of the screen; everything else
   gives its layer back. */
.act.is-near .drift, .act.is-near .float { will-change: transform; }

.scrim { position: absolute; inset: 0; z-index: 2; pointer-events: none; }

/* A mask on a layer that transforms every frame is a mask composite every
   frame. Every plane on this page moves, so none of them carry one. The edge
   that used to be cut out of the image is painted back over it instead: a
   static gradient in the card's own ground, a sibling above the plane, in the
   flat colour the mask was dissolving into. Same edge, one paint, no mask. */
.planefade { position: absolute; z-index: 1; pointer-events: none; }

/* A raised surface: canvas-tinted offset shadow, hairline, 1 px edge light. */
.plate {
  position: relative;
  border: 1px solid var(--hair);
  border-radius: 16px;
  /* Near-solid. Fourteen of these are on the page at once; a 12 px
     backdrop-filter on each is fourteen full readbacks of everything behind
     them, recomputed on every frame any of them moves. */
  background: rgba(18, 21, 27, .92);
  box-shadow: var(--sc-e2), inset 0 1px 0 var(--edge);
}

/* ============================================================== 1 hero == */
/* The hero's back plane is the approved Codex renderer (vendor/loquen-wind.js,
   handoff of 2026-09-04, energy 1.00). It paints an opaque #020507 ground and
   owns its own loop, ResizeObserver, pointer listeners on the stage, hidden-tab
   suspension and reduced-motion still. The handoff forbids anything over it:
   no scrim, no fade, no blend, no mask, no CSS transform on the canvas. The
   stage is the sized parent, so it carries the approved min-heights. */
.loquen-hero__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; }
/* The handoff asks for a 580 px floor under the renderer. A sticky stage in
   a deck cannot be taller than the window it sticks to: on any viewport under
   580 px (a zoomed browser, a split pane) the floor pushed the stage past the
   window and cut its top off. The floor is gone; the bands compress a little
   on very short windows instead, which the handoff itself allows. */
.stage--wind { min-height: 0; }
@media (max-width: 680px) { .stage--wind { min-height: 500px; } }



/* The approved renderer's ribbons live in the lower two thirds of the frame
   and swell upward on a gust, and its handoff forbids a scrim. So the copy
   and the note field sit in the calm upper area (the handoff's own guidance)
   instead of at the vertical centre, the lede is full ink rather than mid,
   and the field's own card is opaque. Nothing is painted over the canvas. */
.card--hero {
  display: grid;
  grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 5rem);
  padding-top: calc(var(--bar-h) + clamp(2rem, 6vh, 4.5rem));
}
/* The handoff asks for copy in the calm upper area rather than a layer over
   the ribbons, so the block sits at the top of its column and the note keeps
   the lower half with the capsule. */
.hero__copy { display: flex; flex-direction: column; gap: clamp(.8rem, 1.8vh, 1.2rem); align-items: flex-start; align-self: start; }
.hero__copy .lede { max-width: 40ch; color: var(--sc-ink); font-weight: 600; }
.card--hero .field { background: #12151b; }
.card--hero .field__foot { margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--hair); color: var(--sc-ink-soft); }

/* The headline: "Dictation." in the product face, "done right." in the
   wordmark's Tangerine as per-glyph outlines. The block is kept short so it
   stays in the calm upper third, above where a gust reaches. */
.hero-h1 { display: flex; flex-direction: column; align-items: flex-start; font-size: clamp(56px, 7.4vw, 108px); line-height: .96; }
.typed { display: inline-flex; align-items: baseline; white-space: nowrap; }
.typed__caret {
  display: inline-block; width: .055em; height: .84em; margin-left: .06em;
  background: var(--sc-accent); border-radius: 1px; transform: translateY(.08em);
  opacity: 0;
}
.hero-h1.is-typing .typed__caret { opacity: 1; animation: caret-blink 1s steps(1, end) infinite; }
@keyframes caret-blink { 50% { opacity: 0; } }
.flourish { display: block; margin: -.24em 0 0 -.03em; }
.flourish svg { display: block; height: 1.62em; width: auto; overflow: visible; }
.flourish .g { fill: var(--coral); fill-opacity: 1; stroke: var(--coral); stroke-width: 10; stroke-linecap: round; stroke-linejoin: round; }

/* The entrance (JS only, never under Reduce Motion). Outlines draw on in
   glyph order, then flood with ink; the copy below and the note field rise in
   once the last letter has landed. Engine cues own the cued elements' own
   opacity, so the entrance rides on inner wrappers (.enter) instead. */
.hero-h1.will-draw .g { fill-opacity: 0; stroke-dasharray: 1; stroke-dashoffset: 1; }
.hero-h1.is-drawing .g {
  animation: ink-draw 620ms cubic-bezier(.4, 0, .2, 1) forwards, ink-fill 420ms ease-out forwards;
  animation-delay: calc(var(--i) * 95ms), calc(var(--i) * 95ms + 380ms);
}
@keyframes ink-draw { to { stroke-dashoffset: 0; } }
@keyframes ink-fill { to { fill-opacity: 1; } }
.card--hero.will-enter .enter { opacity: 0; transform: translateY(12px); }
.card--hero.is-entered .enter { opacity: 1; transform: none; transition: opacity 560ms var(--sc-ease-out), transform 560ms var(--sc-ease-out); }
.card--hero.is-entered .btn.enter { transition-delay: 60ms; }
.card--hero.is-entered .cta-note.enter { transition-delay: 120ms; }
.card--hero.is-entered .field.enter { transition-delay: 160ms; }

.cta-row { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.cta-note { font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: 0; color: var(--sc-ink-soft); }

/* The field is the front plane: it crosses the back plane's masked edge. */
/* The note sits on the pill's own line: the card already reserves --pill-space
   at the bottom, so ending the field there puts its lower edge right above the
   capsule. The two read as one exchange instead of two corners. */
.hero__field { justify-self: end; align-self: end; width: min(100%, 34rem); margin-left: -6%; margin-bottom: clamp(.5rem, 2vh, 1.25rem); }

/* ------------------------------------------------------------- fields --- */
.field {
  border: 1px solid var(--hair);
  border-radius: 16px;
  /* Fully opaque, not .94: the last 6% let the hero's ribbons through and put
     the note's own body text under 3:1 on a phone at a gust crest. */
  background: #12151b;
  padding: 15px 18px 18px;
}
.field--float { box-shadow: var(--sc-e2), inset 0 1px 0 var(--edge); }
.field--object {
  padding: 18px 22px 22px;
  border-color: rgba(255, 255, 255, .14);
  box-shadow: var(--sc-e3), inset 0 1px 0 rgba(255, 255, 255, .14);
}

.field__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-bottom: 10px; margin-bottom: 12px;
  border-bottom: 1px solid var(--hair);
}
.field__title { font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--sc-ink-soft); }
.field__tag {
  font-family: var(--sc-font-mono);
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--hair);
  color: var(--ink-dim);
}
.field__meta { margin: 0 0 8px; font-size: var(--sc-t-sm); color: var(--ink-dim); }
.field__body {
  margin: 0;
  min-height: 4.4em;
  font-size: var(--sc-t-base); line-height: 1.55;
  color: var(--sc-ink); text-wrap: pretty;
}
.field__body--lines { min-height: 7.4em; }
.field__body--lines .field__text { display: block; }
/* `display: block` here beat the user-agent's `[hidden] { display: none }`,
   which is a rule with no specificity at all. So every line the page had
   hidden was still painted, and the exam looked finished the moment the card
   arrived, whatever the demo clock said. The [hidden] branch has to win. */
.field__body--lines .line { display: block; }
.field__body--lines .line[hidden] { display: none; }
.card--phrases .field__body--lines { min-height: 8.4em; }

.field__caret {
  display: inline-block;
  width: 2px; height: 1.05em; margin-left: 2px;
  vertical-align: text-bottom;
  background: var(--sc-accent);
  opacity: 0;
}
.field.is-live .field__caret { opacity: 1; animation: caret 1.06s steps(1) infinite; }
@keyframes caret { 0%, 49% { opacity: 1 } 50%, 100% { opacity: 0 } }

/* ============================================================== 2 story = */
.plane--photo { inset: 0 0 0 auto; width: 58%; }
.plane--photo img { opacity: .88; }
.planefade--photo {
  inset: 0 0 0 auto; width: 58%;
  background: linear-gradient(to right, #0e1016 0%, rgba(14, 16, 22, .55) 16%, rgba(14, 16, 22, 0) 32%);
}
.scrim--column {
  background: linear-gradient(to right,
    rgba(14, 16, 22, .96) 0%, rgba(14, 16, 22, .9) 34%,
    rgba(14, 16, 22, .35) 52%, transparent 68%);
}

.card--story {
  display: grid;
  grid-template-columns: minmax(0, 56fr) minmax(0, 44fr);
  grid-template-areas: "copy portrait" "copy sig";
  grid-template-rows: 1fr auto;
  align-items: center;
  gap: 0 clamp(1.5rem, 3.5vw, 3.5rem);
}
.story__copy { grid-area: copy; align-self: center; display: flex; flex-direction: column; gap: clamp(.6rem, 1.5vh, 1rem); }

/* His account, set in two columns. One column runs it past the fold; two keeps
   it on one screen, which is what the card's long hold is for. */
.story__cols {
  columns: 2; column-gap: clamp(1.2rem, 3vw, 2.4rem);
  max-width: 46rem;
  font-size: var(--sc-t-sm); line-height: 1.62; color: var(--sc-ink-soft);
  text-wrap: pretty;
}
.story__cols p { margin: 0 0 .75em; break-inside: avoid; }
.story__cols p:last-child { margin-bottom: 0; }
.story__punch { color: var(--sc-ink); font-weight: 600; max-width: 38ch; }
@media (max-width: 1100px) { .story__cols { columns: 1; font-size: var(--sc-t-xs); } }
.story__copy .lede { max-width: 40ch; }
.story__copy .lede--lg { max-width: 22ch; }

/* The portrait is a cut-out, not a framed photograph: the clinic behind him is
   gone, so he stands in the card's own ground with the desk shot showing past
   his shoulder. No frame, no radius, no border. A gradient sibling in the card
   ground dissolves the bottom crop, the same trick the photo planes use, so
   there is no hard edge where the coat ends. */
.story__portrait { grid-area: portrait; position: relative; margin: 0 auto 0 0; align-self: end; justify-self: start; width: min(100%, 14.5rem); }
.portrait {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(0 24px 34px rgba(0, 0, 0, .55));
}
/* Only the last sliver of the coat is dissolved, so the crop disappears
   without eating the chest. It sits under the caption, never over it. */
.portrait__foot {
  position: absolute; left: -10%; right: -10%; bottom: -1px; height: 34%;
  /* An ellipse, not a band: a rectangular gradient over the desk photograph
     shows its own vertical edges, which reads as a panel nobody drew. */
  background: radial-gradient(120% 100% at 50% 108%,
    var(--card-ground) 34%,
    color-mix(in oklab, var(--card-ground) 62%, transparent) 62%,
    transparent 88%);
  pointer-events: none; z-index: 0;
}
/* The signature hangs off the portrait's bottom-left corner and crosses into
   the ground. Sized against the portrait, not the viewport, so it can never
   grow wider than the photograph it belongs to. */
/* Its own block, and its own ground. The contrast pass grades the CUED element
   against the fill that element carries, so the caption cannot borrow a plate
   from a parent or a sibling: it has to own one. Kept to the ink's own tint and
   pulled under the portrait's corner so it still reads as part of the picture. */
.story__sig {
  grid-area: sig; position: relative; z-index: 1;
  justify-self: start; align-self: start;
  margin: -1.1rem 0 0 -10%;
  width: min(132%, 26rem);
  padding: 10px 16px 12px;
  border-radius: 14px;
  background: #0e1016;
  border: 1px solid var(--hair);
}
.story__sig .float { display: flex; flex-direction: column; gap: .2rem; align-items: flex-start; }
.sig-svg { display: block; }
.sig-svg svg { display: block; width: min(100%, 12.5rem); height: auto; overflow: visible; }
.sig-svg .g { fill: var(--coral); stroke: var(--coral); stroke-width: 10; stroke-linecap: round; stroke-linejoin: round; }
.sig-line { width: 100%; font-family: var(--sc-font-mono); font-size: var(--sc-t-xs); letter-spacing: 0; line-height: 1.55; color: var(--sc-ink); text-wrap: pretty; }
.sig-line strong { color: var(--sc-ink); font-weight: 600; font-family: var(--sc-font-text); font-size: var(--sc-t-sm); letter-spacing: 0; display: block; margin-bottom: 2px; }

/* The draw-on: armed by the page as the card arrives, so it runs exactly
   once per visit and never under Reduce Motion. */
@media (prefers-reduced-motion: no-preference) {
  .act--story:not(.is-arrived) .sig-svg .g { fill-opacity: 0; stroke-dasharray: 1; stroke-dashoffset: 1; }
  .act--story.is-arrived .sig-svg .g {
    animation: ink-draw 560ms cubic-bezier(.4, 0, .2, 1) forwards, ink-fill 380ms ease-out forwards;
    animation-delay: calc(var(--i) * 80ms + 200ms), calc(var(--i) * 80ms + 540ms);
  }
}

/* ============================================================== 3 speed = */
.plane--keys { inset: auto 0 0 auto; width: 64%; height: 74%; }
.plane--keys img { opacity: .7; }
.planefade--keys {
  inset: auto 0 0 auto; width: 64%; height: 74%;
  background: radial-gradient(88% 96% at 78% 78%, rgba(10, 12, 16, 0) 12%, #0a0c10 76%);
}

.card--speed { display: grid; grid-template-columns: minmax(0, 54fr) minmax(0, 46fr); align-items: center; gap: clamp(2rem, 5vw, 4.5rem); }
.speed__copy { display: flex; flex-direction: column; gap: clamp(.85rem, 2.1vh, 1.5rem); grid-column: 1; grid-row: 1; }

.metric { margin-top: .2em; }
.metric .drift { display: flex; align-items: baseline; gap: clamp(12px, 2vw, 26px); flex-wrap: wrap; }
.metric__value {
  margin: 0;
  font-family: var(--sc-font-display);
  font-size: clamp(3.2rem, 1.4rem + 5.2vw, 6.4rem);
  font-weight: 640; letter-spacing: -.05em; line-height: 1;
  padding-block: .06em;
  color: var(--sc-ink);
}
.metric__value .sc-nums { font-variant-numeric: tabular-nums; }
.metric__label {
  margin: 0 0 .3em;
  max-width: 26ch;
  font-family: var(--sc-font-mono); font-size: var(--sc-t-xs);
  letter-spacing: 0; line-height: 1.5;
  color: var(--sc-ink-soft);
}

/* The latency plate crosses the figure's baseline. */
.lat { width: min(38rem, 106%); margin-top: .25rem; }
.lat__plate { padding: 16px 18px; display: flex; flex-direction: column; gap: 10px; }
.lat__bar { display: flex; gap: 2px; height: 10px; border-radius: 999px; overflow: hidden; background: rgba(255, 255, 255, .05); }
.lat__seg { width: var(--w); background: rgba(243, 241, 238, .3); }
.lat__seg--hot { background: var(--sc-accent); }
.lat__legend {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin: 0; padding: 0; list-style: none;
  font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: 0;
}
.lat__legend li { display: flex; gap: 6px; color: var(--sc-ink-soft); }
.lat__legend b { color: var(--sc-ink); font-weight: 500; font-variant-numeric: tabular-nums; }
.lat__legend .is-hot b { color: var(--sc-accent); }
.lat__caption { margin: 0; font-size: var(--sc-t-sm); color: var(--sc-ink-soft); max-width: 52ch; }

.speed__body { display: flex; flex-direction: column; gap: 6px; }
.speed__body .body { color: var(--sc-ink); }

/* The Mail field crosses the figure's right edge. */
/* Pulled back off the right edge and out of the figure, so the number and
   its label are never under the box as the card arrives. */
.speed__field { grid-column: 2; grid-row: 1; justify-self: center; width: min(100%, 26rem); margin-left: 0; }

/* ============================================================ 4 phrases = */
/* No mix-blend-mode either: screen against a #0d0b0e ground is within a
   couple of levels of plain source-over, and a blend mode on a full-viewport
   plane forces the whole stage into a non-opaque group. */
.plane--ribbonbed { opacity: .5; }
.planefade--ribbonbed {
  inset: 0;
  background: radial-gradient(80% 70% at 50% 52%, rgba(13, 11, 14, 0) 10%, #0d0b0e 76%);
}

.card--phrases {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 17rem);
  grid-template-areas: "head head" "said said" "field rail";
  align-content: center;
  gap: clamp(.8rem, 2.2vh, 1.5rem) 0;
}
.phrases__head { grid-area: head; display: flex; flex-direction: column; gap: clamp(.35rem, 1vh, .7rem); }
.phrases__head .lede { max-width: 62ch; font-size: var(--sc-t-base); color: var(--sc-ink-soft); }
.phrases__said { grid-area: said; }

/* The name plate is the mid plane; the field's right edge covers it by 40 px. */
.phrases__rail { grid-area: rail; align-self: center; z-index: 1; margin-left: -40px; }
.names__plate { padding: 18px 20px 18px 52px; }
.names { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; }
.names li {
  padding: 7px 0;
  border-top: 1px solid var(--hair);
  font-family: var(--sc-font-mono); font-size: 12.5px; letter-spacing: 0;
  color: var(--sc-ink);
}
.names li:first-child { border-top: 0; }
.names__note { margin: 12px 0 0; font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: 0; color: var(--ink-dim); }

.phrases__field { grid-area: field; z-index: 2; }

/* ============================================================ 5 privacy = */
.vault { position: absolute; inset: 0; z-index: 0; }
.plane--vault img { opacity: .62; transform: scale(1.06); }
/* If the vault still is not there, the flat ground carries the act on its own. */
.act--privacy .stage {
  background-image: radial-gradient(120% 100% at 26% 48%, rgba(255, 51, 71, .10), transparent 58%);
  background-color: var(--card-ground);
}

.card--privacy { align-items: center; }
.privacy__stack { margin-left: auto; width: min(100%, 52%); display: flex; flex-direction: column; align-items: stretch; gap: clamp(1.4rem, 4vh, 2.6rem); }
.privacy__copy {
  margin-left: auto;
  width: min(100%, 86%);
  display: flex; flex-direction: column; gap: clamp(.7rem, 1.8vh, 1.15rem);
}
.privacy__copy .display { max-width: 13ch; }
.privacy__copy .body { color: var(--ink-mid); }

/* The list plate crosses the copy column's bottom edge. */
.privacy__checks { width: 100%; }
.checks { margin: 0; padding: 12px 20px; list-style: none; display: flex; flex-direction: column; }
.checks li { padding: 9px 0; border-top: 1px solid var(--hair); font-size: var(--sc-t-sm); color: var(--sc-ink); }
.checks li:first-child { border-top: 0; }

/* ============================================================== 6 packs = */
/* The heading no longer travels with the rail. It was the first item in the
   pan, so it slid off the moment the visitor started scrolling and they never
   got to read what the card was about. It stands still above the collection
   now, and only the pack cards move. */
.card--packs { padding-inline: 0; justify-content: flex-start; gap: clamp(1rem, 3vh, 2rem); padding-top: calc(var(--bar-h) + clamp(1rem, 3vh, 2.2rem)); }
.card--packs .rail { padding-block: 24px 8px; }
/* Heading beside the copy, so the block is wide and short and the rail and the
   demo both fit under it on one screen. */
.packs__head {
  padding-inline: var(--sc-gutter);
  display: grid; grid-template-columns: minmax(0, 34fr) minmax(0, 66fr);
  align-items: start; gap: clamp(1.2rem, 3.5vw, 3rem);
}
.packs__head h2 { max-width: 12ch; margin: 0; }
.packs__head .body { max-width: 62ch; color: var(--sc-ink-soft); margin: 0; }
.packs__head .body + .body { margin-top: .55rem; }
.packs__head b { color: var(--sc-ink); font-weight: 600; }
.packs__head em { font-style: normal; color: var(--sc-accent); }
.packs__more { font-size: var(--sc-t-sm); }

/* The demo field sits at the foot of the card, directly above the capsule that
   is dictating into it, so the two are read as one exchange. */
.packs__demo { padding-inline: var(--sc-gutter); width: min(100%, 34rem); margin-inline: auto; }

@media (max-width: 980px) {
  .packs__head { grid-template-columns: minmax(0, 1fr); }
  .packs__more { display: none; }
}
.rail { display: flex; align-items: center; gap: 22px; padding: 40px var(--sc-gutter); width: max-content; }

.railcard {
  flex: 0 0 auto;
  width: clamp(16rem, 24vw, 22rem);
  --dy: 0px;
  transform: translate3d(0, var(--dy), 0);
}
/* Two depths, alternating. Even items ride high with the heavier shadow. */
.rail > .railcard:nth-child(even) { --dy: -24px; }
.rail > .railcard:nth-child(odd)  { --dy: 24px; }
.rail > .railcard:nth-child(even) .railcard__in { box-shadow: var(--sc-e2), inset 0 1px 0 var(--edge); }
.rail > .railcard:nth-child(odd)  .railcard__in { box-shadow: var(--sc-e1), inset 0 1px 0 var(--edge); }

.railcard__in {
  position: relative; overflow: hidden;
  height: 100%;
  display: flex; flex-direction: column; gap: 12px;
  padding: 24px;
}
.railcard h3 {
  margin: 0;
  font-family: var(--sc-font-display);
  font-size: var(--sc-t-lg); font-weight: 600;
  letter-spacing: -.03em; line-height: 1.1;
  color: var(--sc-ink);
}
.railcard p { margin: 0; font-size: var(--sc-t-sm); line-height: 1.5; color: var(--sc-ink-soft); }
.railcard__foot {
  margin-top: auto !important;
  padding-top: 12px;
  border-top: 1px solid var(--hair);
  font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-dimmer) !important;
}

/* The lead card's order field crosses into the first pack card. */

.railcard--next .railcard__bed { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.railcard--next .railcard__bed img {
  width: 100%; height: 100%; object-fit: cover; max-width: none;
  opacity: .22;
}
/* The rail translates every frame of the pan act, so this bed's fade is a
   sibling gradient in the plate's own composited ground, not a mask. */
.railcard--next .planefade {
  inset: 0;
  background: linear-gradient(to top, rgba(18, 20, 26, 0) 0%, #12141a 78%);
}
.railcard--next h3, .railcard--next .next-list, .railcard--next .railcard__foot { position: relative; z-index: 1; }
.next-list {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-wrap: wrap; gap: 6px 10px;
  font-family: var(--sc-font-mono); font-size: 12px; letter-spacing: 0;
  color: var(--sc-ink-soft);
}
.next-list li::after { content: " ·"; color: var(--ink-dimmer); }
.next-list li:last-child::after { content: ""; }
.railcard--next .railcard__foot { text-transform: none; letter-spacing: 0; font-size: 11px; }

/* Staggered settle from the act's own progress. First item exempt: a pan act
   needs its opening content already present. site.js writes --i per item. */
@media (prefers-reduced-motion: no-preference) {
  .rail > .railcard[style*="--i"] {
    --t: clamp(0, calc((var(--sc-p, 0) - var(--i, 0) * .042) / .09), 1);
    opacity: calc(.55 + .45 * var(--t));
    transform: translate3d(0, calc(var(--dy) + (1 - var(--t)) * 16px), 0);
  }
}

/* ================================================================ 7 fit = */
.plane--everyday { inset: 0 auto 0 0; width: 58%; }
.plane--everyday img { opacity: .62; }
.planefade--everyday {
  inset: 0 auto 0 0; width: 58%;
  background: radial-gradient(88% 92% at 26% 52%, rgba(10, 12, 16, 0) 8%, #0a0c10 72%);
}
.fit__inner {
  position: relative; z-index: 3;
  width: 100%; max-width: var(--sc-maxw); margin-inline: auto;
  display: flex; flex-direction: column; gap: clamp(1.5rem, 4vh, 2.75rem);
}
.fit__cols { display: grid; grid-template-columns: 7fr 5fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
.fit__left { display: flex; flex-direction: column; gap: 16px; }
.fit__left .body { font-size: var(--sc-t-lg); line-height: 1.45; color: var(--sc-ink); max-width: 34ch; }
.fit__list { margin: 0; padding: 0; list-style: none; }
.fit__list li { padding: 12px 0; border-top: 1px solid var(--hair); font-size: var(--sc-t-sm); color: var(--sc-ink-soft); }
.fit__list li:last-child { border-bottom: 1px solid var(--hair); }
.glyph { display: inline-block; vertical-align: -3px; margin-left: 6px; width: 18px; height: 18px; filter: invert(1); opacity: .55; }

/* ============================================================== 8 close = */
.plane--icon {
  inset: auto; left: 50%; top: 24%;
  width: 220px; height: 220px;
  translate: -50% -50%;
  opacity: .55;
}
/* This fade rides inside the plane, because the edge belongs to the icon and
   the icon is what moves. Still a plain gradient, still one paint. */
.plane--icon .planefade {
  inset: 0;
  background: linear-gradient(to bottom, rgba(8, 9, 12, 0) 0%, rgba(8, 9, 12, 0) 52%, #08090c 92%);
}
.plane--icon img {
  position: static; width: 220px; height: 220px;
  border-radius: 48px;
  transform: translate3d(calc(var(--sc-mx, .5) * 16px - 8px), calc(var(--sc-my, .5) * 16px - 8px), 0);
  transition: transform 600ms var(--sc-ease-out);
}

.card--close { align-items: center; text-align: center; gap: clamp(1rem, 3vh, 2.2rem); }
.close__copy { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: clamp(.55rem, 1.7vh, 1.05rem); margin-inline: auto; max-width: 46rem; }
.close__copy .lede { max-width: 40ch; }
.compare { margin: 0; max-width: 52ch; font-size: var(--sc-t-sm); color: var(--sc-ink-soft); }
.close__cta { margin: clamp(.2rem, .8vh, .6rem) 0 0; }
.close__terms { margin: 0; font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: 0; color: var(--ink-dim); }

.foot {
  position: relative; z-index: 1;
  width: 100%; max-width: 46rem; margin-inline: auto;
  padding-top: clamp(.9rem, 2.4vh, 1.5rem);
  border-top: 1px solid var(--hair);
  display: flex; flex-direction: column; align-items: center; gap: 7px;
}
.foot__mark { width: 48px; height: auto; opacity: .8; }
.foot__line { margin: 0; font-size: var(--sc-t-sm); color: var(--sc-ink-soft); }
.foot__links { display: flex; gap: 20px; }
.foot__links a { font-size: var(--sc-t-sm); color: var(--sc-ink-soft); text-decoration-color: var(--ink-dimmer); text-underline-offset: 4px; text-decoration-thickness: 1px; }
.foot__links a:hover { color: var(--sc-ink); }
.foot__copy { margin: 0; font-size: var(--sc-t-xs); color: var(--ink-dim); }

/* ================================================================ pill == */
.pillbar {
  position: fixed;
  left: 50%; bottom: var(--pill-bottom);
  transform: translateX(-50%);
  z-index: 70;
  width: var(--pill-w);
  pointer-events: none;
}
/* The hold-to-try target: a transparent button over the pill's own rectangle,
   present only while the hero is on screen so it never eats a click meant for
   a card underneath. */
.pillhit {
  position: fixed;
  left: 50%; bottom: var(--pill-bottom);
  transform: translateX(-50%);
  z-index: 71;
  width: var(--pill-w);
  aspect-ratio: 760 / 102;
  padding: 0; margin: 0; border: 0;
  background: transparent;
  border-radius: 999px;
  cursor: grab;
  touch-action: none;
}
.pillhit:active { cursor: grabbing; }
.pillhit:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 4px; }

/* ============================================================ responsive= */
@media (max-width: 1180px) {
  .card--phrases { grid-template-columns: minmax(0, 1fr); grid-template-areas: "head" "field" "rail"; }
  .phrases__rail { align-self: start; margin-left: 0; margin-top: -28px; z-index: 1; }
  .names__plate { padding: 16px 20px; }
  .names { flex-flow: row wrap; gap: 0 20px; }
  .names li { border-top: 0; border-bottom: 1px solid var(--hair); }
}

@media (max-width: 980px) {
  .lat { margin-top: -1.2rem; width: 100%; }
  .speed__field, .hero__field { margin-left: 0; justify-self: stretch; }
}

@media (max-width: 860px) {
  .card--hero, .card--story, .card--speed, .fit__cols { grid-template-columns: minmax(0, 1fr); }
  .card { justify-content: center; padding-top: calc(var(--bar-h) + 1rem); gap: 1rem; }
  .hero__field, .speed__field { justify-self: stretch; width: 100%; grid-column: 1; grid-row: auto; }
  .story__copy, .speed__copy { grid-column: 1; grid-row: auto; }
  .card--story { grid-template-areas: "copy" "portrait" "sig"; grid-template-rows: auto auto auto; }
  .story__portrait { justify-self: start; width: min(100%, 12rem); margin-top: .5rem; }
  .story__sig { margin-left: 0; width: 100%; }
  .plane--photo, .plane--keys, .plane--everyday { inset: 0; width: 100%; height: 100%; }
  .planefade--keys, .planefade--everyday { inset: 0; width: 100%; height: 100%; }
  .plane--photo img { opacity: .5; }
  .planefade--photo {
    inset: 0; width: 100%;
    background: linear-gradient(to bottom, rgba(14, 16, 22, 0) 0%, rgba(14, 16, 22, .4) 46%, #0e1016 76%);
  }
  .scrim--column { background: linear-gradient(to top, rgba(14, 16, 22, .96) 0%, rgba(14, 16, 22, .82) 44%, rgba(14, 16, 22, .3) 72%, transparent 92%); }
  .privacy__copy, .privacy__checks { margin-left: 0; margin-right: 0; width: 100%; }
    .hint { display: none; }
}

@media (max-width: 700px) {
  .display--xl { font-size: var(--sc-t-2xl); }
  .display--lg { font-size: var(--sc-t-xl); }
  .lede, .lede--lg { font-size: var(--sc-t-base); }
  .metric__value { font-size: clamp(3rem, 12vw, 4.5rem); }
  .field__body { min-height: 3.4em; font-size: var(--sc-t-sm); }
  .field__body--lines { min-height: 5.4em; }
  .card--phrases .field__body--lines { min-height: 8.2em; }
  .story__copy { gap: .45rem; }
  .story__copy .lede { font-size: var(--sc-t-sm); line-height: 1.4; }
  .story__copy .lede--lg { font-size: var(--sc-t-base); }
  .speed__copy { gap: .55rem; }
  .lat__caption, .source { display: none; }
  .phrases__head .lede { font-size: var(--sc-t-sm); }
  .privacy__copy { gap: .55rem; }
  .checks li { padding-block: 7px; font-size: var(--sc-t-xs); }
  .fit__left .body { font-size: var(--sc-t-sm); }
  .fit__inner { gap: .9rem; }
  .fit__cols { gap: 1rem; }
  .fit__left { gap: 8px; }
  .fit__list li { padding-block: 7px; font-size: var(--sc-t-xs); }
  .act--fit .card { padding-block: calc(var(--bar-h) + .75rem) var(--pill-space); }
  .cta-row { gap: 12px; }
  .foot__links { flex-wrap: wrap; justify-content: center; gap: 12px 18px; }
  /* At this width the copy column is the whole frame, so the icon has to sit
     clear above the body line rather than behind it. */
  .plane--icon { top: 19%; opacity: .72; }
  .plane--icon, .plane--icon img { width: 132px; height: 132px; }
  .plane--icon img { border-radius: 30px; }
}

/* A short desktop window composes in roughly 460 px between the top bar and
   the pill, so the display ramp and the vertical gaps step down there. Micro
   type is left alone: it is already at its 11 px floor. */
@media (min-width: 861px) and (max-height: 820px) {
  :root { --pill-space: 152px; --pill-rest: 20px; --pill-bottom: 20px; }
  .card { padding-top: calc(var(--bar-h) + .9rem); }
  .display--xl { font-size: var(--sc-t-3xl); }
  .display--lg { font-size: var(--sc-t-2xl); }
  .display--md { font-size: var(--sc-t-xl); }
  .lede { font-size: var(--sc-t-base); }
  .lede--lg { font-size: var(--sc-t-xl); }
  .metric__value { font-size: clamp(3rem, 5.2vw, 5.5rem); }
  .hero__copy { gap: .8rem; }
  .story__copy { gap: .5rem; }
  .speed__copy { gap: .5rem; }
  .lat { margin-top: -1.2rem; }
  .lat__plate { padding: 13px 16px; gap: 8px; }
  .privacy__copy { gap: .55rem; }
  .checks li { padding-block: 7px; }
  .phrases__head { gap: .55rem; }
  .card--phrases .field__body--lines { min-height: 8.4em; }
  .fit__inner { gap: 1.1rem; }
  .fit__list li { padding-block: 8px; }
  .fit__left .body { font-size: var(--sc-t-base); }
  .card--close { gap: 1rem; }
  .close__copy { gap: .5rem; }
  .foot { padding-top: .9rem; gap: 5px; }
  .plane--icon, .plane--icon img { width: 170px; height: 170px; }
  .plane--icon img { border-radius: 38px; }
}

/* ======================================================== reduced motion = */
@media (prefers-reduced-motion: reduce) {
  /* The deck still stacks. Sticky is not motion. The recede scale and the
     rotation go; the dimming stays, because it is what says "this card is
     behind that one". */
  .card { transform: none; }
  .recede { opacity: calc(var(--cover, 0) * .4); }
  .stage, .act--fit .card { border-radius: 0; }
  .plane--icon img { transition: none; transform: none; }
  .field.is-live .field__caret { animation: none; opacity: 1; }
  .skip { transition: none; }
  .pillhit { display: none; }
  /* The engine hands the rail back as a native scroll region here, so the
     stage has to be able to scroll and the card must not clip it. */
  .act--packs .card { padding-inline: 0; }
  .rail > .railcard { opacity: 1; transform: none; }
}

/* =============================================== phrases: the script title */
/* The wordmark's face, naming the feature. Outlines, so no font is loaded. */
.script-title { margin: 0 0 .1em; }
.script-title svg { display: block; height: clamp(2.2rem, 4.2vw, 3.4rem); width: auto; overflow: visible; }
.script-title .g { fill: var(--sc-accent); stroke: var(--sc-accent); stroke-width: 10; stroke-linecap: round; stroke-linejoin: round; }
@media (prefers-reduced-motion: no-preference) {
  .act--phrases:not(.is-arrived) .script-title .g { fill-opacity: 0; stroke-dasharray: 1; stroke-dashoffset: 1; }
  .act--phrases.is-arrived .script-title .g {
    animation: ink-draw 520ms cubic-bezier(.4, 0, .2, 1) forwards, ink-fill 360ms ease-out forwards;
    animation-delay: calc(var(--i) * 70ms), calc(var(--i) * 70ms + 340ms);
  }
}

/* Say / get, so the cause is legible at any scroll position. */
.phrases__said { display: flex; align-items: center; gap: clamp(10px, 1.6vw, 22px); flex-wrap: wrap; }
.said { display: flex; flex-direction: column; gap: 3px; margin: 0; }
.said__lab { font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-dim); }
.said__quote { font-size: var(--sc-t-lg); color: var(--sc-ink); }
/* The spoken words paint on left to right, the way they arrive on the pill.
   A clip, not a per-character reveal: the quote stays one text node, so it is
   read whole by a screen reader and never reflows mid-paint. */
.said__paint { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .said__paint { clip-path: inset(0 calc((1 - var(--say, 1)) * 100%) 0 0); }
}
/* The right-hand half arrives in two beats. "Five lines, exactly as you wrote
   them." is typed in by site.js, character by character, once the quote has
   finished painting. "Instantly." is withheld until the very end and appears on
   the same frame as the five lines in the note, which is the whole claim. */
.said--out { opacity: 0; }
.act--phrases.is-typing-get .said--out,
.act--phrases.is-popped .said--out { opacity: 1; transition: opacity 140ms linear; }
.said__type::after {
  content: ""; display: inline-block;
  width: 2px; height: 1em; margin-left: 2px;
  vertical-align: -.14em; background: var(--sc-accent);
  opacity: 0;
}
.act--phrases.is-typing-get:not(.is-popped) .said__type::after {
  opacity: 1; animation: caret 1.06s steps(1) infinite;
}
.said__pop { opacity: 0; }
.act--phrases.is-popped .said__pop {
  opacity: 1;
  animation: pop-in 260ms var(--sc-ease-out) 1;
}
@keyframes pop-in { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .said--out, .said__pop { opacity: 1; }
  .said__type::after { display: none; }
}
.said__quote em { font-style: normal; color: var(--sc-accent); }
.said__count { font-size: var(--sc-t-base); color: var(--sc-ink-soft); }
.said__count b { color: var(--sc-accent); font-weight: 600; }
.said__arrow { width: 34px; height: 1px; margin: 14px 0 0; background: linear-gradient(90deg, transparent, var(--sc-accent)); position: relative; }
.said__arrow::after { content: ""; position: absolute; right: 0; top: -3px; border: 3.5px solid transparent; border-left-color: var(--sc-accent); }
.names__head { margin: 0 0 8px; font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-dim); }

/* ==================================================== two other arrivals ==
   Every card sliding up in a finished state is one transition repeated seven
   times. Two cards arrive differently instead. Neither touches the deck: the
   stage still slides, only what is inside it behaves differently.            */

/* BUILD (story). The ground arrives empty and the scene assembles on it: the
   photograph fades up from black, then the copy. It reads as a dissolve. */
@media (prefers-reduced-motion: no-preference) {
  .act--build .plane--photo { opacity: calc(1 - var(--enter, 0)); }
  .act--build .plane--photo img { transform: scale(calc(1 + .05 * var(--enter, 0))); }
  .act--build .story__copy > *, .act--build .story__portrait {
    transform: translateY(calc(var(--enter, 0) * 26px));
  }
  .act--build .story__copy > *:nth-child(2) { transform: translateY(calc(var(--enter, 0) * 38px)); }
  .act--build .story__copy > *:nth-child(3) { transform: translateY(calc(var(--enter, 0) * 50px)); }
  .act--build .story__copy > *:nth-child(4) { transform: translateY(calc(var(--enter, 0) * 62px)); }
  .act--build .story__copy > *:nth-child(5) { transform: translateY(calc(var(--enter, 0) * 74px)); }
}

/* IRIS (privacy). The card opens from the middle: a circle widens over the
   slide, so the vault is uncovered rather than pushed up. The clip sits on the
   inner card, never on the sticky stage. */
@media (prefers-reduced-motion: no-preference) {
  .act--iris .stage > :not(.recede) {
    clip-path: circle(calc((1 - var(--enter, 0)) * 78% + 12%) at 50% 50%);
  }
}

/* The paste flash on the phrases card: the block arrives, the field edge picks
   up the pill's green for a beat, then settles. One shot, restarted by JS. */
.field.did-paste { animation: paste-land 640ms var(--sc-ease-out) 1; }
.field.did-paste .line { animation: paste-lines 460ms var(--sc-ease-out) 1; }
@keyframes paste-land {
  0%   { border-color: rgba(67, 209, 127, .85); box-shadow: var(--sc-e3), 0 0 0 3px rgba(67, 209, 127, .18); }
  100% { border-color: rgba(255, 255, 255, .14); box-shadow: var(--sc-e3), 0 0 0 3px rgba(67, 209, 127, 0); }
}
@keyframes paste-lines { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .field.did-paste, .field.did-paste .line { animation: none; }
}

/* The hero price. It was a mono footnote beside the button and readers missed
   it, which is the one number this page most needs them to carry away. Now it
   sits at the button's own weight: the figure large, the terms beside it. */
/* The price carries its own surface, exactly like the button beside it. The
   ribbons pass under this corner and a bare line dipped below 3:1 there; a
   text-shadow cannot fix it, because the contrast pass hides a line and its
   shadow together and grades the raw frame. */
.price {
  display: flex; align-items: center; gap: 10px; margin: 0;
  padding: 9px 16px 10px;
  border: 1px solid var(--hair); border-radius: 14px;
  background: #0d1015;
}
.price__num {
  font-family: var(--sc-font-display);
  font-size: clamp(1.75rem, 1.2rem + 1.5vw, 2.6rem);
  font-weight: 640; letter-spacing: -.04em; line-height: 1;
  color: var(--sc-ink);
}
.price__note {
  font-size: var(--sc-t-sm); line-height: 1.35;
  color: var(--sc-ink); text-wrap: pretty;
}
@media (max-width: 700px) { .price__note br { display: none; } }

/* ==================================================== docking the capsule ==
   The pill parks under the active card's demo field, so each field must be the
   lowest element on its own card and must leave a capsule's worth of room
   beneath it. --pill-space already reserves that room at the card's foot; these
   rules put the field on that line and move the surrounding copy above it. */
.card--speed { align-items: end; }
.speed__copy { align-self: start; }
.speed__field { align-self: end; margin-bottom: clamp(.4rem, 1.6vh, 1rem); }
.card--phrases { align-content: start; }
.phrases__field { align-self: end; }
.card--packs .lead__field, .rail__lead .field { margin-bottom: 0; }

/* ============================================ legibility over live light ==
   The hero's ribbons are a live canvas and the handoff forbids a scrim, a
   blend, a filter or any layer over it. So the copy carries its own contrast
   instead: a tight shadow keyed to the renderer's own ground colour, which
   darkens only the pixels immediately around each glyph. The art is untouched.
   Measured need: the lede and the price both dipped under 3:1 when a gust
   crest passed beneath them, against means of 7:1 and 13:1. */
.card--hero .lede,
.card--hero .price,
.card--hero .price__num,
.card--hero .price__note {
  text-shadow:
    0 1px 2px rgba(2, 5, 7, .92),
    0 0 10px rgba(2, 5, 7, .78),
    0 0 26px rgba(2, 5, 7, .55);
}
.card--hero h1 { text-shadow: 0 2px 18px rgba(2, 5, 7, .5); }

/* The signature sits over the desk photograph, which is a still image, so it
   takes the same treatment rather than a plate that would box it in. */
.sig-line strong { color: #fff; }

/* ===================================================== the HIPAA callout ==
   The one line a clinician is scanning for. It was a second grey paragraph and
   it read as a footnote; it now carries the accent and a tag, which is the
   only place on the page outside the pill and the CTA that the red appears. */
.hipaa {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 0; padding: 14px 18px 15px;
  border-radius: 14px;
  border: 1px solid color-mix(in oklab, var(--sc-accent) 34%, transparent);
  background: color-mix(in oklab, var(--sc-accent) 9%, #0d1015);
  font-size: var(--sc-t-base); line-height: 1.55; color: var(--sc-ink);
}
.hipaa__tag {
  flex: 0 0 auto; margin-top: .12em;
  padding: 3px 9px 4px; border-radius: 999px;
  background: var(--sc-accent); color: var(--sc-accent-ink);
  font-family: var(--sc-font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: .06em;
}

/* The close card runs the renderer, so it takes the hero's ground and the same
   no-overlay rule: its copy carries its own contrast. */
/* The last card is the end of the document, so it may grow past one screen
   when a short window cannot hold it, and every part of it stays reachable by
   scrolling. Every other card must fit its window; this one need not. */
.act--close .stage--wind { height: auto; min-height: 100svh; overflow: visible; }
.card--close .display, .card--close .lede, .card--close .compare, .card--close .close__terms {
  text-shadow: 0 1px 2px rgba(2, 5, 7, .92), 0 0 12px rgba(2, 5, 7, .7);
}
.card--close .close__copy { position: relative; z-index: 1; }

/* The fit card is pinned now rather than flowing past. */
.act--fit .card { min-height: auto; box-shadow: none; border-radius: 0; }
.act--fit .card::before { display: none; }

/* Small print on the close card sits over the live renderer, which takes no
   overlay, so each line carries its own quiet surface instead. Sized to the
   text, not to the column, so the card still reads as open. */
.plate-sm {
  display: inline-block;
  padding: 7px 14px 8px;
  border-radius: 12px;
  border: 1px solid var(--hair);
  background: #0b0e13;
  text-shadow: none !important;
}
.card--close .close__terms { color: var(--sc-ink-soft); }
.card--close .compare { color: var(--sc-ink); }

/* The close card's copy each sits on its own quiet surface, because the
   renderer beneath it takes no overlay and a bright gust crosses this corner.
   Sized to the line, so the card still reads as open rather than boxed. */
.card--close .lede.plate-sm { padding: 10px 20px 12px; max-width: 44ch; }
.foot.plate-sm { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px 18px; padding: 12px 20px 13px; }
.foot.plate-sm .foot__line, .foot.plate-sm .foot__copy { margin: 0; }

/* The hero lede takes the same surface as the close card's copy, for the same
   reason: the renderer under it accepts no overlay, and a gust crest crossing
   this corner put a body paragraph under 3:1. Sized to the text. */
.card--hero .lede.plate-sm { padding: 11px 18px 13px; max-width: 40ch; }

/* A buy button with nowhere to go. Dimmed and inert rather than hidden, so the
   page still reads correctly while the store is being set up. */
.btn--soon { opacity: .55; cursor: default; }
.btn--soon:hover { transform: none; }

/* ==================================================== the packs rail, lit ==
   The collection was fourteen grey cards and read as a spreadsheet. Each name
   now carries the brand red and a hairline of it above the card, which is the
   only decoration on them: the labels stay factual. */
.railcard h3 { color: var(--sc-accent); }
/* The pack the rail is parked on, while its example plays under it. */
.railcard.is-live .railcard__in { box-shadow: 0 0 0 1px var(--sc-accent), 0 0 28px -6px var(--sc-accent), inset 0 1px 0 var(--edge); }
.railcard .railcard__in { transition: box-shadow 260ms ease; }
.railcard__in { position: relative; }
.railcard__in::after {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg,
    var(--sc-accent) 0%, color-mix(in oklab, var(--sc-accent) 45%, transparent) 46%, transparent 92%);
  opacity: .85; pointer-events: none;
}
.railcard--next h3, .railcard--own h3 { color: var(--coral); }
.railcard--own .railcard__in::after { background: linear-gradient(90deg, var(--coral), transparent 88%); }
.railcard--own p { color: var(--sc-ink-soft); }
.next-list li { color: var(--sc-ink); }

/* The rail is panned by site.js, not by the engine, so the transform lives
   here and reads two custom properties the page writes: the measured overflow
   and a 0..1 that holds at each end. */
.rail {
  will-change: transform;
  transform: translate3d(calc(-1 * var(--rail-travel, 0px) * var(--rail-p, 0)), 0, 0);
}
@media (prefers-reduced-motion: reduce) {
  /* No transform at all: the stage becomes a real scroll region so every card
     stays reachable by keyboard and trackpad. */
  .act--packs .stage { overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; }
  .rail { transform: none; will-change: auto; }
}

.packs__drugs { margin-top: .3rem; }
.packs__drugs b { color: var(--sc-ink); font-weight: 600; }
.packs__drugs em { font-style: normal; color: var(--sc-accent); }

/* The features list had no heading and read as loose text beside a paragraph.
   It gets the wordmark's own face, in the brand red, at a size that names the
   column without competing with the card's headline. */
.script-title--sm svg { height: clamp(1.7rem, 3vw, 2.5rem); }
.fit__more { display: flex; flex-direction: column; gap: .4rem; }
.act--fit .script-title .g { fill: var(--sc-accent); stroke: var(--sc-accent); }
@media (prefers-reduced-motion: no-preference) {
  .act--fit:not(.is-arrived) .script-title .g { fill-opacity: 0; stroke-dasharray: 1; stroke-dashoffset: 1; }
  .act--fit.is-arrived .script-title .g {
    animation: ink-draw 500ms cubic-bezier(.4, 0, .2, 1) forwards, ink-fill 340ms ease-out forwards;
    animation-delay: calc(var(--i) * 60ms), calc(var(--i) * 60ms + 320ms);
  }
}

.fit__list b { color: var(--sc-ink); font-weight: 600; }

/* ============================================== the overlay, at both sizes ==
   The card was a headline, two paragraphs and a list, and the photograph behind
   it is nearly black, so it read as empty. This is the product's own surface,
   drawn in CSS rather than screenshotted: the capsule at both of its sizes and
   the real preset colours from LoquenCore's RibbonColor. */
.looks { margin: clamp(1rem, 3vh, 1.8rem) 0 0; display: flex; flex-direction: column; gap: 14px; }
.looks__row { display: flex; align-items: flex-end; gap: 22px; flex-wrap: wrap; }
.looks__one { display: flex; flex-direction: column; gap: 7px; }
.looks__one figcaption {
  font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-dim);
}

.pillshot {
  position: relative; display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: rgba(7, 10, 16, .92);
  border: 1px solid rgba(255, 255, 255, .19);
  box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .9);
  overflow: hidden;
}
.pillshot--full { width: clamp(15rem, 26vw, 20rem); height: 3.4rem; }
/* Mini is a pill, not a bar: the app's 104 x 46 pt capsule (2.26:1), same glass
   and hairline as the full one, with the thread across its middle and room to
   breathe above and below. */
.pillshot--mini { width: 6.5rem; height: 2.875rem; }
.pillshot__words {
  position: absolute; top: 33.3%; transform: translateY(-50%);
  font-size: 12px; color: rgba(255, 255, 255, .55); white-space: nowrap;
}
/* The ribbon: a bright core with the tapered bloom above and below it, the
   same shape the real renderer draws, held at one representative frame. */
.pillshot__ribbon {
  position: absolute; left: 8%; right: 8%; top: 59%; height: 2px;
  background: linear-gradient(90deg, transparent, var(--sc-accent) 22%, #ff604e 50%, var(--sc-accent) 78%, transparent);
  border-radius: 2px;
  box-shadow: 0 0 10px 2px rgba(255, 51, 71, .55), 0 0 26px 8px rgba(255, 51, 71, .22);
}
.pillshot--mini .pillshot__ribbon {
  top: 50%; left: 9%; right: 9%;
  box-shadow: 0 0 12px 3px rgba(255, 51, 71, .6), 0 0 30px 11px rgba(255, 51, 71, .26);
}

.swatches { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin: 0; padding: 0; list-style: none; }
.swatches li { display: flex; align-items: center; gap: 7px; font-family: var(--sc-font-mono); font-size: 11px; color: var(--sc-ink-soft); }
.swatches span {
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--c);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22);
}
.swatches .is-signature span { box-shadow: inset 0 0 0 1px rgba(255,255,255,.3), 0 0 0 2px color-mix(in oklab, var(--sc-accent) 55%, transparent); }
.looks__note { margin: 0; max-width: 48ch; font-size: var(--sc-t-sm); line-height: 1.5; color: var(--sc-ink-soft); }


@media (max-width: 860px) { .looks { display: none; } }

.foot__line b { color: var(--sc-accent); font-weight: 600; font-style: italic; }
.foot.plate-sm { max-width: 64rem; }

/* ================================================== the audit: conversion ==
   Risk reversal beside the price, the real requirements where the buyer is
   deciding, a FAQ card that answers the refund-generating questions before the
   price line, and a cost table instead of a sentence. */
.price__trial { display: block; color: var(--sc-ink); font-weight: 600; }
.reqs { margin: 0; font-family: var(--sc-font-mono); font-size: 11.5px; letter-spacing: 0; color: var(--sc-ink-soft); text-shadow: 0 1px 2px rgba(2,5,7,.9); }
.reqs__win { color: var(--sc-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in oklab, var(--sc-accent) 60%, transparent); }
.reqs__win.is-soon, .foot__links a.is-soon { opacity: .55; cursor: default; }

.card--faq { justify-content: center; gap: clamp(1.2rem, 3vh, 2rem); }
.faq__head { max-width: 40rem; }
.faq__head .body { color: var(--sc-ink-soft); margin: .4rem 0 0; }
.faq {
  margin: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.9rem, 2vh, 1.4rem) clamp(1.5rem, 4vw, 3.5rem);
  max-width: 64rem;
}
.faq__item { border-top: 1px solid var(--hair); padding-top: .8rem; }
.faq dt { margin: 0 0 .3rem; font-weight: 600; color: var(--sc-ink); font-size: var(--sc-t-base); }
.faq dd { margin: 0; font-size: var(--sc-t-sm); line-height: 1.55; color: var(--sc-ink-soft); text-wrap: pretty; }
@media (max-width: 860px) { .faq { grid-template-columns: minmax(0, 1fr); } .faq__item:nth-child(n+6) { display: none; } }

.glance { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 0; margin: 0; padding: 8px 6px; list-style: none; }
.glance li { padding: 3px 12px; font-family: var(--sc-font-mono); font-size: 11.5px; letter-spacing: 0; color: var(--sc-ink); border-right: 1px solid var(--hair); }
.glance li:last-child { border-right: 0; }

.compare.plate-sm { display: table; padding: 6px 10px; border-collapse: collapse; }
.compare th, .compare td { padding: 6px 12px; font-size: var(--sc-t-sm); text-align: left; white-space: nowrap; }
.compare th { font-weight: 500; color: var(--sc-ink-soft); }
.compare td:nth-child(2) { font-family: var(--sc-font-display); font-weight: 640; letter-spacing: -.02em; color: var(--sc-ink); font-size: var(--sc-t-base); }
.compare td:nth-child(3) { color: var(--sc-ink-soft); }
.compare .is-us th, .compare .is-us td { color: var(--sc-ink); }
.compare .is-us td:nth-child(2) { color: var(--sc-accent); }
.compare tr + tr th, .compare tr + tr td { border-top: 1px solid var(--hair); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (max-width: 700px) { .compare td:nth-child(3) { display: none; } }

/* The close, fitted back onto one screen. */
.card--close { gap: clamp(.7rem, 1.8vh, 1.2rem); }
.close__copy { gap: clamp(.45rem, 1.2vh, .8rem); }
.compare th, .compare td { padding: 4px 10px; }
.foot.plate-sm { display: grid; grid-template-columns: auto 1fr auto; grid-template-areas: "mark voce links" "mark made copy"; align-items: center; gap: 4px 18px; padding: 10px 18px; text-align: left; }
.foot__mark { grid-area: mark; }
.foot__line { grid-area: voce; font-size: var(--sc-t-sm); }
.foot__line--made { grid-area: made; color: var(--ink-dim); font-size: var(--sc-t-xs); }
.foot__links { grid-area: links; }
.foot__copy { grid-area: copy; justify-self: end; font-size: var(--sc-t-xs); }
@media (max-width: 860px) { .foot.plate-sm { grid-template-columns: 1fr; grid-template-areas: "mark" "voce" "made" "links" "copy"; text-align: center; } .foot__copy { justify-self: center; } }

/* "or buy now" under the trial button: present for the person who has already
   decided, quiet enough not to compete with the free door. */
.buynow { display: inline-block; margin-top: 2px; font-size: var(--sc-t-sm); color: var(--sc-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in oklab, var(--sc-accent) 55%, transparent); text-shadow: 0 1px 2px rgba(2,5,7,.9); }
.buynow.btn--soon { opacity: .5; }
.reqs.plate-sm { padding: 6px 12px 7px; text-shadow: none; }
.faq__item:nth-child(n+9) { display: none; }
@media (min-width: 861px) { .faq__item:nth-child(n+9) { display: block; } .faq { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 72rem; } }

/* The close card composes above a pill that RESTS at the bottom (it has no
   demo field to dock under), so it needs only the capsule's own height of
   clearance, not the full docking reserve every other card keeps. On short
   laptop screens the strip goes and the type steps down, so the button and
   the footer are never pushed off the bottom. */
.act--close .card { padding-bottom: 140px; padding-top: calc(var(--bar-h) + clamp(.8rem, 2vh, 1.6rem)); }
@media (max-height: 820px) {
  .card--close .display--lg { font-size: var(--sc-t-2xl); }
  .glance { display: none; }
  .compare th, .compare td { padding: 3px 10px; }
  .card--close .lede.plate-sm { display: none; }
}

/* The full field, two tables side by side, sorted by what a year costs. */
.compare-wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; padding: 8px 12px 6px; text-align: left; }
.compare-wrap .compare { display: table; width: 100%; border-collapse: collapse; padding: 0; border: 0; background: none; }
.compare-wrap .compare th, .compare-wrap .compare td { padding: 3px 8px; font-size: 12.5px; white-space: nowrap; }
.compare-wrap .compare td:nth-child(2) { font-size: 13.5px; }
.compare__note { grid-column: 1 / -1; margin: 6px 0 0; font-family: var(--sc-font-mono); font-size: 10.5px; letter-spacing: 0; color: var(--ink-dim); text-align: center; }
@media (max-width: 860px) { .compare-wrap { grid-template-columns: 1fr; } .compare-wrap .compare td:nth-child(3) { display: none; } }
@media (max-height: 820px) { .compare-wrap .compare th, .compare-wrap .compare td { padding: 2px 8px; font-size: 12px; } }

/* ================================================== the close, two columns ==
   The pitch on the left, the whole field's prices on the right, the footer
   under both. One screen at desktop; on a phone it stacks and the last card
   is allowed to run past the fold, since it is the end of the page. */
.card--close { align-items: stretch; text-align: left; }
.close__copy {
  display: grid; grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
  align-items: center; gap: clamp(1.2rem, 3vw, 3rem);
  max-width: 76rem; margin-inline: auto; width: 100%;
}
.close__pitch { display: flex; flex-direction: column; align-items: flex-start; gap: clamp(.7rem, 1.6vh, 1.1rem); }
.close__pitch .display { max-width: 9ch; }
.close__pitch .lede.plate-sm { max-width: 34ch; font-size: var(--sc-t-base); }
.close__cta { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 0; }
.close__pitch .reqs.plate-sm { font-size: 11px; }

.compare-wrap { display: block; padding: 10px 14px 8px; justify-self: end; width: min(100%, 34rem); }
.compare__head { margin: 0 0 4px; padding: 0 8px; font-family: var(--sc-font-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-dim); }
.compare-wrap .compare { display: table; width: 100%; border-collapse: collapse; }
.compare-wrap .compare th, .compare-wrap .compare td { padding: 3px 8px; font-size: 12.5px; line-height: 1.3; white-space: nowrap; }
.compare-wrap .compare td:nth-child(2) { font-size: 13px; }
.compare__note { margin: 6px 0 0; padding: 0 8px; text-align: left; }
.foot.plate-sm { max-width: 76rem; width: 100%; margin: clamp(.8rem, 2vh, 1.4rem) auto 0; }
.glance { display: none; }
@media (max-width: 980px) {
  .close__copy { grid-template-columns: minmax(0, 1fr); }
  .compare-wrap { justify-self: stretch; width: 100%; }
}
@media (max-height: 820px) { .close__pitch .lede.plate-sm { display: none; } .compare-wrap .compare th, .compare-wrap .compare td { padding: 2px 8px; font-size: 12px; } }

/* The buy-now link carries a surface like every other small line over the
   renderer: a bare underlined link dipped to 2.2:1 under a gust crest. */
.buynow.plate-sm { padding: 8px 14px 9px; margin-top: 0; text-decoration-thickness: 1px; }

/* ==================================================== redact: the card ===
   Copy left, the review field right with the capsule docked under it. The
   field renders the redacted text with every stand-in marked, the way the
   app's own review card does: an unmarked name would be conspicuous. */
.card--redact { display: grid; grid-template-columns: minmax(0, 50fr) minmax(0, 50fr); align-items: center; gap: clamp(1.5rem, 4vw, 4rem); }
.redact__copy { display: flex; flex-direction: column; gap: clamp(.55rem, 1.4vh, .95rem); }
.redact__copy .lede { max-width: 46ch; font-size: var(--sc-t-base); color: var(--sc-ink-soft); }
.redact__list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; max-width: 48ch; }
.redact__list li { padding-left: 14px; position: relative; font-size: var(--sc-t-sm); line-height: 1.5; color: var(--sc-ink-soft); text-wrap: pretty; }
.redact__list li::before { content: ""; position: absolute; left: 0; top: .62em; width: 5px; height: 5px; border-radius: 50%; background: var(--sc-accent); }
.redact__list b { color: var(--sc-ink); font-weight: 600; }
.redact__honest { margin: .2rem 0 0; font-size: var(--sc-t-sm); color: var(--sc-ink); max-width: 46ch; }
.redact__honest b { color: var(--sc-accent); font-weight: 600; }
.act--redact .script-title .g { fill: var(--sc-accent); stroke: var(--sc-accent); }
@media (prefers-reduced-motion: no-preference) {
  .act--redact:not(.is-arrived) .script-title .g { fill-opacity: 0; stroke-dasharray: 1; stroke-dashoffset: 1; }
  .act--redact.is-arrived .script-title .g {
    animation: ink-draw 520ms cubic-bezier(.4, 0, .2, 1) forwards, ink-fill 360ms ease-out forwards;
    animation-delay: calc(var(--i) * 70ms), calc(var(--i) * 70ms + 340ms);
  }
}
.redact__field { align-self: end; justify-self: end; width: min(100%, 32rem); margin-bottom: clamp(.4rem, 1.6vh, 1rem); }
.field__body--review { min-height: 6.6em; font-size: var(--sc-t-base); line-height: 1.6; }
.field__body--review mark {
  background: color-mix(in oklab, var(--sc-accent) 22%, transparent);
  color: var(--sc-ink); border-radius: 4px; padding: 0 3px;
  box-shadow: inset 0 -1px 0 color-mix(in oklab, var(--sc-accent) 70%, transparent);
}
.review__foot { display: flex; justify-content: space-between; gap: 12px; margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--hair); color: var(--sc-ink-soft); }
.review__foot b { color: var(--sc-ink); font-weight: 600; }
.review__count { color: var(--sc-accent); font-weight: 600; }

/* ---- burst: a ring that flashes out from an element, and motes off its edge */
.burst { position: fixed; z-index: 80; pointer-events: none; }
.burst i {
  position: absolute; width: var(--s); height: var(--s);
  margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  border-radius: 50%;
  background: rgb(var(--burst)); box-shadow: 0 0 6px 1px rgba(var(--burst), .75);
  animation: burst-fly var(--d) cubic-bezier(.2, .7, .3, 1) 1 forwards;
}
@keyframes burst-fly {
  0%   { transform: translate(0, 0) scale(1); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(.25); opacity: 0; }
}
.is-burst { animation: burst-ring 720ms ease-out 1; }
@keyframes burst-ring {
  0%   { outline: 2px solid rgba(var(--burst, 255, 51, 71), 1); outline-offset: 1px; }
  100% { outline: 2px solid rgba(var(--burst, 255, 51, 71), 0); outline-offset: 16px; }
}
@media (prefers-reduced-motion: reduce) { .burst { display: none; } .is-burst { animation: none; } }
/* While the pill listens, one row per identifier heard: the words that were
   said, in red, and what kind of thing they were. The newest row flashes. */
.field__body--review .catch { display: flex; align-items: baseline; gap: .7em; line-height: 1.55; }
.field__body--review .catch__said { color: var(--sc-accent); font-weight: 600; white-space: nowrap; }
.field__body--review .catch__kind { color: var(--sc-ink-soft); font-size: .92em; }
.field__body--review .catch__kind::before { content: "\2192"; margin-right: .55em; color: var(--sc-ink-soft); }
.field__body--review .catch--new { animation: catch-in 320ms var(--sc-ease-out) 1; }
.field__body--review .catch--new .catch__said { animation: catch-flash 380ms ease-out 3; }
@keyframes catch-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes catch-flash { 0%, 100% { opacity: 1; } 50% { opacity: .18; } }
@media (prefers-reduced-motion: reduce) { .field__body--review .catch--new, .field__body--review .catch--new .catch__said { animation: none; } }
@media (max-width: 980px) { .card--redact { grid-template-columns: minmax(0, 1fr); } .redact__field { justify-self: stretch; width: 100%; } .redact__list li:nth-child(n+3) { display: none; } }

/* ============================================================ 8 languages =
   Twenty-eight names, each written in its own language. That is the whole
   design: the Cyrillic and Greek rows are the feature proving itself on the
   page, which no flag can do. Deliberately no flags -- a language is not a
   country (Serbian, Bosnian and Croatian share one region, Belarusian's flag
   is contested), and flag emoji render as bare letter pairs on Windows. */
.card--langs {
  padding-inline: 0;
  justify-content: flex-start;
  gap: clamp(1rem, 3vh, 2rem);
  padding-top: calc(var(--bar-h) + clamp(1rem, 3vh, 2.2rem));
}
.langs__head {
  padding-inline: var(--sc-gutter);
  display: grid; grid-template-columns: minmax(0, 36fr) minmax(0, 64fr);
  align-items: start; gap: clamp(1.2rem, 3.5vw, 3rem);
}
.langs__head h2 { max-width: 14ch; margin: 0; }
.langs__head .body { max-width: 62ch; color: var(--sc-ink-soft); margin: 0; }
.langs__head .body + .body { margin-top: .55rem; }
.langs__head b { color: var(--sc-ink); font-weight: 600; }
.langs__more { font-size: var(--sc-t-sm); }
/* Stays on a phone where .langs__more does not: a buyer reading "twenty-eight
   languages" next to "eleven specialty packs" will assume the two work
   together, and right now they do not. */
.langs__packs { font-size: var(--sc-t-sm); }
.langs__packs b { color: var(--sc-accent); font-weight: 600; }

/* auto-fill, so the grid reflows to the viewport rather than to a fixed count.
   11rem is set by the longest pair on one line: Slovenscina / Slovenian. */
.langs {
  margin: 0; padding: 0 var(--sc-gutter); list-style: none;
  display: grid; gap: 9px;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
}
/* Two rows: the name in its own language across the top, then the English name
   with the ISO code pinned to the right. Named areas rather than line numbers,
   because the three spans are siblings with no wrapper of their own. */
.langs li {
  min-width: 0; position: relative; overflow: hidden; isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "own own" "en code";
  gap: 2px 8px;
  padding: 10px 12px;
  border: 1px solid var(--edge);
  border-radius: 12px;
  background: rgba(255, 255, 255, .022);
}

/* The flag sits behind the name, faint, and comes up when the pointer is on
   the tile. It is decoration, not a label: the name in its own language is
   what identifies the language, which is why the flag is aria-hidden by
   being a pseudo-element and why a shared flag would not mislead anyone.
   Rasterised to 160px WebP rather than shipped as SVG -- Serbia's coat of
   arms alone is 181 KB of vector nobody can see at 13% opacity. */
.langs li::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: var(--flag) center / cover no-repeat;
  opacity: .13;
  transition: opacity 240ms var(--sc-ease-out);
}
/* A veil, because half these flags are white or yellow and the name has to
   stay readable when the flag comes up. */
.langs li::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(100deg, rgba(11, 14, 20, .9) 0%, rgba(11, 14, 20, .62) 62%, rgba(11, 14, 20, .5) 100%);
  transition: opacity 240ms var(--sc-ease-out);
  opacity: .55;
}
.langs li > * { position: relative; z-index: 2; }
@media (hover: hover) and (pointer: fine) {
  .langs li:hover::before { opacity: .5; }
  .langs li:hover::after { opacity: .82; }
}
@media (prefers-reduced-motion: reduce) {
  .langs li::before, .langs li::after { transition: none; }
}
.langs__own {
  grid-area: own;
  font-size: var(--sc-t-base); font-weight: 600; line-height: 1.25;
  color: var(--sc-ink);
  min-width: 0; overflow-wrap: anywhere;
}
.langs__en {
  grid-area: en;
  font-size: 11px; line-height: 1.3; color: var(--sc-ink-soft);
  min-width: 0; overflow-wrap: anywhere;
}
.langs__code {
  grid-area: code; align-self: end;
  font-family: var(--sc-font-mono); font-size: 10px; letter-spacing: .04em;
  color: var(--sc-accent); opacity: .85;
}

/* On a phone twenty-eight chips cannot carry three lines each and still fit a
   pinned card, so the English gloss and the code go and the native name --
   the thing worth showing -- stays. */
@media (max-width: 980px) {
  .langs__head { grid-template-columns: minmax(0, 1fr); }
  .langs__more { display: none; }
  .langs {
    grid-template-columns: repeat(auto-fill, minmax(5.6rem, 1fr));
    gap: 5px;
  }
  .langs li { grid-template-areas: "own own"; padding: 6px 8px; border-radius: 8px; }
  .langs__en, .langs__code { display: none; }
  .langs__own { font-size: var(--sc-t-sm); font-weight: 500; }
}
