/* ============================================================
   openroar.org — "walk through the loft"
   native-scroll landing. NO scroll interception anywhere.
   All motion = CSS class toggles + CSS custom properties.
   ============================================================ */

/* fonts are loaded via a <link rel="stylesheet"> in the HTML <head>
   (de-serialized the render-blocking @import chain). */

/* ---------- DNA tokens ---------- */
:root {
  --paper:      #F2EEE7;
  --ink:        #28211C;
  --gold:       #7d5e28;
  --gold-deco:  #B68A3C;
  --terracotta: #8F5F45;
  --sage:       #8a9a7e;
  --sage-soft:  #b9c4ad;

  --bg:      var(--paper);
  --fg:      var(--ink);
  --muted:   #5b5148;
  --dim:     #463e35;   /* de-emphasized-but-legible (AA) for not-yet lines */
  --hair:    rgba(40, 33, 28, 0.16);
  --scrim:   #E7DEC9;   /* light: warm-paper veil (NOT the dark near-black) */
  --bloom:   #f6d38a;   /* savannah gold */

  /* light-mode backdrop: loft recedes to a faint daytime watermark */
  --loft-opacity: .32;
  --loft-filter: saturate(.5) brightness(1.1) contrast(.92);
  --veil-ceiling: .5;
  --veil-range: .2;

  /* consolidated radius + shadow (flat editorial, no SaaS glass) */
  --r: 2px;
  --shadow: 0 6px 16px rgba(0,0,0,.08);

  /* scroll-linked, written by walk.js (reading scroll only, never setting it) */
  --progress: 0;

  --measure: 34rem;
  --display: "Fraunces", "Fraunces-fallback", Georgia, serif;
  --body:    "Inter", "Inter-fallback", system-ui, sans-serif;
}

/* explicit dark theme (toggle) + prefers-color-scheme (auto) below */
:root[data-theme="dark"] {
  --paper:  #1b1713;
  --ink:    #efe8dd;
  --bg:     #1b1713;
  --fg:     #efe8dd;
  --muted:  #b7ab9c;
  --dim:    #c7bdac;
  --hair:   rgba(239, 232, 221, 0.18);
  --gold:      #c99a4e;
  --gold-deco: #d8ab5c;
  --sage:   #9fb091;
  --scrim:  #0d0b09;
  --loft-opacity: 1;
  --loft-filter: none;
  --veil-ceiling: .86;
  --veil-range: .66;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:  #1b1713;
    --ink:    #efe8dd;
    --bg:     #1b1713;
    --fg:     #efe8dd;
    --muted:  #b7ab9c;
    --dim:    #c7bdac;
    --hair:   rgba(239, 232, 221, 0.18);
    --gold:      #c99a4e;
    --gold-deco: #d8ab5c;
    --sage:   #9fb091;
    --scrim:  #0d0b09;
    --loft-opacity: 1;
    --loft-filter: none;
    --veil-ceiling: .86;
    --veil-range: .66;
  }
}

/* ---------- base ---------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--body);
  font-size: 18px;
  line-height: 1.6;
  letter-spacing: 0.01em;
  overflow-x: hidden;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

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

.voice {
  font-family: var(--display);
  font-weight: 380;
  letter-spacing: -0.01em;
  line-height: 1.18;
  text-transform: lowercase;
}
strong, .em { font-weight: 560; }
em { font-style: italic; }

/* skip link */
.skip {
  position: absolute; left: -999px; top: 0; z-index: 200;
  background: var(--fg); color: var(--bg); padding: .7rem 1rem;
  border-radius: 2px; font-family: var(--body);
}
.skip:focus { left: 12px; top: 12px; }

/* ============================================================
   THE LOFT — fixed backdrop the copy walks across.
   position:fixed so it never scroll-jacks; only its veil opacity
   changes with --progress (dim door -> lit room).
   ============================================================ */
.loft {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--bg);
  /* iOS hardening: promote the whole fixed backdrop to its own GPU layer so it
     is composited once and NOT repainted on every scroll frame (the classic
     real-iPhone scroll-jank on a position:fixed illustration). */
  transform: translateZ(0);
  will-change: transform;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.loft__img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 58%;
  /* faint continuous parallax "breath" driven purely by --progress (no transform of scroll) */
  transform: scale(1.06) translateY(calc(var(--progress) * -2.2%)) translateZ(0);
  opacity: var(--loft-opacity);
  filter: var(--loft-filter);
  will-change: transform;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
/* the dim veil: opaque at the door (progress 0), clears as the room lights (progress 1) */
.loft__veil {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 80% at 50% 40%, rgba(32,26,21,0) 0%, var(--scrim) 82%),
    var(--scrim);
  opacity: calc(var(--veil-ceiling) - var(--progress) * var(--veil-range));
}
/* savannah gold bloom — off by default, blooms on the peak scene */
.loft__bloom {
  position: absolute; inset: 0;
  background: radial-gradient(90% 70% at 72% 46%, var(--bloom) 0%, rgba(246,211,138,0) 62%);
  mix-blend-mode: soft-light;
  opacity: 0;
  transition: opacity 1.2s ease;
}
body[data-scene="savannah"] .loft__bloom { opacity: .92; }
body[data-scene="pledge"]   .loft__bloom { opacity: .60; } /* keep the gold glow through the oath */
body[data-scene="join"]     .loft__bloom { opacity: .45; }
/* paper wash keeps copy legible over the busy illustration (AA) */
.loft__wash {
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
     color-mix(in srgb, var(--bg) 92%, transparent) 0%,
     color-mix(in srgb, var(--bg) 62%, transparent) 46%,
     color-mix(in srgb, var(--bg) 30%, transparent) 100%);
}

/* ============================================================
   SIGNATURE — sage rule down the left margin, ink dot travels
   with --progress. Pure CSS var; reads scroll, never sets it.
   ============================================================ */
.rail {
  position: fixed;
  left: clamp(14px, 3.4vw, 46px);
  top: 12vh; bottom: 12vh;
  width: 2px;
  z-index: 40;
  background: linear-gradient(var(--sage-soft), color-mix(in srgb, var(--sage) 60%, transparent));
  opacity: .8;
  pointer-events: none;
}
.rail__dot {
  position: absolute;
  left: 50%;
  top: calc(var(--progress) * 100%);
  width: 11px; height: 11px;
  margin: -5.5px 0 0 -5.5px;
  border-radius: 50%;
  background: var(--terracotta);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--paper) 70%, transparent);
}
.rail__dot::after { /* the ink bleed */
  content: ""; position: absolute; inset: -3px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--terracotta) 45%, transparent);
}
@media (max-width: 640px) {
  .rail { left: 9px; }
}

/* ---------- chrome: skip nav / theme toggle ---------- */
.chrome {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px clamp(16px, 4vw, 40px);
  font-family: var(--body);
  pointer-events: none;
}
.chrome > * { pointer-events: auto; }
.brand {
  font-family: var(--display);
  font-weight: 560;
  font-size: 1.05rem;
  letter-spacing: .02em;
  text-transform: lowercase;
  text-decoration: none;
  color: var(--fg);
  mix-blend-mode: normal;
}
.brand::before { content: "◆"; color: var(--gold-deco); margin-right: .4em; font-size: .8em; }
.themeToggle {
  font: inherit; font-size: .82rem;
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  color: var(--fg);
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: .35rem .8rem;
  cursor: pointer;
  backdrop-filter: blur(6px);
}
.themeToggle:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 2px; }

/* ============================================================
   CONTENT — scroll column over the fixed loft
   ============================================================ */
main { position: relative; z-index: 10; }

.scene {
  /* the right gutter is named so the readability scrims below can clamp their
     negative bleed to it and never push the page wider than the viewport.
     Same computed value as before (measured: 24px @320, 27.3px @390, 90px @1440). */
  --gutter-r: clamp(24px, 7vw, 90px);
  min-height: 100vh;
  min-height: 100svh; /* iOS: stable against the dynamic toolbar (no 100vh jump) */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 16vh var(--gutter-r) 16vh clamp(52px, 9vw, 120px);
  max-width: 1100px;
}
.scene__inner { max-width: var(--measure); }

/* beat = a line/block that reveals as it enters. class .in added by IO. */
.beat {
  opacity: 1;
  transform: none;
  transition: opacity .9s cubic-bezier(.2,.7,.2,1), transform .9s cubic-bezier(.2,.7,.2,1);
  transition-delay: var(--d, 0ms);
}
/* hide-then-reveal ONLY when JS confirmed IntersectionObserver will reveal (html.reveal added by walk.js).
   base .beat stays visible, so no browser (esp. iOS Safari) can ever get stuck on a blank page. */
html.reveal .beat { opacity: 0; transform: translateY(18px); }
html.reveal .beat.in { opacity: 1; transform: none; }

.lede {
  font-family: var(--display);
  font-weight: 350;
  text-transform: lowercase;
  font-size: clamp(1.9rem, 5.4vw, 3.6rem);
  line-height: 1.14;
  letter-spacing: -0.015em;
  margin: 0 0 .2em;
}
.lede .accent { color: var(--gold); font-style: italic; }
.step {
  font-family: var(--display);
  font-weight: 360;
  text-transform: lowercase;
  font-size: clamp(1.4rem, 3.6vw, 2.35rem);
  line-height: 1.22;
  margin: .15em 0 1.15em;
}
.kicker {
  font-family: var(--body);
  font-size: .74rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1.8rem;
}
.note {
  font-family: var(--body);
  font-size: 1.02rem;
  color: var(--muted);
  max-width: 30rem;
}
.hedge {
  font-family: var(--body);
  font-style: italic;
  color: var(--muted);
  border-left: 2px solid var(--sage);
  padding-left: .9rem;
  margin-top: 1.3rem;
  max-width: 30rem;
}

/* scene hierarchy: give the first line after a kicker a modest size bump so
   each scene opens with a little of the rhythm the door has, instead of a flat
   wall of same-size lines. Modest on mobile (min just above base) so it doesn't
   force awkward wraps at ~390px. */
#pride .kicker + .step,
#gate .kicker + .step,
#everyday .kicker + .step,
#safety .kicker + .step,
#join .kicker + .step {
  font-size: clamp(1.5rem, 3.6vw, 2.4rem);
}

/* ============================================================
   READABILITY SCRIM — a soft, feathered paper panel behind each
   copy column. Guarantees WCAG AA over the busy loft in BOTH
   themes (measured: dark ink >10:1, muted >5:1 even over black);
   the illustration still shows around the words. No scroll code.
   ============================================================ */
.scene__inner { position: relative; isolation: isolate; }
/* HORIZONTAL BLEED IS CLAMPED TO THE GUTTER — WCAG 1.4.4 (Resize Text).
   The scrims bleed sideways in rem, but `.scene`'s right padding is px-clamped
   with a 24px floor, so the bleed outgrew the gutter and pushed the page wider
   than the viewport. Measured on the deployed build (WebKit):
     320px / root 16px  scrollWidth 322 vs 320   (+2)
     320px / root 24px  scrollWidth 334 vs 320  (+14)
     390px / root 32px  scrollWidth 414 vs 390  (+24)  <- 200% text = h-scroll
   Attributed by elimination, NOT guessed: hiding .loft__img changes nothing
   (it is absolute inside a fixed layer and cannot extend the scroll area);
   hiding .scene__inner::before alone drops 322 -> 320, and hiding all three
   scrims drops 414 -> 390. So all three get the clamp, and only the RIGHT edge
   is touched — the left gutter is >=52px and never overflowed.
   min(original, --gutter-r) => byte-identical at every width >= 366px, i.e. no
   change at all on any phone AG uses, on tablet or on desktop. */
.scene__inner::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -1.9rem -1.6rem;
  right: calc(-1 * min(1.6rem, var(--gutter-r)));
  border-radius: 0;
  background: color-mix(in srgb, var(--paper) 72%, transparent);
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
:root[data-theme="dark"] .scene__inner::before {
  background: color-mix(in srgb, var(--paper) 88%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .scene__inner::before {
    background: color-mix(in srgb, var(--paper) 88%, transparent);
  }
}
/* media scene: don't panel the whole grid — hug its two text pieces,
   so the vienna window keeps breathing next to a clear text column */
#media .scene__inner::before { display: none; }
#media .kicker, .mediaSteps { position: relative; isolation: isolate; }
#media .kicker::before,
.mediaSteps::before {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 0;
  background: color-mix(in srgb, var(--paper) 72%, transparent);
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
:root[data-theme="dark"] :is(#media .kicker, .mediaSteps)::before {
  background: color-mix(in srgb, var(--paper) 88%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) :is(#media .kicker, .mediaSteps)::before {
    background: color-mix(in srgb, var(--paper) 88%, transparent);
  }
}
/* same gutter clamp as .scene__inner::before above (see that comment) */
#media .kicker::before { inset: -0.7rem -1rem;   right: calc(-1 * min(1rem,   var(--gutter-r))); }
.mediaSteps::before   { inset: -1.4rem -1.3rem; right: calc(-1 * min(1.3rem, var(--gutter-r))); }

/* iOS hardening: a live backdrop-filter blur over the fixed loft is repainted
   every scroll frame and is the heaviest per-frame cost on real touch devices
   (the reported "scrolling feels broken on iPhone"). Drop the blur on coarse
   pointers only — the opaque paper panel + bloom below already carry WCAG AA
   legibility, so nothing becomes unreadable; the page just scrolls smooth. */
@media (pointer: coarse) {
  .scene__inner::before,
  #media .kicker::before,
  .mediaSteps::before,
  .gate {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  /* touch: every gate/ask button at least ~44px tall so a fingertip lands it cleanly */
  .gate__chip, .ask__chip {
    min-height: 44px;
  }
  /* firm the panel up slightly so it never leans on the (now-removed) blur */
  .scene__inner::before,
  #media .kicker::before,
  .mediaSteps::before {
    background: color-mix(in srgb, var(--paper) 93%, transparent);
  }
  /* touch: give the theme toggle a full ~44px tap target */
  .themeToggle {
    min-height: 44px;
  }
}

/* ---------- 1. THE DOOR ---------- */
#door { min-height: 108vh; min-height: 108svh; justify-content: center; }
#door .lede { font-size: clamp(2.4rem, 8vw, 5rem); }

/* ---------- 2. MEDIA HISTORY (vienna window) ---------- */
#media { max-width: 1180px; }
#media .scene__inner { max-width: 980px; width: 100%; }
.media__layout {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: clamp(24px, 5vw, 64px);
  align-items: start;
}
@media (max-width: 720px) {
  .media__layout { grid-template-columns: 1fr; gap: 0; }
}
.window {
  position: relative;
  width: min(320px, 62vw);
  margin-bottom: 2.4rem;
  box-shadow: var(--shadow), 0 0 0 1px var(--hair);
}
/* the vienna window stays pinned while the era-copy walks past it (native sticky) */
.media__window {
  position: sticky;
  top: 16vh;
  margin-bottom: 0;
}
/* mobile: NO sticky — the pinned card overlapped the era copy on real iPhones
   (AG photo 2026-07-31: caption collided with the text, lines hidden under the
   card). In one column the window simply sits in flow above the steps; the
   era-shift still tints it while it is on screen, and the steps carry the
   story on their own once it scrolls away. */
/* 2026-08-06 — `position: static` above killed the sticky, but it also stopped the
   figure being a containing block, so BOTH of its absolutely-positioned children
   escaped up to `.scene__inner` (the nearest positioned ancestor):
     · .window__tint (inset:0, mix-blend-mode:multiply) stretched to the WHOLE media
       section and multiplied a .30–.42 era slab over the copy — the "card painted on
       top of the text" AG photographed;
     · .window__era (bottom:-1.7rem) teleported to the bottom-left of the section,
       ~200px under the illustration it labels and buried in the steps' paper panel.
   Fix = keep it out of the sticky flow, but make it a containing block again
   (`relative` + `top:auto` so the inherited 16vh offset can't shift it), and give it
   a z-index so the caption paints above `.mediaSteps` — that sibling isolates its own
   `z-index:-1` scrim, so without this the panel covers the label. No geometry,
   size, spacing or colour of the artwork changes. */
@media (max-width: 720px) {
  .media__window {
    position: relative;
    top: auto;
    z-index: 1;
    width: min(220px, 52vw);
    margin: 0 auto 1.25rem;
  }
  /* and the label goes into normal FLOW here. Absolute + bottom:-1.7rem was fine
     against a 320px desktop figure, but the mobile figure is only 166–215px wide
     while the longest label ("~1990 · the world wide web") needs 241px — so it
     wrapped to two lines and, being bottom-anchored, grew UPWARDS over the
     artwork (measured 2413–3099px²). In flow it reserves its own height and
     wraps downwards, so it can never collide with the art or the copy no matter
     how long a future era label gets. nowrap was rejected: it pushes the label
     off-screen at 320px (right edge 331.7 > 320) and forces horizontal scroll. */
  /* …and because it is in FLOW, its line count is now part of the figure's height.
     walk.js swaps #eraLabel five times per pass, and at every phone width two of
     the five wrap to two lines ("~1440 · the printing press" wants 218.4px and
     "~1990 · the world wide web" 228.1px against a figure only 166.4–215.3px
     wide); the other three fit on one. Measured: 1-line box 23.20px, 2-line
     41.63px — so the figure, the copy under it, #pride, #join and the footer all
     jumped 18.4px twice per scroll-through. Reserve the TALLEST label's height so
     a short era leaves the layout exactly where a long one does: two line boxes
     plus the .15rem×2 padding. box-sizing here is border-box (measured via
     getComputedStyle), so min-height INCLUDES that padding and it has to be added
     in. line-height is stated explicitly — it only inherits body's 1.6 today, and
     the reservation must not silently drift if that ever changes. Derived, not a
     magic number: 3.2em = 2 × 1.6 line-height at this element's own .72rem.
     Do NOT "tidy" this to nowrap — at 320px the label's right edge lands at
     331.7 > 320 and forces horizontal scroll.
     COPY BUDGET, and this is the realistic way it breaks: the reservation covers
     exactly TWO lines. The longest shipped label ("~1990 · the world wide web")
     has ~8 characters of headroom at 320px (11 at 360, 17 at 390, 18 at 414)
     before it wraps to a third line and the 18.4px jump comes straight back.
     Nothing in the build catches that — if you reword an era label in
     index.html/js/walk.js, re-check it at 320px. It is min-height not height, so
     a 3-line label degrades to the old jump, never to clipped or overlapping text. */
  .media__window .window__era {
    position: static;
    display: block;
    margin-top: .55rem;
    padding-left: 0;
    background: none;
    line-height: 1.6;
    min-height: calc(3.2em + .3rem);
  }
  /* the figure box now includes the in-flow label, so the era tint (inset:0) would
     stretch over the label too — at era="capture" that is a .42 near-black multiply
     straight across the caption text. Lay the figure out as a one-column grid and
     put the artwork and the tint in the SAME cell: the tint then sizes itself to
     the artwork exactly, at any width, with no hard-coded ratio. (Don't be tempted
     by aspect-ratio here. NOTE 2026-08-07: index.html USED to declare the img as
     896x1152 against a real 896x1200 asset, so a literal ratio undershot by
     ~9-12px. The declared height is now the true 1200, but the same-cell grid
     below still sizes the tint to the artwork exactly at any width, with no
     hard-coded ratio to keep in sync — leave it that way.) */
  .media__window {
    display: grid;
    grid-template-columns: 100%;
  }
  .media__window > img,
  .media__window > .window__tint { grid-area: 1 / 1; }
  .media__window > .window__era  { grid-area: 2 / 1; }
  .media__window .window__tint {
    position: relative;
    inset: auto;
  }
  .mediaSteps { margin-top: .4rem; }
}
.window img { width: 100%; height: auto; border-radius: var(--r); }
/* scroll-linked era tint over the window; hue set by data-era */
.window__tint {
  position: absolute; inset: 0; border-radius: var(--r);
  mix-blend-mode: multiply;
  opacity: .0;
  transition: background 1.1s ease, opacity 1.1s ease;
  background: transparent;
}
.window[data-era="press"]    .window__tint { opacity:.30; background:#6b5836; } /* sepia / candle */
.window[data-era="web"]      .window__tint { opacity:.26; background:#3a5b6b; } /* cathode blue */
.window[data-era="ai"]       .window__tint { opacity:.24; background:#4a3a6b; } /* violet now */
.window[data-era="capture"]  .window__tint { opacity:.42; background:#231f1b; } /* the enclosure */
.window[data-era="turn"]     .window__tint { opacity:.0;  background:transparent; } /* clears */
.window__era {
  position: absolute; left: 0; bottom: -1.7rem;
  font-family: var(--body); font-size: .72rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--fg);
  background: color-mix(in srgb, var(--bg) 70%, transparent);
  padding: .15rem .4rem;
}
/* TODO(AG/IDA): real per-era window art (press candlelight / crt web / ai glow).
   For pass-1 we approximate the era shift with the tint + label above. */
/* progressive reveal: the ACTIVE era line wins (full ink + weight); the
   others are de-emphasized to --muted but stay legible over the scrim
   (measured >5:1 both themes) — never a pile of overlapping bright lines.
   Opt these lines out of the beat fade + scroll-timeline so JS owns them. */
.mediaSteps .step {
  max-width: 32rem;
  color: var(--dim);
  opacity: 1 !important;
  transform: none !important;
  animation: none !important;
  transition: color .5s ease, font-weight .5s ease;
}
.mediaSteps .step.is-active { color: var(--fg); font-weight: 480; }

/* ---------- 3. WHO'S BUILDING THIS (humble colophon) ---------- */
#pride { max-width: 1080px; }
.masthead {
  font-family: var(--body);
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: lowercase;
  color: var(--muted);
  margin-top: 1.6rem;
  max-width: 30rem;
}
.masthead span { opacity: .5; margin: 0 .2em; }

/* ---------- 4. THE GATE — real interactive, client-side, no backend ---------- */
#gate { max-width: 1080px; }
.gate {
  margin-top: 1.6rem;
  max-width: 34rem;
  border: 1px solid var(--hair);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  box-shadow: none;
  padding: 1.1rem 1.2rem 1.3rem;
  border-radius: var(--r);
  font-family: var(--body);
  font-size: .95rem;
}
.gate__try { margin: 0 0 .7rem; color: var(--muted); font-size: .88rem; }

/* chips: flat paper buttons, no glow, no radius beyond the house --r */
.gate__chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.gate__chip {
  font: inherit; font-size: .84rem; cursor: pointer;
  padding: .5rem .8rem;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  text-align: left;
  line-height: 1.3;
}
.gate__chip:hover { border-color: var(--gold-deco); }
.gate__chip:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 1px; }
.gate__chip.is-on { border-color: var(--gold); color: var(--gold); }
.gate__chip--ask { background: var(--fg); color: var(--bg); border-color: var(--fg); flex: 0 0 auto; }
.gate__chip--ask:hover { background: var(--gold); border-color: var(--gold); color: #fff; }

.gate__form { display: flex; gap: .5rem; margin-top: .6rem; }
.gate__form input[type="text"] {
  flex: 1 1 auto; min-width: 0;
  font: inherit; font-size: .9rem;
  padding: .55rem .7rem;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
}
.gate__form input:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 1px; }

/* the verdict: one plain line + reason, no icons/glow, colour carries the read */
.gate__verdict {
  margin-top: 1rem;
  padding: .8rem .9rem;
  border: 1px solid var(--hair);
  border-radius: var(--r);
  background: var(--bg);
}
.gate__verdict-head { font-family: var(--display); font-size: 1.05rem; text-transform: lowercase; margin: 0 0 .25rem; }
.gate__verdict-body { margin: 0; color: var(--muted); font-size: .88rem; }
.gate__verdict.is-pass .gate__verdict-head { color: #4f6d40; }
.gate__verdict.is-hold .gate__verdict-head { color: var(--terracotta); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gate__verdict.is-pass .gate__verdict-head { color: #9fc98a; }
  :root:not([data-theme="light"]) .gate__verdict.is-hold .gate__verdict-head { color: #dd8f68; }
}
:root[data-theme="dark"] .gate__verdict.is-pass .gate__verdict-head { color: #9fc98a; }
:root[data-theme="dark"] .gate__verdict.is-hold .gate__verdict-head { color: #dd8f68; }
.gate__verdict.is-checking .gate__verdict-head { color: var(--muted); }

.gate__link {
  display: inline-block; margin-top: .8rem;
  font: inherit; font-size: .82rem; color: var(--gold);
  background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
/* [hidden] must win over the display:inline-block above — same fix the pledge got (see .pledge__litany[hidden]) */
.gate__link[hidden] { display: none; }
.gate__link:hover { color: var(--gold-deco); }
.gate__link:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 2px; }
#gate-edit-toggle { display: block; margin-top: .8rem; }
#gate-edit-toggle[aria-pressed="true"] { color: var(--terracotta); }

.gate__record { margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--hair); }
.gate__recordLabel { margin: 0 0 .6rem; color: var(--muted); font-size: .82rem; }
.gate__log { display: flex; flex-direction: column; gap: .5rem; }
.gate__logEntry {
  padding: .5rem .6rem;
  border: 1px solid var(--hair);
  border-radius: var(--r);
  font-size: .78rem;
  line-height: 1.5;
}
.gate__logEntry.is-tampered { border-color: var(--terracotta); }
.gate__logTs { color: var(--muted); margin-right: .5rem; }
.gate__logAction { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.gate__logAction[contenteditable="true"] { background: color-mix(in srgb, var(--gold-deco) 12%, transparent); outline: none; cursor: text; }
.gate__logAction[contenteditable="true"]:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 1px; }
.gate__logVerdict { margin-left: .5rem; font-variant: small-caps; letter-spacing: .04em; }
.gate__logVerdict.pass { color: #4f6d40; }
.gate__logVerdict.hold { color: var(--terracotta); }
:root[data-theme="dark"] .gate__logVerdict.pass { color: #9fc98a; }
:root[data-theme="dark"] .gate__logVerdict.hold { color: #dd8f68; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gate__logVerdict.pass { color: #9fc98a; }
  :root:not([data-theme="light"]) .gate__logVerdict.hold { color: #dd8f68; }
}
.gate__logHash { display: block; margin-top: .2rem; color: var(--muted); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.gate__logHash.is-broken { color: var(--terracotta); font-family: var(--body); }
.gate__chainNote { margin: .6rem 0 0; color: var(--terracotta); font-size: .82rem; font-weight: 560; }

.gate__feedback { margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--hair); }
.gate__feedbackQ { margin: 0 0 .5rem; font-size: .88rem; }
.gate__feedbackRow { display: flex; gap: .5rem; margin-top: .5rem; }
.gate__feedbackRow input[type="text"] {
  flex: 1 1 auto; min-width: 0;
  font: inherit; font-size: .86rem;
  padding: .5rem .65rem;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
}
.gate__feedbackState { margin: .5rem 0 0; font-size: .8rem; color: var(--muted); min-height: 1.1em; }

/* ---------- 4b. THE EVERYDAY ---------- */
#everyday { max-width: 1080px; }
#everyday .step { max-width: 33rem; }
/* the "quiet" line lands softer — the point is calm, not shout */
#everyday .quiet { color: var(--muted); }
#everyday .quiet .em { color: var(--fg); }
/* ---------- scene visualization: a wide editorial illustration that anchors
   a scene (the everyday "ai at home", the "safety scales" arc). Flat editorial
   framing, same family as .window: hairline ring, house --r + --shadow. ---------- */
.viz {
  margin: 1.8rem 0 1.4rem;
  width: min(560px, 100%);
  position: relative;
}
.viz img {
  width: 100%; height: auto;
  border-radius: var(--r);
  box-shadow: var(--shadow), 0 0 0 1px var(--hair);
}
.viz__cap {
  margin: .7rem 0 0;
  font-family: var(--body);
  font-size: .82rem;
  letter-spacing: .01em;
  color: var(--muted);
  max-width: 30rem;
}

/* ---------- 4d. SAFETY SCALES WITH POWER ---------- */
#safety { max-width: 1080px; }
#safety .step { max-width: 33rem; }
/* let the loft carry a faint warm bloom through the safety scene, a touch
   below the savannah peak — power rising, but calm */
body[data-scene="safety"] .loft__bloom { opacity: .34; }

/* ---------- 5. SAVANNAH PEAK ---------- */
#savannah { max-width: 1080px; }
#savannah .step { font-size: clamp(1.6rem, 4.4vw, 2.8rem); }
.roar {
  font-family: var(--display);
  text-transform: lowercase;
  font-weight: 500;
  font-size: clamp(2.2rem, 7vw, 4.4rem);
  color: var(--gold);
  margin: .3em 0 0;
}
.roar .own { color: var(--terracotta); }

/* ---------- 6. JOIN ---------- */
#join { min-height: 100vh; min-height: 100svh; justify-content: center; }
.join__form {
  display: flex; flex-wrap: wrap; gap: .6rem;
  margin: 1.4rem 0 1rem; max-width: 30rem;
}
.join__form input[type="email"] {
  flex: 1 1 15rem;
  min-width: 0; /* let it shrink below the 15rem basis at large text sizes (was clipping at the viewport edge) */
  font: inherit; font-size: 1rem;
  padding: .8rem .9rem;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
}
.join__form input:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 1px; }
.btn {
  font: inherit; font-size: 1rem; cursor: pointer;
  padding: .8rem 1.4rem;
  background: var(--fg); color: var(--bg);
  border: 1px solid var(--fg);
  border-radius: var(--r);
  text-transform: lowercase;
  letter-spacing: .01em;
}
.btn:hover { background: var(--gold); border-color: var(--gold); color: #fff; }
.btn:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 2px; }
.consent { font-size: .82rem; color: var(--muted); max-width: 28rem; }
.listen {
  display: inline-flex; align-items: center; gap: .5rem;
  margin: 1.2rem 0 0; font-size: .9rem; color: var(--muted);
}
.listen audio { height: 34px; }
.listen a { color: var(--gold); text-underline-offset: 3px; }

/* prominent listen section (the two tellings) */
.listen-opts { display: flex; flex-direction: column; gap: 1.5rem; margin-top: 1.7rem; max-width: 34rem; }
.listen-opt__title { font-family: var(--body); font-size: .82rem; letter-spacing: .08em; text-transform: lowercase; color: var(--muted); margin: 0 0 .5rem; }
.listen-opt__len { color: var(--muted); }
.listen-opt audio { width: 100%; max-width: 34rem; }

footer.foot {
  position: relative; z-index: 10;
  padding: 3rem clamp(52px, 9vw, 120px) 4rem;
  border-top: 1px solid var(--hair);
  font-family: var(--body); font-size: .86rem; color: var(--muted);
  background: var(--bg);
}
.foot__made { font-family: var(--display); text-transform: lowercase; font-size: 1.05rem; color: var(--fg); margin: 0 0 .6rem; }
.foot a { color: var(--fg); text-decoration: none; border-bottom: 1px solid var(--hair); }
.foot a:hover { border-color: var(--gold-deco); }
.foot__links { display: flex; gap: 1.2rem; flex-wrap: wrap; margin-top: .3rem; }

/* ---------- 4c. ASK — a clean "ask openroar" (client-side scripted Q&A) ----------
   same flat/minimal family as the gate: paper panel, house --r, no glow. */
#ask { max-width: 1080px; }
.ask {
  margin-top: 1.6rem;
  max-width: 34rem;
  border: 1px solid var(--hair);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  box-shadow: none;
  padding: 1.1rem 1.2rem 1.3rem;
  border-radius: var(--r);
  font-family: var(--body);
  font-size: .95rem;
}
.ask__form { display: flex; gap: .5rem; }
.ask__form input[type="text"] {
  flex: 1 1 auto; min-width: 0;
  font: inherit; font-size: .95rem;
  padding: .6rem .75rem;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
}
.ask__form input:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 1px; }
.ask__send {
  font: inherit; font-size: .9rem; cursor: pointer;
  padding: .6rem 1.1rem;
  background: var(--fg); color: var(--bg);
  border: 1px solid var(--fg);
  border-radius: var(--r);
  text-transform: lowercase; letter-spacing: .01em;
  flex: 0 0 auto;
}
.ask__send:hover { background: var(--gold); border-color: var(--gold); color: #fff; }
.ask__send:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 2px; }

.ask__chips { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .7rem; }
.ask__chip {
  font: inherit; font-size: .84rem; cursor: pointer;
  padding: .5rem .8rem;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  text-align: left; line-height: 1.3;
}
.ask__chip:hover { border-color: var(--gold-deco); }
.ask__chip:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 1px; }
.ask__chip.is-on { border-color: var(--gold); color: var(--gold); }

/* the calm reading panel */
.ask__answer {
  margin-top: 1rem;
  padding: .9rem 1rem 1rem;
  border: 1px solid var(--hair);
  border-radius: var(--r);
  background: var(--bg);
}
.ask__q { margin: 0 0 .55rem; font-size: .8rem; letter-spacing: .02em; color: var(--muted); }
.ask__q::before { content: "you asked — "; color: var(--muted); }
.ask__a {
  margin: 0;
  font-family: var(--display); font-weight: 370;
  text-transform: lowercase;
  font-size: 1.12rem; line-height: 1.42;
  color: var(--fg);
}
.ask__a + .ask__a { margin-top: .75rem; }
.ask__a .em { color: var(--gold); font-weight: 560; font-style: normal; }
.ask__deeper {
  display: inline-block; margin-top: .85rem;
  font: inherit; font-size: .82rem; color: var(--gold);
  background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.ask__deeper:hover { color: var(--gold-deco); }
.ask__deeper:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 2px; }
/* the honest fallback reads as plain body copy, not the serif "answer" voice */
.ask__fallback .ask__a {
  font-family: var(--body); text-transform: none;
  font-size: .95rem; line-height: 1.6; color: var(--muted);
}
.ask__fallback .ask__a a { color: var(--gold); text-underline-offset: 3px; }

/* ---------- 5b. THE PLEDGE — a quiet oath, revealed on activate ---------- */
#pledge { max-width: 1080px; min-height: 82vh; min-height: 82svh; justify-content: center; }
#pledge .scene__inner { max-width: 40rem; margin: 0 auto; text-align: center; }
#pledge .kicker { margin-bottom: 1.5rem; }
.pledge__reveal {
  display: inline-flex; align-items: center; gap: .6rem;
  font-family: var(--body); font-size: .9rem;
  color: var(--muted); background: none; cursor: pointer;
  border: 1px solid var(--hair);
  border-radius: 999px;
  padding: .55rem 1.15rem;
  transition: color .25s ease, border-color .25s ease, opacity .3s ease;
}
.pledge__reveal:hover, .pledge__reveal:focus-visible { color: var(--gold); border-color: var(--gold-deco); }
.pledge__reveal:focus-visible { outline: 2px solid var(--gold-deco); outline-offset: 3px; }
.pledge__spark { color: var(--gold-deco); font-size: 1.15em; line-height: 1; display: inline-block; }
.pledge__reveal[aria-expanded="true"] { opacity: .45; }

.pledge__litany { margin-top: 2rem; }
.pledge__litany[hidden] { display: none; }
.pl-line {
  margin: 0 0 .7rem;
  font-family: var(--display); font-weight: 400;
  text-transform: lowercase;
  font-size: clamp(1.4rem, 3.4vw, 2.2rem); line-height: 1.28; letter-spacing: -0.005em;
  color: var(--fg);
  opacity: 0; transform: translateY(12px);
  transition: opacity .6s cubic-bezier(.16,1,.3,1), transform .6s cubic-bezier(.16,1,.3,1);
  transition-delay: calc(var(--i, 0) * 300ms);
}
.pledge__litany.on .pl-line { opacity: 1; transform: none; }
.pl-close { margin-top: 1.2rem; color: var(--gold); font-style: italic; }
@media (prefers-reduced-motion: reduce) {
  .pl-line { transition: none; opacity: 1; transform: none; }
}

/* ============================================================
   REDUCED MOTION — room starts lit, everything readable, no wipes
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .beat { opacity: 1 !important; transform: none !important; transition: none !important; }
  .loft__veil { opacity: .28 !important; }         /* room already lit */
  .loft__img { transform: scale(1.04) !important; }
  .loft__bloom { transition: none; }
  .rail__dot { transition: none; }
  .window__tint { transition: none; }
}

/* progressive enhancement: where the browser supports scroll-driven
   animation we let the rail + beats ride the timeline natively too.
   (Still class-based fallback above; NEVER touches scroll position.) */
/* (Removed the animation-timeline reveal: on iOS Safari a view() timeline over the fixed
   backdrop can pin content at opacity:0 and blank the page, and a running animation with
   fill:both overrides the .in class so the JS fallback can't recover it. The transition-based
   IntersectionObserver reveal above is robust everywhere and never leaves content hidden.) */

/* ============================================================
   THEME-TOGGLE POLISH — soft cross-fade of theme-driven colors so
   the manual toggle doesn't snap. Reduced-motion users are excluded.
   NOTE: this deliberately does NOT transition any scroll/reveal
   transform. .window__tint keeps its era cross-fade — only
   color/shadow are added.
   ============================================================ */
@media (prefers-reduced-motion: no-preference){
  body, .scene__inner::before, .gate, .themeToggle{
    transition: background-color .35s ease, color .35s ease, border-color .35s ease, box-shadow .35s ease;
  }
  .gate__chip, .gate__chip--ask, .ask__chip, .ask__send, .btn,
  .gate__link, .ask__deeper, .foot a, .listen a{
    transition: background-color .2s ease, color .2s ease, border-color .2s ease;
  }
  .window__tint{
    transition: background 1.1s ease, opacity 1.1s ease;
  }
}
