@charset "utf-8";
/* ============================================================================
   Vellum — marketing site
   ----------------------------------------------------------------------------
   The palette, the shape scale, the motion durations and the type ramp are the
   iOS design system verbatim (design-system.md `Color`, audited Aug 12 2026
   against the shipped client). The web-only additions are marked G1..G6 and
   each one derives from an inherited token — no new colors were invented for
   the web, and in particular there is no red anywhere in this file. An absent
   feature is an em dash. A validation error is inkMuted. Nothing turns red
   because somebody was busy.
   ========================================================================= */

/* ------------------------------------------------------------------ fonts */
/* Self-hosted and subset to latin. No CDN — see the note in layout.html. */
@font-face {
  font-family: 'Nunito';
  src: url('/fonts/nunito-var-latin.woff2') format('woff2');
  font-weight: 200 1000;
  font-display: swap;
}

/* ----------------------------------------------------------------- tokens */
:root {
  /* Inherited — iOS palette, verbatim */
  --canvas: #FDFAF4;
  --surface: #FFFDF9;
  --border: #EDE5DA;
  --ink: #23253C;
  --ink-muted: #6E6A63;
  --ink-faint: #B4ADA3;          /* merely present — not a reading color */
  --terracotta: #C05A2B;         /* missions, photo/video, primary — fill, not body text */
  --terracotta-soft: #FBEDE2;
  --terracotta-deep: #9A431E;    /* pressed; and terracotta-as-text at body size */
  --periwinkle: #5566D6;         /* questions, voice, written; focus ring */
  --periwinkle-soft: #E9EBFB;
  --periwinkle-border: #DADDF7;
  --periwinkle-deep: #3F4FB0;
  --sage: #E8F0E6;               /* did-it / completed */
  --sage-border: #D8E4D5;
  --sage-ink: #4B7A4F;
  --sage-soft: #DCE8DA;
  --chip-plain: #F4EEE5;
  --sealed-border: #F0DFD5;
  --sealed-ink: #A79A92;
  --rule-terracotta: #EBD8C8;
  --rule-periwinkle: #C6CCF2;
  --rule-sage: #B7CDB3;
  --wash: linear-gradient(135deg, #FDE8DC 0%, #F7DDE8 50%, #FBF6EF 100%);

  /* Shape / elevation / motion — inherited */
  --r-card: 20px;
  --r-row: 18px;
  --r-quote: 16px;
  --r-media: 14px;
  --r-glyph: 11px;
  --r-pill: 999px;
  --r-slab: 28px;                /* web-only: the full-bleed feature panels */
  --shadow-card: 0 2px 8px rgba(35, 37, 60, 0.04);
  --shadow-hover: 0 3px 10px rgba(35, 37, 60, 0.07);   /* G2 */
  --shadow-lift: 0 14px 36px rgba(35, 37, 60, 0.09);
  --shadow-deep: 0 40px 90px rgba(35, 37, 60, 0.22), 0 4px 14px rgba(35, 37, 60, 0.08);
  --dur-tap: 0.12s;
  --dur-enter: 0.28s;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* G1 — terracotta at body size is 4.25:1 and fails AA. Following the sageInk
     precedent, terracotta-as-text resolves to the deep step: 6.31:1 on canvas. */
  --text-terracotta: var(--terracotta-deep);

  /* G3 — periwinkle clears 3:1 on every ground in the system */
  --focus-ring: 2px solid var(--periwinkle);

  /* G6 — deep for the word, base terracotta for the underline */
  --link: var(--terracotta-deep);
  --link-underline: var(--terracotta);

  /* G5 — fluid type. Every curve lands exactly on the app's value at a 393px
     viewport and grows to the desktop cap at 1200px. */
  --t-hero: clamp(2.125rem, 1.212rem + 3.717vw, 4rem);
  --t-section: clamp(1.8125rem, 1.356rem + 1.859vw, 2.75rem);
  --t-title: clamp(1.375rem, 1.192rem + 0.743vw, 1.75rem);
  --t-prompt: 20px;
  --t-card-title: 17px;
  --t-body: 16px;
  --t-quote: 14px;
  --t-meta: 13px;
  --t-label: 12px;

  --display: 'Nunito', ui-rounded, system-ui, -apple-system, sans-serif;
  --text: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* G4 — max content width and the three margin steps */
  --wrap: 1120px;
  --gutter: 16px;
}
@media (min-width: 600px) { :root { --gutter: 28px; } }
@media (min-width: 900px) { :root { --gutter: 48px; } }

/* ------------------------------------------------------------------ reset */
*, *::before, *::after { box-sizing: border-box; }
html { overflow-x: clip; -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font: 400 var(--t-body)/1.45 var(--text);
  -webkit-font-smoothing: antialiased;
}
/* The window frame. A terracotta glow banked against the viewport edge, the way
   light sits in the rim of a warm room — the page looks lit rather than pasted
   onto the screen. Decorative and nothing else: fixed so it never scrolls, no
   markup, no layout box, pointer-events off so it cannot swallow a click, and
   invisible to a screen reader because there is nothing there to describe.

   Three insets, not one. The hairline draws the edge, the tight glow gives it a
   source, and the wide falloff is the only layer doing real work — a single
   large shadow reads as a grey vignette, and the site has no grey. --frame is
   the one dial: 0 removes the effect without removing the rule, and it multiplies
   all three alphas at once so they keep their ratio to each other. It sits at
   1.15 — the alphas below are the tuned baseline, and the dial carries the 15%
   the owner asked for on top, which is why the intent stays readable here
   instead of disappearing into three re-typed decimals.

   It does not breathe. The reference this borrows from pulses, and a pulse on a
   marketing page is a thing in the corner of the eye that never resolves into
   information — the whole site is built on not nagging the reader, and a frame
   that moves is the same nag in another costume. It lights the edge once and
   then it is furniture. Nothing here animates, so there is no motion for
   prefers-reduced-motion to reduce.

   Alphas are tuned to the restrained end deliberately: on the #FDFAF4 canvas
   this is a warm rim you notice second, and over the navy panels — where the
   contrast is far higher — the same values are already assertive. The dark
   sections are what set the ceiling, not the light ones. */
:root { --frame: 1.15; }

body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
  box-shadow:
    inset 0 0  0 1px rgba(192, 90, 43, calc(0.30 * var(--frame))),
    inset 0 0 26px    rgba(192, 90, 43, calc(0.22 * var(--frame))),
    inset 0 0 80px    rgba(192, 90, 43, calc(0.14 * var(--frame)));
}

/* A glow around the paper is a screen idea; on paper it is a band of wasted ink. */
@media print { body::after { display: none; } }

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; }

/* G3 — every interactive element, one ring */
:focus-visible { outline: var(--focus-ring); outline-offset: 2px; border-radius: 3px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--canvas);
  padding: 12px 20px; border-radius: 0 0 var(--r-media) 0; text-decoration: none;
}
.skip:focus { left: 0; }

.vh {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* The signup honeypot. Deliberately NOT display:none or hidden -- both are
   the first thing a form-filling bot checks for, and skipping the field is
   the behaviour this is trying to catch. Moved off-screen instead, so it is
   absent for a human and ordinary in the DOM. */
.hp {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}

/* ------------------------------------------------------------------- type */
h1, h2, h3, h4 { font-family: var(--display); font-weight: 700; text-wrap: pretty; }

.t-hero    { font: 700 var(--t-hero)/1.06 var(--display); letter-spacing: -0.01em; }
.t-section { font: 700 var(--t-section)/1.12 var(--display); }
.t-title   { font: 600 var(--t-title)/1.2 var(--display); }
.t-prompt  { font: 400 var(--t-prompt)/1.3 var(--display); }
.t-card    { font: 600 var(--t-card-title)/1.3 var(--display); }
.t-body    { font: 400 var(--t-body)/1.45 var(--text); }
.t-meta    { font: 400 var(--t-meta) var(--text); color: var(--ink-muted); }
.t-label {
  font: 600 var(--t-label) var(--text);
  letter-spacing: 0.6px; text-transform: uppercase; color: var(--ink-muted);
}
.eyebrow {
  font: 600 var(--t-label) var(--text);
  letter-spacing: 2px; text-transform: uppercase; color: var(--ink-faint);
}
.lede { font: 400 18px/1.6 var(--text); color: var(--ink-muted); max-width: 34em; }
.muted { color: var(--ink-muted); }
.accent { color: var(--text-terracotta); }
.peri { color: var(--periwinkle-deep); }
.num { font-variant-numeric: tabular-nums; }

/* G6 — inline links */
a {
  color: var(--link);
  text-decoration: underline;
  text-decoration-color: var(--link-underline);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
a:hover { text-decoration-thickness: 2px; text-decoration-color: var(--link); }
/* :visited deliberately unchanged — the palette has no second link hue, and an
   archive product does not restyle your history. */

/* ----------------------------------------------------------------- layout */
.wrap { max-width: var(--wrap); margin: 0 auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: 720px; }
.wrap--mid { max-width: 900px; }

.section { padding-block: clamp(64px, 9vw, 110px); }
.section--tight { padding-block: clamp(48px, 6vw, 76px); }
.section--rule { border-top: 1px solid var(--border); }
.section--surface { background: var(--surface); border-top: 1px solid var(--border); }
.section--ink { background: var(--ink); color: var(--canvas); }
.section--ink .eyebrow { color: var(--ink-faint); }
.section--ink h2, .section--ink h3 { color: var(--canvas); }

.stack { display: flex; flex-direction: column; }
.stack > * + * { margin-top: var(--gap, 16px); }
.gap-8  { --gap: 8px; }  .gap-12 { --gap: 12px; } .gap-14 { --gap: 14px; }
.gap-20 { --gap: 20px; } .gap-24 { --gap: 24px; } .gap-32 { --gap: 32px; }
.gap-44 { --gap: 44px; }

.cols { display: grid; gap: clamp(32px, 5vw, 64px); }
@media (min-width: 900px) {
  .cols--2 { grid-template-columns: 1fr 1fr; }
  .cols--sidebar { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  .cols--flip { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .cols--top { align-items: start; }
  .cols--mid { align-items: center; }
  /* A sidebar heading that holds the top of the screen while its column is
     read. Only inside the two-column grid: below 900px the sidebar and its
     content are the same column, so a sticky heading would sit on top of the
     text scrolling under it. Never set this inline — the breakpoint is the
     whole rule. */
  .sticky-side { position: sticky; top: 110px; }
}
/* min(…, 100%) so the floor never exceeds the container — a 260px minimum
   inside a narrow column is the classic 320px-viewport sideways scroll. */
.grid-auto { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
.grid-auto--wide { grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }

.center { text-align: center; }
.measure { max-width: 34em; }
.measure--tight { max-width: 26em; }

/* --------------------------------------------------------------- masthead */
.masthead {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--canvas) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: 1px solid var(--border);
}
@supports not (backdrop-filter: blur(1px)) { .masthead { background: var(--canvas); } }

.masthead__in {
  max-width: var(--wrap); margin: 0 auto;
  padding: 12px var(--gutter);
  display: flex; align-items: center; gap: 20px;
}
.wordmark {
  font: 800 22px var(--display);
  color: var(--ink); text-decoration: none; letter-spacing: -0.01em;
  white-space: nowrap;
}
.wordmark:hover { text-decoration: none; }

.navwrap { margin-left: auto; }
.navwrap__toggle {
  display: flex; align-items: center; gap: 9px;
  min-height: 44px; padding: 0 4px;
  list-style: none; cursor: pointer;
  font: 600 15px var(--text); color: var(--ink-muted);
}
.navwrap__toggle::-webkit-details-marker { display: none; }
.navwrap__bars { display: grid; gap: 4px; }
.navwrap__bars i { display: block; width: 20px; height: 2px; background: currentColor; border-radius: 2px; }

.nav { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.nav a {
  font: 400 15px var(--text); color: var(--ink-muted); text-decoration: none;
  padding: 6px 0; transition: color var(--dur-tap) ease-out;
}
.nav a:hover { color: var(--ink); }
/* .nav a's (0,1,1) specificity beats .btn--sm's (0,1,0), so the CTA pill's
   padding has to be restated here or the text sits flush against the pill. */
.nav a.btn { color: var(--surface); padding: 10px 20px; }

/* The current page is stated, not just colored — aria-current would need JS to
   set, so the route on <body> does it in CSS instead. */
body[data-route="/how-it-works"] .nav a[href="/how-it-works"],
body[data-route="/prompts"]      .nav a[href="/prompts"],
body[data-route="/pricing"]      .nav a[href="/pricing"],
body[data-route="/promise"]      .nav a[href="/promise"],
body[data-route^="/blog"]        .nav a[href="/blog"] {
  color: var(--ink); font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--terracotta);
}

@media (max-width: 899px) {
  .navwrap[open] { position: relative; }
  .navwrap[open] .nav {
    position: absolute; right: 0; top: calc(100% + 10px); z-index: 60;
    flex-direction: column; align-items: stretch; gap: 2px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--r-card); box-shadow: var(--shadow-lift);
    padding: 10px; min-width: 220px;
  }
  .navwrap[open] .nav a { padding: 12px 14px; border-radius: var(--r-media); min-height: 44px; display: flex; align-items: center; }
  .navwrap[open] .nav a:hover { background: var(--canvas); }
  .nav__cta { justify-content: center; margin-top: 6px; }
}
@media (min-width: 900px) {
  .navwrap__toggle { display: none; }
  .navwrap .nav { display: flex !important; }
  /* Belt and braces with site.js's open-state sync: a closed <details> hides
     its content via UA content-visibility, which plain display can't beat.
     This pseudo-element override shows the nav even before (or without) JS. */
  .navwrap::details-content { content-visibility: visible; }
}

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 14px 28px;
  border: 1px solid transparent; border-radius: var(--r-pill);
  font: 700 19px var(--display); text-decoration: none; white-space: nowrap;
  cursor: pointer;
  transition: background var(--dur-tap) ease-out, transform var(--dur-tap) ease-out,
              border-color var(--dur-tap) ease-out, box-shadow var(--dur-tap) ease-out;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: scale(0.98); }

/* Primary. The 19px/700 label clears the large-text bar at 4.36:1; hover goes to
   the pressed color, which is the app's TapScaleButtonStyle translated. */
.btn--primary { background: var(--terracotta); color: var(--surface); box-shadow: 0 10px 24px rgba(192, 90, 43, 0.28); }
.btn--primary:hover { background: var(--terracotta-deep); color: var(--surface); }
.btn--primary[disabled], .btn--primary[aria-disabled="true"] {
  background: var(--chip-plain); color: var(--ink-faint);
  box-shadow: none; cursor: not-allowed;
}

.btn--quiet { background: var(--surface); color: var(--ink); border-color: var(--border); box-shadow: var(--shadow-card); }
.btn--quiet:hover { border-color: var(--terracotta); color: var(--ink); }

.btn--peri { background: var(--periwinkle); color: var(--canvas); }
.btn--peri:hover { background: var(--periwinkle-deep); color: var(--canvas); }

.btn--sm { min-height: 44px; padding: 10px 20px; font-size: 15px; }
.btn--lg { padding: 17px 34px; font-size: 20px; }

/* Secondary is a link, never a second filled button. */
.btn--text {
  background: none; border: none; box-shadow: none;
  color: var(--ink-muted); font: 400 16px var(--text);
  text-decoration: underline; text-underline-offset: 3px;
  padding: 10px 4px; min-height: 44px;
}
.btn--text:hover { color: var(--ink); }

.ctarow { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.ctarow--center { align-items: center; }
.ctarow__note { font: 400 14px var(--text); color: var(--ink-muted); }

/* ------------------------------------------------------------------ cards */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card); padding: 26px;
  box-shadow: var(--shadow-card);
}
.card--flat { box-shadow: none; }
.card--pad { padding: clamp(26px, 4vw, 40px); }
.card--canvas { background: var(--canvas); }
.card--wash { background: var(--wash); border-color: var(--sealed-border); }
.card--peri { background: var(--periwinkle-soft); border-color: var(--periwinkle-border); }
.card--terra { background: var(--terracotta-soft); border-color: var(--border); }
.card--sage { background: var(--sage); border-color: var(--sage-border); }

a.card, .card--tap {
  display: block; text-decoration: none; color: inherit;
  transition: box-shadow var(--dur-tap) ease-out, transform var(--dur-tap) ease-out;
}
a.card:hover, .card--tap:hover {
  box-shadow: var(--shadow-hover); transform: translateY(-1px); text-decoration: none;
}
/* Sage stays sage and sealed stays still — hover is for the tappable. */

/* ------------------------------------------------------------------ chips */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--r-pill);
  font: 600 var(--t-label) var(--display);
  letter-spacing: 0.6px; text-transform: uppercase; white-space: nowrap;
  background: var(--chip-plain); color: var(--ink-muted);
}
.chip--terra { background: rgba(192, 90, 43, 0.12); color: var(--terracotta-deep); }
.chip--peri  { background: rgba(85, 102, 214, 0.12); color: var(--periwinkle-deep); }
.chip--sage  { background: var(--sage-soft); color: var(--sage-ink); }
.chip--md { font-size: var(--t-meta); padding: 5px 11px; text-transform: none; letter-spacing: 0; }

.dot { width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--terracotta); flex: none; }

.tick {
  width: 26px; height: 26px; border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  font: 700 13px var(--text); flex: none;
  background: var(--sage-ink); color: var(--sage);
}
.tick--terra { background: var(--terracotta); color: var(--surface); }
.tick--lg { width: 30px; height: 30px; font-size: 14px; }

/* ------------------------------------------------------------------ quote */
.quote {
  font: italic 400 var(--t-quote)/1.4 var(--text); color: var(--ink-muted);
  border-left: 2px solid var(--rule-terracotta); padding-left: 12px;
}
.quote--lg { font-size: 19px; line-height: 1.55; padding-left: 16px; }
.quote--peri { border-color: var(--rule-periwinkle); }
.quote--sage { border-color: var(--rule-sage); }

.rule { height: 1px; background: var(--border); border: 0; }
.rule--accent { height: 2px; background: var(--terracotta); border-radius: var(--r-pill); }

/* ------------------------------------------------------------------- prose */
.prose { max-width: 68ch; }
.prose > * + * { margin-top: 22px; }
.prose p { font: 400 17px/1.75 var(--text); }
.prose h2 { font: 700 clamp(1.4rem, 1.2rem + 0.9vw, 1.75rem)/1.25 var(--display); margin-top: 44px; }
.prose h3 { font: 600 var(--t-card-title) var(--display); margin-top: 32px; }
.prose ul, .prose ol { padding-left: 22px; }
.prose li { font: 400 17px/1.7 var(--text); }
.prose li + li { margin-top: 8px; }
.prose blockquote {
  font: italic 400 19px/1.55 var(--text); color: var(--ink-muted);
  border-left: 2px solid var(--rule-terracotta); padding-left: 16px; margin: 0;
}
.prose code { font: 400 14px var(--mono); background: var(--chip-plain); padding: 2px 6px; border-radius: 6px; }
.prose strong { color: var(--ink); }

/* ------------------------------------------------------------------ tables */
.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tbl {
  width: 100%; min-width: 520px; border-collapse: collapse;
  font: 400 15px/1.5 var(--text);
}
.tbl caption { text-align: left; font: 400 var(--t-meta) var(--text); color: var(--ink-muted); padding-bottom: 12px; }
.tbl th, .tbl td { padding: 14px 16px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--border); }
.tbl thead th { font: 600 var(--t-label) var(--text); letter-spacing: 0.6px; text-transform: uppercase; color: var(--ink-muted); }
.tbl tbody th { font: 600 15px var(--text); color: var(--ink); width: 34%; }
.tbl td.is-ours { background: var(--terracotta-soft); color: var(--ink); }
.tbl thead th.is-ours { background: var(--terracotta-soft); color: var(--terracotta-deep); border-radius: var(--r-media) var(--r-media) 0 0; }
/* An absent feature is an em dash, never a red ✗. There is no red in this file. */
.tbl .none { color: var(--ink-faint); }

/* --------------------------------------------------------------------- faq */
.faq { border-top: 1px solid var(--border); }
.faq__item { border-bottom: 1px solid var(--border); }
.faq__q {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 18px 0; min-height: 44px; cursor: pointer; list-style: none;
  font: 600 var(--t-card-title) var(--display); color: var(--ink);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after {
  content: ''; flex: none; width: 10px; height: 10px;
  border-right: 2px solid var(--ink-faint); border-bottom: 2px solid var(--ink-faint);
  transform: rotate(45deg) translateY(-2px);
  transition: transform var(--dur-enter) var(--ease);
}
.faq__item[open] .faq__q::after { transform: rotate(225deg) translateY(-2px); }
.faq__a { padding: 0 0 20px; font: 400 var(--t-body)/1.65 var(--text); color: var(--ink-muted); max-width: 60ch; }
.faq__a > * + * { margin-top: 12px; }

/* ------------------------------------------------------------------- forms */
.form { display: flex; gap: 10px; flex-wrap: wrap; max-width: 520px; }
.field {
  flex: 1 1 220px; min-width: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-media);
  padding: 15px 18px; font: 400 17px var(--text); color: var(--ink);
  transition: border-color var(--dur-tap) ease-out;
}
.field::placeholder { color: var(--ink-faint); }
/* Invalid is a thicker terracotta hairline and a line of inkMuted text. Not red,
   not an alert, not a shake. The palette has no red and this one isn't special. */
.field[aria-invalid="true"] { border-color: var(--terracotta); border-width: 2px; padding: 14px 17px; }
.form__msg { font: 400 14px/1.5 var(--text); color: var(--ink-muted); margin-top: 10px; }
.form__fine { font: 400 14px/1.55 var(--text); color: var(--ink-muted); max-width: 44ch; }

.consent { display: flex; gap: 10px; align-items: flex-start; font: 400 14px/1.5 var(--text); color: var(--ink-muted); }
.consent input { margin: 2px 0 0; width: 18px; height: 18px; accent-color: var(--terracotta); flex: none; }

.select {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-media);
  padding: 14px 16px; font: 400 16px var(--text); min-height: 48px;
}

/* ------------------------------------------------------------------ footer */
.foot { border-top: 1px solid var(--border); background: var(--surface); }
.foot__in { max-width: var(--wrap); margin: 0 auto; padding: clamp(40px, 6vw, 64px) var(--gutter); }
.foot__tagline { font: 600 var(--t-card-title) var(--display); color: var(--ink); }
.foot__cols {
  display: grid; gap: 28px; margin-top: 32px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.foot__col { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.foot__head { font: 600 var(--t-label) var(--text); letter-spacing: 0.6px; text-transform: uppercase; color: var(--ink-faint); margin: 0; }
.foot__col a { font: 400 15px var(--text); color: var(--ink-muted); text-decoration: none; min-height: 24px; }
.foot__col a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.foot__fine {
  margin-top: 36px; padding-top: 24px; border-top: 1px solid var(--border);
  font: 400 var(--t-meta)/1.6 var(--text); color: var(--ink-muted); max-width: 62ch;
}

/* ------------------------------------------------------------------ motion */
/* Reserve space before animating. seo-plan.md flags CLS on the animated hero
   specifically: every reveal moves opacity and translate only, never layout. */
[data-reveal] { opacity: 0; transform: translateY(16px); }
[data-reveal].is-in {
  opacity: 1; transform: none;
  transition: opacity var(--dur-enter) var(--ease), transform var(--dur-enter) var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}
.no-js [data-reveal], html:not(.js) [data-reveal] { opacity: 1; transform: none; }

[data-rule-grow] { transform: scaleX(0); transform-origin: left; }
[data-rule-grow].is-in { transform: scaleX(1); transition: transform 0.6s var(--ease); }
.no-js [data-rule-grow], html:not(.js) [data-rule-grow] { transform: none; }

/* The motion doctrine floor. Every animation on the site also gates on this. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  [data-rule-grow] { transform: none; }
}

/* ------------------------------------------------------------------ device */
.device {
  background: var(--ink); border-radius: 52px; padding: 11px;
  box-shadow: var(--shadow-deep); width: max-content; max-width: 100%;
}
.device img { border-radius: 42px; width: min(320px, 70vw); }
.device--stack { position: relative; }
/* The stacked frames wrap each img in <picture> for the webp source, so the
   sibling selector has to match the wrappers too — img + img alone leaves the
   frames stacked vertically inside a very tall, very empty phone. */
/* Surface-colored while the lazy image is still fetching, so the frame reads
   as an empty screen for a beat instead of a solid navy slab. Only the in-flow
   frame paints it. The stacked siblings sit on top of it, and the cross-fade
   runs on the img, not the wrapper — an opaque background on the wrappers hides
   whichever screen is currently faded in underneath, leaving an empty phone
   unless the topmost one happens to be the active screen. */
.device--stack picture { display: block; border-radius: 42px; min-height: 200px; }
.device--stack picture:first-child { background: var(--surface); }
.device--light.device--stack picture { border-radius: 28px; }
.device--stack picture + picture,
.device--stack img + img { position: absolute; inset: 11px; }
.device--stack img { transition: opacity 0.35s var(--ease); }
.device--light { background: var(--surface); border: 1px solid var(--sealed-border); border-radius: 36px; padding: 10px; box-shadow: 0 30px 70px rgba(35, 37, 60, 0.14); }
.device--light img { border-radius: 28px; width: min(280px, 68vw); }
.device--light.device--stack picture + picture,
.device--light.device--stack img + img { inset: 10px; }

/* ------------------------------------------------------------------- blobs */
/* Decorative only: aria-hidden at the use site, and they never carry meaning. */
.blob { position: absolute; border-radius: var(--r-pill); filter: blur(70px); pointer-events: none; z-index: 0; }
@keyframes drift1 { from { transform: translate(0, 0); } to { transform: translate(26px, -18px); } }
@keyframes drift2 { from { transform: translate(0, 0); } to { transform: translate(-22px, 20px); } }
@keyframes breathe { 0%, 100% { opacity: 0.5; } 50% { opacity: 0.85; } }
@keyframes softpulse { 0%, 100% { opacity: 0.55; transform: scale(1); } 50% { opacity: 1; transform: scale(1.35); } }
.blob--a { background: var(--terracotta-soft); opacity: 0.8; animation: drift1 26s ease-in-out infinite alternate; }
.blob--b { background: var(--periwinkle-soft); opacity: 0.7; animation: drift2 34s ease-in-out infinite alternate; }
.blob--breathe { animation: breathe 14s ease-in-out infinite; }
.has-blobs { position: relative; overflow: hidden; isolation: isolate; }
.has-blobs > .wrap { position: relative; z-index: 1; }

/* ============================================================ page: home */

.hero { padding-block: clamp(56px, 8vw, 92px); }
.hero__grid { display: grid; gap: clamp(40px, 6vw, 56px); align-items: center; }
/* The H1 is real text and is never faded in by script — it is the LCP element
   and measuring it after a script runs is how a fast page scores slow. */
/* The measure is capped in em, so it holds ~20 characters a line at whatever
   size the curve lands on. Only the stacked band between 700 and 999px is
   actually wide enough to hit it — the phone column caps the line above that
   and the viewport caps it below, so this is a no-op everywhere else. Without
   it that band alone set 26 characters, a paragraph measure on a headline. It
   also pins the break when Nunito hasn't loaded: on fallback metrics the
   uncapped headline collapses to three lines of thirty. */
.hero h1 {
  font: 800 clamp(2.125rem, 1rem + 4.6vw, 4.75rem)/1.06 var(--display);
  letter-spacing: -0.015em; text-wrap: balance; max-width: 11em;
}
/* Two columns only once the words have room for a display size beside the
   phone. The media column is sized to the phone itself — as a fraction it
   reserved ~120px of nothing next to a 342px frame and took it from the
   headline. And the full-width type curve tops out at 76px, which set nine
   lines in that leftover gutter and stood a head taller than the image; beside
   the phone the H1 is sized to its column instead, five even lines inside the
   frame's height. Below this the hero stacks, where the wide curve is right. */
/* The curve is in rem, so it scales with the reader's browser font size — and
   at Chrome's "Large" the same headline set nine lines and stood a head taller
   than the phone again, the exact shape this breakpoint exists to prevent. So
   the words column is a query container and the size is capped against its own
   width. The curve peaks at 10.28% of that column (52px in the 506px column at
   1000px wide), so 10.4cqi clears every default-size width by a hair and never
   bites at 16px root — it only takes over once the type would outgrow the
   column it lives in. Declared twice on purpose: where cq units are missing
   the second rule drops whole and the plain curve above still lands. */
@media (min-width: 1000px) {
  .hero__grid { grid-template-columns: minmax(0, 1fr) auto; }
  .hero__grid > .stack { container-type: inline-size; }
  .hero h1 { font-size: clamp(3.25rem, 0.75rem + 4vw, 3.75rem); }
  .hero h1 { font-size: min(clamp(3.25rem, 0.75rem + 4vw, 3.75rem), 10.4cqi); }
}
.hero__badge {
  display: inline-flex; align-items: center; gap: 9px; align-self: flex-start;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-pill); padding: 7px 14px;
}

/* Marquee — a sample of the library, paused on hover and on reduced motion. */
.marquee { overflow: hidden; padding-block: 28px; display: flex; flex-direction: column; gap: 14px; }
.marquee__row { display: flex; width: max-content; gap: 14px; }
@keyframes marqL { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes marqR { from { transform: translateX(-50%); } to { transform: translateX(0); } }
.marquee__row--l { animation: marqL 80s linear infinite; }
.marquee__row--r { animation: marqR 96s linear infinite; }
.marquee:hover .marquee__row, .marquee:focus-within .marquee__row { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .marquee__row { animation: none; width: 100%; overflow-x: auto; scrollbar-width: thin; }
}
.pcard {
  width: 290px; flex: none;
  border: 1px solid var(--border); border-radius: var(--r-row);
  padding: 14px 16px; display: flex; flex-direction: column; gap: 9px;
  background: var(--surface);
}
.pcard--terra { background: var(--terracotta-soft); }
.pcard--peri { background: var(--periwinkle-soft); border-color: var(--periwinkle-border); }
.pcard__body { font: 400 15px/1.35 var(--display); color: var(--ink); }

/* Mosaic — the four-thousand-photos grid that fades to one */
.mosaic { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.mosaic__tile {
  aspect-ratio: 1; border-radius: 12px; display: flex; align-items: flex-end; padding: 7px;
  opacity: 0; transition: opacity 0.45s var(--ease);
  font: 400 9px var(--mono); color: rgba(253, 250, 244, 0.6);
  /* grid items default to min-width auto, so the unwrappable mono label sets
     the column floor and the whole page scrolls sideways at 320px */
  min-width: 0; overflow: hidden;
}
.mosaic.is-in .mosaic__tile { opacity: 1; }
.mosaic.is-dim .mosaic__tile { opacity: 0.16; }
.mosaic.is-dim .mosaic__tile.is-kept { opacity: 1; box-shadow: 0 0 0 2px #E28B5B; }
.mosaic__tile:nth-child(3n+1) { background: linear-gradient(135deg, rgba(226,139,91,0.30), rgba(253,250,244,0.05)); }
.mosaic__tile:nth-child(3n+2) { background: linear-gradient(135deg, rgba(154,166,240,0.26), rgba(253,250,244,0.05)); }
.mosaic__tile:nth-child(3n+3) { background: rgba(253, 250, 244, 0.08); }
.mosaic__note { opacity: 0; transition: opacity 0.5s var(--ease) 0.2s; }
.mosaic__note.is-in { opacity: 1; }

/* Deck — the interactive centrepiece */
.deck { position: relative; width: min(100%, 520px); height: 300px; touch-action: pan-y; margin-inline: auto; }
.deck__card { position: absolute; inset: 0; will-change: transform; }
.deck__card article {
  height: 100%; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card); padding: 22px;
  display: flex; flex-direction: column; gap: 16px;
  box-shadow: var(--shadow-lift); user-select: none;
}
.deck__body { margin-top: auto; font: 700 clamp(1.25rem, 0.95rem + 1.2vw, 1.75rem)/1.28 var(--display); }
.filters { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.filter {
  min-height: 44px; padding: 9px 16px; cursor: pointer;
  background: var(--surface); color: var(--ink-muted);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  font: 600 15px var(--text);
  transition: background var(--dur-tap) ease-out, color var(--dur-tap) ease-out,
              border-color var(--dur-tap) ease-out, transform var(--dur-tap) ease-out;
}
.filter:hover { border-color: var(--terracotta); }
.filter:active { transform: scale(0.98); }
.filter[aria-pressed="true"] { background: var(--terracotta); color: var(--canvas); border-color: var(--terracotta); }

/* Three shapes. The one justified !important in this file: a hidden panel must
   stay hidden against .stack's display:flex AND the did-panel's inline
   display:flex — without it, switching pills leaves the old panel showing. */
.shapes__out { min-height: 232px; }
[data-shape-panel][hidden] { display: none !important; }
.ring { width: 30px; height: 30px; flex: none; }

/* Archive — copy scrolls, the phone stays put */
.arch__step { min-height: 58vh; display: flex; flex-direction: column; justify-content: center; gap: 14px; }
.arch__sticky { position: sticky; top: 96px; display: flex; justify-content: center; padding-block: 20px; }
@media (max-width: 899px) {
  .arch__step { min-height: 0; }
  .arch__sticky { position: static; }
  /* Only one phone is meaningful without the scroll pairing it to the copy. */
  .arch__sticky .device--stack picture + picture,
  .arch__sticky .device--stack img + img { display: none; }
}

/* Waitlist inbox preview */
.inbox__item { border-left: 3px solid var(--border); }
.inbox__item--peri { border-left-color: var(--periwinkle); }
.inbox__item--terra { border-left-color: var(--terracotta); }

/* ========================================================= page: prompts */

.plib { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.prompt {
  scroll-margin-top: 90px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-row); padding: 16px 18px;
  display: flex; flex-direction: column; gap: 10px;
}
.prompt--terra { background: var(--terracotta-soft); }
.prompt--peri { background: var(--periwinkle-soft); border-color: var(--periwinkle-border); }
.prompt--sage { background: var(--sage); border-color: var(--sage-border); }
.prompt__body { font: 400 17px/1.35 var(--display); color: var(--ink); }
.prompt__meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: auto; }
.prompt[hidden] { display: none; }
.prompt:target { box-shadow: 0 0 0 2px var(--periwinkle); }

.plib__bar {
  position: sticky; top: 61px; z-index: 20;
  background: color-mix(in srgb, var(--canvas) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  padding-block: 14px; margin-bottom: 28px;
}
@supports not (backdrop-filter: blur(1px)) { .plib__bar { background: var(--canvas); } }

/* Search sits on the same line as the count, which is empty until something is
   actually filtered — the row is 44px tall either way, so the sticky bar never
   changes height under the reader and the page never jumps. */
.plib__find { display: flex; gap: 14px; align-items: center; justify-content: center; flex-wrap: wrap; }
.plib__count { font: 400 var(--t-meta) var(--text); color: var(--ink-muted); }
/* A search box with nothing behind it is a worse promise than no search box,
   so the field only exists once site.js has claimed the document. */
.plib__search { display: none; }
.js .plib__search { display: block; flex: 1 1 240px; max-width: 360px; }
.plib__search input {
  width: 100%; min-height: 44px; padding: 9px 16px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  font: 400 15px var(--text);
  transition: border-color var(--dur-tap) ease-out;
}
.plib__search input::placeholder { color: var(--ink-faint); }
.plib__search input:hover { border-color: var(--terracotta); }
.plib__search input:focus { border-color: var(--periwinkle); }
.plib__empty { margin-top: 28px; }

/* Below 900px the pills wrapped, and a wrapped sticky bar is a bar that owns
   the phone: 393px of a 700px viewport at 320, half the screen, permanently.
   One line each, scrolled sideways, holds it at 185px at every width. The rows
   bleed into the gutter and pad themselves back, so the pill at the edge is cut
   rather than tidily stopped — which is the thing that says keep swiping. */
@media (max-width: 899px) {
  .plib__bar .filters {
    flex-wrap: nowrap; justify-content: flex-start;
    overflow-x: auto; scrollbar-width: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    scroll-padding-inline: var(--gutter);
  }
  .plib__bar .filters::-webkit-scrollbar { display: none; }
  .plib__bar .filter { flex: none; }
}

/* ============================================================ page: blog */

.post__hero { max-width: 680px; margin-inline: auto; }
.post__dek { font: 400 19px/1.55 var(--text); color: var(--ink-muted); }
.post__body { max-width: 680px; margin-inline: auto; }
.postcard { display: flex; flex-direction: column; gap: 12px; height: 100%; }
.postcard__meta { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.postcard__title { font: 700 21px/1.25 var(--display); }
.postcard__more { margin-top: auto; padding-top: 4px; font: 600 14px var(--text); color: var(--text-terracotta); }
.postcard--featured .postcard__title { font: 700 clamp(1.5rem, 1.2rem + 1.3vw, 2.25rem)/1.15 var(--display); }
.postcard--featured .postcard__more { font-size: 15px; }
.postcard--featured .postcard__dek { font: 400 17px/1.6 var(--text); color: var(--ink-muted); }

/* The featured card keeps the prototype's stronger treatment: a 24px radius
   and a deeper hover lift than the four secondary cards. */
.card--featured { border-radius: 24px; }
a.card--featured:hover { box-shadow: var(--shadow-lift); transform: translateY(-2px); }

/* The post headline sits between t-title and t-hero — the .dc.html curve. */
.post__title { font: 700 clamp(1.9rem, 1.3rem + 2.4vw, 3rem)/1.12 var(--display); }

/* A 2px rule in the post's tone separates the hero from the body. */
.post__rule { height: 2px; border: 0; border-radius: var(--r-pill); background: var(--rule-terracotta); }
body.post--peri .post__rule { background: var(--rule-periwinkle); }
body.post--sage .post__rule { background: var(--rule-sage); }
body.post--peri .prose blockquote { border-color: var(--rule-periwinkle); }
body.post--sage .prose blockquote { border-color: var(--rule-sage); }

/* A pull-out inside a post: a real prompt, in the app's own card shape. */
.promptbox {
  border-radius: var(--r-row); padding: 18px 20px;
  display: flex; flex-direction: column; gap: 9px;
  background: var(--terracotta-soft); border: 1px solid var(--border);
}
.promptbox--peri { background: var(--periwinkle-soft); border-color: var(--periwinkle-border); }
.promptbox--sage { background: var(--sage); border-color: var(--sage-border); }
.promptbox__body { font: 400 18px/1.35 var(--display); color: var(--ink); }

/* ========================================================= page: compare */

/* Every competitor claim carries the date it was checked, in the source and on
   the page. Prices in this category move — Tinybeans moved theirs ~87% in a
   year — and a stale number on a page that sells honesty is self-inflicted. */
.verified {
  display: inline-flex; align-items: center; gap: 8px;
  font: 400 var(--t-meta) var(--text); color: var(--ink-muted);
  background: var(--chip-plain); border-radius: var(--r-pill); padding: 6px 12px;
}

.callout {
  border-left: 2px solid var(--rule-terracotta); padding: 4px 0 4px 18px;
}
.callout--peri { border-color: var(--rule-periwinkle); }
.callout--sage { border-color: var(--rule-sage); }

/* =================================================== page: how-it-works */

/* The page is told as the product's own artifact: a timeline. One spine runs
   down the scenes, a terracotta fill tracks the reader's place in it (CSS
   scroll timeline — browsers without it keep the quiet border-colored line,
   reduced motion gets the line already full), and each scene opens with a
   sticky time marker whose dot rides the spine. Time accelerates down the
   page: tomorrow morning, then weeks, then years. */
.hiw {
  --indent: clamp(30px, 5vw, 52px);
  --spine-x: 6px;
  position: relative;
  padding-left: var(--indent);
}
.hiw::before, .hiw__fill {
  position: absolute; top: 8px; bottom: 0; left: var(--spine-x); width: 2px;
  border-radius: var(--r-pill);
  -webkit-mask-image: linear-gradient(#000 90%, transparent);
  mask-image: linear-gradient(#000 90%, transparent);
}
.hiw::before { content: ''; background: var(--border); }
.hiw__fill { background: var(--terracotta); transform: scaleY(0); transform-origin: top; }
@supports (animation-timeline: view()) {
  .hiw__fill {
    animation: hiw-fill linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
}
@keyframes hiw-fill { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) {
  .hiw__fill { animation: none !important; transform: none; }
}

.hiw-scene { position: relative; padding-block: clamp(30px, 5vw, 58px); }
.hiw-scene--arch { padding-block: clamp(16px, 3vw, 30px); }
/* Grid items keep a min-content floor, and the nested card grid's floor is
   wider than a 320px viewport once the spine's indent is spent. Zero it. */
.hiw-scene .cols > * { min-width: 0; }
/* .stack stretches children; a pill button stretched to a column is a bar. */
.hiw-scene .btn { align-self: flex-start; }

/* The time marker. Sticky, so the current moment holds the top of the screen
   while its scene is read — the page always says what time it is. */
.hiw-when {
  position: sticky; top: 74px; z-index: 6;
  display: inline-flex; align-items: center;
  width: fit-content;
  margin-bottom: 16px;
  padding: 7px 13px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-pill); box-shadow: var(--shadow-hover);
  font: 600 var(--t-label)/1 var(--text);
  letter-spacing: 1.1px; text-transform: uppercase; color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}
.arch__step .hiw-when { margin-bottom: 0; }
.hiw-when__dot {
  position: absolute;
  left: calc(var(--spine-x) - 6.5px - var(--indent));
  top: 50%; transform: translateY(-50%);
  width: 9px; height: 9px; border-radius: var(--r-pill);
  background: var(--terracotta);
  border: 3px solid var(--surface);
  box-shadow: 0 0 0 1px var(--border);
}
/* On the ink finale there is no spine to reach, so the dot sits inside the
   pill and the pill quiets down to a hairline. */
.hiw-when--ink {
  position: static;
  background: transparent; border-color: rgba(253, 250, 244, 0.22);
  box-shadow: none; color: var(--ink-faint);
  gap: 8px;
}
.hiw-when--ink .hiw-when__dot {
  position: static; transform: none;
  border: none; box-shadow: none;
}

/* The morning pair arrives the way the deck deals — slightly fanned. The tilt
   lives on a wrapper because [data-reveal].is-in resolves to transform: none. */
.hiw-deal { max-width: 720px; }
@media (min-width: 600px) {
  .hiw-deal__l { transform: rotate(-1.4deg); }
  .hiw-deal__r { transform: rotate(1.2deg) translateY(6px); }
}

.hiw-verbs { max-width: 580px; }

/* A month of the rhythm: a dot most days, a bigger one on a weekend, one
   measurement at the end. Decorative — the caption under it carries the fact. */
.hiw-month {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px;
  max-width: 400px;
}
.hiw-month i {
  aspect-ratio: 1; border-radius: 9px; background: var(--chip-plain);
  display: flex; align-items: center; justify-content: center;
}
.hiw-month i::after {
  content: ''; width: 6px; height: 6px; border-radius: var(--r-pill);
  background: var(--terracotta); opacity: 0.55;
}
.hiw-month .is-off { background: transparent; box-shadow: inset 0 0 0 1px var(--border); }
.hiw-month .is-off::after { content: none; }
.hiw-month .is-wk { background: var(--terracotta-soft); }
.hiw-month .is-wk::after { width: 9px; height: 9px; opacity: 0.9; }
.hiw-month .is-msr { background: var(--terracotta); }
.hiw-month .is-msr::after { width: 9px; height: 9px; background: var(--canvas); opacity: 1; }

/* The export, drawn as what it is: files. Decoration only — the copy beside
   it makes every claim. #E28B5B is the mosaic's terracotta-on-ink step. */
.hiw-tree {
  margin: 0; overflow-x: auto;
  font: 400 13px/1.8 var(--mono); color: var(--ink-faint);
  background: rgba(253, 250, 244, 0.05);
  border: 1px solid rgba(253, 250, 244, 0.14);
  border-radius: var(--r-card); padding: 22px 26px;
}
.hiw-tree b { font-weight: 600; color: var(--canvas); }
.hiw-tree i { font-style: normal; color: #E28B5B; }
/* The widest line must FIT at phone widths — a scrolled tree truncates the
   punch line at "double-click", which is the whole joke. */
@media (max-width: 380px) {
  .hiw-tree { font-size: 11px; padding: 16px 14px; }
}

/* Below 900px the copy/phone scroll pairing is off and one frame survives.
   The global arch rule keeps the first frame; on this page the surviving
   frame sits directly under the search copy, so keep the search screen —
   the claim nothing else has — instead. The !important beats the inline
   opacity that site.js's resize-down sync writes. */
@media (max-width: 899px) {
  .hiw .arch__sticky .device--stack picture:first-child { display: none; }
  .hiw .arch__sticky .device--stack picture + picture {
    display: block; position: static; background: var(--surface);
  }
  .hiw .arch__sticky .device--stack img { opacity: 1 !important; }
}

/* --------------------------------------------------------------- utility */
.pill-list { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.check-list { list-style: none; display: flex; flex-direction: column; gap: 10px; }
.check-list li { display: flex; gap: 10px; align-items: flex-start; font: 400 15px/1.5 var(--text); color: var(--ink-muted); }
.check-list .tick { width: 20px; height: 20px; font-size: 11px; margin-top: 2px; }

.numbered { list-style: none; counter-reset: step; display: flex; flex-direction: column; gap: 28px; }
.numbered > li { counter-increment: step; display: grid; grid-template-columns: 40px 1fr; gap: 18px; align-items: start; }
.numbered > li::before {
  content: counter(step);
  width: 40px; height: 40px; border-radius: var(--r-glyph);
  background: var(--terracotta-soft); color: var(--terracotta-deep);
  font: 700 17px var(--display);
  display: flex; align-items: center; justify-content: center;
}

/* ── the brand lockup ─────────────────────────────────────────────────────
   Drawn geometry, inlined. The card gaps are cut out of the card behind rather than
   painted in the page colour, which is what lets one mark sit on the masthead's
   translucent cream and the footer's --surface without either being told which.

   That matters most in the masthead: it is color-mix(canvas 88%, transparent) over a
   backdrop-filter, so page content scrolls underneath and tints it continuously. No
   solid stroke colour stays right at every scroll position; a cut gap does.

   The mask's shapes carry .brand__card too, so the gap travels with the cards when the
   fan opens. Leave that class off them and the mark tears the moment it moves. */
.brand { display: inline-block; line-height: 0; color: var(--ink); border-radius: 6px; }
.brand svg { display: block; height: 34px; width: auto; overflow: visible; }

/* One rule, two jobs. The cards carry this class and so do the shapes inside each
   knockout mask, so the gap between two cards travels with the cards rather than staying
   where they used to be. Without that the mark tears the moment it opens. */
.brand__card {
  transform: rotate(calc(var(--a) * 1deg)) translateY(-120px);
  transition: transform 260ms cubic-bezier(.4, 0, .2, 1);
}
/* Opening staggers from the middle outward; closing does not, so the hand snaps shut
   rather than unravelling. The delay lives in the hover rule for exactly that reason. */
.brand:hover .brand__card,
.brand:focus-visible .brand__card {
  transform: rotate(calc(var(--a) * 1.45deg)) translateY(-127px);
  transition: transform 460ms cubic-bezier(.22, .9, .28, 1);
  transition-delay: calc(var(--i) * 45ms);
}
.brand:focus-visible { outline: 2px solid #C05A2B; outline-offset: 6px; }

@media (prefers-reduced-motion: reduce) {
  .brand__card,
  .brand:hover .brand__card,
  .brand:focus-visible .brand__card {
    transform: rotate(calc(var(--a) * 1deg)) translateY(-120px);
    transition: none;
  }
}

/* Sized at the use site — the viewBox carries the proportion, so height is the only
   number either surface sets. 30px puts the word's ascender at roughly the 22px the
   live-text wordmark occupied, so the masthead's rhythm is unchanged. */
.wordmark svg { height: 30px; }
.foot__mark { margin-bottom: 18px; }
.foot__mark svg { height: 32px; }
@media (max-width: 599px) { .wordmark svg { height: 26px; } }
