/* Virell — the current
   Two stocks: warm ink and paper cream. One current running the length of the
   page: a glowing ribbon on ink, a drawn indigo line on paper.

   Layer order (all in the root stacking context — sections must NOT create one):
     0  the field (glow canvas + ambient bloom)
     1  section backdrops (.sec__bg)
     2  the ink line canvas — draws only where it crosses paper
     3  section content
    50  nav
   ------------------------------------------------------------------------- */

:root {
  /* stocks */
  --ink:            #0B0A14;
  --ink-2:          #14121F;
  --ink-3:          #1E1B2E;
  --cream:          #F5F1E8;
  --cream-2:        #E8E3D6;
  --cream-mute:     #A39E92;

  /* the current */
  --indigo:         #4F46E5;
  --indigo-400:     #6366F1;
  --indigo-700:     #3730A3;
  --violet:         #6D28D9;
  --blue:           #2563EB;
  --blue-900:       #1E3A8A;
  --lavender:       #C7C2F8;

  /* text on paper */
  --on-cream:       #0B0A14;
  --on-cream-body:  #33302A;
  --on-cream-mute:  #6E6858;
  --on-cream-line:  rgba(11, 10, 20, .12);

  --border:         rgba(245, 241, 232, .08);
  --border-2:       rgba(245, 241, 232, .16);

  /* the one thing that can go wrong — added 2026-08-16 with the contact form,
     the first element on this site capable of failing. A warm brick that
     belongs to the ink/paper world rather than a generic UI red; 5.43:1 on
     Paper Cream, so it passes AA as body text. Documented in DESIGN.md. */
  --negative:       #B4322A;

  /* both exactly as documented in Virell/brand/assets/colors/tokens.json */
  --grad:           linear-gradient(135deg, #C7C2F8 0%, #4F46E5 50%, #2563EB 100%);  /* signal */
  --grad-charged:   linear-gradient(135deg, #4F46E5 0%, #2563EB 60%, #1E3A8A 100%);  /* deep   */

  --ease:           cubic-bezier(.2, .8, .2, 1);
  --gutter:         clamp(22px, 5vw, 72px);
  --section:        clamp(96px, 11vw, 168px);
  --block:          clamp(48px, 6vw, 88px);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--cream);
  font-family: Inter, system-ui, -apple-system, sans-serif;
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* a whisper of tooth over both stocks — never a theme, just less plastic */
body::after {
  content: "";
  position: fixed; inset: 0;
  z-index: 60;
  pointer-events: none;
  opacity: .42;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.96  0 0 0 0 0.94  0 0 0 0 0.91  0 0 0 0.06 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

::selection { background: var(--lavender); color: var(--ink); }

a { color: inherit; }

img, canvas { display: block; max-width: 100%; }

.wrap { max-width: 1200px; margin: 0 auto; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 12px 18px; border-radius: 999px;
  background: var(--indigo); color: var(--cream);
  font-size: 14px; text-decoration: none;
}
.skip-link:focus { left: 12px; top: 12px; }

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

/* ============ THE FIELD ============ */

.field {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.field__glow {
  position: absolute; inset: -20%;
  background:
    radial-gradient(ellipse 46% 38% at 28% 22%, rgba(79, 70, 229, .30), transparent 68%),
    radial-gradient(ellipse 40% 34% at 76% 68%, rgba(37, 99, 235, .22), transparent 70%),
    radial-gradient(ellipse 30% 28% at 62% 8%, rgba(109, 40, 217, .18), transparent 72%);
}
.field__canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

/* the same current, rendered as ink where it crosses paper */
.field__ink {
  position: fixed; inset: 0; z-index: 2;
  width: 100%; height: 100%;
  pointer-events: none;
}

/* ============ SECTION SHELL ============ */

/* no z-index here on purpose: sections must not open a stacking context, or the
   ink canvas can't slide between a paper backdrop and the type sitting on it */
.sec { position: relative; padding: var(--section) var(--gutter); }
.sec > .sec__bg { position: absolute; inset: 0; z-index: 1; }
.sec > *:not(.sec__bg) { position: relative; z-index: 3; }

.sec--ink { color: var(--cream); }
.sec--ink > .sec__bg {
  background: linear-gradient(to bottom,
    rgba(11, 10, 20, .94) 0%, rgba(11, 10, 20, .78) 16%,
    rgba(11, 10, 20, .78) 84%, rgba(11, 10, 20, .94) 100%);
}

.sec--cream { color: var(--on-cream); }
.sec--cream > .sec__bg { background: var(--cream); }

/* ============ TYPE ============ */

/* Section kickers. Reworked 2026-08-16 (Jan): the em-dash prefix is gone from
   every one of them, and they are no longer whispered. They were 12px mute grey
   with a leading "—", which read as a caption apologising for the heading under
   it; a section label is a signpost and should be legible at a glance. Now 13px
   at full cream, and the dash is not replaced by another ornament — the label
   stands on its own. */
.kicker {
  margin: 0 0 22px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--cream-2);
}
.sec--cream .kicker { color: var(--on-cream); }

.h-section {
  margin: 0;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(32px, 4.4vw, 60px);
  line-height: 1.04;
  letter-spacing: -.028em;
  /* 26ch, up from 20 (2026-08-16). At 20 the plain half of a heading could not
     finish on its own line, so the break landed mid-sentence and the italic
     started stranded at the end of line one — "One flat rate. *Nothing* / left
     for you to run." 26ch is wide enough for the longest first clause on the
     page to complete before the turn. */
  max-width: 26ch;
  text-wrap: balance;
}
/* The emphasis always starts its own line. These headings are built as two
   sentences — a statement and its turn — and the turn is the payload, so the
   break belongs at the full stop and nowhere else. Left to `text-wrap: balance`
   it lands wherever the line lengths happen to even out, which repeatedly split
   the first sentence and orphaned the first word of the second.
   Deliberately NOT applied to `.hero__title`: that line is one sentence and
   fits on one line at desktop, and blocking the em would break it in two. */
.h-section em, .close__pitch em { display: block; }
.h-section em, .hero__title em, .close__pitch em {
  font-style: italic; font-weight: 300;
  background: linear-gradient(100deg, #C7C2F8 0%, #8B83F3 42%, #6D7CEB 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.sec--cream .h-section em {
  background: linear-gradient(100deg, #4F46E5 0%, #2563EB 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}

.lede {
  margin: 26px 0 0;
  max-width: 56ch;
  font-size: 17px;
  color: rgba(245, 241, 232, .74);
  text-wrap: pretty;
}
.sec--cream .lede { color: var(--on-cream-mute); }

/* ============ BUTTONS ============ */

.btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 13px 22px;
  border: 1px solid transparent; border-radius: 999px;
  font-family: inherit; font-size: 14px; font-weight: 500; line-height: 1;
  text-decoration: none; white-space: nowrap;
  position: relative; overflow: hidden;
  transition: transform .25s var(--ease), background .25s var(--ease),
              box-shadow .25s var(--ease), color .25s var(--ease);
}
.btn__arrow { display: inline-block; transition: transform .35s var(--ease); }
.btn:hover .btn__arrow { transform: translateX(4px); }
.btn:active { transform: translateY(0); }

.btn--cream { background: var(--cream); color: var(--ink); }
.btn--cream::before {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 30%, rgba(255, 255, 255, .85) 50%, transparent 70%);
  transform: translateX(-120%);
  transition: transform .7s var(--ease);
  pointer-events: none;
}
.btn--cream:hover {
  background: #fff; transform: translateY(-2px);
  box-shadow: 0 16px 40px -12px rgba(199, 194, 248, .55), 0 0 0 1px rgba(199, 194, 248, .4);
}
.btn--cream:hover::before { transform: translateX(120%); }

.btn--ghost { color: var(--cream); }
.btn--ghost:hover { background: rgba(245, 241, 232, .08); }

.btn--ink { background: var(--ink); color: var(--cream); }
.btn--ink:hover {
  background: var(--indigo); transform: translateY(-2px);
  box-shadow: 0 16px 40px -14px rgba(79, 70, 229, .7);
}

.btn--lg { padding: 16px 28px; font-size: 15px; }

/* One route out of the hero, so it carries the glow the capsule used to. */
.hero__cta { margin-top: 38px; }
.hero__cta .btn--cream {
  box-shadow: 0 24px 60px -20px rgba(79, 70, 229, .55);
}

/* ============ BADGE (replaces the old stamp) ============ */

.badge {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px 7px 12px;
  border-radius: 999px;
  border: 1px solid rgba(79, 70, 229, .3);
  background: rgba(79, 70, 229, .1);
  color: var(--indigo);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  white-space: nowrap;
}
.badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 10px currentColor;
}
.badge--onCharged {
  border-color: rgba(245, 241, 232, .32);
  background: rgba(245, 241, 232, .14);
  color: var(--cream);
}

/* ============ NAV ============ */

.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  padding: clamp(15px, 1.8vw, 20px) var(--gutter);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px; letter-spacing: .04em;
  transition: background .3s var(--ease), border-color .3s var(--ease);
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: rgba(11, 10, 20, .72);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border-bottom-color: var(--border);
}

/* A 1200px bar rather than edge-to-edge, matching `.wrap` so the nav sits on the
   same grid as the page under it. Full-bleed, the brand and the CTA were pinned
   to opposite corners of a 1440px screen with a void between them; contained,
   they read as one bar. Three columns with the links in the middle one and 1fr
   on either side is what centres the links *truly* — space-between would only
   centre them if the brand and the button happened to be the same width. */
.nav__inner {
  max-width: 1200px; margin: 0 auto;
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: clamp(16px, 2vw, 28px);
}
/* Columns pinned rather than auto-placed: below 560px `.nav__links` goes
   display:none, and with auto-placement the CTA would then slide into the middle
   column and stop being right-aligned. */
.nav__brand { grid-column: 1; justify-self: start; }
.nav__links { grid-column: 2; justify-self: center; }
.nav__cta   { grid-column: 3; justify-self: end; }

.nav__brand { display: flex; align-items: center; gap: 10px; color: var(--cream); text-decoration: none; }
.nav__mark {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  background: conic-gradient(from 200deg, #4F46E5, #2563EB, #6D28D9, #4F46E5);
  box-shadow: 0 0 18px rgba(79, 70, 229, .55);
}
.nav__wordmark {
  font-family: Fraunces, Georgia, serif;
  font-size: 18px; font-weight: 500; letter-spacing: -.01em;
}

/* Equal-width columns, sized to the widest label. This is not cosmetic: it is
   what lets the highlight animate on transform alone. With links of different
   widths the pill has to animate `width` to match each one, and animating width
   is a layout property — it thrashes layout every frame. Equal columns mean the
   pill's width is written once and never changes, so the travel is pure
   transform and stays on the compositor. `1fr` columns in an auto-width grid
   resolve to the widest item's max-content, so there is no magic number to
   maintain when a link is added or renamed. */
.nav__links {
  position: relative;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: 4px;
}
/* Padding moved onto the links themselves so each one owns a hit area the
   highlight can sit inside. The visual gap between labels is now padding, not
   grid gap, which is what lets the pill travel without a dead stretch between. */
.nav__links a {
  position: relative; z-index: 1;
  padding: 8px 14px; border-radius: 999px;
  text-align: center;
  color: var(--cream-2);                    /* was cream-mute — too dim to read at 12px mono */
  text-decoration: none;
  transition: color .2s var(--ease);
}
.nav__links a:hover,
.nav__links a:focus-visible { color: var(--cream); }

/* The travelling highlight. Position and width are written by script.js on
   hover; everything here is the look and the easing. It fades rather than
   snapping, and because only one element moves, going from one link to the next
   reads as the outline gliding across rather than two separate things blinking. */
.nav__pill {
  position: absolute; top: 0; left: 0; z-index: 0;
  height: 100%; width: 0;
  border-radius: 999px;
  background: rgba(245, 241, 232, .07);
  border: 1px solid rgba(245, 241, 232, .16);
  opacity: 0;
  pointer-events: none;
  transform: translateX(0);
  /* transform and opacity only — both composited. `width` is deliberately not in
     here; see .nav__links above for why it never needs to animate. */
  transition: transform .34s var(--ease), opacity .22s var(--ease);
}
.nav__links.is-hovering .nav__pill { opacity: 1; }
/* First appearance shouldn't slide in from x=0 — it fades in where it belongs. */
.nav__pill.is-placing { transition: opacity .22s var(--ease); }

@media (prefers-reduced-motion: reduce) {
  .nav__pill { transition: opacity .22s linear; }
}

.nav__cta { padding: 9px 16px; font-family: Inter, sans-serif; font-size: 13px; }

/* ============ 1 · HERO ============ */

.hero {
  padding: 0 var(--gutter) clamp(80px, 10vw, 140px);
  text-align: center;
  display: flex; flex-direction: column; align-items: center;
}

/* The first screen belongs to the claim alone. `.hero__inner` owns a full
   viewport, which puts the run below the fold by construction — so nothing is
   animating in the corner of your eye while you read the line, and the run only
   plays when you scroll to it. Do not let anything else into this block. */
.hero__inner {
  /* a full viewport, exactly (2026-08-16). At 90svh the run title cleared the
     fold by 58px and leaked into the first screen, which put a second sentence
     about the AI under the one you were reading. 100svh + a bottom padding that
     reserves the cue means the first screen ends where the hero ends: the cue is
     the last thing on it, and the run is not visible until you scroll. */
  position: relative;
  min-height: 100svh;
  max-width: 940px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: clamp(96px, 14vh, 150px) 0 128px;
}
/* the hero shows the current at full strength — only a scrim for legibility */
.hero > .sec__bg {
  background:
    radial-gradient(ellipse 62% 46% at 50% 34%, rgba(11, 10, 20, .8) 0%, rgba(11, 10, 20, .42) 45%, transparent 74%),
    linear-gradient(to bottom, rgba(11, 10, 20, .55) 0%, transparent 22%, transparent 64%, var(--ink) 100%);
}

.eyebrow {
  display: inline-flex; align-items: center; gap: 12px;
  margin: 0;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  /* The kicker step. Was 11.5px/.2em — off the ramp on both values, and the
     smallest text in the hero, which is backwards: PRODUCT.md puts the whole
     job of saying what this product *is* on this line, because the headline is
     a promise rather than a category. Almost all traffic arrives cold from a
     cold email and has to place the product in about a second, so the line
     doing that work cannot be the quietest thing on the screen. */
  font-size: 13px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--cream);
  text-shadow: 0 1px 8px rgba(11, 10, 20, .7);
}
.eyebrow__bar { width: 24px; height: 1px; background: rgba(245, 241, 232, .35); }

.hero__title {
  margin: 30px 0 0;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(46px, 7.6vw, 108px);
  line-height: .95;
  letter-spacing: -.036em;
  text-wrap: balance;
  text-shadow: 0 2px 26px rgba(11, 10, 20, .6);
}

/* -- the hail: Virell introducing itself, in its own voice, to the buyer --
      It replaced a four-line `.hero__sub` paragraph on 2026-08-16. The hero's
      problem was never that it lacked a component; it was that it explained the
      product in prose, and a stranger arriving from a cold email does not read
      prose. This says the same thing in the first person, in a bright object.

      Three rules it must keep:
      1. **No input field.** A text box reads as a website chat widget, which is
         the exact category this product is not ("not a chatbot on the website —
         an email that feels like the agent was already waiting"). The message
         alone reads as something the machine wrote. An input would undo the
         whole positioning in the first half second.
      2. **It speaks to the buyer, not to a lead.** The visitor here is the
         agent. The run below has a cast — Dana is the `Lead`, Virell is the
         machine, `You` are the agent — and a greeting aimed at the visitor
         would scramble who is who before they have met anyone.
      3. **It is cream.** Paper is the brightest stock on ink, and it is the only
         pop available: the charged gradient is spent on exactly three surfaces
         by rule and a fourth would make it wallpaper. */
.hail {
  margin: 34px auto 0;
  width: 100%; max-width: 580px;
  text-align: left;
  padding: 13px 18px 16px;
  border: 1px solid rgba(11, 10, 20, .08);
  border-radius: 20px;
  background: var(--cream);
  color: var(--on-cream-body);
  box-shadow:
    0 30px 70px -34px rgba(11, 10, 20, .85),
    0 0 56px -22px rgba(79, 70, 229, .5),
    inset 0 1px 0 rgba(255, 255, 255, .7);
}
.hail__head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding-bottom: 11px;
  border-bottom: 1px solid var(--on-cream-line);
}
.hail__state {
  flex: none;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11.5px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase;
}
.hail__writing { color: var(--indigo); }
.hail__writing i { font-style: normal; animation: dots 1.4s steps(1) infinite; }
.hail__writing i:nth-child(2) { animation-delay: .2s; }
.hail__writing i:nth-child(3) { animation-delay: .4s; }
/* once it has said its piece the state stops claiming to be working and becomes
   the one standing fact about the product: it is never not running */
.hail__live { display: none; color: var(--on-cream-mute); }
.hail.is-done .hail__writing { display: none; }
.hail.is-done .hail__live { display: inline; }

/* Nothing may move while it types — same rule as the run's letters, solved
   better. The run reserves a measured `min-height` per breakpoint, which works
   but has to be re-derived whenever the copy or a column width changes (and it
   silently broke once when it wasn't). Here the height comes from a hidden copy
   of the finished text sitting in the same box, so the reserve is exact at every
   width by construction and there is nothing to re-measure, ever.
   `.hail__line` overlays it and is what actually gets typed into. */
.hail__text {
  position: relative;
  margin: 13px 0 0;
  font-size: 17px; line-height: 1.58;
  color: var(--on-cream-body);
}
.hail__ghost { visibility: hidden; }
.hail__line { position: absolute; inset: 0; }

.hero__note {
  margin: 20px 0 0;
  font-size: 14px; color: var(--cream-mute);
}

/* the cue closes the first screen and says, in words, what is below it. It is
   pinned to the bottom of the hero rather than flowing after the note, so the
   fold lands on the cue at every viewport height and nothing below it shows. */
.hero__cue {
  position: absolute; bottom: 34px; left: 0; right: 0;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  text-align: center; text-decoration: none;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--cream-mute);
  transition: color .4s var(--ease);
}
.hero__cue:hover { color: var(--cream-2); }
.hero__cue-line {
  width: 1px; height: 44px;
  background: linear-gradient(to bottom, rgba(199, 194, 248, .6), transparent);
}

/* -- the stage: the run, as three beats reading left to right --
      form fill → the reply writing itself → the slot filling on the calendar.
      The current is a background layer here (z-0), so it passes behind these
      panels and there is no lane to route it through. */

.hero__stage {
  margin-top: clamp(30px, 3.6vh, 46px);
  width: 100%; max-width: 1300px;
  display: flex; flex-direction: column; align-items: center;
}

/* says in one plain line what the three panels are about to show */
.run__title {
  margin: 0 0 clamp(22px, 2.4vw, 32px);
  max-width: 44ch;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  /* dropped from `pitch` to the documented `title` step 2026-08-16: the run has
     to clear one viewport, and this line was spending height the panels needed.
     A step off the ramp is not the way to buy that — take the next one down. */
  font-size: clamp(20px, 2vw, 28px);
  line-height: 1.14;
  letter-spacing: -.022em;
  color: var(--cream);
  text-wrap: balance;
  text-shadow: 0 2px 22px rgba(11, 10, 20, .6);
}
/* the second half is the whole claim — it gets its own line */
.run__title b {
  display: block;
  margin-top: .2em;
  font-weight: 400; font-style: italic;
  color: var(--lavender);
}

.run {
  list-style: none; margin: 0; padding: 0;
  width: 100%;
  display: grid;
  /* the thread column is deliberately greedy and the connectors are thin: the
     whole run has to clear one desktop viewport, and horizontal room is the only
     currency there is — every character the letter doesn't wrap is a line of
     height the run doesn't spend.
     2026-08-16: the thread came back from 2fr to 1.68 and the side beats went
     up to 1fr. At 2fr the letter ran ~600px wide and the messages read as three
     wide slabs, while the form panel was narrow enough to wrap its own header.
     The narrower measure also fills the reserve the letter already had, so the
     dead band above the signature is gone — tighter and shorter at once. */
  grid-template-columns:
    minmax(0, 1fr) clamp(74px, 6.4vw, 104px)
    minmax(0, 1.68fr) clamp(74px, 6.4vw, 104px)
    minmax(0, 1fr);
  /* the thread column is now the tallest thing in the run by some margin, so the
     trigger and the outcome centre against it rather than stretching to match */
  align-items: center;
  text-align: left;
}
.beat { display: flex; }
.beat > .panel { width: 100%; }

/* each side panel sits level with the message it belongs to, not with the middle
   of a column it has nothing to do with: the form pairs with the 9:43 reply at
   the top, the calendar with the 9:52 confirm at the bottom. That is the run's
   causality expressed as position.
   Selected by data-role, not :first-of-type — every child here is an li, so
   :first-of-type would match the beats, not the connectors. */
.run > .beat:first-child { align-self: start; }
.run > .beat:last-child  { align-self: end; }
.run > [data-role="link-1"] { align-self: start; margin-top: 104px; }
.run > [data-role="link-2"] { align-self: end; margin-bottom: 92px; }

.panel {
  position: relative;
  padding: 12px 16px 13px;
  border: 1px solid var(--border); border-radius: 20px;
  background: rgba(20, 18, 31, .72);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  opacity: 0; transform: translateY(12px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.panel.is-on { opacity: 1; transform: none; }

.panel__head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11.5px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--cream-mute);
}
.panel__label { display: inline-flex; align-items: center; gap: 9px; }
.panel__time { flex: none; }

/* the AI attribution. Without this the run reads as a person doing the work by
   hand — which is exactly the wrong story. */
.ai-tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 9px;
  border-radius: 999px;
  /* the deep gradient, not the signal one: cream type is the point here (matching
     the founding-rate badge on the pricing card) and `--grad` opens on lavender,
     where cream would be about 1.3:1 and unreadable. `--grad-charged` starts at
     indigo and only gets darker, so the label holds contrast across the pill. */
  background: var(--grad-charged);
  color: var(--cream);
  font-size: 10.5px; font-weight: 500; letter-spacing: .1em;
  white-space: nowrap;
}
.ai-tag::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--cream); opacity: .75;
}

/* Dana is the one participant in the run nobody at Virell wrote. The AI panels
   carry a gradient pill; hers is deliberately the opposite — outlined, unlit —
   so the machine/human split is a thing you can see rather than infer. */
.human-tag {
  display: inline-flex; align-items: center;
  padding: 3px 8px;
  border: 1px solid var(--border-2); border-radius: 999px;
  color: var(--cream-mute);
  font-size: 10.5px; font-weight: 500; letter-spacing: .1em;
  white-space: nowrap;
}

.panel__state { flex: none; }
/* the header only claims to be writing once it actually is — during the log's
   reading and calendar-check beats there is nothing being written yet */
.panel__writing { color: var(--indigo-400); display: none; }
.panel--mail.is-writing .panel__writing { display: inline; }
.panel__writing i {
  font-style: normal;
  animation: dots 1.4s steps(1) infinite;
}
.panel__writing i:nth-child(2) { animation-delay: .2s; }
.panel__writing i:nth-child(3) { animation-delay: .4s; }
@keyframes dots { 0%, 60% { opacity: 0; } 61%, 100% { opacity: 1; } }
.panel--mail.is-sent .panel__writing { display: none; }

.panel__dot {
  position: relative;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--indigo-400); flex: none;
}
.panel__dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(99, 102, 241, .7);
}
.panel.is-on .panel__dot::after { animation: ping 2200ms var(--ease) infinite; }
@keyframes ping {
  0%   { box-shadow: 0 0 0 0 rgba(99, 102, 241, .7); }
  70%  { box-shadow: 0 0 0 10px rgba(99, 102, 241, 0); }
  100% { box-shadow: 0 0 0 0 rgba(99, 102, 241, 0); }
}

/* 1 — the form fill */
.form { margin: 0; }
.form__row {
  display: grid; grid-template-columns: 76px minmax(0, 1fr);
  align-items: baseline; gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid rgba(245, 241, 232, .05);
  opacity: 0; transform: translateY(5px);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.form__row:last-child { border-bottom: 0; padding-bottom: 2px; }
.panel--form.is-on .form__row { opacity: 1; transform: none; }
.panel--form.is-on .form__row:nth-child(1) { transition-delay: 120ms; }
.panel--form.is-on .form__row:nth-child(2) { transition-delay: 300ms; }
.panel--form.is-on .form__row:nth-child(3) { transition-delay: 480ms; }
.form dt {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--cream-mute);
}
.form dd { margin: 0; font-size: 15px; color: var(--cream-2); }

/* the connector between beats — runs left to right, the way the strip reads */
.link {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px;
  padding: 0 10px;
}
.link__line {
  position: relative;
  width: 100%; height: 2px; border-radius: 999px;
  background: linear-gradient(to right, rgba(99, 102, 241, .1), var(--indigo));
  transform: scaleX(0); transform-origin: left;
  transition: transform .55s var(--ease);
}
.link.is-on .link__line { transform: scaleX(1); }
.link__pulse {
  position: absolute; top: 50%; left: 0;
  width: 6px; height: 6px; margin-top: -3px; border-radius: 50%;
  background: var(--lavender);
  box-shadow: 0 0 14px 2px rgba(199, 194, 248, .9);
  opacity: 0;
}
.link.is-on .link__pulse { animation: flow 1500ms linear 400ms infinite; }
@keyframes flow {
  0%   { left: 0;    opacity: 0; }
  22%  { opacity: 1; }
  78%  { opacity: 1; }
  100% { left: 100%; opacity: 0; }
}
/* the connector caption names who is acting — it carries the claim, so it is
   sized to be read, not to be decorative */
.link__note {
  position: absolute; top: calc(50% + 18px); left: 4px;
  width: calc(100% - 8px);
  text-align: center;
  font-size: 12.5px; line-height: 1.45;
  color: var(--cream-mute);
  opacity: 0; transition: opacity .5s var(--ease) .25s;
}
.link__note b {
  display: block;
  font-weight: 500;
  color: var(--lavender);
}
.link.is-on .link__note { opacity: 1; }

/* 2 — the exchange. Three messages stacked in one column: Virell writes, Dana
      answers, Virell confirms and books it. Paper is Virell's stock; Dana's
      message stays on ink, so at a glance you can see which side of the thread
      the product is doing the work on. */
.thread {
  width: 100%;
  display: flex; flex-direction: column;
  gap: 10px;
}
/* the two Virell messages carry the full lift; a stack of three heavy shadows
   would read as clutter, so Dana's sits flat between them */
.thread > .panel { flex: none; }

.panel--reply {
  align-self: flex-end;
  width: min(100%, 74%);
  background: rgba(30, 27, 46, .78);
  border-color: var(--border-2);
  box-shadow: none;
}
.panel--reply .panel__head { padding-bottom: 8px; }
.reply__text {
  margin: 9px 0 0;
  font-size: 15px; line-height: 1.5;
  color: var(--cream-2);
  min-height: 1.5em;
}

/* the confirm is short and decisive — it gets no signature block, because by
   this point the question of who wrote it has already been answered */
.panel--confirm .mail__text { min-height: 4.8em; }

.panel--mail {
  border-color: rgba(11, 10, 20, .08);
  background: var(--cream);
  color: var(--on-cream-body);
  box-shadow:
    0 30px 70px -34px rgba(11, 10, 20, .85),
    0 0 56px -22px rgba(79, 70, 229, .5),
    inset 0 1px 0 rgba(255, 255, 255, .7);
}
.panel--mail .panel__head {
  border-bottom-color: var(--on-cream-line);
  color: var(--on-cream-mute);
}
.panel--mail .panel__time { opacity: 0; transition: opacity .5s var(--ease); }
.panel--mail.is-sent .panel__time { opacity: 1; }

.mail__to {
  margin: 10px 0 0;
  font-size: 13.5px; color: var(--on-cream-mute);
}
.mail__to span { color: var(--on-cream); }

/* Both letters reserve the height their finished text needs, so nothing below
   them shifts while they type. The reserve is per breakpoint because the line
   count is: at desktop width the reply lands in 4 lines and the confirm in 2,
   and these values are measured, not guessed. If the copy in either message
   changes, re-measure — an under-reserve shows up as the panel growing and
   shunting everything under it mid-animation. */
/* The reserve is a function of how many lines the letter wraps to, which is a
   function of the column, which is a function of the viewport — so it is banded,
   and the DEFAULT is the generous value. Get this backwards and the failure mode
   is a panel growing mid-type; this way the worst case is a little slack.
   Measured 2026-08-16 by wrapping both strings across text widths 300–520px:
     text ≥ 410px → letter 3 lines, confirm 2   (only above ~1260px viewport)
     text 340–400 → letter 4 lines, confirm 2
     text 310–330 → letter 4 lines, confirm 3
   Hence: 6.4em/4.8em everywhere by default, tightened only above 1300px (which
   is 1260 plus margin), and deepened again below 1000px where the run is one
   column at 520px. Re-derive this table if either message changes. */
.mail__text {
  margin: 10px 0 0;
  font-size: 15px; line-height: 1.58;
  min-height: 6.4em;
}
/* the tight band: above 1300px the thread column is wide enough that the letter
   lands in 3 lines and the confirm in 2, so the reserve comes down to what they
   actually take. This is the state the 809px one-viewport budget is measured in.
   It has to sit AFTER the base rule, not before it — same specificity, so source
   order decides, and above it the base 6.4em quietly wins. */
@media (min-width: 1300px) {
  .mail__text { min-height: 4.8em; }
  .panel--confirm .mail__text { min-height: 3.2em; }
}

/* a block cursor, not a hairline — the letter should read as machine output
   being produced, which a terminal caret says and a text-cursor doesn't */
.mail__text .caret {
  display: inline-block; width: .5em; height: 1.02em;
  margin-left: 3px; vertical-align: -.16em;
  background: var(--indigo);
  animation: blink 1s steps(1) infinite;
}
@keyframes blink { 0%, 48% { opacity: 1; } 52%, 100% { opacity: 0; } }

/* the signature is where the whole claim lands, so the attribution sits right
   next to it: it goes out as the agent, and Virell is what wrote it */
.mail__sig {
  margin: 12px 0 0; font-size: 15px; font-weight: 500; color: var(--on-cream);
  opacity: 0; transition: opacity .5s var(--ease);
}
.mail__sig em {
  display: block; margin-top: 3px;
  font-style: normal; font-size: 12.5px; font-weight: 400;
  color: var(--indigo);
}
.panel--mail.is-signed .mail__sig { opacity: 1; }

/* The AI's working log, sitting inside the message it produced (moved in from a
   separate card below the panel, 2026-08-16). Below the panel it read as a
   caption *about* the email; inside it, above the letter, it reads as the
   machine that wrote it — which is the point. Order on screen is the order of
   events: read the form, check the calendar, then write. This band carries the
   only mention of the calendar check anywhere on the run, so it is mechanism
   copy, not decoration. */
.ailog {
  list-style: none;
  margin: 9px 0 0; padding: 8px 12px;
  border: 1px solid rgba(79, 70, 229, .16); border-radius: 10px;
  background: rgba(79, 70, 229, .055);
  display: grid; gap: 5px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  /* 12px, not the 11px mono-label floor: these lines are read, not glanced at —
     they carry the mechanism. The Legibility Floor puts meaning at 12px+. */
  font-size: 12px; line-height: 1.45; letter-spacing: .02em;
  color: var(--on-cream-mute);
}
.ailog__line {
  display: grid; grid-template-columns: 11px minmax(0, 1fr);
  align-items: start; gap: 9px;
  opacity: 0; transform: translateY(4px);
  transition: opacity .45s var(--ease), transform .45s var(--ease), color .45s var(--ease);
}
.ailog__line.is-on { opacity: .72; transform: none; }
/* the step being worked is lit; finished steps fall back to a record of it */
.ailog__line.is-active { opacity: 1; color: var(--indigo); }
.ailog__line--done.is-on { opacity: 1; color: var(--indigo); font-weight: 500; }

.ailog__mark {
  position: relative; top: .36em; justify-self: center;
  width: 5px; height: 5px; border-radius: 50%;
  background: currentColor;
}
.ailog__line.is-active .ailog__mark { animation: logpulse 1.2s ease-in-out infinite; }
@keyframes logpulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(79, 70, 229, .6); }
  50%      { box-shadow: 0 0 0 5px rgba(79, 70, 229, 0); }
}
.ailog__line--done .ailog__mark {
  top: 0; width: auto; height: auto;
  border-radius: 0; background: none;
  font-size: 12px; line-height: 1.4;
}
.ailog__line--done .ailog__mark::before { content: "\2713"; color: var(--indigo); }

/* 3 — the booking */
.cal { margin-top: 10px; }
.cal__slot {
  display: grid; grid-template-columns: 40px minmax(0, 1fr);
  align-items: center; gap: 12px;
  min-height: 32px;
}
.cal__t {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11.5px; letter-spacing: .06em;
  color: var(--cream-mute);
}
.cal__rule { height: 1px; background: rgba(245, 241, 232, .07); }

.cal__slot--book { min-height: 46px; }
.cal__event {
  display: flex; flex-direction: column; gap: 1px;
  padding: 7px 12px;
  border-radius: 10px;
  border-left: 3px solid var(--indigo);
  background: rgba(79, 70, 229, .18);
  box-shadow: 0 0 26px -8px rgba(79, 70, 229, .8);
  transform: scaleX(.4); transform-origin: left; opacity: 0;
  transition: transform .55s var(--ease), opacity .4s var(--ease);
}
.cal__slot--book.is-booked .cal__event { transform: none; opacity: 1; }
.cal__event b { font-size: 13.5px; font-weight: 500; color: var(--cream); }
.cal__event i { font-style: normal; font-size: 12.5px; color: rgba(245, 241, 232, .62); }

/* The payoff. It used to be a 15px mute three-clause caption that recapped what
   you had just watched — the one moment on the page where the reader is fully
   convinced, spent on a line built to be skipped. It is now one line on the
   documented `title` step, in the page's own voice: the fact, then the twist in
   lavender italic. Keep it to ONE line at desktop — if the copy changes, check
   it still is one, because two lines here reads as a caption again. */
.hero__caption {
  margin: 26px 0 0; max-width: none;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(20px, 2vw, 28px);
  line-height: 1.18;
  letter-spacing: -.018em;
  color: var(--cream);
  text-wrap: balance;
  text-shadow: 0 2px 22px rgba(11, 10, 20, .6);
}
.hero__caption em {
  font-style: italic;
  color: var(--lavender);
}

/* Illustration disclosure. Quiet on purpose — it has to be legible and
   findable without competing with the payoff line it sits under. Small, but
   never below 12px and never dimmer than this: a disclosure nobody can read
   is not a disclosure. */
.demo-note {
  margin: 16px 0 0;
  max-width: 62ch;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: .04em;
  color: rgba(163, 158, 146, .92);
}

/* Centred with the rest of the close, and given real air. At 14px it clung to
   the pitch like a caption on the headline, which put a disclaimer between the
   payoff line and the CTA at exactly the moment the reader is deciding. */
.demo-note--close { margin: 26px auto 0; max-width: 54ch; }

/* ============ 2 · PROOF ============ */

/* Two bars on one shared scale, each with the who and the how-long spelled out
   in words. The previous build was a single 8px track with two hairline markers
   and mono tags — clean, but you had to work out what you were looking at. */
.ruler { margin: clamp(56px, 7vw, 92px) 0 0; }
.ruler__caption {
  font-size: 15px;
  color: var(--cream-2);
}

.ruler__rows {
  display: flex; flex-direction: column; gap: 22px;
  margin-top: 28px;
}
/* who | bar, with the duration printed at the end of its own bar. The numeric
   0h–15h axis that used to sit under this is gone: both durations are spelled
   out in words now, so it was one more small thing to squint at for nothing. */
.ruler__row {
  display: grid; grid-template-columns: 200px minmax(0, 1fr);
  align-items: center; gap: 22px;
}
.ruler__who {
  margin: 0;
  font-size: 15px; font-weight: 500;
  color: var(--cream-mute);
}
.ruler__row--virell .ruler__who { color: var(--lavender); }

.ruler__track {
  position: relative;
  display: flex; align-items: center; gap: 14px;
  min-height: 26px;
}
.ruler__bar {
  height: 18px; border-radius: 999px;
  transform: scaleX(0); transform-origin: left;
  flex: none;
}
/* two minutes against fifteen hours is 0.22% — floored at 8px so it is visible
   at all. The foot note says so, rather than quietly lying about the scale. */
.ruler__bar--virell {
  width: 8px;
  background: var(--grad);
  box-shadow: 0 0 22px 2px rgba(79, 70, 229, .8);
}
.ruler__bar--agent {
  flex: 1 1 auto; min-width: 0;
  background: linear-gradient(90deg, rgba(163, 158, 146, .18), rgba(163, 158, 146, .5));
}
.ruler.is-live .ruler__bar--virell { animation: fill 420ms var(--ease) 200ms both; }
.ruler.is-live .ruler__bar--agent { animation: fill 2000ms var(--ease) 700ms both; }
@keyframes fill { to { transform: scaleX(1); } }

.ruler__value {
  font-size: 15px; font-weight: 500; color: var(--cream);
  white-space: nowrap;
  opacity: 0;
}
.ruler__value--mute { color: var(--cream-mute); font-weight: 400; }
.ruler.is-live .ruler__value { animation: strike 500ms var(--ease) 700ms both; }
.ruler.is-live .ruler__row:last-child .ruler__value { animation-delay: 2500ms; }
@keyframes strike { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }

.ruler__foot {
  margin: 20px 0 0 222px;        /* aligns to the bar column: 200 + 22 gap */
  font-size: 13.5px; color: rgba(163, 158, 146, .8);
}

.stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
  margin: var(--block) 0 0;
}
.stat {
  margin: 0;
  padding: clamp(24px, 2.6vw, 34px);
  border: 1px solid var(--border); border-radius: 20px;
  background: var(--ink-2);
}
.stat dt {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--cream-mute);
}
.stat__figure {
  margin: 18px 0 14px;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(40px, 5vw, 68px);
  line-height: 1; letter-spacing: -.03em;
  color: var(--cream);
}
.stat__note { margin: 0; font-size: 15.5px; line-height: 1.55; color: rgba(245, 241, 232, .62); }

.card-charged {
  background: var(--grad-charged);
  border-color: transparent;
  color: var(--cream);
  position: relative; overflow: hidden;
}
.card-charged::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse 70% 60% at 18% 0%, rgba(199, 194, 248, .4), transparent 58%);
  pointer-events: none;
}
.card-charged > * { position: relative; }
/* Virell's own answer isn't another data cell — it is the charged one */
.stat--charged {
  background: var(--grad-charged);
  border-color: transparent;
  box-shadow: inset 0 90px 130px -80px rgba(199, 194, 248, .8),
              0 30px 70px -40px rgba(79, 70, 229, .8);
}
.stat--charged dt { color: rgba(245, 241, 232, .8); }
.stat--charged .stat__note { color: rgba(245, 241, 232, .85); }

/* every number on this page is somebody else's research, so it says whose.
   Cold traffic has no reason to believe a stat on a stranger's site — the
   presence of a citation line does most of that work whether or not it's read. */
.sources {
  margin: 20px 0 0;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; line-height: 1.75; letter-spacing: .04em;
  color: var(--cream-mute);
}
.sources a {
  color: var(--cream-2);
  text-decoration: underline;
  text-decoration-color: var(--border-2);
  text-underline-offset: 3px;
  transition: color .3s var(--ease), text-decoration-color .3s var(--ease);
}
.sources a:hover { color: var(--cream); text-decoration-color: var(--indigo-400); }
.sources__sep { padding: 0 7px; opacity: .5; }

/* ============ 3 · HOW IT WORKS ============ */

.days {
  list-style: none;
  margin: var(--block) 0 0; padding: 0;
  border-top: 1.5px solid var(--on-cream);
}
.day {
  display: grid; grid-template-columns: 140px 1fr; gap: clamp(18px, 3vw, 44px);
  padding: clamp(26px, 3vw, 38px) 0;
  border-bottom: 1px solid var(--on-cream-line);
}
.day__label {
  margin: 0; padding-top: 5px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--on-cream-mute);
}
.day--live .day__label { color: var(--indigo); }
.day--live .day__label::after {
  content: ""; display: inline-block;
  width: 6px; height: 6px; margin-left: 8px; border-radius: 50%;
  background: var(--indigo);
  box-shadow: 0 0 0 3px rgba(79, 70, 229, .18);
  vertical-align: middle;
}
.day__body { max-width: 62ch; }
.day__name {
  margin: 0;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(20px, 2vw, 28px);     /* the documented `title` step */
  line-height: 1.16; letter-spacing: -.018em;
  color: var(--on-cream);
}
.day__note { margin: 12px 0 0; font-size: 16px; color: var(--on-cream-mute); }

/* ============ 4 · PRICING ============ */

/* 8/5 with a tighter gap, up from 7/5 at clamp(36,5vw,76) — 2026-08-16. The
   longest offer bullet needed 646px of text and had 632, so it broke with one
   word ("out") alone on a second line. The width came out of the price card,
   which could afford it: its widest line is the terms row at 322px against 357
   of content, so nothing in there moved. */
.offer__grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(36px, 5vw, 76px);
  align-items: start;
}
/* Above 1264px the copy column takes the extra width, because that is exactly
   where it buys the longest bullet its single line (it needs 646px of text and
   7/5 gives 632). Below that it cannot win anyway — the bullet wraps at 7/5 and
   at 8/5 alike — and taking the width from the card there costs something real:
   at 1180 the card's terms row drops to two lines. So the wide ratio is scoped
   to the range where it is a gain and nothing else has to pay for it. */
@media (min-width: 1264px) {
  .offer__grid {
    grid-template-columns: minmax(0, 8fr) minmax(0, 5fr);
    gap: clamp(36px, 4vw, 64px);
  }
}
.offer__list {
  list-style: none;
  margin: var(--block) 0 0; padding: 0;
  border-top: 1px solid var(--border);
}
.offer__list li {
  position: relative;
  padding: 18px 0 18px 22px;
  border-bottom: 1px solid var(--border);
  font-size: 16px;
  color: rgba(245, 241, 232, .78);
}
.offer__list li::before {
  content: ""; position: absolute; left: 0; top: 28px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--indigo-400);
  box-shadow: 0 0 12px rgba(99, 102, 241, .8);
}

.offer__card {
  padding: clamp(32px, 3.4vw, 48px);
  border-radius: 24px;
  box-shadow: 0 40px 90px -40px rgba(79, 70, 229, .85);
}
.offer__phase {
  margin: 22px 0 0;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(245, 241, 232, .75);
}
.offer__price { margin: 10px 0 0; display: flex; align-items: baseline; gap: 10px; }
.offer__amount {
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(52px, 6.4vw, 92px);
  line-height: 1; letter-spacing: -.035em;
}
.offer__per { font-size: 16px; color: rgba(245, 241, 232, .8); }
/* Was 11px/.08em — below every documented mono step and off the ramp's tracking,
   which made "cancel any time" (the objection-killer on this card) the quietest
   text in it. Now the monoNav step, 12px/.04em. Not the 13px kicker step: at
   .16em that string needs ~425px and the card gives it ~338px at 1200, so it
   broke to "cancel / any time" — the same two-line failure the comment above
   .offer__grid describes. Bigger and one line beats bigger and wrapped. */
.offer__terms {
  margin: 18px 0 0;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px; letter-spacing: .04em;
  color: rgba(245, 241, 232, .8);
}
.offer__cta { margin-top: 32px; width: 100%; justify-content: center; }
.offer__note { margin: 18px 0 0; font-size: 13.5px; line-height: 1.55; color: rgba(245, 241, 232, .78); }

/* ============ 5 · FAQ ============ */

.faq__wrap { max-width: 880px; margin: 0 auto; }
.faq__list { margin-top: var(--block); border-top: 1.5px solid var(--on-cream); }

.faq__item { border-bottom: 1px solid var(--on-cream-line); }
.faq__item summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  padding: clamp(22px, 2.4vw, 30px) 0;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(20px, 1.9vw, 26px);
  line-height: 1.2; letter-spacing: -.018em;
  color: var(--on-cream);
  transition: color .2s var(--ease);
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover { color: var(--indigo); }
.faq__item summary::after {
  content: ""; flex: none;
  width: 13px; height: 13px;
  background:
    linear-gradient(var(--on-cream), var(--on-cream)) center/100% 1.5px no-repeat,
    linear-gradient(var(--on-cream), var(--on-cream)) center/1.5px 100% no-repeat;
  transition: transform .3s var(--ease);
}
.faq__item[open] summary::after { transform: rotate(45deg); }
.faq__item p {
  margin: 0 0 clamp(22px, 2.4vw, 30px);
  max-width: 66ch;
  font-size: 16px;
  color: var(--on-cream-mute);
}

/* ============ 6 · THREAD ============ */

.trail {
  position: relative;
  margin: var(--block) 0 0;
  padding-left: clamp(30px, 4vw, 56px);
  max-width: 860px;
}
.trail__spine {
  position: absolute; left: 0; top: 10px; bottom: 10px;
  width: 2px; border-radius: 999px;
  background: var(--grad);
  box-shadow: 0 0 18px rgba(79, 70, 229, .6);
  transform: scaleY(0); transform-origin: top;
}
.trail.is-live .trail__spine { animation: grow 900ms var(--ease) both; }

.slip {
  position: relative;
  margin-bottom: 14px;
  padding: clamp(20px, 2.4vw, 28px);
  border: 1px solid var(--border); border-radius: 20px;
  background: var(--ink-2);
  opacity: 0; transform: translateY(16px);
}
.slip::before {
  content: ""; position: absolute; top: 30px;
  left: calc(-1 * clamp(30px, 4vw, 56px));
  width: 9px; height: 9px; margin-left: -3.5px; border-radius: 50%;
  background: var(--indigo-400);
  box-shadow: 0 0 0 4px rgba(79, 70, 229, .16), 0 0 16px rgba(99, 102, 241, .8);
}
.slip::after {
  content: ""; position: absolute; top: 34px;
  left: calc(-1 * clamp(30px, 4vw, 56px));
  width: clamp(30px, 4vw, 56px); height: 1px;
  background: linear-gradient(90deg, rgba(99, 102, 241, .8), rgba(99, 102, 241, .1));
}
.trail.is-live .slip { animation: rise 620ms var(--ease) both; }
.trail.is-live .slip:nth-child(2) { animation-delay: 320ms; }
.trail.is-live .slip:nth-child(3) { animation-delay: 520ms; }
.trail.is-live .slip:nth-child(4) { animation-delay: 720ms; }
.trail.is-live .slip:nth-child(5) { animation-delay: 920ms; }
@keyframes rise { to { opacity: 1; transform: none; } }

.slip__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 18px;
  margin-bottom: 14px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
}
.slip__when { color: var(--lavender); }
.slip__you { color: var(--cream-mute); }
.slip__text { margin: 0; font-size: 16px; color: rgba(245, 241, 232, .8); }

/* the only charged surface in the thread: the reply that finally lands */
.slip--reply {
  background: var(--grad-charged);
  border-color: transparent;
  box-shadow: inset 0 90px 120px -80px rgba(199, 194, 248, .75);
}
.slip--reply .slip__when { color: var(--cream); }
.slip--reply .slip__you { color: rgba(245, 241, 232, .78); }
.slip--reply .slip__text { color: var(--cream); }
.slip--reply .badge { margin-top: 18px; }
.slip--reply::before { background: var(--lavender); box-shadow: 0 0 0 4px rgba(199, 194, 248, .2), 0 0 20px rgba(199, 194, 248, .9); }

/* Centred, not left-aligned: the close repeats the hero's line ("that's a lead
   that never went cold") and the hero is centre-composed, so centring makes the
   bookend literal instead of leaving the last words of the page floating in the
   left half of a very wide dark band. */
.close {
  max-width: 720px;
  margin: clamp(64px, 8vw, 110px) auto 0;
  padding-top: clamp(40px, 5vw, 64px);
  border-top: 1px solid var(--border);
  text-align: center;
}
.close__pitch {
  margin: 0 auto; max-width: 22ch;
  font-family: Fraunces, Georgia, serif;
  font-weight: 400;
  font-size: clamp(26px, 3.2vw, 42px);
  line-height: 1.12; letter-spacing: -.024em;
  text-wrap: balance;
}
.close__actions {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(18px, 3vw, 32px);
  flex-wrap: wrap;
  margin-top: 36px;
}
/* On its own line under the buttons rather than third item in the action row.
   Beside them it read as a third choice competing with the CTA; below, it is
   what it actually is — the terms attached to the button above it. */
.close__terms {
  margin: 24px 0 0;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px; letter-spacing: .16em;
  color: var(--cream-mute);
}

/* ============ FOOTER ============ */

.foot { position: relative; padding: clamp(64px, 8vw, 100px) var(--gutter) 34px; }
.foot > .sec__bg { position: absolute; inset: 0; z-index: 1; background: var(--ink); }
.foot > *:not(.sec__bg) { position: relative; z-index: 3; }

.foot__top {
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1.2fr);
  gap: clamp(32px, 5vw, 64px);
  max-width: 1200px; margin: 0 auto;
  padding-bottom: clamp(40px, 5vw, 64px);
  border-bottom: 1px solid var(--border);
}
.foot__lockup { display: flex; align-items: center; gap: 10px; margin: 0; }
.foot__wordmark { font-family: Fraunces, Georgia, serif; font-size: 20px; font-weight: 500; }
.foot__line { margin: 16px 0 0; max-width: 32ch; font-size: 14.5px; color: var(--cream-mute); }

.foot__col { display: flex; flex-direction: column; align-items: flex-start; gap: 9px; }
.foot__head {
  margin: 0 0 6px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--cream-mute);
}
.foot__col a { font-size: 14.5px; color: rgba(245, 241, 232, .78); text-decoration: none; transition: color .2s; }
.foot__col a:hover { color: var(--lavender); }
.foot__contact-note { margin: 6px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--cream-mute); max-width: 34ch; }

.foot__bottom {
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  max-width: 1200px; margin: 26px auto 0;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
  color: rgba(163, 158, 146, .7);
}
.foot__bottom p { margin: 0; }

/* Legal Notice + Privacy must be reachable from every page in one click
   (§ 5 DDG: "leicht erkennbar, unmittelbar erreichbar"). Same size as the
   rest of the bottom row, but readable rather than greyed out — a link that
   has to be hunted for does not count as directly accessible. */
.foot__legal { display: flex; gap: 20px; flex-wrap: wrap; }
.foot__legal a {
  color: rgba(245, 241, 232, .82);
  text-decoration: none;
  border-bottom: 1px solid rgba(245, 241, 232, .24);
  padding-bottom: 2px;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.foot__legal a:hover { color: var(--cream); border-bottom-color: var(--lavender); }

/* ============ 6 · MESSAGE (contact form) ============
   Paper section. The form is the artifact here, so it gets the same treatment
   as the letters in the run: ink on cream, generous line-height, nothing
   chrome-y. Inputs are underlines rather than boxes — a boxed form on this page
   would read as a web app, and the whole promise is that there is no app. */

.contact__inner { max-width: 720px; margin: 0 auto; }

.close__alt { margin: 14px 0 0; }
.close__alt a {
  font-family: Inter, sans-serif;
  font-size: 14.5px;
  color: rgba(245, 241, 232, .78);
  text-decoration: none;
  border-bottom: 1px solid rgba(245, 241, 232, .3);
  padding-bottom: 2px;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.close__alt a:hover { color: var(--cream); border-bottom-color: var(--lavender); }

.cform { margin: 40px 0 0; }

.cform__row { margin: 0 0 26px; }

.cform__label {
  display: block;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--on-cream-mute);
  margin: 0 0 8px;
}

.cform__input {
  display: block;
  width: 100%;
  font-family: Inter, system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.5;
  color: var(--on-cream);
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(11, 10, 20, .26);
  border-radius: 0;
  padding: 8px 2px 10px;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
  -webkit-appearance: none;
  appearance: none;
}

.cform__input::placeholder { color: var(--on-cream-mute); opacity: .72; }

.cform__input:focus {
  outline: none;
  border-bottom-color: var(--indigo);
  box-shadow: 0 1px 0 0 var(--indigo);
}

/* Only scold after they have actually interacted — plain :invalid would mark
   every required field red on first paint, before anyone has done anything
   wrong. :user-invalid is the selector that means exactly this, and it is the
   right one here: the ":not(:placeholder-shown)" trick people reach for
   silently fails on any field without a placeholder, which is most of them. */
.cform__input:user-invalid { border-bottom-color: var(--negative); }

.cform__input--area { resize: vertical; min-height: 130px; }

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

/* Column, not row. Beside the button the privacy line sat on the same baseline
   and read as a second element of equal weight, which is how the submit ended up
   feeling optional. Stacked, the order is what the eye needs: fields, the one
   action, then the fine print that qualifies it. */
.cform__foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
  margin: 36px 0 0;
}

.cform__legal {
  flex: none;
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--on-cream-mute);
}
.cform__legal a { color: var(--indigo); text-decoration: underline; text-underline-offset: 2px; }

.cform__status {
  margin: 22px 0 0;
  font-size: 16px;
  line-height: 1.6;
  min-height: 1.55em;             /* reserved, so a reply never shifts the page */
}
.cform__status.is-pending { color: var(--on-cream-mute); }
.cform__status.is-ok      { color: var(--indigo); font-weight: 500; }
.cform__status.is-bad     { color: var(--negative); }

.cform button[disabled] { opacity: .55; cursor: default; }

@media (max-width: 640px) {
  .cform__foot { gap: 16px; }
  .cform__foot .btn { width: 100%; justify-content: center; }
}

/* ============ SCROLL REVEALS ============ */

[data-reveal] {
  opacity: 0; transform: translateY(16px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* ============ RESPONSIVE ============ */

@media (max-width: 1000px) {
  .offer__grid { grid-template-columns: 1fr; }
  .stats { grid-template-columns: 1fr; }
  .foot__top { grid-template-columns: 1fr 1fr; }

  /* no room for three across: the run folds back into a vertical column and the
     connectors turn with it */
  .hero__stage { max-width: 520px; }
  .run { grid-template-columns: minmax(0, 1fr); }
  /* one column: the time-pairing offsets above have nothing left to pair with */
  .run > .beat:first-child, .run > .beat:last-child { align-self: stretch; }
  .run > [data-role="link-1"], .run > [data-role="link-2"] {
    align-self: stretch; margin: 0;
  }
  .link { flex-direction: row; justify-content: flex-start; gap: 14px; height: 62px; padding: 0 0 0 30px; }
  .link__line {
    width: 2px; height: 100%;
    background: linear-gradient(to bottom, rgba(99, 102, 241, .1), var(--indigo));
    transform: scaleY(0); transform-origin: top;
  }
  .link.is-on .link__line { transform: scaleY(1); }
  .link__pulse { top: 0; left: 50%; margin: -3px 0 0 -3px; }
  .link.is-on .link__pulse { animation-name: flow-down; }
  .link__note {
    position: static; transform: none; text-align: left;
    width: auto;
  }
  /* the two halves run onto one line here, so they need the word space that
     display:block was providing */
  .link__note b { display: inline; margin-right: .32em; }

  /* the ruler's name moves above its bar */
  .ruler__row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .ruler__foot { margin-left: 0; }

  /* narrow column, so both letters wrap further and need a deeper reserve —
     see the note on .mail__text. Measured at 520px, not guessed. */
  .mail__text { min-height: 8em; }
  .panel--confirm .mail__text { min-height: 4.8em; }
}
@keyframes flow-down {
  0%   { top: 0;    opacity: 0; }
  22%  { opacity: 1; }
  78%  { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

@media (max-width: 760px) {
  body { font-size: 16px; }
  /* the hail goes with body to the `bodySmall` step here. At 17px in a phone
     column the message runs to six lines and the card crowds the button and the
     cue underneath it; at 16px it is five and the first screen breathes again. */
  .hail__text { font-size: 16px; }
  .hail { margin-top: 26px; padding: 12px 16px 14px; }
  .nav__links { display: none; }
  .day { grid-template-columns: 1fr; gap: 10px; }
  .day__label { padding-top: 0; }
  .foot__top { grid-template-columns: 1fr; }
  .close__pitch { max-width: none; }
}

@media (max-width: 560px) {
  /* the extra top room goes on .hero__inner, not on .hero: padding on the section
     sits *outside* the 100svh block, so putting it there pushed the whole first
     screen down and took the scroll cue below the fold on phones */
  .hero__inner { padding-top: clamp(112px, 17vh, 150px); }
  .eyebrow__bar { display: none; }
  /* stays a centred pill rather than a full-bleed bar — the hero is centred and
     a bar reads heavy — but wide enough to be a comfortable tap target */
  .hero__cta .btn { min-width: 240px; justify-content: center; }
  .ruler__marker--agent .ruler__tag,
  .ruler__tag--virell { font-size: 10px; }
  .panel__head { flex-direction: column; align-items: flex-start; gap: 5px; }
  .form__row { grid-template-columns: 1fr; gap: 2px; }
  .cal__slot { grid-template-columns: 34px minmax(0, 1fr); gap: 9px; }
}

/* ============ REDUCED MOTION ============ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  .slip { opacity: 1; transform: none; }
}
