/* ============================================================================
   Yours — teaser site
   One typeface (Newsreader), one warm palette, one orchestrated page load.
   ========================================================================= */

/* --- the typeface ---------------------------------------------------------
   Self-hosted, deliberately. This was on Google Fonts, and when that request
   is blocked — privacy blocklists carry fonts.googleapis.com, and plenty of
   European networks drop it — the page falls back to Georgia. That is not a
   small downgrade here: the overture is sized `max-width:15em`, so the line
   box is measured in the font's own em and the wrap is decided by the font's
   metrics. Georgia is wider and has no 300 weight, so the opening line breaks
   across three lines instead of two and renders heavier. Serving the file
   ourselves removes the third party that could take the design down with it.

   One variable file per subset, carrying both axes: wght 200–800 and
   opsz 6–72, which is what `font-optical-sizing:auto` below reads. The
   vietnamese subset Google also offers is left out — nothing here needs it.
   `unicode-range` means the browser only fetches a subset it actually has
   characters for, so latin-ext costs nothing on an all-English page. */
@font-face{
  font-family:'Newsreader';
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url('/assets/fonts/newsreader-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,
    U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,
    U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Newsreader';
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url('/assets/fonts/newsreader-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,
    U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,
    U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* --- tokens -------------------------------------------------------------- */
:root{
  /* paper & ink */
  --paper:#F7F2E8;
  --paper-warm:#F1E8DA;
  --surface:#FFFDF8;
  --ink:#2B2621;
  --ink-soft:#453C33;
  --ink-faint:#6B6055;
  --rule:rgba(43,38,33,.14);
  --rule-strong:rgba(43,38,33,.22);

  /* light — three embers, each carrying a contrast job:
     surface (white text on it), text (on paper), and pressed. */
  --ember:#A85F16;
  --ember-ink:#9A560F;
  --ember-deep:#8A4C0C;
  --glow:224,145,63;

  /* type — a single family across every role */
  --face:'Newsreader',Georgia,'Times New Roman',serif;
  --w-light:300;
  --w-book:400;
  --w-medium:500;

  --t-overture:clamp(2rem,5.6vw,3.5rem);
  --t-display:clamp(2.125rem,4.9vw,3.25rem);
  --t-lead:clamp(1.1875rem,2.2vw,1.5rem);
  --t-mark:clamp(1.375rem,2.6vw,2rem);
  --t-mark-splash:clamp(2rem,4.6vw,3.75rem);
  --t-body:1.125rem;
  --t-small:.9375rem;
  --t-micro:.8125rem;

  /* measure & rhythm. The larger steps are viewport-relative and deliberately
     tight: each page is meant to land inside one screen, footer included, so
     nobody has to scroll to find the form. */
  --column:44rem;
  --measure:30em;
  --s1:.5rem;
  --s2:.875rem;
  --s3:1.25rem;
  --s4:clamp(1.375rem,2.8vh,2.25rem);
  --s5:clamp(1.75rem,4vh,3rem);
  --s6:clamp(2.25rem,5vh,3.75rem);

  /* motion. The two fade lengths are the single source of truth for the load
     sequence: script.js reads them back off :root to work out when the line is
     whole, so changing them here changes the timing everywhere. */
  --ease:cubic-bezier(.22,.61,.36,1);

  /* Fades get their own curve. --ease is a strong ease-out: on opacity it
     spends 87% of the change in the first half, so a 0.9s fade reads as a word
     appearing instantly and then finishing invisibly. This one is symmetric —
     50% opacity at the true midpoint — so the fade lasts as long as it says. */
  --ease-fade:cubic-bezier(.4,0,.6,1);
  --fade-word:.9s;
  --fade-lead:1s;
}

/* --- base ---------------------------------------------------------------- */
*{box-sizing:border-box}
[hidden]{display:none !important}

html{
  -webkit-text-size-adjust:100%;
  scrollbar-gutter:stable;
}

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--face);
  font-optical-sizing:auto;
  font-weight:var(--w-book);
  font-size:var(--t-body);
  line-height:1.72;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
body.theme-warm{background:var(--paper-warm)}

h1,h2,h3{font-weight:var(--w-light);margin:0;letter-spacing:-.012em}
h1{font-size:var(--t-display);line-height:1.14;text-wrap:balance}
h2{font-size:var(--t-lead);line-height:1.32;letter-spacing:-.008em}
p{margin:0;text-wrap:pretty}

a{color:var(--ember-ink);text-underline-offset:.18em}
a:hover{color:var(--ember-deep)}

:focus-visible{outline:2px solid var(--ember);outline-offset:3px}

/* --- shell --------------------------------------------------------------- */
.page{
  position:relative;
  min-height:100vh;
  min-height:100svh;
  display:flex;
  flex-direction:column;
  align-items:center;
  padding:clamp(1.75rem,4.5vh,3.5rem) clamp(1.5rem,6vw,5rem) clamp(1.75rem,4.5vh,3.5rem);
  overflow:hidden;
}

.glow{
  position:absolute;
  left:50%;
  width:min(1400px,150vw);
  height:min(1200px,120vh);
  transform:translate(-50%,0);
  filter:blur(60px);
  pointer-events:none;
  background:radial-gradient(closest-side,
    rgba(var(--glow),.34),
    rgba(var(--glow),.07) 55%,
    rgba(var(--glow),0) 76%);
}
.glow--top{top:-18vh}
.glow--low{bottom:-30vh}
.glow--soft{
  top:-24vh;
  width:min(1200px,140vw);
  height:min(1000px,100vh);
  background:radial-gradient(closest-side,
    rgba(var(--glow),.22),
    rgba(var(--glow),0) 74%);
}

/* --- wordmark ------------------------------------------------------------ */

/* The masthead and the content below it are centred as one group in the room
   above the footer, so the wordmark sits with the text rather than pinned to
   the top edge. The auto margins pair with margin-bottom:auto on .stage and
   .legal: free space splits evenly above the mark and below the content. Both
   collapse to nothing once the content fills the screen, so a long page simply
   starts at the top. */
.masthead{
  position:relative;
  z-index:2;
  width:100%;
  max-width:var(--column);
  margin-top:auto;
  display:flex;
  justify-content:center;
}

.wordmark{
  display:inline-flex;
  align-items:center;
  gap:.42em;
  font-size:var(--t-mark);
  font-weight:var(--w-book);
  line-height:1;
  color:var(--ink);
  text-decoration:none;
  transform-origin:50% 50%;
}
a.wordmark:hover{color:var(--ink)}

/* The dot stands in for the O, so it aligns to the capitals, not to the line
   box. align-items:center would centre it on the full em including descender
   space, which lands it 0.122em below the cap-height centre — measured, not
   estimated. The offset is in em, so it holds at every size and survives the
   scale-up during the load sequence. */
.wordmark__dot{
  width:1.12em;
  height:1.12em;
  transform:translateY(-.122em);
  border-radius:50%;
  background:radial-gradient(circle at 50% 50%,
    #FFF 18%,#F5B45E 42%,#E0913F 62%,rgba(var(--glow),0) 78%);
  box-shadow:0 0 28px 8px rgba(var(--glow),.35);
}

/* --- main columns -------------------------------------------------------- */
.stage{
  position:relative;
  z-index:1;
  width:100%;
  max-width:var(--column);
  margin:0 auto auto;
  display:flex;
  flex-direction:column;
  align-items:center;
  text-align:center;
  padding-top:var(--s5);
}

.eyebrow{
  font-size:var(--t-micro);
  font-weight:var(--w-medium);
  letter-spacing:.24em;
  text-indent:.24em;          /* offset the trailing letter-space */
  text-transform:uppercase;
  color:var(--ink-faint);
}

/* --- overture (page-load headline) ---------------------------------------
   Purely a device of the load sequence: it is a fixed overlay, so without
   JavaScript to retire it, it would sit on top of the page forever. Hidden
   by default and shown only once .js is set — see the sequence below. */
.overture{
  display:none;
  position:fixed;
  inset:0;
  z-index:4;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  padding:clamp(1.5rem,4vh,3rem) clamp(1.5rem,6vw,5rem);
  pointer-events:none;
}

/* The splash carries its own wordmark, larger and sitting close above the
   line, rather than borrowing the masthead's. Nothing travels on entry: this
   one fades out as the masthead's fades in. */
.overture__mark{
  font-size:var(--t-mark-splash);
  margin-bottom:clamp(1.5rem,3.5vh,2.5rem);
}
.overture p{
  max-width:15em;
  font-size:var(--t-overture);
  font-weight:var(--w-light);
  line-height:1.16;
  letter-spacing:-.018em;
  text-align:center;
  text-wrap:balance;
}
/* Each word is its own box so it can be revealed on its own. inline-block
   keeps it in the flow, so the sentence is fully laid out before the first
   word is visible and nothing shifts as the rest arrive. */
.overture .word{display:inline-block}

/* The way in. A real button so it is reachable by keyboard and announced as
   an action — clicking anywhere on the page does the same thing. */
.overture__hint{
  margin-top:clamp(2.25rem,5.5vh,3.5rem);
  font-family:inherit;
  font-size:var(--t-micro);
  font-weight:var(--w-medium);
  letter-spacing:.24em;
  text-indent:.24em;          /* offset the trailing letter-space */
  text-transform:uppercase;
  color:var(--ink-faint);
  background:none;
  border:0;
  padding:.75rem 1rem;
  cursor:pointer;
  pointer-events:auto;
  transition:color .2s var(--ease);
}
.overture__hint:hover{color:var(--ember-ink)}

/* --- manifesto ----------------------------------------------------------- */
/* Three equal beats of one statement — same size, same weight, same colour.
   The rhythm comes from the gaps between them, not from a size hierarchy. */
.manifesto{
  display:flex;
  flex-direction:column;
  gap:var(--s4);
  max-width:22em;
}
.manifesto p{
  font-size:var(--t-lead);
  font-weight:var(--w-light);
  line-height:1.42;
  letter-spacing:-.008em;
  color:var(--ink);
}

.pitch{margin-top:var(--s3);max-width:13em}
.sub{
  max-width:var(--measure);
  margin-top:var(--s3);
  color:var(--ink-soft);
}

/* --- waitlist ------------------------------------------------------------ */
.widget{
  width:100%;
  max-width:32.5rem;
  margin-top:var(--s6);
  padding:clamp(1.5rem,3.2vh,2.5rem) clamp(1.5rem,4vw,2.5rem);
  text-align:left;
  border:1px solid var(--rule-strong);
  background:rgba(255,253,248,.7);
}
.widget__sub{margin-top:var(--s2);color:var(--ink-faint)}

.widget form{
  display:flex;
  flex-direction:column;
  gap:.625rem;
  margin-top:var(--s4);
}
.widget input,
.widget button{
  font-family:inherit;
  font-size:var(--t-body);
  line-height:1.4;
  padding:.8125rem 1.125rem;
  border-radius:0;
}
.widget input{
  width:100%;
  color:var(--ink);
  background:var(--surface);
  border:1px solid var(--rule-strong);
}
.widget input::placeholder{color:#7E7264}
.widget input:focus{outline:none;border-color:var(--ember)}
.widget input:focus-visible{outline:2px solid var(--ember);outline-offset:2px}

.widget button{
  font-weight:var(--w-medium);
  letter-spacing:.02em;
  color:var(--surface);
  background:var(--ember);
  border:none;
  cursor:pointer;
  transition:background .2s var(--ease);
}
.widget button:hover{background:var(--ember-deep)}
.widget button[disabled]{opacity:.6;cursor:default}

.widget__error{
  margin-top:var(--s2);
  font-size:var(--t-small);
  color:var(--ember-deep);
}
/* The line stays in the page and is emptied rather than hidden — a live region
   has to be there before it changes for a screen reader to announce it. Empty,
   it must cost nothing: a paragraph with no content generates no line box. */
.widget__error:empty{margin-top:0}

/* Google's disclosure, standing in for the badge hidden below. Fine print: a
   step under the error line, in the quietest ink on the page, and tighter than
   the body leading, which is far too loose at this size. */
/* 12px rather than --t-micro is doing real work, not shaving: at 13px the
   sentence wraps to three lines on a 390px screen, at 12px to two, which is the
   difference between 59px and 34px. /thereel is the tightest page on the site
   and it is the one that could not absorb the extra line. */
.widget__fine{
  margin-top:var(--s2);
  font-size:.75rem;
  line-height:1.4;
  color:var(--ink-faint);
}
.widget__fine a{color:inherit}
.widget__fine a:hover{color:var(--ember-ink)}

/* reCAPTCHA's badge is fixed to the bottom-right corner, above everything.
   Google allows hiding it as long as the line above is shown wherever it runs —
   and on a page budgeted to land in one screen it sits on the footer. Use
   visibility, not display:none, which has broken execution in past versions. */
.grecaptcha-badge{visibility:hidden}

.widget__done{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:var(--s3);
  text-align:center;
}
/* Focused when it replaces the form, so the swap is announced. It is not
   something you can act on, so it should not draw a ring for it. */
.widget__done:focus{outline:none}
.widget__done p{
  font-size:var(--t-lead);
  font-weight:var(--w-light);
  line-height:1.4;
}
.glowdot{
  width:2rem;
  height:2rem;
  border-radius:50%;
  background:radial-gradient(circle at 50% 50%,
    #FFF 18%,#F5B45E 42%,#E0913F 64%,rgba(var(--glow),0) 80%);
}

/* --- footer -------------------------------------------------------------- */
.footer{
  position:relative;
  z-index:1;
  width:100%;
  max-width:var(--column);
  margin-top:var(--s5);
  padding-top:var(--s3);
  border-top:1px solid var(--rule);
  display:flex;
  flex-wrap:wrap;
  gap:.75rem 2rem;
  justify-content:space-between;
  align-items:baseline;
  font-size:var(--t-small);
  color:var(--ink-faint);
}
.footer__nav{display:flex;flex-wrap:wrap;gap:.75rem 1.25rem}
.footer a{color:var(--ink-faint);text-decoration:none}
.footer a:hover{color:var(--ember-ink)}

/* Every page carries the same three links in the same order, so the footer
   never changes shape as you move between them. The page you are on is marked
   rather than removed — dropping it would reflow the other two. */
.footer [aria-current="page"]{color:var(--ink)}

/* --- legal --------------------------------------------------------------- */
/* A document starts at the top. The marketing pages centre their masthead and
   content as a group, which reads as a composition; on a policy that is short
   — or still waiting on the API — it would strand the wordmark halfway down an
   empty screen instead. */
.layout-legal .masthead{margin-top:0}

.legal{
  position:relative;
  z-index:1;
  width:100%;
  max-width:var(--column);
  margin:0 auto auto;
  padding-top:var(--s5);
}
.legal .updated{
  margin-top:var(--s2);
  font-size:var(--t-small);
  color:var(--ink-faint);
}
.pledge{
  margin-top:var(--s5);
  padding:clamp(1.5rem,3vh,2.25rem) clamp(1.5rem,3.5vw,2.25rem);
  border:1px solid var(--rule-strong);
  background:rgba(255,253,248,.7);
  font-size:var(--t-lead);
  font-weight:var(--w-light);
  line-height:1.45;
}
.policy{
  display:flex;
  flex-direction:column;
  gap:var(--s5);
  margin-top:var(--s5);
}
/* The column is the same width on every page; the policy prose keeps its own
   measure inside it rather than running the full 44rem. */
.policy p{margin-top:var(--s2);max-width:34em;color:var(--ink-soft)}

/* Status lines: the placeholder, the loading line, the failure line, and the
   contact line. Never italic — Newsreader's italics are not loaded, and the
   browser would synthesise a slanted roman. */
.policy__status{color:var(--ink-faint)}

/* ----------------------------------------------------------------------------
   Narrow screens. Three nav links and the credit are a few pixels too wide for
   a phone at the full small size, and wrapping the footer onto two rows costs
   nearly 40px of the one-screen budget. Trimming the size and the gaps keeps
   it on one row.
   -------------------------------------------------------------------------- */
@media (max-width:30rem){
  .footer{gap:.5rem 1.25rem;font-size:.875rem}
  .footer__nav{gap:.5rem 1rem}
}

/* ----------------------------------------------------------------------------
   Short viewports. A phone showing its address bar leaves roughly 700px, which
   is the real target — not the 844 the device claims. This tightens the scale
   so the footer still lands above the fold there, and leaves the roomier
   setting alone on taller screens.
   -------------------------------------------------------------------------- */
/* The reCAPTCHA disclosure costs the widget two lines, and /thereel is the page
   with the least slack to give. Between the short-viewport breakpoint below and
   a screen tall enough to absorb it, there is a band — a 1280x800 laptop most
   obviously — where those two lines are exactly enough to push the footer under
   the fold. Tighten the widget there, and only the widget: the type scale at
   this height is fine and should not shift. */
@media (min-height:761px) and (max-height:860px){
  .widget{
    margin-top:var(--s5);
    padding:clamp(1.125rem,2.6vh,2rem) clamp(1.5rem,4vw,2.5rem);
  }
  .widget form{gap:.5rem;margin-top:var(--s3)}
}

@media (max-height:760px){
  :root{
    --s4:clamp(.875rem,2.2vh,1.5rem);
    --s5:clamp(1.125rem,3vh,2rem);
    --s6:clamp(1.375rem,3.6vh,2.5rem);
    --t-overture:clamp(1.75rem,4.6vw,2.75rem);
    --t-display:clamp(1.75rem,4.4vw,2.5rem);
    --t-lead:clamp(1.0625rem,2.2vw,1.375rem);
    --t-mark-splash:clamp(1.75rem,4vw,3rem);
  }
  .page{
    padding-top:clamp(1rem,2.4vh,2rem);
    padding-bottom:clamp(1rem,2.4vh,2rem);
  }
  .widget{padding:clamp(1.125rem,2.6vh,2rem) clamp(1.25rem,4vw,2.5rem)}
  .widget input,
  .widget button{padding:.6875rem 1rem}
  /* Reclaiming the last of what the reCAPTCHA disclosure costs, only on the
     short screens where the footer has nothing to spare. */
  .widget form{gap:.5rem}
}

/* ============================================================================
   Page-load sequence — index only, JavaScript-enhanced.
   Without JS (no .js class) every rule below is inert and the page is static.
   ========================================================================= */

/* start state — the line is laid out in full from the first frame, every word
   already in its final position at zero opacity. Nothing reflows as the words
   arrive, however scrambled their order. */
.js .overture{display:flex;transition:opacity .95s var(--ease)}

/* Each word carries its own fade length and its own delay (set inline by
   script.js), so the whole stagger is one style change rather than a dozen
   timers. The two cued phrases fade slower than the fill. */
.js .word{
  opacity:0;
  transform:translateY(.14em);
  transition:opacity var(--fade-word) var(--ease-fade),
             transform var(--fade-word) var(--ease-fade);
}
.js .word[data-cue]{
  transition-duration:var(--fade-lead);
}
.js .overture__mark{opacity:0;transition:opacity var(--fade-lead) var(--ease-fade)}
.js .overture__hint{
  opacity:0;
  transition:opacity var(--fade-lead) var(--ease-fade),color .2s var(--ease);
}
.js .masthead .wordmark{opacity:0;transition:opacity .95s var(--ease)}
.js .glow{opacity:0;transition:opacity 1.4s var(--ease)}
.js [data-reveal]{
  opacity:0;
  transform:translateY(12px);
  transition:opacity .95s var(--ease) var(--d,0ms),transform .95s var(--ease) var(--d,0ms);
}

/* Until the visitor enters, the page under the splash is invisible but still
   in the document — and still clickable. Without this, a click meant for
   "enter" can land on the footer's "Yours" link or the waitlist button behind
   the overlay and navigate or submit instead. The hint re-enables itself, and
   clicks that hit nothing still reach the document listener. */
.js:not(.settled) .page{pointer-events:none}

/* 1 — the light comes up behind an empty page */
.js.lit .glow{opacity:1}

/* 2 — the words arrive one at a time, out of order (JS sets .is-in) */
.js .word.is-in{opacity:1;transform:none}

/* 3 — the sentence is whole: the mark and the way in appear together,
        and then it waits. Nothing below this happens on a timer. */
.js.arrive .overture__mark{opacity:1}
.js.arrive .overture__hint{opacity:1}

/* 4 — entering: the splash clears as the masthead and the page arrive */
.js.settled .overture{opacity:0;transition-duration:.6s}
.js.settled .masthead .wordmark{opacity:1}
.js.settled [data-reveal]{opacity:1;transform:none}

/* entering before the sequence has played out cuts it short */
.js.hurry .overture,
.js.hurry .word,
.js.hurry .overture__mark,
.js.hurry .overture__hint,
.js.hurry .masthead .wordmark,
.js.hurry .glow,
.js.hurry [data-reveal]{transition-duration:.45s;transition-delay:0ms}

@media (prefers-reduced-motion:reduce){
  /* keep the sequence, drop the movement — the words still arrive one by one,
     they just fade rather than drift */
  .js .word,
  .js .word.is-in{transform:none}
  .js [data-reveal],
  .js.settled [data-reveal]{transform:none}
  .widget button{transition:none}
}
