/* Public marketing surface (landing, pricing, and the two auth doors).
   Same identity as the app: the basalt world, Bricolage display, a mono data
   voice. Tokens are duplicated from app.css (canonical) because these pages
   ship without the app shell.

   Register: one committed dark surface end to end. Every public page wears
   .drench (or, for the auth doors, body.auth-body), which REDEFINES the
   tokens rather than restyling components, so the whole system flips at once
   instead of accumulating dark-mode one-offs. */

@font-face {
  font-family: 'Bricolage';
  src: url('/fonts/bricolage-latin.woff2') format('woff2');
  font-weight: 600 700;
  font-display: swap;
}

:root {
  color-scheme: light dark;
  --bg: oklch(0.972 0.013 82);
  --surface: oklch(0.998 0.004 85);
  --panel: oklch(0.950 0.018 80);
  --line: oklch(0.888 0.022 74);
  --line-strong: oklch(0.800 0.028 70);
  /* ---------------------------------------------------------------------
     THE PALETTE IS THE BIRD'S GROUND, NOT ITS BACK.
     A puffin stands on burnt basalt over cold water, and the thing you see
     first is the marigold ring the mark is drawn inside. So the page is that
     rock (a warm near-black with real chroma, never a navy), the ink is the
     bird's cream face, and there are exactly two accents doing two jobs:

       MARIGOLD  #f3b93f  yours. Your name, your row, every primary button.
       SEA-GLASS #69d3d4  everything that already exists and can be counted:
                          links, citations, the quiet cool the page is read
                          against. The one cold thing in a warm world.

     A rival is neither, so rivals take a muted slate blue (--viz-value) that
     is deliberately the dullest saturated value here.

     Warm and cold are load bearing: the ground, the ink and "yours" are warm
     (h 36-88), the accent and the rivals are cold (h 196 and h 250). Nothing
     sits in between, so nothing on this page is ambiguous about which side it
     is on. Measured, not picked; every number below was walked against
     dev/bands.js on the painted page.
     --------------------------------------------------------------------- */
  --world: #290e05;                     /* burnt basalt */
  --world-deep: #00090a;                /* the pool it holds: the one COLD dark. At
                                           this lightness sRGB has almost no chroma
                                           left in a cool hue (max 0.026 at h205 vs
                                           0.055 at h43), so a cold ground can only
                                           ever be a cold near-black. That is the
                                           whole reason the page itself is warm. */
  --world-ink: #fbf3e0;                 /* the face, 15.7:1 on --world */
  --world-ink-2: #cbbba8;               /* 9.2:1 on --world */
  --world-line: #5b3e33;                /* the rock, split: 1.92:1 on --world */
  --world-accent: #6bd7d3;              /* sea glass, 10.1:1 on --world */
  --ink: oklch(0.240 0.030 48);
  --ink-2: oklch(0.455 0.030 52);
  --ink-3: oklch(0.512 0.028 55);
  --brand: oklch(0.505 0.090 205);
  --brand-ink: oklch(0.440 0.085 207);
  --brand-soft: oklch(0.935 0.032 200);
  --on-brand: oklch(0.99 0.008 85);
  --gold: oklch(0.520 0.115 68);         /* marigold, roasted for paper (4.9:1 on --panel) */
  --viz-value: oklch(0.520 0.090 250);
  --viz-promo: oklch(0.545 0.145 45);    /* the bill, deepened for paper */
  --ok: oklch(0.480 0.115 152);
  --bad: oklch(0.505 0.185 19);
  --shadow-2: 0 1px 2px oklch(0.24 0.03 48 / 0.06), 0 6px 20px oklch(0.24 0.03 48 / 0.09);
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --display: 'Bricolage', var(--font);
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* Stacking order, named rather than guessed. Every z-index on these pages
     reads from this scale, so a new layer is placed by meaning instead of by
     picking a bigger number than whatever was there before. */
  --z-flat: 0;      /* in flow */
  --z-raise: 1;     /* lifted inside its own component (a rail segment, a mark) */
  --z-sticky: 20;   /* something that follows the scroll (the FAQ index) */
  --z-skip: 100;    /* the bypass link, which must clear everything */
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Elevation runs UP from the page, never down: --panel is the well a
       header strip or a track sits in, --surface is the card that lifts off
       the ground. Reversing these is what made every card read as a hole. */
    --bg: oklch(0.205 0.048 42);
    --surface: oklch(0.315 0.040 42);
    --panel: oklch(0.125 0.022 204);
    --line: oklch(0.400 0.046 40);
    --line-strong: oklch(0.520 0.050 40);
    --world: #290e05;
    --world-deep: #00090a;
    --world-line: #5b3e33;
    --world-accent: #6bd7d3;
    --ink: oklch(0.965 0.026 88);
    --ink-2: oklch(0.800 0.032 72);
    --ink-3: oklch(0.712 0.032 64);
    --brand: oklch(0.815 0.100 192);
    --brand-ink: oklch(0.815 0.100 192);
    --brand-soft: oklch(0.300 0.055 200);
    --on-brand: oklch(0.170 0.030 55);
    --gold: #f3b93f;
    --viz-value: oklch(0.705 0.068 250);
    --viz-promo: #f4772b;
    --ok: oklch(0.78 0.135 152);
    --bad: oklch(0.715 0.190 19);
    --shadow-2: 0 1px 2px oklch(0 0 0 / 0.45), 0 10px 30px oklch(0 0 0 / 0.4);
  }
}

* { box-sizing: border-box; }
/* Author rules (a .board-head that sets display:flex, say) outrank the UA's
   [hidden] rule and silently resurrect hidden sections. Settle it once. */
[hidden] { display: none !important; }

/* THE ROOT STAYS 16px. Every rem in both stylesheets resolves against this,
   so it is not a type choice, it is the unit. A pass that snapped font sizes
   onto a scale moved it to 15 and silently rescaled the entire site by 6.25%:
   an 8px gap became 7.5, a 16px pad became 15. Body type is set on body. */
html { font-size: 16px; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  font-variant-numeric: tabular-nums;
}
a { color: var(--brand-ink); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3 { font-family: var(--display); text-wrap: balance; margin: 0; }
img { max-width: 100%; }

.wrap { max-width: 1120px; margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2rem); }

/* Visually hidden but reachable by assistive tech. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Bypass block. Off-screen until focused, then a real, visible control. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: var(--z-skip);
  background: var(--world-deep); color: var(--world-ink);
  border: 1px solid var(--world-accent); border-radius: 8px;
  padding: 0.5rem 1rem; font-weight: 600;
}
.skip:focus { left: 1rem; top: 0.6rem; text-decoration: none; }
:where(main):focus { outline: none; }
:where(section, div)[tabindex="-1"]:focus { outline: none; }

/* The icon sprite is a document-level definition, never painted. */
svg.sprite { display: none; }
.ic {
  width: 1em; height: 1em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
  vertical-align: -0.125em;
}

/* Focus. The surface colour is overridden throughout these pages, so the UA
   ring (which is picked for the light scheme) cannot be relied on. */
:is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}
.drench :is(a, button, input, select, textarea, summary):focus-visible,
.auth-body :is(a, button, input, select, textarea, summary):focus-visible,
/* The skip link sits OUTSIDE .drench, so it inherited the light-surface ring
   (measured 2.65:1 against the nav). It also ties on specificity with the rule
   above, because :is(..., [tabindex]) counts as a class, so it has to come
   after it rather than before. The public shell is dark on every page. */
.skip:focus-visible {
  outline-color: var(--world-accent);
}

/* ---------- the cobalt world: nav ---------- */

/* The world band is dark in BOTH themes, so it carries its own marigold: the
   paper marigold is a dark roast and turned the primary CTA muddy on basalt.
   Everything inside the band inherits this brighter value. */
.world { background: var(--world); color: var(--world-ink); --gold: #f3b93f; }
.world a { color: var(--world-ink); }

.site-nav {
  display: flex; align-items: center; gap: 1.5rem;
  padding-block: 1rem; /* block only: the shorthand ate .wrap's gutter */
}
.wordmark {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--display); font-weight: 700; font-size: 1.25rem;
  letter-spacing: -0.01em;
}
/* The mark is a drawing now, not a dot. It keeps its own colours (a puffin is
   not a monochrome glyph), so it is never repainted by a surface's ink. */
.wordmark .mark-svg { flex: none; display: block; border-radius: 4px; }
/* nowrap: with a fourth link in the bar the primary button broke across two
   lines at 390px. A two-line button is not a button. */
.site-nav .links { margin-left: auto; display: flex; align-items: center; gap: 1.5rem; font-size: 0.9375rem; }
.site-nav .links a { white-space: nowrap; }
.site-nav .links a:hover { color: var(--world-accent); text-decoration: none; }
/* ONE PRIMARY BUTTON COLOUR, EVERYWHERE. Get started in the nav, Get started
   in the hero, Start with Solo on /pricing and Create account on /signup are
   the same button at four points of one funnel, and they used to be three
   different colours (cream, marigold, sky blue). They are all marigold now:
   the page has exactly one thing that looks like the next step. */
.site-nav .cta {
  background: var(--gold); color: oklch(0.170 0.030 55); border-radius: 8px;
  padding: 0.5rem 1rem; font-weight: 600;
}
.site-nav .cta:hover { filter: brightness(1.08); text-decoration: none; }

/* ---------- hero ---------- */

/* padding-BLOCK, not the shorthand. `padding: <y> 0 <y>` zeroed the inline
   padding that .wrap sets, so every wrapped section ran edge to edge at
   390px (measured: .hero.wrap paddingLeft 0px). */
.hero { padding-block: clamp(2.25rem, 5.5vw, 4rem) clamp(1.25rem, 3vw, 2.25rem); }
/* The picture gets more width than the words (4fr of type, 5fr of card), and
   the four children are DIRECT children of the grid so the phone can reorder
   them: heading, card, sub-line, buttons. The two 1fr rows top and bottom are
   what centre the text block against a taller card without wrapping it in a
   div the phone would then have to break apart. */
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 5fr);
  grid-template-rows: 1fr auto auto auto 1fr;
  gap: 0 clamp(2rem, 5vw, 4rem);
  align-items: start;
}
.hero-grid > h1 { grid-area: 2 / 1; }
.hero-grid > .sub { grid-area: 3 / 1; }
.hero-grid > .actions { grid-area: 4 / 1; }
.hero-grid > .scene { grid-area: 1 / 2 / -1 / 3; align-self: center; }
.hero h1 {
  font-size: clamp(2rem, 4.9vw, 3.5rem);
  line-height: 1.1; font-weight: 700; letter-spacing: -0.02em;
}
.hero h1 em { font-style: normal; color: var(--world-accent); }
.hero .sub {
  margin: 1.25rem 0 0; max-width: 34rem; font-size: clamp(1rem, 1.6vw, 1.1rem);
  color: var(--world-ink-2); text-wrap: pretty;
}
.hero .actions { margin-top: 1.5rem; display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; }
.btn-solid {
  display: inline-flex; align-items: center; gap: 0.5rem;
  background: var(--gold); color: oklch(0.13 0.02 80);
  font-weight: 700; border-radius: 8px; padding: 0.75rem 1rem; font-size: 0.9375rem;
}
.btn-solid:hover { filter: brightness(1.08); text-decoration: none; }
.btn-ghost {
  display: inline-flex; align-items: center; gap: 0.5rem;
  border: 1px solid var(--world-line); border-radius: 8px;
  padding: 0.75rem 1rem; color: var(--world-ink); font-weight: 600;
}
.btn-ghost:hover { border-color: var(--world-accent); color: var(--world-accent); text-decoration: none; }

/* ---------- DRENCHED SURFACE ----------
   Rather than restyling every component for a dark parent, the tokens are
   REDEFINED here: .scene, .plan, .qcard and the rest already read from them,
   so they flip as a system. */

.drench,
body.auth-body {
  /* ELEVATION RUNS UP. --panel is the WELL (a header strip, a bar track, an
     input): darker than the page. --surface is the CARD: lighter than the
     page, so it lifts instead of sinking. The old order had both below the
     ground at 1.11:1 and 1.16:1, which is why structure fell entirely to
     hairlines. MEASURED on the painted page: card on page 1.39:1 (was 1.11
     and upside down), well inside a card 1.54:1 (was 1.16), rules 1.92:1 and
     3.21:1 on the page (were 1.61 and 1.67). --line-strong is STRONGER than
     --line, which it previously was not.

     The well is also the one COLD dark in the system, and it separates by
     temperature as much as by luminance: below OKLCH L 0.2 sRGB has almost no
     chroma left in a cool hue (0.022 at h204 against 0.063 at h42), so a cold
     ground can only ever be a cold near-black. That asymmetry is exactly why
     the page itself is warm. */
  --bg: var(--world);
  --surface: oklch(0.315 0.040 42);
  --panel: var(--world-deep);
  --line: var(--world-line);
  --line-strong: oklch(0.520 0.050 40);
  --ink: var(--world-ink);
  --ink-2: var(--world-ink-2);
  --ink-3: oklch(0.712 0.032 64); /* 7.03:1 on the page, 5.07:1 on a card */
  --brand: var(--world-accent);
  --brand-ink: var(--world-accent);
  --brand-soft: oklch(0.300 0.055 200);
  --on-brand: oklch(0.170 0.030 55);
  --gold: #f3b93f;
  --viz-value: oklch(0.705 0.068 250);  /* a rival: the dullest saturated value here */
  --viz-promo: #f4772b;                 /* the bill: a post that sells */
  --ok: oklch(0.78 0.135 152);
  --bad: oklch(0.715 0.190 19);
  --shadow-2: 0 1px 2px oklch(0 0 0 / 0.45), 0 10px 30px oklch(0 0 0 / 0.4);
  background: var(--world);
  color: var(--world-ink);
}
/* Inline links only. A blanket `.drench a` beats .btn-solid on specificity and
   silently repainted every button's label, including the primary CTA. */
.drench p a,
.drench .lede a,
.drench .plans-more a,
.drench dd a { color: var(--world-accent); }
/* Buttons re-assert their own label colours inside the drench. */
.drench .btn-solid { color: oklch(0.16 0.03 80); }
.drench .btn-ghost,
.drench .site-nav .links a,
.drench .wordmark { color: var(--world-ink); }
/* a.cta must outrank `.links a` above, or the button label takes the light ink
   colour on its own light background (measured 1:1, invisible). */
.drench .site-nav .links a.cta { color: var(--world); }
.drench .plan .go { color: var(--on-brand); }

/* ---------- section heads ----------
   No eyebrow above each section: a repeated tracked-caps kicker is the
   saturated pattern this brand must avoid. The heading carries it, with a
   quiet trailing note where a qualifier genuinely helps. */

.sechead { display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
.sechead h2 { font-size: clamp(1.35rem, 2.6vw, 1.9rem); letter-spacing: -0.02em; }
.sechead-note { font-size: 0.8125rem; color: var(--ink-3); }
.sechead-link { margin-left: auto; font-size: 0.8125rem; color: var(--world-accent); }

.section { padding-block: clamp(2.25rem, 5vw, 3.75rem); }
.section.tight { padding-block-start: 0; }
.section-grid {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: clamp(2rem, 5vw, 4rem); align-items: center;
}
.section-grid.flip { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
.section h2 {
  font-size: clamp(1.5rem, 3vw, 2.2rem); font-weight: 700;
  letter-spacing: -0.02em; line-height: 1.1;
}
.section .lede { margin: 0.9rem 0 0; color: var(--ink-2); max-width: 36rem; text-wrap: pretty; }

/* ---------- the rail: three drawn marks in a hairline strip ----------
   The three things a buyer is anxious about, each one carried by a drawing
   rather than by a sentence. No motion: it is a fact strip, not an event. */

.rail {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 1.5rem;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 0.75rem 0;
}
.rail-i {
  display: flex; align-items: center; gap: 0.5rem; min-width: 0;
  font-size: 0.8125rem; color: var(--ink-2);
}
.rail-i > span:last-child { min-width: 0; }
.rail .dotstrip { flex: none; gap: 3px; flex-wrap: nowrap; }
.rail .dotstrip i { width: 7px; height: 7px; }
.rail-g { flex: none; width: 1rem; height: 1rem; color: var(--gold); }
.rail-ring {
  flex: none; width: 1.35rem; height: 1.35rem; border-radius: 50%;
  border: 1px dashed var(--line-strong); display: grid; place-items: center;
  color: var(--ink-2);
}
.rail-ring .ic { width: 0.8rem; height: 0.8rem; }

/* ---------- chips (used inside scenes and cards) ---------- */

.chip {
  display: inline-flex; align-items: center; gap: 0.25rem;
  font-size: 0.75rem; font-weight: 600; line-height: 1.55;
  border-radius: 999px; padding: 0.1rem 0.5rem;
  background: var(--brand-soft); color: var(--brand-ink);
}
.chip .ic { width: 0.78rem; height: 0.78rem; }
.chip.gold { background: color-mix(in oklch, var(--gold) 18%, transparent); color: var(--gold); }

/* ---------- product scenes ---------- */

/* A scene is a CARD, so it takes the card ground and lifts off the page. It
   used to paint --bg, i.e. the page's own colour, which left a 1120px picture
   held together by one hairline. */
.scene {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow-2); overflow: hidden;
  font-size: 0.8125rem;
}
.scene .bar {
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  background: var(--panel); border-bottom: 1px solid var(--line);
  padding: 0.5rem 0.75rem; font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3);
}
.scene .bar i { width: 8px; height: 8px; border-radius: 50%; background: var(--line-strong); display: inline-block; flex: none; }
/* The caption WRAPS (the bar wraps with it). It used to be one nowrap line with
   an ellipsis, which cut four captions we wrote ourselves rather than shrinking
   them: measured at 390, "mentions across your subreddits · this month vs last"
   needed 361px in a 214px strip, and "the 8 biggest subreddits on the shared
   map" needed 291 in 282. A title strip that grows by a line costs 17px; a
   caption that ends in "…" costs the sentence. */
.scene .bar .bar-t { min-width: 0; }
.scene .pad { padding: 1rem; }
.scene-foot {
  display: flex; gap: 1rem; flex-wrap: wrap;
  border-top: 1px solid var(--line); padding: 0.5rem 1rem;
  font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3);
}
.sf-key { display: inline-flex; align-items: center; gap: 0.25rem; }
.sf-key i { width: 14px; height: 8px; border-radius: 2px; display: inline-block; }
.sf-key i.k-now { background: var(--viz-value); }
.sf-key i.k-prev { background: transparent; border-right: 2px solid var(--ink); width: 8px; }

/* Every mock on these pages is an illustration, and says so. */
.tag {
  margin-left: auto; flex: none;
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.04em;
  color: var(--ink-2); border: 1px solid var(--line-strong);
  border-radius: 999px; padding: 0 0.5rem;
}

/* a neutral results-page mock (no search-engine branding) */
.mock-serp .r { padding: 0.5rem 0.2rem; border-bottom: 1px solid var(--line); }
.mock-serp .r:last-child { border-bottom: none; }
.mock-serp .url { display: flex; align-items: center; gap: 0.25rem; font-family: var(--mono); font-size: 0.6875rem; color: var(--ink-3); }
.mock-serp .t { font-weight: 600; color: var(--brand-ink); }
.mock-serp .rmeta { font-family: var(--mono); font-size: 0.6875rem; color: var(--ink-3); margin-top: 2px; }
/* Colour grammar, page wide: MARIGOLD marks a name or the slot a name goes
   into, SEA GLASS marks something that already exists and can be counted, RED
   marks something not allowed. A Reddit row in a results page is a thing that
   already exists, so it is sea glass. Marigold used to do this job as well as
   the CTA and the promo dot, which meant it said nothing.

   TINT LADDER, three steps and no fourth, chosen by AREA rather than by
   component: 12% washes a PANEL (a big ground, where a stronger tint turns
   into a slab), 18% fills a CHIP or a lit ROW, 36% fills a BAR that is yours.
   Percentages used to be picked per component (8, 10, 12, 20, 30), so one
   meaning painted four different colours.

   AND THE COOL TINTS MIX INTO THE WELL, NOT INTO NOTHING. A transparent cool
   tint laid over the warm ground averages to grey: 18% sea glass over the card
   composited to a khaki slab, which is what the three cited rows in the hero
   looked like. Warm over warm stays warm, so the marigold tints keep their
   transparency; the sea-glass ones are mixed into --panel instead, which is
   the cold value they should have been sitting on all along. */
.mock-serp .r.reddit { background: color-mix(in oklch, var(--brand) 16%, var(--panel)); border-radius: 4px; padding-left: 0.5rem; padding-right: 0.5rem; }
.mock-serp .r.reddit .url { color: var(--brand-ink); font-weight: 600; }
.mock-serp.compact .r { padding-top: 0.5rem; padding-bottom: 0.5rem; }

/* an assistant answer citing reddit */
.mock-ai .ai-q { margin: 0 0 0.7rem; font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3); }
.mock-ai .ai-a { margin: 0; font-size: 0.9375rem; line-height: 1.55; color: var(--ink); }
.ai-cite {
  display: inline-block; vertical-align: super; font-size: 0.6875rem; font-weight: 700;
  font-family: var(--mono); color: var(--on-brand); background: var(--brand);
  border-radius: 4px; padding: 0 0.25rem; margin-left: 2px;
}
.ai-src { margin-top: 1rem; padding-top: 0.75rem; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 0.25rem; }
/* Cobalt, not gold: a cited thread is something that already exists. */
.ai-s { display: flex; align-items: center; gap: 0.5rem; font-family: var(--mono); font-size: 0.75rem; color: var(--brand-ink); font-weight: 600; }
.ai-n {
  flex: none; width: 1.05rem; height: 1.05rem; border-radius: 4px; display: grid; place-items: center;
  background: var(--brand); color: var(--on-brand); font-size: 0.6875rem; font-weight: 700;
}

/* A name, or the slot a name goes into. The one thing gold means. */
.nm {
  font-weight: 700; color: var(--gold);
  box-shadow: inset 0 -0.12em 0 var(--gold);
}

/* ---------- the hero answer card ----------
   The card is a picture of the customer's problem: an answer that names three
   brands, with the threads it was built from exposed underneath. The default
   CSS state is the FINISHED, lit state; every keyframe runs `from` the dim
   state with fill-mode backwards. So a headless render, a background tab, a
   printed page and a reduced-motion visitor all get the complete card, and no
   state exists only inside a keyframe. */

/* ---------- the two registers a question passes through ----------
   A TYPED QUESTION and an ANSWER are different objects and are drawn as
   different objects. They used to be two paragraphs stacked in one card, one
   in mono and one not, and a reader had to work out which half was which.

   .qbox is the field: a border, a magnifier, a caret parked at the end of the
   text. .reply is the answer: no border, an accent rule down its edge and a
   spark mark at the top of it. Both are used on the landing, and .qbox again
   on /pricing, so the grammar is the same everywhere a question appears. */

.qbox {
  display: flex; align-items: center; gap: 0.5rem;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: 999px; padding: 0.5rem 1rem;
  font-size: 0.8125rem; color: var(--ink); min-width: 0;
}
.qbox .ic { flex: none; width: 0.9rem; height: 0.9rem; color: var(--ink-3); }
.qbox .qtext { min-width: 0; line-height: 1.25; }

.reply {
  display: grid; grid-template-columns: 1.4rem minmax(0, 1fr); gap: 0.5rem;
  margin-top: 0.75rem;
}
.reply-mark {
  grid-row: 1 / -1; justify-self: center;
  width: 1.4rem; height: 1.4rem; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brand-soft); color: var(--brand-ink);
}
.reply-mark .ic { width: 0.8rem; height: 0.8rem; }
.scene.answer .ans {
  margin: 0; font-size: 0.9375rem; line-height: 1.55; color: var(--ink);
  align-self: center;
}

/* The rail. A fixed row height is what lets the gold segment land on a row at
   any width: correspondence between a name and a source is taught by the
   shared number and the timing, never by a drawn connector, because a literal
   line from name to row cannot survive reflow. */
.ans-src {
  --row: 2.2rem;
  position: relative; padding-left: 1.5rem;
  margin-top: 1rem; padding-top: 0.75rem; border-top: 1px solid var(--line);
  display: flex; flex-direction: column;
}
.ans-src::before,
.ans-src::after {
  content: ''; position: absolute; left: 0.55rem; width: 2px; border-radius: 1px;
}
.ans-src::before { top: 0.8rem; bottom: 0; background: var(--line-strong); }
.ans-src::after {
  top: 0.8rem; height: var(--row); background: var(--gold);
  z-index: var(--z-raise);
  transform: translateY(calc(var(--row) * 2));
  animation: rail-travel 800ms var(--ease) 300ms backwards;
}
/* The segment holds on a row while that row's name is lit, then travels. The
   percentages are the 300 / 700 / 1100ms beats below, expressed inside an
   800ms run that starts at 300ms. */
@keyframes rail-travel {
  0%, 25% { transform: translateY(0); }
  50%, 75% { transform: translateY(var(--row)); }
  100% { transform: translateY(calc(var(--row) * 2)); }
}
.ans-src .ai-s {
  font-size: 0.6875rem;
  display: grid; grid-template-columns: 1.05rem auto minmax(0, 1fr);
  gap: 0 0.5rem; align-items: center;
  height: var(--row); padding-inline: 0.25rem; border-radius: 4px;
  background: color-mix(in oklch, var(--brand) 16%, var(--panel));
  animation: row-light 240ms var(--ease) backwards;
}
.ans-src .ai-u { white-space: nowrap; }
.ans-src .ai-t {
  font-family: var(--font); font-weight: 600; color: var(--ink-2);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A thread title is either whole or absent, never "with a heav…". The card is
   what decides, not the viewport: MEASURED, this card is 549px wide at 1440 and
   417px at 900, where the hero is still two columns, so a viewport rule cut the
   titles on a desktop and left them on a phone. Below 540px of CARD the row
   carries the subreddit only, which is what the 520px viewport rule below has
   always done at the bottom end. The titles themselves are written to fit
   (views/landing.ejs); this is the guard, not the fix. */
.scene.answer { container-type: inline-size; }
@container (max-width: 539px) {
  .ans-src .ai-t { display: none; }
}
/* The caption is NOT animated. It used to fade in at 3000ms from opacity 0,
   which meant every frame before three seconds was missing a whole line. */
.ans-cap {
  margin: 0.75rem 0 0; font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3);
}
@keyframes row-light { from { background: transparent; opacity: 0.55; } }
/* The dim state is carried by OPACITY and a transparent underline, never by a
   second colour. MEASURED: Chromium 120 renders an `oklch()` colour inside a
   @keyframes `color` declaration as rgb(255,0,0), so `from { color: var(--ink) }`
   put two pure red brand names on the hero for the first two seconds of every
   page load. Animating opacity involves no colour interpolation and no colour
   space, so it cannot go wrong in any engine, and the resting state is still
   the finished gold name.

   NOTHING here starts at opacity 0. A citation chip that faded in from zero
   left a hole in the middle of the sentence ("Quillon␣␣␣␣for something
   bitter") in every frame before its delay expired, which is what an OG
   scrape, a screenshot and a slow paint capture. The whole sentence, all
   three names and all three chips are legible in the FIRST frame; the beats
   only brighten them. The run also finishes at 1.34s rather than 2.44s. */
@keyframes nm-light {
  from { opacity: 0.55; box-shadow: inset 0 -0.12em 0 transparent; }
}
@keyframes cite-in { from { opacity: 0.55; } }
.ans .nm { animation: nm-light 240ms var(--ease) backwards; }
.ans .ai-cite { animation: cite-in 240ms var(--ease) backwards; }
.ans .nm:nth-of-type(1), .ans .ai-cite:nth-of-type(1), .ans-src .ai-s:nth-child(1) { animation-delay: 300ms; }
.ans .nm:nth-of-type(2), .ans .ai-cite:nth-of-type(2), .ans-src .ai-s:nth-child(2) { animation-delay: 700ms; }
.ans .nm:nth-of-type(3), .ans .ai-cite:nth-of-type(3), .ans-src .ai-s:nth-child(3) { animation-delay: 1100ms; }

/* ---------- four categories, four miniature answer cards ----------
   Drawn mock panels carrying different data, not an icon-heading-text grid.
   The differing question lengths are what stop the row reading as a template. */

.cats { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 0.75rem; }
.cat { display: flex; flex-direction: column; }
.cat .pad { display: flex; flex-direction: column; gap: 0.5rem; flex: 1; }
.cat-q {
  display: flex; align-items: flex-start; gap: 0.25rem;
  font-family: var(--mono); font-size: 0.6875rem; line-height: 1.55; color: var(--ink-3);
}
.cat-q .ic { flex: none; width: 0.8rem; height: 0.8rem; margin-top: 0.15rem; }

/* ---------- what it does, as five steps ----------
   The section that says what the product actually does. Every step is a
   LABEL and a drawing of that step's own output: the site it read, the rivals
   it found, the threads it read, the subreddits it picked, the list it hands
   over. No step gets a sentence, because five sentences in a row is the wall
   of text this section exists to replace. */

.steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0.75rem;
  counter-reset: step;
}
.step {
  display: flex; flex-direction: column; gap: 0.5rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 1rem 1rem 1rem;
}
.step-n {
  width: 1.5rem; height: 1.5rem; flex: none; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 0.75rem; font-weight: 700;
  background: var(--brand-soft); color: var(--brand-ink);
}
.step-t { font-size: 0.9375rem; font-weight: 600; line-height: 1.25; color: var(--ink); text-wrap: pretty; }
/* Each figure is the same height so the five cards keep one baseline, and it
   sits at the FOOT of the card so the labels line up across the row. */
.sfig {
  margin-top: auto; padding-top: 0.75rem;
  display: flex; flex-direction: column; gap: 0.25rem; justify-content: flex-end;
  min-height: 4.4rem;
}

/* 1 · a page, read. The gold line is the sentence it took out of it: what you
   sell, in your words, which is the thing every later step is measured against. */
.sf-win { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.sf-winbar {
  display: flex; align-items: center; gap: 3px;
  background: var(--panel); border-bottom: 1px solid var(--line); padding: 0.2rem 0.5rem;
}
.sf-winbar i { width: 4px; height: 4px; border-radius: 50%; background: var(--line-strong); flex: none; }
.sf-winbar em {
  font-style: normal; margin-left: 0.3rem; min-width: 0;
  font-family: var(--mono); font-size: 0.6875rem; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sf-winbody { display: flex; flex-direction: column; gap: 4px; padding: 0.5rem; }
.sf-site b { display: block; height: 5px; border-radius: 3px; background: var(--line-strong); }
.sf-site b.hit { background: var(--gold); }

/* 2 · who else is named, you among them */
.sf-rivals .sf-row { display: grid; grid-template-columns: 3.4rem minmax(0, 1fr); gap: 0.5rem; align-items: center; }
.sf-rivals em {
  font-style: normal; font-family: var(--mono); font-size: 0.6875rem; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sf-rivals i { display: block; height: 6px; border-radius: 3px; background: var(--viz-value); }
.sf-rivals .you em { color: var(--gold); font-weight: 700; }
.sf-rivals .you i { background: var(--gold); }

/* 3 · threads, already there */
/* 4.75rem, not 4.4: "r/cocktails" is a FIXED string in the mock and needs
   73px at the caption size. The column was 70.4 and clipped it on every
   breakpoint. A label column is sized by its longest label, not by rhythm. */
.sf-threads .sf-th { display: grid; grid-template-columns: 4.75rem minmax(0, 1fr); gap: 0.5rem; align-items: center; }
.sf-threads u {
  text-decoration: none; font-family: var(--mono); font-size: 0.6875rem; color: var(--brand-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sf-threads b { display: block; height: 5px; border-radius: 3px; background: var(--line-strong); }

/* 4 · the subreddits, carrying the three states the map records */
.sf-subs { flex-direction: row; flex-wrap: wrap; gap: 0.25rem; align-items: flex-end; justify-content: flex-start; }
.sf-chip {
  display: inline-flex; align-items: center; gap: 0.25rem;
  border: 1px solid var(--line); border-radius: 999px; padding: 0.08rem 0.5rem;
  font-family: var(--mono); font-size: 0.6875rem; color: var(--ink-2);
}
.sf-chip i { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.sf-chip.ok i { background: var(--gold); }
.sf-chip.val i { background: var(--viz-value); }
.sf-chip.no i { background: var(--bad); }

/* 5 · the list, with the one control that matters on it */
.sf-list .sf-task { display: grid; grid-template-columns: 9px minmax(0, 1fr) auto; gap: 0.5rem; align-items: center; }
.sf-list .box { width: 9px; height: 9px; border-radius: 2px; border: 1px solid var(--line-strong); }
.sf-list b { display: block; height: 5px; border-radius: 3px; background: var(--line-strong); }
.sf-list em {
  font-style: normal; font-family: var(--mono); font-size: 0.6875rem; font-weight: 700;
  color: var(--brand-ink); border: 1px solid var(--line); border-radius: 4px; padding: 0 0.25rem;
}
.cat-a { font-size: 0.8125rem; line-height: 1.55; color: var(--ink); }
.cat-s {
  margin-top: auto; padding-top: 0.25rem;
  display: flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.6875rem; color: var(--brand-ink);
}
.cat-s i { flex: none; width: 6px; height: 6px; border-radius: 1px; background: var(--viz-value); }

/* ---------- the morning board (a STATIC picture of the app) ----------
   Every class here is namespaced m-. The mock carries none of the app's
   behaviour hooks, so app.js loaded on a public page could never make it
   answer a keystroke. */

.m-board {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  overflow: hidden; box-shadow: var(--shadow-2);
}
.m-head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.5rem 0.75rem;
  align-items: center;
  background: var(--panel); border-bottom: 1px solid var(--line); padding: 0.5rem 1rem;
}
/* The board's progress, drawn the way the app draws it: ONE proportional
   track carrying done and skipped, with the rest of the track being what is
   left. The old version was six equal units under a label that said five
   tasks, so the picture and the counts disagreed. Six tasks here: 1 done,
   1 skipped, 4 left (the mention is a task, which is why To do reads 3). */
.m-meter {
  grid-column: 1 / -1; display: flex; height: 10px; border-radius: 4px;
  overflow: hidden; background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line-strong);
}
.m-meter i { display: block; height: 100%; flex: none; }
.m-meter i.d { background: var(--ok); }
/* Skipped is hatched as well as grey: it is a different outcome from "left",
   and hue alone does not carry that for everyone. */
/* MEASURED: with --line-strong under the hatch this segment came out at
   1.88:1 against the track, i.e. a state you could not see. The solid colour
   is --ink-3 and the hatch is drawn ON it, so the mark clears 3:1 and still
   reads as a different texture from "left". */
.m-meter i.s {
  background-color: var(--ink-3);
  background-image: repeating-linear-gradient(135deg, oklch(0 0 0 / 0.42) 0 2px, transparent 2px 5px);
}
.m-key { display: flex; flex-wrap: wrap; gap: 0.15rem 1rem; font-size: 0.75rem; color: var(--ink-2); }
.m-key > span { display: inline-flex; align-items: center; gap: 0.25rem; }
.m-key i { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.m-key i.k-d { background: var(--ok); }
.m-key i.k-s { background-color: var(--ink-3); background-image: repeating-linear-gradient(135deg, oklch(0 0 0 / 0.42) 0 2px, transparent 2px 5px); }
.m-key i.k-l { background: transparent; box-shadow: inset 0 0 0 1px var(--ink-3); }
.m-key b { font-family: var(--mono); color: var(--ink); font-weight: 700; }

/* The mention: the thing the user is working toward, so it takes a full gold
   border like .doors-thread, never a side stripe. Five filled marks plus four
   hollow makes nine, and the tenth outlined square is the mention being
   earned, so the arithmetic on screen is internally consistent. */
.m-mention {
  margin: 0.8rem 0.9rem; padding: 0.75rem 0.75rem;
  border: 1px solid var(--gold); border-radius: 8px;
  background: color-mix(in oklch, var(--gold) 12%, transparent);
  display: flex; flex-direction: column; gap: 0.5rem;
}
.m-mention-top { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.m-mention-t { font-weight: 600; font-size: 0.9375rem; }
.m-mention-top .chip { margin-left: auto; }
/* Nine posts, then the mention. Capped so the marks stay marks: stretched to
   a 1120px board each one reads as a bar, and the tenth stops reading as the
   square it has to be. 68% of --viz-value was measured at 3:1 here; 45% was
   2.55:1 and vanished. */
.m-marks { display: flex; gap: 4px; align-items: center; max-width: 24rem; }
.m-marks i {
  flex: 1 1 auto; max-width: 2.1rem; height: 10px; border-radius: 3px;
  background: color-mix(in oklch, var(--viz-value) 82%, transparent);
}
/* --ink-3, not --line-strong: MEASURED at 1.49:1 on the gold-tinted panel,
   i.e. an invisible slot. These four are the posts still to go, which is the
   half of the count the reader most needs to see. */
.m-marks i.o { background: transparent; box-shadow: inset 0 0 0 1px var(--ink-3); }
.m-marks i.goal {
  flex: 0 0 10px; max-width: none; background: transparent;
  border-radius: 2px; margin-left: 0.5rem;
  box-shadow: inset 0 0 0 1.5px var(--gold);
}

.m-zone {
  display: flex; align-items: baseline; gap: 0.5rem;
  border-top: 1px solid var(--line); padding: 0.5rem 1rem;
  font-size: 0.75rem; font-weight: 700; color: var(--ink-2);
}
.m-zone b { font-family: var(--mono); color: var(--ink-3); }
/* A waiting row carries its ordinal; a completed row is compact and drops it,
   which is exactly what the shipped board does. */
.m-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 0.5rem;
  align-items: start; border-top: 1px solid var(--line); padding: 0.75rem 1rem;
}
.m-row.done { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
.m-n { font-family: var(--mono); font-size: 0.75rem; font-weight: 700; color: var(--ink-3); padding-top: 0.05rem; }
.m-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.m-sub { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3); }
.m-t { font-size: 0.9375rem; line-height: 1.25; color: var(--ink); }
/* The reply box carries its own Copy, top right, where the app puts it. */
.m-reply {
  margin-top: 0.5rem; background: var(--panel); border-radius: 8px;
  padding: 0.5rem 0.75rem; font-size: 0.8125rem; line-height: 1.55; color: var(--ink-2);
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.25rem 0.5rem; align-items: center;
}
.m-reply b {
  font-family: var(--mono); font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.04em; color: var(--brand-ink);
}
.m-rt { grid-column: 1 / -1; }
.m-copy {
  justify-self: end; border: 1px solid var(--line-strong); border-radius: 4px;
  padding: 0.1rem 0.5rem; font-size: 0.75rem; font-weight: 600; color: var(--ink-2);
}
.m-acts { flex: none; display: flex; align-items: center; gap: 0.25rem; flex-wrap: wrap; }
.m-acts > span {
  border: 1px solid var(--line-strong); border-radius: 4px;
  padding: 0.16rem 0.5rem; font-size: 0.75rem; font-weight: 600;
  color: var(--ink-2); white-space: nowrap;
}
.m-acts > span.p { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
/* A completed row drops to --ink-3, never to opacity: opacity would undo the
   contrast the tokens in this file were measured for. */
.m-row.done .m-t, .m-row.done .m-sub { color: var(--ink-3); }
.m-acts .m-stamp {
  font-family: var(--mono); font-size: 0.6875rem; border-radius: 999px;
  border-color: currentColor; padding: 0.1rem 0.5rem;
}
.m-acts .m-stamp.ok { color: var(--ok); }
.m-acts .m-stamp.sk { color: var(--ink-3); }
.m-acts .m-back {
  display: inline-flex; align-items: center; gap: 0.25rem;
  border: 0; padding: 0.16rem 0.2rem; font-weight: 600; color: var(--ink-3);
}
.m-acts .m-back .ic { width: 0.8rem; height: 0.8rem; }

/* ---------- the GEO thesis: one thread, two front doors ---------- */

.doors { display: grid; gap: 0; }
.doors-q { justify-self: center; max-width: 100%; }
.doors-panels { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
/* --line-strong measured 1.74:1 on this surface, i.e. an invisible line, and
   the connector is the argument of the whole fold, so it takes --ink-3. The
   DEFAULT state is fully drawn and fully opaque: the fold can never ship
   blank, and the scroll-driven brighten below is an addition to it. */
.doors-join {
  width: 100%; height: 44px; display: block; fill: none;
  stroke: var(--ink-3); stroke-width: 1.5; opacity: 1;
}
.doors-down { color: var(--ink-3); }
/* The two panels are the same height, so the merge below them starts from a
   straight edge. The sources sit at the foot of the shorter one rather than
   leaving a hole. */
.doors-panels .scene { display: flex; flex-direction: column; }
.doors-panels .scene .pad { flex: 1; display: flex; flex-direction: column; }
.doors-panels .mock-ai .ai-src { margin-top: auto; }
.doors-down { display: none; justify-self: center; color: var(--line-strong); }
.doors-down .ic { width: 1.6rem; height: 1.6rem; transform: rotate(90deg); }
.doors-thread {
  justify-self: center; max-width: 34rem; width: 100%;
  display: flex; flex-direction: column; gap: 0.25rem;
  background: var(--surface); border: 1px solid var(--gold); border-radius: 8px;
  padding: 0.75rem 1rem; box-shadow: var(--shadow-2);
}
.dt-sub {
  display: flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.75rem; color: var(--gold); font-weight: 600;
}
.dt-title { font-weight: 600; font-size: 0.9375rem; line-height: 1.25; }
.dt-you {
  margin-top: 0.25rem; display: inline-flex; align-items: center; gap: 0.25rem;
  align-self: flex-start; background: color-mix(in oklch, var(--gold) 18%, transparent);
  color: var(--gold); border-radius: 999px; padding: 0.15rem 0.5rem;
  font-size: 0.75rem; font-weight: 600;
}
/* Three comment rows, the middle one yours. The grey bars are texture rather
   than data, so --line-strong is the right weight for them; the mono scores
   are read, so they stay --ink-3, which this file measured at AA. */
.dt-stack { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.5rem; }
.dt-row {
  display: grid; grid-template-columns: 8px minmax(0, 1fr) 2.2rem;
  gap: 0.5rem; align-items: center;
}
.dt-row > .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line-strong); }
.dt-bars { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.dt-bars > i { display: block; height: 5px; border-radius: 3px; background: var(--line-strong); }
.dt-row > .sc { font-family: var(--mono); font-size: 0.6875rem; color: var(--ink-3); text-align: right; }
.dt-row.mine {
  border: 1px solid var(--gold); border-radius: 8px; padding: 0.5rem 0.5rem;
}
.dt-row.mine > .dot { background: var(--gold); }
.dt-row.mine .dt-bars > i { background: color-mix(in oklch, var(--gold) 36%, transparent); }

/* The same three stations at a third of the size, for /pricing. The arrow is
   normally a phone-only substitute for the fork, so it is forced on here. */
.mini-trace { display: grid; justify-items: center; gap: 0; margin-top: 1.5rem; }
.mini-trace .doors-q { font-size: 0.8125rem; padding: 0.25rem 0.75rem; }
.mini-trace .doors-down { display: block; padding: 0.25rem 0; }
.mini-trace .doors-down .ic { width: 1.2rem; height: 1.2rem; }
.mini-trace .doors-thread { max-width: 28rem; padding: 0.5rem 1rem; gap: 0.1rem; }
.mini-trace .dt-title { font-size: 0.9375rem; }
.mini-trace .dt-you { margin-top: 0.25rem; font-size: 0.75rem; }

/* One line under a fold. It is the only sentence the fold gets. */
.foldline { margin: 1.5rem 0 0; font-size: 0.9375rem; color: var(--ink-2); max-width: 40rem; text-wrap: pretty; }

/* ---------- the seam: what it does, and what only you do ----------
   A standalone 3px gold column between two territories, deliberately NOT a
   coloured border on the side of a card. */

.line-split {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: stretch;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 14px; overflow: hidden;
}
.ls-side { padding: 1rem 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.ls-h {
  font-family: var(--mono); font-size: 0.75rem; font-weight: 700;
  letter-spacing: 0.04em; color: var(--ink-3);
}
.ls-side ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.ls-side li { display: flex; gap: 0.5rem; font-size: 0.9375rem; color: var(--ink-2); }
.ls-side li::before { content: ''; flex: none; width: 6px; height: 6px; background: var(--viz-value); margin-top: 0.5em; }
.ls-you li::before { background: var(--gold); }
.ls-seam { width: 3px; background: var(--gold); }
.ls-label {
  margin: 0.7rem 0 0; display: flex; flex-direction: column; align-items: center; gap: 0.25rem;
  font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3);
}
.ls-label::before { content: ''; width: 3px; height: 0.75rem; background: var(--gold); border-radius: 1px; }

/* The ten unit `.budget` strip lived here. It drew the 9 to 1 rule beside a
   30 day strip that draws the same ratio, in one viewport on /pricing, so the
   page said one thing twice in pictures and twice again in prose. One drawing
   of a rule per page: the strip went, the 30 days stayed. */

/* the promo dot ledger, straight from the product */
.dotstrip { display: flex; flex-wrap: wrap; gap: 4px; }
.dotstrip i { width: 9px; height: 9px; border-radius: 50%; background: var(--viz-value); }
/* Hue alone does not separate these two for anyone with reduced colour
   perception, so a mention dot is a square as well as gold. */
.dotstrip i.promo { background: var(--viz-promo); border-radius: 2px; }
.ledger-legend { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 0.5rem; font-size: 0.75rem; color: var(--ink-3); }
.ledger-legend i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-right: 0.35rem; background: var(--viz-value); }
.ledger-legend .lp i { background: var(--viz-promo); border-radius: 2px; }

/* safety bars */
.safebars { margin-top: 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.sb { display: grid; grid-template-columns: 4.5rem 1fr 1.8rem; gap: 0.5rem; align-items: center; }
.sbl { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3); }
.sbt { height: 10px; border-radius: 4px; background: var(--panel); overflow: hidden; }
.sbt i { display: block; height: 100%; border-radius: 4px; background: var(--viz-value); }
.sb.promo .sbt i { background: var(--viz-promo); }
.sbn { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-2); text-align: right; }

/* ---------- competitor bars (now vs the month before) ---------- */

.mock-bars .row { display: grid; grid-template-columns: 8.5rem 1fr 2.2rem; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem; }
.mock-bars .row:last-child { margin-bottom: 0; }
.mock-bars .lbl { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mock-bars .trk { position: relative; height: 9px; border-radius: 4px; background: var(--panel); }
.mock-bars .trk i { position: absolute; left: 0; top: 0; height: 100%; border-radius: 4px; background: var(--viz-value); }
/* Last month reads as a tick, not a second bar: the overhang sits on the
   scene background where it always clears 3:1, never on the fill. */
.mock-bars .trk u { position: absolute; left: 0; top: -5px; bottom: -5px; border-right: 2px solid var(--ink); }
.mock-bars .you .lbl { color: var(--gold); font-weight: 700; }
.mock-bars .you .trk i { background: var(--gold); }
.mock-bars .n { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-2); text-align: right; }
.mock-bars .ubadge {
  margin-left: 0.35rem; font-size: 0.6875rem; font-weight: 700;
  border: 1px solid var(--gold); border-radius: 999px; padding: 0 0.25rem;
}
.scene-foot .sf-note { margin-left: auto; }

/* ---------- coverage: the split, then the rows ---------- */

.stackbar { display: flex; height: 14px; border-radius: 8px; overflow: hidden; background: var(--panel); }
.stackbar i { display: block; height: 100%; }
/* The three segment colours match the row tags below them exactly, so the bar
   and the list teach the same language. --line-strong measured 1.74:1 for the
   "no promotion" segment, which is a state you cannot afford to miss. */
.stackbar i.s-ok, .stackkey i.s-ok { background: var(--gold); }
.stackbar i.s-val, .stackkey i.s-val { background: var(--viz-value); }
/* MEASURED after the repaint: "mention ok" (the bill's orange) and "no
   promotion" (red) landed a few degrees of hue apart and read as one segment
   with a seam in it. The red moved to a crimson AND took a hatch, so the two
   differ in texture as well as in colour (WCAG 1.4.1), exactly as the promo
   dot differs from the helpful dot by being a square. */
.stackbar i.s-no, .stackkey i.s-no {
  background-color: var(--bad);
  background-image: repeating-linear-gradient(135deg, oklch(0 0 0 / 0.34) 0 2px, transparent 2px 5px);
}
.stackkey { display: flex; gap: 1rem; flex-wrap: wrap; margin: 0.55rem 0 0.9rem; font-size: 0.75rem; color: var(--ink-2); }
.stackkey span { display: inline-flex; align-items: center; gap: 0.25rem; }
.stackkey b { color: var(--ink); }
.stackkey i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

/* The measured coverage panel keeps a little air under the seam above it. */
.safety-panel { margin-top: 1.5rem; }

/* ---------- pricing ----------
   How many brands each plan covers, drawn before anyone reads a bullet. The
   count still comes from plans.js; above eight dots stop reading as a count,
   so the view prints the number instead. */

.brandcount { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1.5rem; margin-bottom: 1rem; }
.bc-l { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-3); }
.bc-i { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.8125rem; color: var(--ink-2); }
.bc-dots { display: inline-flex; gap: 4px; }
.bc-dots i { width: 9px; height: 9px; border-radius: 50%; background: transparent; box-shadow: inset 0 0 0 1px var(--ink-3); }
.bc-dots i.on { background: var(--viz-value); box-shadow: none; }
.bc-n { font-family: var(--mono); font-weight: 700; color: var(--ink); }


/* The cards fill the column they sit in. Capped at 780px they hugged the
   left third of a 1120px wrap and the page read as unfinished. */
/* The card row is sized by HOW MANY PLANS THERE ARE, because 280px is right
   for two or three and wrong for four: at four, auto-fit put three across and
   dropped the last one onto a second row on its own, which reads as a plan
   that did not fit rather than a tier. Four across needs 244px at the 1120px
   wrap, so the row falls to 2x2 at 1040 instead of 3+1. */
.plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: 1rem; }
.plans-4, .plans-5 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 232px), 1fr)); gap: 0.75rem; }
.plans-4 .plan, .plans-5 .plan { padding: 1rem 1rem; }
.plans-4 .plan .price, .plans-5 .plan .price { font-size: 2rem; }
@media (max-width: 1040px) {
  /* 2 x 2 rather than 3 + 1. min(100%, …) keeps a single column on a phone. */
  .plans-4 { grid-template-columns: repeat(2, minmax(min(100%, 232px), 1fr)); }
}
@media (max-width: 560px) {
  .plans-4 { grid-template-columns: minmax(0, 1fr); }
}
.plan {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 1.5rem; display: flex; flex-direction: column;
}
/* A plan whose price is a conversation. Dashed, because it is not a thing you
   can buy from this page, and the price slot says so in words rather than
   sitting empty where every other card has a number. */
.plan-contact { border-style: dashed; }
/* Outranks the .plans-4 .plan .price size below, which is set for a $ figure:
   "On request" at 2rem is bigger than any price on the row and reads as the
   loudest thing on the page. */
.plan .price.price-ask,
.plans-4 .plan .price.price-ask,
.plans-5 .plan .price.price-ask { font-size: 1.5625rem; letter-spacing: -0.01em; }
.plan .price-ask small { display: block; font-size: 0.8125rem; line-height: 1.25; margin-top: 0.15rem; }
/* Marked ONCE, in one colour. The border used to be blue while the flag on the
   same card was marigold, so the recommended plan was labelled twice and the
   two labels disagreed. */
.plan.featured { border-color: var(--gold); box-shadow: var(--shadow-2); }
.plan .name { font-family: var(--display); font-weight: 700; font-size: 1.25rem; letter-spacing: -0.01em; }
.plan .for { color: var(--ink-3); font-size: 0.8125rem; margin-top: 0.15rem; }
.plan .price { margin: 1.1rem 0 0.2rem; font-family: var(--display); font-weight: 700; font-size: 2rem; letter-spacing: -0.02em; }
.plan .price small { font-size: 0.9375rem; font-weight: 600; color: var(--ink-3); font-family: var(--font); letter-spacing: 0; }
.plan .annual-line { font-size: 0.8125rem; color: var(--ink-2); min-height: 1.2em; }
/* The cancellation line never moves when the billing period does: it was the
   annual state that used to drop it, exactly when commitment went up. */
.plan .fixed-line { font-size: 0.8125rem; color: var(--ink-3); margin-top: 0.1rem; }
.plan .save-line { font-size: 0.8125rem; color: var(--gold); font-weight: 600; margin-top: 0.1rem; min-height: 1.2em; }
/* What the plan covers, drawn once on the card. The list of what it includes
   lives in the comparison table below, not twice on one screen. */
.plan-brands {
  display: flex; align-items: center; gap: 0.5rem;
  /* margin-top: auto, not 1rem: this line takes the card's free space, which
     is what puts the allowance on ONE baseline across a row of four plans
     whose blurbs and prices are different lengths. MEASURED before: the four
     lines sat at 837 / 892 / 858 / 903, and a buyer comparing "5 brands" with
     "20 brands" was reading down a staircase. Do not add a second
     margin-top:auto below this (`.plan .go` is a fixed 1rem) or the two
     share the slack and neither lands. */
  margin: auto 0 1.5rem; font-size: 0.9375rem; color: var(--ink-2);
}
.plan-brands b { font-family: var(--mono); font-weight: 700; color: var(--ink); }
.plan ul { margin: 1.1rem 0 1.4rem; padding: 0; list-style: none; font-size: 0.9375rem; }
.plan ul li { display: flex; gap: 0.5rem; margin-bottom: 0.5rem; color: var(--ink-2); }
.plan ul li::before { content: ''; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--ok); margin-top: 0.55em; }
.plan .go {
  margin-top: 1rem; text-align: center; background: var(--gold); color: var(--on-brand);
  border: 0; border-radius: 8px; padding: 0.75rem 1rem; font-weight: 700;
  font-family: inherit; font-size: 0.9375rem; cursor: pointer;
}
.plan .go:hover { filter: brightness(1.08); text-decoration: none; }
.plan .go[disabled] { opacity: 0.6; cursor: default; }
.plan .plan-err { margin: 0.6rem 0 0; font-size: 0.8125rem; color: var(--bad); }
.plan .plan-err:empty { display: none; }
.plan.featured .flag {
  align-self: flex-start; font-size: 0.75rem; font-weight: 700;
  background: color-mix(in oklch, var(--gold) 18%, transparent); color: var(--gold);
  border-radius: 999px; padding: 0.15rem 0.5rem; margin-bottom: 0.75rem;
}
.plans-more { margin: 1rem 0 0; font-size: 0.9375rem; }

/* monthly/annual switch */
.billing-toggle {
  display: inline-flex; border: 1px solid var(--line-strong); border-radius: 999px;
  padding: 3px; margin: 1.2rem 0 1.4rem; background: var(--surface);
}
.billing-toggle button {
  font: inherit; font-weight: 600; font-size: 0.9375rem; border: 0; background: transparent;
  color: var(--ink-2); border-radius: 999px; padding: 0.25rem 1rem; cursor: pointer;
}
.billing-toggle button[aria-pressed="true"] { background: var(--brand); color: var(--on-brand); }
.billing-toggle .save { font-size: 0.75rem; color: var(--gold); font-weight: 700; margin-left: 0.3rem; }
.billing-toggle button[aria-pressed="true"] .save { color: var(--on-brand); }
.billing-status { font-size: 0.8125rem; color: var(--ink-3); margin: 0 0 1.4rem; min-height: 1.2em; }

/* Feature strip on the pricing page. A hairline strip, the same component
   language as the landing's .rail, NOT five bordered boxes: an icon-heading
   card grid is the banned template, and as a grid the fifth card sat alone
   beside an empty cell at 390px. Flex wrapping cannot orphan a cell. */
.featstrip {
  list-style: none; margin: 1.4rem 0 0; padding: 0.75rem 0;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem;
}
.featstrip li {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: 0.8125rem; color: var(--ink-2);
}
.featstrip .ic { width: 1rem; height: 1rem; flex: none; color: var(--brand-ink); }

/* plan comparison */
.tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); }
.cmp { width: 100%; border-collapse: collapse; font-size: 0.9375rem; min-width: 30rem; }
.cmp caption { text-align: left; padding: 1rem 1rem 0; color: var(--ink-3); font-size: 0.8125rem; }
.cmp th, .cmp td { padding: 0.5rem 1rem; text-align: left; border-top: 1px solid var(--line); }
.cmp thead th { border-top: 0; background: var(--panel); color: var(--ink); font-weight: 700; }
.cmp thead th:not(:first-child), .cmp td:not(:first-child) { text-align: center; width: 8rem; }
.cmp td:first-child { color: var(--ink-2); }
.cmp .yes { color: var(--ok); }
.cmp .no { color: var(--ink-3); }
.cmp .ic { width: 1.05rem; height: 1.05rem; }
.cmp .num { font-family: var(--mono); font-weight: 700; color: var(--ink); }

/* FAQ */
/* min(100%, 300px), not a bare 300px: at 320px the column is 288px wide and a
   hard minimum pushed the whole section 12px past its own box (measured). */
.faq { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 1.5rem 2rem; margin-top: 1rem; }
.faq-i h3 { font-family: var(--font); font-size: 0.9375rem; font-weight: 700; letter-spacing: 0; margin-bottom: 0.25rem; }
.faq-i p { margin: 0; color: var(--ink-2); font-size: 0.9375rem; }

/* closing band */
.ctaband {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap;
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  padding: 1.5rem 1.5rem;
}
.ctaband h2 { font-size: clamp(1.2rem, 2.4vw, 1.6rem); }
.ctaband p { margin: 0.35rem 0 0; color: var(--ink-2); font-size: 0.9375rem; }
.ctaband-acts { display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; }

/* ---------- auth doors (login / signup) ---------- */

.auth-body { min-height: 100vh; display: grid; grid-template-rows: auto 1fr; }
.auth-body .world { background: transparent; }
.auth-main { display: grid; place-items: center; padding: 2rem 1rem 4rem; }
.auth-card {
  width: min(360px, 100%);
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 2rem; display: flex; flex-direction: column; gap: 0.75rem;
}
.auth-card h1 { font-size: 1.25rem; letter-spacing: -0.01em; margin-bottom: 0.25rem; }
.auth-card label { font-size: 0.8125rem; font-weight: 600; color: var(--ink-2); }
/* min-width: 0. An input's automatic minimum size is its own `size` attribute,
   which the card cannot shrink below: MEASURED at 320px, the field ran 9px off
   the right of the screen and took the card with it. */
.auth-card input {
  font: inherit; color: var(--ink); background: var(--panel);
  border: 1px solid var(--line-strong); border-radius: 4px; padding: 0.5rem 0.75rem;
  min-width: 0;
}
/* Same marigold as every other primary button in the funnel. */
.auth-card button {
  font: inherit; font-weight: 600; margin-top: 0.5rem;
  background: var(--gold); color: var(--on-brand); border: 0; border-radius: 4px;
  padding: 0.5rem; cursor: pointer;
}
.auth-card button:hover { filter: brightness(1.08); }
.auth-card .err { color: var(--bad); font-size: 0.8125rem; min-height: 1em; margin: 0; }
.auth-card .err:empty { min-height: 0; }
.auth-card .alt { font-size: 0.8125rem; color: var(--ink-3); margin: 0.4rem 0 0; }
.auth-card .alt a { color: var(--world-accent); }

/* ---------- footer ---------- */

.site-foot { border-top: 1px solid var(--line); padding: 2rem 0 3rem; margin-top: 1.5rem; }
.foot-grid { display: grid; grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)); gap: 1.5rem 2rem; }
.foot-brand .wordmark { font-size: 0.9375rem; }
.foot-brand p { margin: 0.6rem 0 0; font-size: 0.8125rem; color: var(--ink-2); max-width: 32rem; }
.foot-brand .foot-fine { color: var(--ink-3); font-size: 0.75rem; }
.foot-col { display: flex; flex-direction: column; gap: 0.5rem; }
.foot-col h2 { font-family: var(--font); font-size: 0.75rem; font-weight: 700; color: var(--ink-3); letter-spacing: 0; margin-bottom: 0.15rem; }
.foot-col a { font-size: 0.8125rem; color: var(--ink-2); }
.foot-col a:hover { color: var(--world-accent); }

/* ---------- motion ----------
   Four events on the whole landing page, each of which says something: the
   hero trace, the two connectors drawing, and the nine-mark meter filling.
   No blanket fade-on-scroll. Every one of them is PAINTED FIRST and animated
   second, so a headless render, a background tab and reduced motion all get
   the finished page. */

.hero h1, .hero .sub, .hero .actions { animation: rise 700ms var(--ease) both; }
.hero .sub { animation-delay: 90ms; }
.hero .actions { animation-delay: 170ms; }
/* No delay on the card: it is the first thing anyone is meant to read, and a
   200ms wait is 200ms of blank hero in a screenshot. */
.hero .scene { animation: rise 600ms var(--ease) both; }
/* Movement only, no fade. An entrance that starts at opacity 0 means the first
   painted frame of the page has no hero in it at all, which is what a scraper,
   a screenshot service and a slow first paint capture. Sliding 14px says the
   same thing and never hides a word. */
@keyframes rise { from { transform: translateY(14px); } }

/* Scroll-driven, and only where the browser has a real view timeline. There
   is no IntersectionObserver and no class toggling, so with JavaScript off
   these are simply already finished. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .doors-join {
      animation: draw-line 600ms var(--ease) both;
      animation-timeline: view(); animation-range: entry 5% cover 22%;
    }
    .doors-join.merge { animation-range: entry 8% cover 25%; }
    .m-marks i.f {
      animation: mark-fill 700ms var(--ease) both;
      animation-timeline: view();
    }
    .m-marks i.f:nth-of-type(1) { animation-range: entry 12% entry 34%; }
    .m-marks i.f:nth-of-type(2) { animation-range: entry 16% entry 38%; }
    .m-marks i.f:nth-of-type(3) { animation-range: entry 20% entry 42%; }
    .m-marks i.f:nth-of-type(4) { animation-range: entry 24% entry 46%; }
    .m-marks i.f:nth-of-type(5) { animation-range: entry 28% entry 50%; }
  }
}
/* The connector BRIGHTENS as the fold arrives. Two things it deliberately is
   not. It is not stroke-dashoffset: MEASURED, with
   vector-effect="non-scaling-stroke" the dash is measured after the transform,
   and these are stretched about eleven times wider than they are tall, so a
   dash long enough to cover the path in viewBox units drew the bracket as a
   row of floating fragments. And it is not a clip wipe: a scroll timeline
   holds the `from` state for everything below the fold, so a wipe left the
   connector missing in a full-page render. A dim line is still a line. */
@keyframes draw-line { from { opacity: 0.32; } }
@keyframes mark-fill { from { background: transparent; box-shadow: inset 0 0 0 1px var(--ink-3); } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* The DELAY has to go too, not just the duration. MEASURED: with only
     animation-duration zeroed, the third name in the hero answer still waited
     out its 2200ms delay showing the dim start state, so a visitor who asked
     for less motion got the staged reveal anyway, just without the tweens. */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: -1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  /* Only the entrance rise is cancelled outright. The answer card's own
     keyframes are NOT listed here on purpose: the rule above lands them on
     their end state, which is the finished, lit card. */
  .hero h1, .hero .sub, .hero .actions, .hero .scene { animation: none !important; }
}

/* ---------- forced colours (Windows High Contrast) ----------
   Every data mark here is a background on an empty element, which forced
   colours flattens to the canvas and erases outright. Meaning is carried by
   graphics on these pages, so each mark is re-stated in system colours. */
@media (forced-colors: active) {
  .dotstrip i, .sbt i, .stackbar i, .mock-bars .trk i,
  .ledger-legend i, .stackkey i, .sf-key i,
  .m-meter i.d, .m-key i.k-d, .m-marks i, .bc-dots i.on, .cat-s i, .ls-side li::before {
    forced-color-adjust: none; background: CanvasText;
  }
  .dotstrip i.promo, .sb.promo .sbt i, .stackbar i.s-ok,
  .stackkey i.s-ok, .ledger-legend .lp i, .mock-bars .you .trk i,
  .ls-seam, .ls-label::before, .ls-you li::before, .dt-row.mine > .dot {
    forced-color-adjust: none; background: Highlight;
  }
  .stackbar i.s-no, .stackkey i.s-no, .m-meter i.s, .m-key i.k-s { forced-color-adjust: none; background: GrayText; }
  .m-key i.k-l, .m-marks i.o, .m-marks i.goal, .bc-dots i { forced-color-adjust: none; background: Canvas; border: 1px solid CanvasText; }
  .sbt, .stackbar, .mock-bars .trk, .m-meter, .m-copy { border: 1px solid CanvasText; }
  .mock-bars .trk u { border-right-color: CanvasText; }
  .ai-n, .m-acts > span.p { border: 1px solid CanvasText; }
  .mock-serp .r.reddit, .dt-you, .chip, .m-mention, .ans-src .ai-s { border: 1px solid CanvasText; }
  .scene, .plan, .m-board, .line-split { border: 1px solid CanvasText; }
  /* The rail segment is the whole point of the trace: keep it visible. */
  .ans-src::after { forced-color-adjust: none; background: Highlight; }
  .ans-src::before { forced-color-adjust: none; background: GrayText; }
}

/* ---------- responsive ---------- */

@media (max-width: 980px) {
  .m-mention { margin-inline: 0.7rem; }
  .m-row, .m-zone, .m-head { padding-inline: 0.75rem; }
}

@media (max-width: 860px) {
  .section-grid, .section-grid.flip, .doors-panels { grid-template-columns: minmax(0, 1fr); }
  .section-grid.flip .scene { order: 2; }
  .doors-join { display: none; }
  .doors-down { display: block; padding: 0.5rem 0; }
  .site-nav .links { gap: 1rem; }
  .site-nav .links .hide-s { display: none; }
  .foot-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .foot-brand { grid-column: 1 / -1; }

  /* One column, and the card moves up under the heading: the picture is the
     argument, so it should not sit below two buttons on a phone. DOM order is
     unchanged, so reading and focus order are untouched (the card is
     role="img" and holds nothing focusable). */
  .hero-grid { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .hero-grid > h1 { grid-area: auto; order: 1; }
  .hero-grid > .scene { grid-area: auto; order: 2; margin-top: 1.5rem; align-self: stretch; }
  .hero-grid > .sub { grid-area: auto; order: 3; }
  .hero-grid > .actions { grid-area: auto; order: 4; }

  .rail { grid-template-columns: minmax(0, 1fr); gap: 0.5rem; }
}

@media (max-width: 640px) {
  /* The comparison table fits rather than scrolls sideways: a phone user who
     has to drag a table horizontally to compare two plans will not.
     MEASURED at four plans, which is five columns: 4.2rem a column put the
     table 78px off the side of a 320px screen. A data cell only ever holds a
     glyph, a small number, or two short words, so the column is sized for that
     and the row LABEL takes the width back by wrapping. */
  .cmp { min-width: 0; font-size: 0.8125rem; }
  .cmp th, .cmp td { padding: 0.5rem 0.5rem; }
  .cmp thead th:not(:first-child), .cmp td:not(:first-child) { width: 4.2rem; }
  .cmp-4 th, .cmp-4 td, .cmp-5 th, .cmp-5 td { padding: 0.5rem 0.25rem; }
  .cmp-4 thead th:not(:first-child), .cmp-4 td:not(:first-child),
  .cmp-5 thead th:not(:first-child), .cmp-5 td:not(:first-child) { width: 2.6rem; }
  .cmp thead th:first-child, .cmp th[scope="row"] { overflow-wrap: anywhere; }
  .tablewrap { overflow-x: visible; }

  .ctaband { flex-direction: column; align-items: flex-start; }
  .plan .price { font-size: 2rem; }

  .m-head { gap: 0.5rem 0.5rem; }

  /* The action chips wrap under the row rather than squeezing the title. The
     ordinal keeps its column so the rows still read as a numbered list. */
  .m-row { grid-template-columns: auto minmax(0, 1fr); }
  .m-row.done { grid-template-columns: minmax(0, 1fr); }
  .m-acts { grid-column: 1 / -1; margin-top: 0.5rem; }
  .m-t { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .mock-bars .row { grid-template-columns: 6.4rem 1fr 2.2rem; }
  .dt-row { grid-template-columns: 8px minmax(0, 1fr) 1.9rem; }
  .line-split { grid-template-columns: minmax(0, 1fr); }
  .ls-seam { width: auto; height: 3px; }
}

@media (max-width: 520px) {
  /* Three wrapped thread titles would treble the height of the hero card, so
     below this width the rail rows carry the subreddit only. */
  .ans-src { --row: 2.6rem; }
  .ans-src .ai-t { display: none; }

  /* MEASURED at 390px, which is the width most of this traffic arrives on: the
     bar came to 375px inside a 358.8px page and the whole document scrolled
     sideways by 19. Pricing and the primary action are the two that have to
     survive, so the bar gives up size before it gives up a door: the wordmark
     drops a step, the button's padding tightens, the gaps close. Re-measured
     after: 320 / 360 / 390 / 430 / 520 all clear, with the sign-in door
     surviving down to 430. */
  .site-nav .links { gap: 0.75rem; }
  .site-nav .links .hide-xs { display: none; }
  .wordmark { font-size: 1.0625rem; gap: 0.5rem; }
  .wordmark .dot { width: 9px; height: 9px; }
  .site-nav { gap: 1rem; }
  .site-nav .cta { padding: 0.5rem 0.75rem; }
}

/* Below this the sign-in door goes too. It is the one link on the bar that is
   reachable from somewhere else on every page: the footer carries it, and the
   signup form it sits next to asks "Already have one?" in its own words. */
@media (max-width: 430px) {
  .site-nav .links .hide-xxs { display: none; }
  .site-nav .wordmark .mark-svg, .auth-body .wordmark .mark-svg { width: 22px; height: 22px; }
  .wordmark { gap: 0.5rem; }
}

/* And below THIS the mark carries the brand on its own. "PuffinScout" is two
   characters longer than the name it replaced and now arrives with a 26px bird
   in front of it, which put the bar 28px over a 320px page (measured). The
   name stays in the accessibility tree, so the link is still "PuffinScout" to
   a screen reader and still the logo to everyone else. */
@media (max-width: 380px) {
  .site-nav .wordmark .wm-name,
  .auth-body .wordmark .wm-name {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
  }
  /* And it goes BACK UP once it is alone. The 430px rule shrinks it to 22 to
     buy room for the name beside it; with the name gone that trade is over,
     and a 22x22 home link is under the 24px minimum target size (WCAG 2.5.8).
     MEASURED at 360 and 320, where this was the only link on the page failing
     it. There is room: the whole name just left. */
  .site-nav .wordmark .mark-svg,
  .auth-body .wordmark .mark-svg { width: 26px; height: 26px; }
}

/* The AUTH DOORS carry a longer primary label ("Create an account", 174px at
   320 against "Get started" at 111), so their bar runs out of room sooner:
   MEASURED at 320, the page scrolled sideways by 64. Pricing is the link that
   goes, because it is in the footer of every page and the button beside it is
   the reason somebody is on this screen. */
@media (max-width: 430px) {
  .auth-body .site-nav .links .hide-xxs { display: none; }
}

/* =======================================================================
   THREE SURFACES THAT LOOK LIKE THREE SURFACES
   =======================================================================
   The page compares where a buyer's question can land: an assistant, a
   search page, and a Reddit thread. All three used to be the same dark
   card with the same three window dots at the top, so the ONLY thing
   telling them apart was the caption. You had to read to see a difference,
   which means the drawing was doing no work.

   Each now carries the chrome of the thing it actually is.
   ----------------------------------------------------------------------- */

/* 1 · THE ASSISTANT. A chat surface: no window furniture, a bubble with one
       square corner where it is spoken from, and a lit mark for the speaker. */
.scene.is-ai {
  border-radius: 14px 14px 14px 4px;
  border-color: color-mix(in oklch, var(--world-accent) 34%, var(--line));
  background:
    radial-gradient(120% 90% at 0% 0%, color-mix(in oklch, var(--world-accent) 9%, transparent), transparent 60%),
    var(--panel);
}
.chrome-ai {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.chrome-av {
  display: grid; place-items: center; width: 24px; height: 24px; flex: none;
  border-radius: 999px; color: var(--world-deep);
  background: var(--world-accent);
}
.chrome-av .ic { width: 14px; height: 14px; stroke-width: 2.2; }
.chrome-t { font-size: 0.75rem; font-weight: 600; color: var(--world-accent); letter-spacing: 0.04em; text-transform: uppercase; }
.chrome-ai .tag { margin-left: auto; }

/* 2 · THE SEARCH PAGE. The one LIGHT object on a dark page, which is the
       whole point: you know what it is before you read a word. It carries an
       address pill instead of window dots, and its results keep the shape
       everybody has looked at ten thousand times (a coloured title over a
       green address).

       IT IS PAINTED IN OUR OWN COLOURS, not in a search engine's. It used to
       hold nine hardcoded blue-greys that belonged to somebody else's brand,
       which made the most colourful, highest-contrast object on the marketing
       site a quotation. Now the paper is our sea glass at paper lightness,
       which is also the only place on the page where a COOL colour gets any
       real area: dark cool grounds cannot hold chroma in sRGB, pale ones can.
       Values below are contrast-measured against this paper, not the page. */
.scene.is-serp {
  border-radius: 8px;
  background: #e4efef;
  border-color: #cbdbdb;
}
.chrome-serp {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 16px; border-bottom: 1px solid #d4e3e3;
}
.omni {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 12px; border-radius: 999px;
  background: #fafefe; border: 1px solid #cbdbdb;
  font-size: 0.75rem; color: #566768;   /* 5.06:1 on #e4efef */
}
.omni .ic { width: 13px; height: 13px; color: #566768; }
.chrome-serp .tag { margin-left: auto; background: #d1e4e4; color: #566768; border-color: #cbdbdb; }
.scene.is-serp .mock-serp .t { color: #006770; }        /* 5.64:1 */
.scene.is-serp .mock-serp .url { color: #1b6c3a; }      /* 5.50:1 */
.scene.is-serp .mock-serp .r { border-color: #d4e3e3; }

/* 3 · THE REDDIT ROWS, which the owner already reads correctly as orange.
       Given the vote arrow that no other surface has, and a rule down the
       left so the orange is a property of the ROW rather than of the text. */
.scene.is-serp .mock-serp .r.reddit {
  position: relative; padding-left: 28px;
  border-left: 3px solid #ac430e;                        /* 5.02:1 on this paper */
  border-radius: 0 4px 4px 0;
  background: color-mix(in oklch, #ac430e 8%, transparent);
}
.scene.is-serp .mock-serp .r.reddit .url { color: #ac430e; font-weight: 600; }
.rd-up {
  position: absolute; left: 9px; top: 14px; width: 10px; height: 10px;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
  background: #ac430e;
}

@media (max-width: 700px) {
  .chrome-ai, .chrome-serp { padding: 8px 12px; }
}
