/* openroar — GUIDED OFFICE build (dist_guided).
   One clear focus at a time: a vertical sequence of full-height "chapters",
   each guided by an agent, built on Design System V1 tokens (tokens.css) and
   the v10 component library (v10.css — buttons, fields, solo-focus, gate
   widget, player, tracks, consent banner). This file adds only what those
   two don't already cover: the blossom intro, the chapter scaffold/scroll
   sequencing, the progress rail, and the pride carousel.

   No CSS-drawn furniture, no free-drag office, no parallax wall — the crisp
   illustrated art (assets/world, assets/solo) carries the atmosphere. */

/* FIX (2026-07-08, stef, QA): `scroll-snap-type:y proximity` combined with
   `scroll-snap-align:start` on every `.chapter` (below) plus the JS-gated
   opacity:0 reveal defaults (removed further down, see "ARRIVAL MOTION")
   made the page depend on a guided-scroll controller (js/guided.v2.js) to
   ever show content below the hero — if that controller's
   IntersectionObserver never fired for a section (different viewport,
   timing, or JS disabled entirely) that section stayed at opacity:0
   forever. Converted to a normal top-to-bottom scroll: no snap, nothing
   hidden by default. Sections just flow in document order now. */
html{ overflow-x:hidden; overflow-x:clip; }
/* FIX (charlie, mobile-overflow audit): `overflow-x:clip` alone isn't
   supported on iOS Safari <16 — declare `hidden` first as a universal
   fallback, then `clip` (browsers that don't parse `clip` simply ignore
   that line and keep `hidden`; browsers that do parse it use `clip` as
   before). Belt-and-suspenders on top of the existing guard; no layout or
   visual change on any browser that already honored `clip`. Also caps
   documentElement/body/.oros at 100vw so no fixed/negative-margin child can
   push the page wider than the viewport. */
body{ overflow-x:hidden; overflow-x:clip; max-width:100vw; }
.oros{ overflow-x:hidden; overflow-x:clip; max-width:100vw; }

/* ============ ARRIVAL FADE (was "blossom") ============
   REWORK (2026-07-07, AG: "not meant literally — looks shit"): the previous
   version drew six literal petals opening outward — read as a flower blossoming,
   not a brand mark. Now: one quiet settle, ~0.8s total. The mark fades + rises a
   few px; the wordmark follows a beat later; nothing rotates, scales past 1, or
   "blooms". Kept the id/classnames (#blossom, .blossom-*) so js/guided.js and
   this page's markup didn't need touching beyond the two now-unused layers. */
#blossom{
  position:fixed; inset:0; z-index:9999; display:flex; align-items:center; justify-content:center;
  background:var(--bg); transition:opacity .5s var(--ease-out); cursor:pointer;
}
#blossom.blossom-hide{ opacity:0; pointer-events:none; }
.blossom-stage{ position:relative; width:180px; height:96px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; }
.blossom-mark{ position:relative; z-index:2; width:44px; height:auto; opacity:0; transform:translateY(8px); }
.blossom-play .blossom-mark{ animation:blossomSettle .6s var(--ease-out) forwards; }
@keyframes blossomSettle{ 0%{ opacity:0; transform:translateY(8px); } 100%{ opacity:1; transform:translateY(0); } }
.blossom-word{
  position:relative; opacity:0; transform:translateY(6px);
  font-family:'Fraunces',serif; font-weight:500; font-size:15px; letter-spacing:.02em; color:var(--muted); white-space:nowrap;
}
.blossom-play .blossom-word{ animation:blossomSettle .5s var(--ease-out) forwards; animation-delay:.18s; }
.blossom-skip{ position:absolute; bottom:26px; left:50%; transform:translateX(-50%); font-size:11px; color:var(--faint); letter-spacing:.04em; }

/* FIX (found in this build's QA pass): v10.css's ".or-consent{display:flex}"
   (specificity 0,1,0) ties with the UA "[hidden]{display:none}" rule at the
   same specificity, and author CSS wins that tie — so setting the `hidden`
   attribute via JS (consent.js, on decline/accept) silently failed to hide
   the banner. This is a latent bug in the shared component, not something
   new here; fixing it in scope since the guided build actually exercises
   the decided/dismissed state. */
.or-consent[hidden]{ display:none !important; }

/* ============ SLIM HEADER ============ */
.g-top{ position:fixed; top:0; left:0; right:0; z-index:70; display:flex; align-items:center; gap:10px; padding:14px 20px;
  background:color-mix(in srgb, var(--bg) 82%, transparent); -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px); }
.g-top .mark{ width:19px; height:21px; flex:none; }
.g-top .word{ font-family:'Fraunces',serif; font-weight:600; font-size:14.5px; letter-spacing:-.01em; color:var(--ink); }
.g-top .a11y-row{ margin-left:auto; display:flex; gap:6px; }

/* ============ THEME TOGGLE (light/dark) ============
   AG: "where is the bright feature? where is the dark feature?" — the dark
   token set already existed (tokens.css); nothing wired a control to it. One
   icon-only pill, same family as the two a11y pills. Also the "opalite"
   easter egg's sun (see js/theme.js). */
.theme-pill{ width:32px; height:26px; padding:0 !important; display:inline-flex; align-items:center; justify-content:center; }
.theme-icon{ display:block; }
.theme-icon-moon{ display:none; }
.oros[data-or-theme="dark"] .theme-icon-sun{ display:none; }
.oros[data-or-theme="dark"] .theme-icon-moon{ display:block; }
@media (prefers-reduced-motion:no-preference){
  .theme-icon{ transition:opacity .3s var(--ease-out), transform .3s var(--ease-spring); }
  .theme-icon-sun{ transform:rotate(0deg) scale(1); }
  .oros[data-or-theme="dark"] .theme-icon-moon{ animation:themeIconIn .3s var(--ease-spring); }
  @keyframes themeIconIn{ 0%{ opacity:0; transform:scale(.5) rotate(-30deg); } 100%{ opacity:1; transform:none; } }
}


/* ============ PROGRESS RAIL (desktop) ============ */
.g-rail{ position:fixed; right:22px; top:50%; transform:translateY(-50%); z-index:60; display:none; flex-direction:column; gap:16px; }
@media (min-width:900px){ .g-rail{ display:flex; } }
.g-rail button{ position:relative; width:9px; height:9px; border-radius:50%; background:var(--hair-2); padding:0; transition:all .25s var(--ease-out); }
.g-rail button.on{ background:var(--accent); transform:scale(1.3); }
.g-rail-label{ position:absolute; right:20px; top:50%; transform:translateY(-50%) translateX(6px); opacity:0; pointer-events:none;
  font-family:'JetBrains Mono',monospace; font-size:10.5px; letter-spacing:.03em; color:var(--ink); background:var(--surface); padding:4px 9px;
  border-radius:var(--wob-pill); box-shadow:var(--shadow-1); white-space:nowrap; transition:opacity .18s, transform .18s; }
.g-rail button:hover .g-rail-label, .g-rail button:focus-visible .g-rail-label{ opacity:1; transform:translateY(-50%) translateX(0); }

/* ============ CHAPTER SCAFFOLD ============ */
.chapter{ position:relative; min-height:100vh; min-height:100svh; box-sizing:border-box; display:flex; flex-direction:column;
  justify-content:center; padding:104px 20px 84px; overflow:hidden; }
.chapter-inner{ position:relative; z-index:2; max-width:640px; margin:0 auto; width:100%; }
.chapter-inner.wide{ max-width:900px; }
.chapter-eyebrow{ font-family:'JetBrains Mono',monospace; font-size:11.5px; letter-spacing:.07em; text-transform:lowercase; margin:0 0 12px; opacity:.86; }
.chapter h1, .chapter h2{ font-family:'Fraunces',serif; font-weight:500; letter-spacing:-.01em; margin:0 0 16px; }
.chapter h1{ font-size:clamp(28px,7.4vw,44px); line-height:1.1; }
.chapter h2{ font-size:clamp(23px,5.2vw,32px); line-height:1.16; }
.chapter p.g-lead{ font-size:clamp(15.5px,3.8vw,17.5px); line-height:var(--lh-body); margin:0 0 18px; max-width:56ch; }

/* full-bleed media chapters (vision / join) — light text over illustrated art.
   Anchored toward the lower third (not dead-centred): shows more of the
   establishing shot above, and avoids a tall empty gap under short content
   (join) before the footer. */
.chapter--media{ color:#F7F3EA; justify-content:flex-end; padding-bottom:120px; }
/* specificity note: tokens.css's ".oros img{height:auto}" (0,1,1) would beat a
   plain ".chapter-bg{height:100%}" (0,1,0) — scope under .chapter--media so
   ours wins (0,2,0) and the backdrop truly fills the section, not its own
   natural aspect-ratio height. */
.chapter--media .chapter-bg{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:0; }
.chapter-scrim{ position:absolute; inset:0; z-index:1; background:linear-gradient(180deg, rgba(31,25,20,.1) 0%, rgba(31,25,20,.38) 42%, rgba(31,25,20,.7) 100%); }
.chapter--media .chapter-eyebrow{ color:#E4C98A; }
.chapter--media h1, .chapter--media h2{ color:#FBF7EF; }
.chapter--media p.g-lead{ color:rgba(251,247,239,.88); }

/* plain-paper chapters (pride / gate / listen / install) */
.chapter--paper{ background:var(--bg); }
.chapter--paper .chapter-eyebrow{ color:var(--accent-deep); }

/* continue hint */
.chapter-next{ position:absolute; bottom:24px; left:50%; transform:translateX(-50%); z-index:2; width:36px; height:36px;
  border-radius:50%; background:var(--surface); box-shadow:var(--shadow-1); display:flex; align-items:center; justify-content:center;
  color:var(--ink); animation:chapterBounce 2.8s ease-in-out infinite; }
.chapter--media .chapter-next{ background:rgba(251,247,239,.16); color:#FBF7EF; box-shadow:none; border:1px solid rgba(251,247,239,.4); backdrop-filter:blur(6px); }
@keyframes chapterBounce{ 0%,100%{ transform:translateX(-50%) translateY(0); } 50%{ transform:translateX(-50%) translateY(6px); } }
.chapter:last-of-type .chapter-next{ display:none; }

/* ============ HERO / VISION ============ */
.g-cta-row{ display:flex; flex-wrap:wrap; gap:10px; margin-top:8px; }

/* ============ PRIDE CAROUSEL ============ */
.pride-stage{ position:relative; max-width:560px; margin:0 auto; width:100%; }
.pride-slide{ display:none; }
.pride-slide.on{ display:flex; flex-direction:column; align-items:center; text-align:center; animation:or-rise .5s var(--ease-out); }
.pride-nav{ display:flex; align-items:center; justify-content:center; gap:18px; margin-top:6px; }
.pride-arrow{ width:38px; height:38px; border-radius:50%; background:var(--surface); border:1px solid var(--hair-2); display:flex; align-items:center; justify-content:center; flex:none; }
.pride-arrow:hover{ border-color:var(--accent); }
.pride-dots{ display:flex; gap:8px; align-items:center; }
.pride-dots button{ width:8px; height:8px; border-radius:50%; background:var(--hair-2); padding:0; transition:all .22s var(--ease-out); }
.pride-dots button.on{ background:var(--accent); width:22px; border-radius:5px; }
.pride-count{ font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--faint); text-align:center; margin-top:10px; }

/* ============ SOLO — compact variant (listen / onboarding guide) ============ */
.solo--compact .solo-avatar{ max-width:132px; margin-bottom:12px; }
.solo--compact .solo-quote{ font-size:15px; }
.solo--left{ align-items:flex-start; text-align:left; }
.solo--left .solo-quote, .solo--left .solo-body{ margin-left:0; }

/* ============ GATE CHAPTER — two-column "mostly just her" layout ============ */
.gate-grid{ display:grid; grid-template-columns:1fr; gap:30px; }
@media (min-width:900px){
  .gate-grid{ grid-template-columns:.86fr 1.14fr; align-items:center; gap:46px; }
  .gate-grid .solo{ align-items:flex-start; text-align:left; }
  .gate-grid .solo-avatar{ max-width:100%; }
}

/* ============ LISTEN — face + players deck ============ */
/* FIX (found in this build's QA pass): the markup shipped with these classes but no CSS
   existed for them anywhere in the bundle — the name/role spans had no gap between them
   ("charlienarrating · agent", no space) and the portrait rendered at full native size
   (896x1200) with no cap, dwarfing the players below it, especially on desktop. */
.listen-deck{ display:flex; flex-direction:column; align-items:center; gap:18px; }
.listen-face{ display:flex; flex-direction:column; align-items:center; flex:none; }
.listen-face img{ width:100%; max-width:132px; height:auto; object-fit:cover; border-radius:var(--wob-card); box-shadow:var(--shadow-1); margin-bottom:10px; }
.listen-face-cap{ display:flex; flex-direction:column; align-items:center; gap:2px; }
.listen-face-name{ font-family:'Inter',system-ui,sans-serif; font-weight:700; font-size:14px; }
.listen-face-role{ font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--faint); text-transform:lowercase; }
.listen-players{ width:100%; max-width:460px; }
@media (min-width:760px){
  .listen-deck{ flex-direction:row; align-items:flex-start; justify-content:center; gap:36px; }
  .listen-face img{ max-width:160px; }
  .listen-players{ margin-top:2px; }
}

/* ============ ONBOARDING guide strip ============ */
.onb-guide{ display:flex; align-items:center; gap:14px; margin-bottom:26px; }
.onb-guide img{ width:52px; height:70px; object-fit:cover; border-radius:var(--wob-in); box-shadow:var(--shadow-1); flex:none; }
.onb-guide .onb-guide-name{ font-family:'Inter',system-ui,sans-serif; font-weight:700; font-size:14px; }
.onb-guide .onb-guide-quote{ font-family:'Inter',system-ui,sans-serif; font-size:13.5px; color:var(--muted); }

/* ============ JOIN card over savannah ============ */
.join-card{ background:var(--glass-bg); -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat)); backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  border:1px solid var(--glass-brd); border-radius:var(--wob-card); padding:26px 24px; box-shadow:var(--shadow-2); }
.chapter--media .join-card{ background:rgba(251,247,239,.14); border-color:rgba(251,247,239,.3); }
.chapter--media .join-card .or-field{ background:rgba(251,247,239,.92); color:#28211C; }
.chapter--media #join-state{ color:rgba(251,247,239,.82) !important; }

/* ============ FOOTER (normal flow, not snapped) ============ */
footer.g-foot{ position:relative; padding:64px 20px 48px; background:var(--bg); }
/* a soft fade from the join chapter's dark scrim into the paper footer — no hard seam */
footer.g-foot::before{ content:""; position:absolute; top:-64px; left:0; right:0; height:64px; z-index:1;
  background:linear-gradient(180deg, rgba(31,25,20,.62), var(--bg)); pointer-events:none; }
.g-foot-links{ display:flex; flex-wrap:wrap; gap:14px; font-size:12.5px; margin-bottom:16px; }
.g-foot-link-btn{ background:none; border:none; padding:0; font-family:inherit; font-size:inherit; color:var(--accent-deep); cursor:pointer; }
.g-foot-link-btn:hover{ color:var(--accent); text-decoration:underline; }
.g-foot-credit{ font-size:11.5px; color:var(--faint); max-width:60ch; }
.g-foot .egg-quote{ font-family:'Fraunces',serif; font-style:italic; font-size:13px; color:var(--faint); margin-top:12px; cursor:pointer; }
.g-foot .egg-quote[data-open="1"]{ color:var(--accent-deep); }
.g-foot .egg-reveal{ display:none; font-size:12px; color:var(--muted); margin-top:6px; max-width:52ch; }
.g-foot .egg-quote[data-open="1"] + .egg-reveal{ display:block; }

/* ============ DESKTOP polish ============ */
@media (min-width:900px){
  .chapter{ padding:120px 40px 96px; }
  .onb-guide img{ width:64px; height:86px; }
}

/* ============ REDUCED MOTION ============ */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; scroll-snap-type:none; }
  .chapter-next{ animation:none; }
  /* the arrival fade still SHOWS (brand mark, legible, on load) — it just
     doesn't move. js/guided.js skips the animation classes for this
     preference and holds briefly before removing the overlay; without this
     rule the mark's un-animated base state (opacity:0) would leave a blank
     paper flash instead. */
  .blossom-mark{ opacity:1; transform:none; }
  .blossom-word{ opacity:1; }
}
.oros[data-or-motion="reduced"] .chapter-next{ animation:none; }

/* ================================================================
   QUALITY PASS (5-star rework) — layered ON TOP of everything above.
   Fixes the four things that read as "unfinished" in QA:
     1. the consent card was a big floating panel that covered the hero
        CTAs, the gate widget, and the join form (worst on mobile);
     2. paper chapters put a narrow, left-aligned column adrift in a wide
        empty field — reads as "shoved right / broken", not composed;
     3. light text over the illustrated media chapters sat low-contrast on
        the busy warmest parts of the art;
     4. no arrival motion, so the "guided" walk felt static.
   ================================================================ */

/* ---------- 1 · CONSENT → slim, non-blocking system bar ---------- */
/* Still the first interactive thing (DOM order + consent.js unchanged) and it
   still persists until the visitor decides — it just no longer sits ON TOP of
   the content. A thin, full-width, blurred bar docked to the bottom edge:
   one row on desktop, a compact stack on mobile. */
.or-consent{ padding:0 !important; justify-content:stretch !important; }
.or-consent-card{
  max-width:none !important; width:100%; border-radius:0 !important;
  border:none; border-top:1px solid var(--hair-2);
  background:color-mix(in srgb, var(--surface) 88%, transparent);
  -webkit-backdrop-filter:blur(18px) saturate(150%); backdrop-filter:blur(18px) saturate(150%);
  box-shadow:0 -8px 30px rgba(40,33,28,.12);
  display:flex; align-items:center; gap:10px 26px; flex-wrap:wrap;
  padding:12px 20px calc(12px + env(safe-area-inset-bottom, 0px));
  animation:or-rise var(--mo-slow, .5s) var(--ease-out);
}
.or-consent-text{ margin:0 !important; flex:1 1 320px; font-size:12.75px; line-height:1.5; color:var(--ink-2); }
.or-consent-actions{ margin:0 0 0 auto; flex:0 0 auto; gap:8px; }
/* FIX (2026-07-09 QA): the decline "thanks" card carries THREE buttons. As a
   flex:0 0 auto content-width group it stayed ~416px wide and did not wrap on
   narrow screens, pushing "clear openroar's data" off the edge and "done"
   entirely off-screen (unreachable). On phone widths let the action row take the
   full card width and wrap its buttons so every control stays tappable. */
@media (max-width:640px){
  .or-consent-actions{ margin:0; flex:1 1 100%; flex-wrap:wrap; justify-content:flex-start; }
  .or-consent-actions .or-btn{ flex:0 1 auto; }
}
@media (min-width:760px){
  .or-consent-card{
    padding-left:max(24px, calc((100% - 1120px) / 2));
    padding-right:max(24px, calc((100% - 1120px) / 2));
  }
  .or-consent-text{ flex:1 1 auto; font-size:13px; }
}

/* ---------- 2 · MEDIA CHAPTER legibility over the art (AG QA, 2026-07-07) ---------- */
/* PROBLEM (confirmed via screenshot review at 390px + 1440px): the eyebrow label and,
   on the brighter savannah art, the lead paragraph too, sat over light/warm areas of the
   illustration (books, sunlit wall, sunset sky) with only a thin scrim behind them —
   near-illegible at a glance. Root cause was twofold: (a) the gradient was too weak in
   the upper-middle band where the eyebrow lands on tall hero copy, and (b) the eyebrow's
   gold ink is close in hue/lightness to the warm art beneath it, so no amount of subtle
   shadow fixes it — a hue-matched color sitting on a hue-matched background needs a
   solid backing, not a shadow.
   FIX: (1) a substantially deeper, more uniform scrim across the whole frame so both the
   dark loft art and the bright sunset savannah art clear WCAG AA (4.5:1) for body text
   under it; (2) the eyebrow becomes a solid dark chip (not translucent-over-art) so it is
   legible regardless of what's directly behind it — this is the "mono-label" fix. */
.chapter-scrim{ background:linear-gradient(180deg, rgba(17,13,9,.46) 0%, rgba(17,13,9,.56) 28%, rgba(17,13,9,.68) 55%, rgba(17,13,9,.86) 100%); }
.chapter--media .chapter-eyebrow{
  display:inline-block; color:#FBF0D6; background:rgba(15,11,7,.62);
  -webkit-backdrop-filter:blur(8px) saturate(140%); backdrop-filter:blur(8px) saturate(140%);
  border:1px solid rgba(251,247,239,.16); border-radius:var(--wob-pill);
  padding:6px 14px; text-shadow:none;
}
.chapter--media h1, .chapter--media h2{ text-shadow:0 2px 4px rgba(10,7,4,.55), 0 4px 28px rgba(10,7,4,.6); }
.chapter--media p.g-lead{ text-shadow:0 1px 3px rgba(10,7,4,.6), 0 2px 14px rgba(10,7,4,.5); }

/* ---------- 3 · PAPER CHAPTERS → centered editorial statements ---------- */
/* Centre the intro type so the whitespace reads as deliberate (statement
   sections), not as a column pushed off to one side. Grids/cards inside keep
   their own alignment — reset explicitly below. */
#pride .chapter-inner, #listen .chapter-inner, #install .chapter-inner{ text-align:center; }
#pride .g-lead, #listen .g-lead, #listen .body, #install .chapter-inner > .body{
  margin-left:auto; margin-right:auto; max-width:54ch;
}
/* install: header centred, but the guide strip and the three track cards stay
   left-read internally */
#install .onb-guide{ justify-content:center; text-align:left; }
#install .tracks{ text-align:left; }
/* listen: players are content blocks, not prose — keep them left-internal */
#listen .or-player{ text-align:left; }

/* ---------- 3b · PRIDE carousel → horizontal card on desktop ---------- */
/* One tall centred stack per agent wasted the width. On desktop the portrait
   sits beside the name/role/quote/body, using the space and reading like a
   proper "meet the pride" card. */
.pride-slide.solo .solo-avatar{ border-radius:var(--wob-card); box-shadow:var(--shadow-1); }
.pride-slide .solo-copy{ display:contents; } /* mobile: children stack naturally in the column */
@media (min-width:900px){
  .pride-stage{ max-width:820px; }
  .pride-slide.on{ flex-direction:row; align-items:center; justify-content:center; text-align:left; gap:40px; }
  .pride-slide.on .solo-avatar{ flex:0 0 290px; max-width:290px; margin:0; }
  .pride-slide.on .solo-copy{ display:flex; flex-direction:column; align-items:flex-start; flex:1 1 auto; max-width:400px; }
  .pride-slide.on .solo-copy .solo-quote, .pride-slide.on .solo-copy .solo-body{ margin-left:0; margin-right:0; }
  .pride-slide.on .solo-copy .solo-quote{ max-width:36ch; }
}

/* ---------- 3c · GATE two-column balance ---------- */
/* Constrain the portrait so cee's column and the interactive card read as a
   matched pair rather than a huge photo next to a floating box. */
@media (min-width:900px){
  .gate-grid{ grid-template-columns:.82fr 1.18fr; align-items:start; gap:52px; }
  .gate-grid .solo-avatar{ max-width:280px; }
  /* nudge the interactive card down so its top lines up with cee's portrait,
     not the eyebrow above it — reads as a matched pair */
  .gate-grid .gate-card{ margin-top:4px; }
}

/* ---------- 4 · ARRIVAL MOTION — REMOVED (2026-07-08, stef) ----------
   This used to gate every chapter's content behind `opacity:0` until
   js/guided.v2.js's IntersectionObserver added `.in`, with only a 2.2s
   setTimeout as a fallback net. That's a scroll-hijack dependency, not
   progressive enhancement: any section the observer missed (or JS that
   hadn't run yet) rendered invisible. Normal flow now — no motion gate. */

/* Consent banner overlap fix (2026-07-07 QA sweep, js/consent.js) — reserve
   scroll room at the true bottom of the page while the banner is undecided,
   so it never sits on top of (and blocks clicks on) the footer links /
   "we pledge allegiance" egg beneath it. */
html.or-consent-open .g-foot{ padding-bottom:150px; }
@media (max-width:560px){ html.or-consent-open .g-foot{ padding-bottom:210px; } }

/* ---------- 5 · HIDDEN EGGS (see js/eggs.js) — tasteful, opt-in discovery ---------- */
/* Toast: shared tiny pill for every quiet, ephemeral egg payoff. */
.or-egg-toast{
  position:fixed; left:50%; bottom:28px; transform:translateX(-50%) translateY(12px);
  z-index:60; max-width:min(420px,86vw); padding:12px 20px; border-radius:999px;
  background:rgba(31,26,20,.92); color:#FBF7EF; font-size:13.5px; line-height:1.4;
  text-align:center; box-shadow:0 8px 28px rgba(0,0,0,.28); backdrop-filter:blur(6px);
  opacity:0; pointer-events:none; transition:opacity .4s ease, transform .4s ease;
}
.or-egg-toast.on{ opacity:1; transform:translateX(-50%) translateY(0); }
@media (prefers-reduced-motion:reduce){
  .or-egg-toast{ transition:opacity .01s linear; transform:translateX(-50%); }
  .or-egg-toast.on{ transform:translateX(-50%); }
}

/* Piertotum locomotor — the pride stirs. A gentle, bounded breathing pulse on
   whichever chapter background is on screen; never a spin/shake (motion
   comfort). Fully skipped under reduced-motion — the toast alone is the payoff. */
@media (prefers-reduced-motion:no-preference){
  @keyframes orPrideStir{
    0%,100%{ transform:scale(1); filter:saturate(1) brightness(1); }
    50%{ transform:scale(1.018); filter:saturate(1.08) brightness(1.03); }
  }
  body.or-egg-stir .chapter-bg{ animation:orPrideStir 8s ease-in-out 1; }
}

/* The snitch — a small, quiet golden light. Appears only after the visitor
   has explored 2+ chapters (js/eggs.js). No spin under reduced-motion, just a
   soft fixed glow; a gentle float otherwise. */
/* Positioned top-right, well clear of .g-top (slim header, ~50px), .g-rail
   (desktop-only, vertically centered), and .or-consent (bottom band) — all
   three already claim other screen edges; see guided.css/v10.css for those. */
.or-snitch{
  position:fixed; right:16px; top:84px; z-index:65; width:30px; height:30px;
  border-radius:50%; border:none; padding:0; cursor:pointer;
  background:radial-gradient(circle at 35% 30%,#FFE9A8,#E4B94A 55%,#B8862B 100%);
  box-shadow:0 2px 10px rgba(180,130,30,.45), 0 0 0 1px rgba(255,255,255,.25) inset;
  opacity:0; transform:scale(.6); transition:opacity .5s ease, transform .5s ease;
}
.or-snitch.on{ opacity:1; transform:scale(1); }
@media (prefers-reduced-motion:no-preference){
  @keyframes orSnitchFloat{ 0%,100%{ margin-top:0 } 50%{ margin-top:-8px } }
  .or-snitch.on{ animation:orSnitchFloat 2.6s ease-in-out infinite; }
}
.or-snitch:focus-visible{ outline:2px solid var(--accent,#E4B94A); outline-offset:3px; }

/* loneliness → lioness (charter.html) — no visual hint before the click,
   just an honest pointer cursor so a curious hand can find it. */
.or-egg-word{ cursor:pointer; }

/* ============================================================
   PERSISTENT FEEDBACK + CHARLIE CHAT — always-reachable, every
   section, every scroll position (js/feedback.js, js/chat.js).
   FLOATING again (2026-07-08, AG: "make them float"). Fixed
   bottom-right, stacked vertically (chat above feedback), tucked
   hard into the corner so they clear real in-page controls, with
   safe-area-inset padding for mobile. Hushed cream/ink, soft — no
   loud colour, no heavy shadow. Sit below the consent band (z 80,
   first-run privacy ask wins) and below the panels (z 9995, an open
   panel covers them). Generous ~50px tap targets. ============ */
.icon-pill{ width:32px; height:26px; padding:0 !important; display:inline-flex; align-items:center; justify-content:center; }

.or-fabs{
  position:fixed; z-index:75;
  right:calc(14px + env(safe-area-inset-right, 0px));
  bottom:calc(16px + env(safe-area-inset-bottom, 0px));
  display:flex; flex-direction:column; gap:10px;
}
.or-fab{
  width:50px; height:50px; padding:0; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--surface); color:var(--ink-2);
  border:1px solid var(--hair-2); box-shadow:0 3px 12px rgba(40,33,28,.14);
  cursor:pointer; -webkit-tap-highlight-color:transparent;
  transition:color .18s var(--ease-out), border-color .18s var(--ease-out), transform .18s var(--ease-out);
}
.or-fab:hover{ color:var(--accent-deep); border-color:var(--accent); }
.or-fab:active{ transform:scale(.94); }
.or-fab:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }
.or-fab svg{ width:19px; height:19px; }
@media (max-width:480px){
  .or-fabs{ right:calc(11px + env(safe-area-inset-right, 0px)); bottom:calc(12px + env(safe-area-inset-bottom, 0px)); gap:9px; }
  .or-fab{ width:48px; height:48px; }
}

.or-panel{ position:fixed; inset:0; z-index:9995; display:flex; align-items:flex-start; justify-content:flex-end; padding:14px; padding-top:64px; background:rgba(20,16,12,.32); }
.or-panel[hidden]{ display:none; }
.or-panel-card{
  width:100%; max-width:360px; max-height:min(70vh,560px); display:flex; flex-direction:column;
  background:var(--surface); border:1px solid var(--hair-2); border-radius:var(--wob-card,18px);
  box-shadow:0 12px 40px rgba(0,0,0,.28); overflow:hidden;
}
.or-panel-head{ display:flex; align-items:center; justify-content:space-between; padding:14px 16px; border-bottom:1px solid var(--hair); flex:none; }
.or-panel-title{ font-family:'Inter',system-ui,sans-serif; font-weight:700; font-size:14px; color:var(--ink); }
.or-panel-close{ background:none; border:none; font-size:20px; line-height:1; color:var(--muted); cursor:pointer; padding:4px 6px; }
.or-panel-close:hover{ color:var(--ink); }
.or-panel-sub{ padding:0 16px; margin-top:10px; font-size:12.5px; color:var(--muted); }
.or-panel-state{ padding:0 16px 14px; font-size:12.5px; color:var(--muted); min-height:1em; }

.or-chat-log{ flex:1; overflow-y:auto; padding:14px 16px; display:flex; flex-direction:column; gap:10px; min-height:120px; }
.or-chat-msg{ font-size:13.5px; line-height:1.55; padding:9px 12px; border-radius:14px; max-width:88%; }
.or-chat-msg.me{ align-self:flex-end; background:var(--accent-soft); color:var(--ink); }
.or-chat-msg.charlie{ align-self:flex-start; background:var(--surface-2); color:var(--ink); }
.or-chat-form{ display:flex; gap:8px; padding:12px; border-top:1px solid var(--hair); flex:none; }
.or-chat-form .or-field{ flex:1; }

.or-feedback-form{ display:flex; flex-direction:column; gap:10px; padding:12px 16px 6px; }
.or-feedback-form textarea.or-field{ min-height:88px; }

.or-gate-feedback{ margin-top:14px; padding-top:12px; border-top:1px dashed var(--hair-2); }
.or-gate-feedback-q{ font-size:12.5px; font-weight:600; color:var(--ink); margin-bottom:8px; }
.or-gate-feedback .or-chip.on{ background:var(--accent); color:var(--on-accent); border-color:transparent; }

/* ============ PIXEL WALL — "the picture we paint together" ============
   A shared flat-silhouette savannah (assets/world/pixel-savannah.jpg), warm-washed
   to cream/gold, that starts behind frosted cream glass and comes into focus as
   pledges grow. Canvas + reveal logic in js/pixelwall.js. Honest metric = the
   progress bar (real pixels / 1,000,000); the de-blur is the emotional layer on
   top. Cream/gold only — no purple, matches the sketch world around it. */
.pixelwall{ margin:6px 0 26px; }
.pixelwall-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-bottom:10px; }
.pixelwall-title{ font-family:'Inter',system-ui,sans-serif; font-weight:700; font-size:15px; color:var(--ink); margin:0; }
.pixelwall-sub{ font-size:12.5px; color:var(--muted); margin:0; max-width:46ch; }
.pixelwall-frame{ position:relative; width:100%; aspect-ratio:1408/768; border-radius:var(--wob-card);
  overflow:hidden; box-shadow:var(--shadow-2); border:1px solid var(--hair); background:var(--bg); }
.pixelwall-canvas{ position:absolute; inset:0; width:100%; height:100%; display:block; }
.pixelwall-bar{ position:relative; height:8px; border-radius:999px; background:var(--surface-3);
  overflow:hidden; margin-top:12px; box-shadow:var(--shadow-in); }
.pixelwall-bar > i{ display:block; height:100%; width:0; border-radius:999px;
  background:linear-gradient(90deg, var(--accent), var(--accent-deep)); transition:width .9s var(--ease-out); }
.pixelwall-stats{ display:flex; gap:18px; flex-wrap:wrap; margin-top:9px; font-size:12px; color:var(--muted); }
.pixelwall-stats b{ color:var(--ink); font-weight:600; }
@media (prefers-reduced-motion: reduce){
  .pixelwall-canvas{ transition:none !important; }
}

/* ============ PLEDGE AMOUNTS — money AND hours, together ============
   Two small, calm, labelled number inputs (2026-07-08, AG: not either/or).
   A person can give money, hours, or both in one submit; the equiv line
   below reads out the combined founding-pixel total. */
.or-pledge-amounts{ display:flex; gap:8px; flex:1 1 100%; }
.or-pledge-amount{ flex:1 1 0; display:flex; flex-direction:column; gap:5px; min-width:0; }
.or-pledge-amount-label{ font-size:12px; font-weight:600; color:var(--ink-2); }
/* FIX (2026-07-09 QA): v10.css:73 `.or-join-form input{min-width:180px}` was
   written for the single email+button join form, but it also lands on these two
   nested number inputs and floored them at 180px each — so two 180px boxes
   (+8px gap) could never fit the ~110-310px pledge track, overlapping each other
   and bursting past the card at every viewport (the AG bug). Higher-specificity
   min-width:0 lets each input shrink with its flex:1 1 0 column. */
.or-pledge-amount .or-field{ width:100%; min-width:0; }
.or-pledge-amount-hint{ font-size:11px; color:var(--muted); }
.or-pledge-equiv{ font-size:12px; color:var(--muted); margin-top:8px; min-height:1em; flex:1 1 100%; }
.or-pledge-equiv b{ color:var(--ink); font-weight:600; }

/* already-in nudge (waitlist + pledge) — a warm, playful second step */
.or-nudge{ margin-top:12px; padding:12px 14px; border:1px dashed var(--hair-2);
  border-radius:var(--wob-in); background:var(--accent-soft); font-size:13px; color:var(--ink); }
.or-nudge a, .or-nudge .g-foot-link-btn{ color:var(--accent-deep); font-weight:600; }

/* consent decline second-panel (the "you said no — good instinct" reward) */
/* a hidden card must truly hide — the .or-consent-card{display:flex} rule would
   otherwise beat the UA [hidden] rule, leaving the hidden ask-card rendered
   beside the thanks-card (each ~half width, pushing buttons off a 390px screen). */
.or-consent-card[hidden]{ display:none !important; }
.or-consent-thanks[hidden]{ display:none !important; }
.or-consent-note{ flex:1 1 100%; margin:2px 0 0 !important; font-size:12px; line-height:1.55; color:var(--muted); }
.or-consent-note b{ color:var(--ink-2); font-weight:600; }
.or-consent-note[hidden]{ display:none !important; }
