/* ==========================================================================
   timeline — site styles
   Editorial serif + grotesk, pure-black canvas, photo-forward.
   ========================================================================== */

:root {
  --bg:          #090909;
  --bg-raise:    #161618;
  --bg-card:     #121214;
  --ink:         #f4f3f1;
  --ink-dim:     rgba(244, 243, 241, 0.60);
  --ink-faint:   rgba(244, 243, 241, 0.40);
  --hair:        rgba(255, 255, 255, 0.10);
  --hair-soft:   rgba(255, 255, 255, 0.06);
  --pill:        #f4f3f1;
  --pill-ink:    #0a0a0a;
  --halo:        rgba(224, 122, 130, 0.16); /* the app's faint rose halo */

  --serif: "Instrument Serif", Georgia, "Times New Roman", serif;
  --sans:  "Familjen Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --system: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --maxw: 1120px;
  --gutter: clamp(20px, 5vw, 56px);
}

* { box-sizing: border-box; }

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

  /* Reserve the scrollbar's width on every page, whether or not that page
     scrolls. The landing page is exactly one screen tall and so has no
     scrollbar, while the legal pages do — without this the centred footer (and
     headline) sit ~7px further left on the long pages than on the landing, and
     the shift is visible when you navigate between them.

     both-edges rather than plain `stable` because this design centres
     everything: reserving on one side only would keep the pages consistent with
     each other but leave all of them fractionally off-centre in the window. */
  scrollbar-gutter: stable both-edges;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  letter-spacing: 0.01em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;

  /* Every page is a full-height column, so the footer sits at the bottom of the
     window even when the content doesn't fill it. Without this, a short page
     (support.html) drops its footer right under the last paragraph while the
     long ones hold theirs at the bottom of the screen — the same footer in two
     different places depending on which page you're on. */
  min-height: 100vh;
  min-height: 100svh;   /* mobile: the small viewport, so the footer isn't under the URL bar */
  display: flex;
  flex-direction: column;
}

img { max-width: 100%; display: block; }
a { color: inherit; }

/* ---- Layout primitives ------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: clamp(64px, 12vw, 128px); }

/* ---- Typography -------------------------------------------------------- */

.serif { font-family: var(--serif); font-weight: 400; }

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -0.01em;
  margin: 0;
}

.eyebrow {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.lede { color: var(--ink-dim); font-size: 1.08rem; }

/* ---- Buttons ----------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.98rem;
  letter-spacing: 0.01em;
  padding: 0.85em 1.6em;
  border-radius: 999px;
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, opacity 0.15s ease, background 0.15s ease;
}
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--pill); color: var(--pill-ink); }
.btn-primary:hover { opacity: 0.88; }

.btn-ghost { background: transparent; color: var(--ink); border-color: var(--hair); }
.btn-ghost:hover { border-color: var(--ink-faint); }

/* ---- Wordmark ---------------------------------------------------------- */

/* Every page's header is now just this, in a .stage-head — the sticky nav bar
   (.nav / .nav-inner / .nav-links) was removed on 2026-07-26 so the prose pages
   match the landing page. It's in git if the site ever grows enough pages to
   need a nav again. */
.wordmark {
  font-family: var(--serif);
  font-size: 1.6rem;
  line-height: 1;
  letter-spacing: 0.005em;
  text-decoration: none;
  color: var(--ink);
}

/* ==========================================================================
   Landing — single-statement stage (the shipped index.html).
   Everything below this block down to "Prose" styles the fuller marketing page
   (hero art, chaptered clip showcase, bands). That page is currently unused but
   kept intact so the sections can be restored without rebuilding them; it
   shares the .clip rule defined here.
   ========================================================================== */

/* The full-height column that used to live here is on `body` now, since every
   page needs it. The .landing class stays on index.html — it's what the prose
   pages are distinguished from via body:not(.landing). */

/* Every page's header, landing and prose alike — the wordmark alone, anchored to
   the viewport gutter. Deliberately NOT wrapped to the prose column: it stays put
   as the page width changes, rather than drifting inward with the text. */
.stage-head { padding: 14px var(--gutter) 0; }

.stage {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Height-driven, so it scales with the space it actually divides. Symmetric:
     the headline and button are the whole composition now, and they should sit
     on the true centre line. */
  padding: clamp(24px, 5vh, 64px) var(--gutter);
  /* Safety net for the never-wrapping headline: clip sideways rather than let it
     scroll the page. Vertical overflow stays visible so a short viewport scrolls
     instead of cropping the CTA. */
  overflow-x: clip;
}

.rotator {
  position: relative;
  flex: none;          /* only the reel flexes; the headline keeps its line box */
  width: 100%;
  margin: 0;
  line-height: 1.06;
  /* Opens up the h1 default of -0.01em. Nudges toward the app, which ships an
     Instrument Serif whose glyph advances were widened ~4% em by hand; the web
     pulls stock upstream, so it tracks tighter than the same string on device.
     The fitter probe carries .rotator, so measurement follows this for free. */
  letter-spacing: 0.015em;
  text-align: center;
  white-space: nowrap;          /* one line, always */
  display: flex;
  align-items: center;
  justify-content: center;
  /* Fallback only. The script overrides this with a size measured to fit the
     LONGEST phrase, so every phrase renders at one size and none ever wraps. */
  font-size: clamp(1.3rem, 5.6vw, 5rem);
}
.rot-visual { display: block; width: 100%; }

/* Off-screen twin of the headline, measured at a known size to derive the
   scale. It carries the same classes, so it inherits the same face, weight and
   tracking — the metrics can't drift from the real thing. */
.rot-fitter {
  position: absolute;
  top: 0;
  left: 0;
  visibility: hidden;
  pointer-events: none;
  display: block;
  width: auto;
  font-size: 100px;
}

/* Words stay whole; characters carry --i, which staggers the reveal from the
   start of the string to the end. */
.rot-word { display: inline-block; white-space: nowrap; }

.rot-char {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.28em);
  filter: blur(7px);
  transition:
    opacity   0.62s ease,
    transform 0.62s cubic-bezier(0.22, 0.61, 0.36, 1),
    filter    0.62s ease;
}
.rotator.is-in .rot-char {
  opacity: 1;
  transform: none;
  filter: none;
  transition-delay: calc(var(--i) * 26ms);
}
/* Declared after .is-in so it wins on equal specificity — the clear-out keeps
   the same left-to-right direction, just quicker. */
.rotator.is-out .rot-char {
  opacity: 0;
  transform: translateY(-0.22em);
  filter: blur(7px);
  transition-duration: 0.38s;
  transition-delay: calc(var(--i) * 14ms);
}

/* Arrives after the first phrase has finished resolving, so it doesn't compete
   with the headline for attention on load. */
.stage-cta {
  flex: none;
  margin-top: clamp(12px, 1.8vh, 26px);   /* height-driven, same reason as the stage padding */

  /* The hidden state is the animation's first keyframe, not an `opacity: 0`
     declaration here, and the fill is `backwards`, not `forwards`. Both halves
     of that matter:

     `backwards` fills the delay with the from-keyframe. A plain `opacity: 0`
     declaration loses the cascade to `.btn-primary:hover`, so a cursor already
     parked where the button appears would pop it into view at hover opacity
     instead of waiting out the 1.6s. An animation-applied value outranks
     :hover, so the button stays hidden until it's meant to arrive.

     Not `forwards`, for the mirror-image reason: a forwards fill keeps the
     animation's `opacity: 1` applied once it's done, which would outrank the
     :hover dim for the rest of the session and leave the button unresponsive to
     the cursor. With no fill at the end it lands on its own default opacity and
     hover behaves normally. */
  animation: cta-in 0.7s ease 1.6s backwards;

  /* Native system font, not the site's grotesk — the CTA reads as an OS
     affordance rather than another piece of the editorial type. Scoped here so
     the rest of the site keeps --sans. */
  font-family: var(--system);
  letter-spacing: 0;
}
@keyframes cta-in {
  /* pointer-events rides along so the button can't be clicked while it's still
     invisible. It's a discrete property, so it flips at the midpoint of the
     fade — by which point the button is visibly there. */
  from { opacity: 0; transform: translateY(8px); pointer-events: none; }
  to   { opacity: 1; transform: none; }
}

/* The closed-beta state: the pill is a status label, not something to click. It
   keeps the shape so the page's composition is unchanged, but every affordance
   that invited a click is off — no hover shift, no press nudge, no pointer.
   Must stay after .btn-ghost, which it overrides at equal specificity. */
.cta-static {
  color: var(--ink-dim);
  cursor: default;
}
.cta-static:hover { border-color: var(--hair); }
.cta-static:active { transform: none; }

.stage-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px 24px;
  padding: 0 var(--gutter) 22px;
  font-size: 0.86rem;
  color: var(--ink-faint);
}
.stage-footer a { color: var(--ink-faint); text-decoration: none; transition: color 0.15s ease; }
.stage-footer a:hover { color: var(--ink); }
.stage-legal { color: var(--ink-faint); }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .rot-char { transform: none; filter: none; transition: opacity 0.4s ease; }
  .rotator.is-in .rot-char  { transform: none; filter: none; transition-delay: 0s; }
  .rotator.is-out .rot-char { transform: none; filter: none; transition-delay: 0s; }
  /* No opacity reset needed — with the animation off, the button falls back to
     its own default of fully opaque. */
  .stage-cta { animation: none; }
}

/* ---- Hero -------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: clamp(56px, 10vw, 104px) clamp(64px, 11vw, 120px);
}
.hero::before {
  content: "";
  position: absolute;
  top: -20%;
  left: 50%;
  width: 900px;
  max-width: 120vw;
  aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle at center, var(--halo), transparent 62%);
  pointer-events: none;
}
.hero-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(32px, 6vw, 72px);
  align-items: center;
}
.hero h1 {
  font-size: clamp(2.7rem, 6.4vw, 4.9rem);
  max-width: 12ch;
}
.hero .lede { margin-top: 1.4rem; max-width: 42ch; font-size: 1.18rem; }
.hero-cta { margin-top: 2.2rem; display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.hero-note { margin-top: 1.1rem; font-size: 0.85rem; color: var(--ink-faint); }

@media (max-width: 860px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-art { order: -1; max-width: 300px; margin-inline: auto; }
}

/* ---- Hero screenshot (frameless, blends into the page) ----------------- */

.hero-art .shot {
  overflow: hidden;
  aspect-ratio: 1320 / 2268;   /* crops the baked-in headline band off the top */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 7%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 7%);
}
.hero-art .shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center bottom;
}

/* ---- Rotating showcase (features) -------------------------------------- */

.showcase-grid {
  display: grid;
  grid-template-columns: 0.92fr 1.08fr;
  gap: clamp(32px, 6vw, 84px);
  align-items: center;
}
.showcase-copy { max-width: 460px; }
.chapters { margin-top: 1.5rem; }

.chapter {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.chapter + .chapter { margin-top: 4px; }

.chapter-kicker {
  display: block;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color 0.4s ease;
}
.chapter-title {
  display: block;
  font-size: clamp(1.5rem, 3vw, 2.05rem);
  line-height: 1.1;
  margin-top: 0.35rem;
  color: var(--ink-dim);
  transition: color 0.4s ease;
}
.chapter-body {
  display: block;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  color: var(--ink-dim);
  font-size: 1rem;
  line-height: 1.55;
  transition: max-height 0.55s ease, opacity 0.4s ease, margin 0.45s ease;
}
.chapter-track {
  display: block;
  position: relative;
  height: 2px;
  margin-top: 18px;
  border-radius: 2px;
  background: var(--hair);
  overflow: hidden;
}
.chapter-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--ink);
  border-radius: 2px;
}
.chapter:hover .chapter-title { color: var(--ink); }
.chapter.is-active .chapter-kicker { color: var(--ink-dim); }
.chapter.is-active .chapter-title { color: var(--ink); }
.chapter.is-active .chapter-body { max-height: 220px; opacity: 1; margin-top: 0.7rem; }

.showcase-stage { display: flex; justify-content: center; }
.screen {
  position: relative;
  width: min(330px, 74vw);
  aspect-ratio: 1320 / 2230;   /* tallest clip; shorter ones letterbox invisibly into the matching bg */
  background: transparent;
}
.clip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;    /* clips share the page's bg, so letterboxing is invisible */
  object-position: center;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.clip.is-active { opacity: 1; }

@media (max-width: 820px) {
  .showcase-grid { grid-template-columns: 1fr; gap: 10px; }
  .showcase-copy { max-width: none; order: 2; }
  .showcase-stage { order: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .chapter-kicker, .chapter-title, .chapter-body, .clip { transition: none; }
}

/* ---- Safe-space band --------------------------------------------------- */

.band {
  border-top: 1px solid var(--hair);
  border-bottom: 1px solid var(--hair);
  text-align: center;
}
.band h2 { font-size: clamp(2rem, 5vw, 3.2rem); max-width: 20ch; margin-inline: auto; }
.band .lede { max-width: 52ch; margin: 1.4rem auto 0; }

/* ---- Final CTA --------------------------------------------------------- */

.cta { text-align: center; }
.cta h2 { font-size: clamp(2.4rem, 6vw, 4rem); }
.cta .hero-cta { justify-content: center; margin-top: 2rem; }

/* ---- Footer ------------------------------------------------------------ */

/* Every page uses .stage-footer (defined up in the landing block). The prose
   pages hold it at the bottom of the window so the links stay reachable without
   scrolling to the end — on the landing it's already there, since that page is
   one screen tall and never scrolls.

   Two things it needs that the landing's copy doesn't, both because prose runs
   underneath it rather than ending above it: an opaque backdrop, and a top
   padding to match the bottom so text doesn't run right up against the links. */
body:not(.landing) .stage-footer {
  position: sticky;
  bottom: 0;
  z-index: 40;
  padding-top: 22px;
  background: var(--bg);
}

/* ---- Prose (legal + support pages) ------------------------------------- */

.prose-head { padding-block: clamp(48px, 9vw, 96px) 0; }
.prose-head h1 { font-size: clamp(2.4rem, 6vw, 3.8rem); }
.prose-head .updated { margin-top: 1rem; color: var(--ink-faint); font-size: 0.9rem; }

/* Takes the slack in the body column, which is what pushes the footer to the
   bottom of the window on a page too short to fill it. `1 0 auto` rather than
   `1`: grow into free space, but never shrink below the text's own height. */
.prose {
  flex: 1 0 auto;
  max-width: 720px;
  padding-block: clamp(32px, 6vw, 56px) clamp(64px, 11vw, 112px);
}
.prose h2 {
  font-size: 1.7rem;
  margin-top: 2.6em;
  padding-top: 1.4em;
  border-top: 1px solid var(--hair-soft);
}
.prose h2:first-of-type { border-top: 0; padding-top: 0; margin-top: 1.2em; }
.prose h3 { font-family: var(--sans); font-weight: 600; font-size: 1.05rem; margin-top: 2em; }
.prose p, .prose li { color: var(--ink-dim); }
.prose a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.prose ul { padding-left: 1.2em; }
.prose li { margin-block: 0.4em; }
.prose strong { color: var(--ink); font-weight: 600; }

.callout {
  border: 1px solid var(--hair);
  border-radius: 16px;
  padding: 24px 26px;
  background: var(--bg-raise);
  margin-block: 1.8em;
}
.callout p { margin: 0; color: var(--ink); }
.callout p + p { margin-top: 0.6em; }

/* The .placeholder highlight lived here to make unfilled [bracketed] tokens
   impossible to miss before launch. The last one — the support response time —
   was filled in on 2026-07-26, so the rule has no consumers. */

/* Legal-page tables. The wrapper scrolls on its own so a wide table never makes
   the page itself scroll sideways on a phone. */
.table-scroll {
  overflow-x: auto;
  margin-block: 1.6em;
  border: 1px solid var(--hair);
  border-radius: 14px;
  -webkit-overflow-scrolling: touch;
}
.prose table {
  border-collapse: collapse;
  width: 100%;
  min-width: 520px;
  font-size: 0.92rem;
}
.prose th,
.prose td {
  text-align: left;
  vertical-align: top;
  padding: 12px 16px;
  border-bottom: 1px solid var(--hair-soft);
}
.prose thead th {
  color: var(--ink);
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--bg-raise);
  white-space: nowrap;
}
.prose tbody td { color: var(--ink-dim); }
.prose tbody td:first-child { color: var(--ink); }
.prose tbody tr:last-child td { border-bottom: 0; }
