/* Just Divine Journey site. Design tokens + calm system.
   Palette + type per Website Build Master Draft (Fable 5) 2026-07-07, section 4.
   Motion obeys the Regulation Principle: nothing startles a resting person. */

:root {
  /* Brand palette (Visual Identity, locked) */
  --cream: #F9EDDB;      /* page ground */
  --butter: #FFECC9;     /* raised cards */
  --sand: #D2CBB8;       /* rules, borders */
  --sage: #9F9E7D;       /* secondary text, glyphs */
  --forest: #627044;     /* primary text on light, buttons */
  --deep-forest: #3D4A28;/* hero grounds, footers */

  /* Derived, accessible pairings */
  --ink: #2C331F;        /* body text on cream, > 7:1 */
  --ink-soft: #55603C;   /* secondary text on cream, ~5:1 */
  --on-dark: #F4ECD9;    /* text on deep-forest grounds */
  --on-dark-soft: #CFD3BC;

  --maxw: 68rem;
  --measure: 38rem;      /* ~65-70ch reading column */
  --pad: clamp(1.25rem, 4vw, 3rem);
  --radius: 14px;
  --shadow: 0 1px 2px rgba(61,74,40,.06), 0 12px 32px rgba(61,74,40,.08);

  --serif: "Lora", Georgia, "Times New Roman", serif;
  --sans: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --fade-in: 560ms;      /* within the 400-700ms doctrine band */
  --ease: cubic-bezier(.22, .61, .36, 1); /* ease-out, no overshoot */
}

/* Self-hosted fonts. Add the woff2 files to assets/fonts/ (vendored, no CDN).
   Fallbacks (Georgia, system-ui) render cleanly until they are added. */
@font-face {
  font-family: "Lora"; font-style: normal; font-weight: 400 600;
  font-display: swap; src: local("Lora"), url("../fonts/lora-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Montserrat"; font-style: normal; font-weight: 400 600;
  font-display: swap; src: local("Montserrat"), url("../fonts/montserrat-latin.woff2") format("woff2");
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(1.02rem, 0.98rem + 0.3vw, 1.15rem);
  line-height: 1.72;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { font-family: var(--serif); font-weight: 500; line-height: 1.18; color: var(--forest); letter-spacing: -0.01em; }
h1 { font-size: clamp(2.1rem, 1.5rem + 3vw, 3.4rem); }
h2 { font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.1rem); }
h3 { font-size: 1.2rem; }
p { max-width: var(--measure); }
a { color: var(--forest); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--deep-forest); }
:focus-visible { outline: 3px solid var(--forest); outline-offset: 3px; border-radius: 4px; }
img { max-width: 100%; display: block; }

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--pad); }
.section { padding-block: clamp(3rem, 7vw, 6rem); }
.center { text-align: center; }
.center p { margin-inline: auto; }
.lede { font-family: var(--serif); font-size: clamp(1.3rem, 1.1rem + 1vw, 1.7rem); line-height: 1.5; color: var(--ink-soft); }

/* ---- Nav (scrolls away; nothing chases the reader) ---- */
.site-nav { position: absolute; inset: 0 0 auto 0; z-index: 10; }
.site-nav .wrap { display: flex; align-items: center; justify-content: space-between; padding-block: 1.4rem; }
.brandmark { display: inline-flex; align-items: center; gap: .6rem; font-family: var(--serif); font-size: 1.15rem; color: var(--forest); text-decoration: none; }
.brandmark img { height: 30px; width: auto; }
.nav-links { display: flex; gap: clamp(1rem, 3vw, 2rem); align-items: center; }
.nav-links a { font-size: .96rem; text-decoration: none; color: var(--ink-soft); }
.nav-links a:hover { color: var(--forest); }
.on-dark .brandmark, .on-dark .nav-links a { color: var(--on-dark); }
.on-dark .nav-links a:hover { color: #fff; }
/* Solid nav for pages with no dark hero (legal, long-form): in flow, cream ground. */
.site-nav.solid { position: static; background: var(--cream); border-bottom: 1px solid var(--sand); }

/* ---- Legal / long-form pages ---- */
.legal { padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(3rem, 8vw, 6rem); }
.legal .wrap { max-width: 48rem; }
.legal h1 { margin-bottom: .4rem; }
.legal .effective { color: var(--ink-soft); font-size: .92rem; margin: 0 0 2.5rem; }
.legal h2 { font-size: 1.3rem; margin: 2.4rem 0 .9rem; }
.legal p, .legal li { max-width: none; }
.legal ul { margin: 0 0 1.4rem 1.4rem; }
.legal li { margin-bottom: .5rem; }
.legal strong { font-weight: 600; }

/* ---- Hero ----
   The per-hero painted layer (.hero-art, its ken-burns inner, and its left-weighted
   scrim) was retired in Rev 1: one continuous .realm canvas replaced it, and app.js
   stopped injecting those nodes. The rules are removed rather than left to rot,
   because that scrim's 100deg gradient reads exactly like the left veil we just
   deleted and would send the next reader down the wrong path. */
.hero { position: relative; color: var(--on-dark); background: linear-gradient(160deg, #45532E 0%, var(--deep-forest) 60%, #333f22 100%); overflow: clip; }
.hero .wrap { position: relative; z-index: 1; padding-block: clamp(7rem, 16vh, 11rem) clamp(3.5rem, 9vw, 6rem); }
.hero h1 { color: var(--on-dark); max-width: 20ch; }
.hero .sub { color: var(--on-dark-soft); font-size: clamp(1.1rem, 1rem + .5vw, 1.35rem); max-width: 44ch; margin-top: 1.1rem; }
.hero .cta-row { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 2rem; align-items: center; }
.underline-note { color: var(--on-dark-soft); font-size: .92rem; margin-top: 1rem; }

/* ---- Music embeds: click-to-load facade (no third-party request until press) ---- */
.embed-grid { display: grid; grid-template-columns: 1fr; gap: 1.25rem; }
@media (min-width: 52rem) { .embed-grid { grid-template-columns: repeat(3, 1fr); } }
.embed { position: relative; aspect-ratio: 16 / 9; border: 1px solid var(--sand); border-radius: var(--radius); overflow: hidden; background: linear-gradient(160deg, #45532E, var(--deep-forest)); }
/* The real YouTube still, fetched at build time and self-hosted: no runtime
   request to Google, no cookie, until the visitor presses play. */
.embed-thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 200ms var(--ease), filter 200ms var(--ease); }
.embed::after { content: ""; position: absolute; inset: 0; pointer-events: none; transition: background 200ms var(--ease);
  background: linear-gradient(180deg, rgba(20,26,12,.34) 0%, rgba(20,26,12,.18) 42%, rgba(20,26,12,.66) 100%); }
.embed.playing::after { display: none; }
.embed .embed-play { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .7rem; background: transparent; border: 0; color: var(--on-dark); cursor: pointer; font-family: var(--serif); font-size: 1.02rem; line-height: 1.3; text-align: center; padding: 1rem; text-shadow: 0 1px 3px rgba(14,20,8,.8), 0 2px 16px rgba(14,20,8,.6); }
.embed .glyph { width: 52px; height: 52px; border-radius: 999px; border: 1.5px solid rgba(244,236,217,.7); display: grid; place-items: center; transition: background 200ms var(--ease), border-color 200ms var(--ease), box-shadow 200ms var(--ease); }
.embed .glyph::before { content: ""; border-style: solid; border-width: 8px 0 8px 14px; border-color: transparent transparent transparent var(--on-dark); margin-left: 3px; }
.embed:hover .embed-thumb { transform: scale(1.03); filter: saturate(1.04); }
.embed:hover::after { background: linear-gradient(180deg, rgba(20,26,12,.22) 0%, rgba(20,26,12,.08) 42%, rgba(20,26,12,.56) 100%); }
.embed:hover .glyph, .embed .embed-play:focus-visible .glyph { background: rgba(244,236,217,.2); border-color: #fff; box-shadow: 0 0 0 6px rgba(244,236,217,.08); }
.embed iframe { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; border: 0; }
.embed.held .embed-play { cursor: default; color: var(--on-dark-soft); }
.embed.held .glyph { display: none; }

/* Channel galaxies row */
.channels { display: grid; grid-template-columns: 1fr; gap: 1.5rem; margin-top: 3rem; justify-items: center; }
@media (min-width: 46rem) { .channels { grid-template-columns: 1fr 1fr; } }

/* ---- Buttons ----
   Hover is a calm lift plus a soft glow, 200ms ease-out, no overshoot and no
   bounce (Regulation Principle). Feedback, never a jolt. */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .5rem; min-height: 48px; padding: .8rem 1.5rem; border-radius: 999px; font-family: var(--sans); font-size: 1rem; font-weight: 600; text-decoration: none; cursor: pointer; border: 1.5px solid transparent; transition: background 200ms var(--ease), color 200ms var(--ease), border-color 200ms var(--ease), transform 200ms var(--ease), box-shadow 200ms var(--ease); }
.btn:hover { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(20,26,12,.26); }
.btn:active { transform: translateY(0); box-shadow: 0 2px 8px rgba(20,26,12,.2); }
.btn-primary { background: var(--butter); color: var(--deep-forest); }
.btn-primary:hover { background: #FFE4B0; color: var(--deep-forest); }
.btn-ghost { background: transparent; color: var(--on-dark); border-color: rgba(244,236,217,.5); }
.btn-ghost:hover { background: rgba(244,236,217,.12); border-color: var(--on-dark); color: #fff; }
/* Forest fill, for CTAs that sit on butter or on the warmer half of the canvas. */
.btn-forest { background: var(--forest); color: var(--cream); }
.btn-forest:hover { background: var(--deep-forest); color: #fff; }
.on-light .btn-primary { background: var(--forest); color: var(--cream); }
.on-light .btn-primary:hover { background: var(--deep-forest); }

/* ---- Cards (the two doors) ---- */
.cards { display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
@media (min-width: 46rem) { .cards { grid-template-columns: 1fr 1fr; } }
.trio { display: grid; grid-template-columns: 1fr; gap: 1.25rem; align-items: start; }
@media (min-width: 52rem) { .trio { grid-template-columns: repeat(3, 1fr); } }
.trio .card h3 { font-size: 1.12rem; margin-top: .15rem; }
.phase-days { display: block; font-family: var(--sans); font-size: .78rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--sage); }
.card { background: var(--butter); border: 1px solid var(--sand); border-radius: var(--radius); padding: clamp(1.5rem, 3vw, 2.25rem); box-shadow: var(--shadow); transition: transform 200ms var(--ease), box-shadow 200ms var(--ease), background 200ms var(--ease), border-color 200ms var(--ease); }
.card:hover { transform: translateY(-3px); box-shadow: 0 1px 2px rgba(61,74,40,.06), 0 16px 38px rgba(61,74,40,.18); }
.card h3 { margin-top: 0; }
.card a { font-weight: 600; text-decoration: none; }
.card a:hover { text-decoration: underline; }

/* A whole card that is one link (the two Home doors). The cue is a span, not a
   nested anchor: a link inside a link is invalid and unreachable by keyboard. */
.card-link { display: block; text-decoration: none; color: inherit; }
.card-link .cue { display: inline-block; margin-top: .4rem; font-weight: 600; color: var(--forest); }
.card-link:hover .cue { text-decoration: underline; }

/* ---- Phase cards: the card is the button, the seven days open in a modal. ---- */
.phase-card { display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer; -webkit-appearance: none; appearance: none; }
.phase-title { display: block; font-family: var(--serif); font-size: 1.12rem; font-weight: 500; line-height: 1.18; letter-spacing: -0.01em; color: var(--forest); margin: .15rem 0 .6rem; }
.phase-blurb { display: block; color: var(--ink-soft); }
.phase-more { display: inline-flex; align-items: center; gap: .5rem; margin-top: 1.15rem; font-family: var(--sans); font-size: .84rem; font-weight: 600; letter-spacing: .04em; color: var(--forest); }
.phase-more::after { content: "\203A"; font-weight: 400; font-size: 1.1rem; line-height: 1; color: var(--sage); transition: transform 200ms var(--ease); }
.phase-card:hover .phase-more::after { transform: translateX(2px); }

/* The modal: native <dialog>, so Esc closes it and focus is handled by the browser.
   Fades, never scales: a panel that springs at a resting person is a jolt. */
/* position MUST be fixed. A top-layer dialog with position:relative resolves to
   absolute against its nearest positioned ancestor (.section), so it opens at the top
   of that section, off-screen, and the browser rescues it by scrolling the page to 0.
   On a phone, with scroll locked, no rescue happens: the backdrop darkens over nothing.
   inset:0 + margin:auto with a bounded size centres it in the viewport at any scroll. */
.phase-modal { position: fixed; inset: 0; margin: auto; width: min(38rem, calc(100vw - 2rem)); max-height: min(82vh, 48rem); overflow-y: auto; overscroll-behavior: contain; padding: clamp(1.6rem, 3.4vw, 2.4rem); border: 1px solid var(--sand); border-radius: var(--radius); background: var(--cream); color: var(--ink); box-shadow: 0 30px 90px rgba(14,20,8,.45); }
.phase-modal::backdrop { background: rgba(14,20,8,.62); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.phase-modal[open], .phase-modal[open]::backdrop { animation: fade var(--fade-in) var(--ease); }
.phase-modal h3 { margin: .2rem 0 .9rem; font-size: 1.45rem; }
.phase-modal .phase-days { margin-bottom: .2rem; }
.phase-close { position: absolute; top: .85rem; right: .95rem; width: 40px; height: 40px; display: grid; place-items: center; border-radius: 999px; border: 1px solid var(--sand); background: transparent; color: var(--ink-soft); font-size: 1.35rem; line-height: 1; cursor: pointer; transition: background 200ms var(--ease), color 200ms var(--ease), border-color 200ms var(--ease); }
.phase-close:hover { background: rgba(98,112,68,.1); color: var(--forest); border-color: var(--forest); }
.phase-intro { margin: 0; color: var(--ink-soft); font-size: .98rem; max-width: none; }
.phase-modal ol { list-style: none; margin: 1.2rem 0 0; padding: 0; }
.phase-modal li { margin: 0; padding: .65rem 0; border-top: 1px solid var(--sand); font-size: .95rem; line-height: 1.55; color: var(--ink-soft); }
.phase-modal li b { font-family: var(--serif); font-weight: 600; color: var(--forest); }

/* ---- Channel galaxies (/music). The painted galaxies from the Ops Analytics room,
   whose own spin hook was parked there. Each galaxy IS the link; its text fades in on
   hover. Rotation is one turn every 220s: present, never noticeable. ---- */
.channels-head { margin-top: 3.25rem; }
.galaxy { position: relative; display: flex; flex-direction: column; align-items: center; text-decoration: none; color: var(--on-dark); padding-bottom: 9.5rem; }
/* Rev 1 polish 4: orbs up ~28% (18rem -> 23rem, 58vw -> 74vw). */
.galaxy-orb { display: block; width: min(23rem, 74vw); will-change: transform, filter; filter: drop-shadow(0 0 22px rgba(255,236,201,.18)); transition: transform 420ms var(--ease), filter 420ms var(--ease); }
/* The channel's actual name, always readable. The hover text adds the rest. */
.galaxy-label { margin-top: .55rem; font-family: var(--serif); font-size: clamp(1.15rem, 1rem + .5vw, 1.4rem); line-height: 1.2; text-align: center; color: var(--on-dark); transition: color 200ms var(--ease); }
.galaxy:hover .galaxy-label, .galaxy:focus-visible .galaxy-label { color: var(--butter); }
.galaxy-img { display: block; width: 100%; height: auto; animation: galaxy-spin 220s linear infinite; }
@keyframes galaxy-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
/* Paused only while off-screen, and only by script. If the script never runs the
   galaxies still turn, which is the failure mode worth having. */
.channels.at-rest .galaxy-img { animation-play-state: paused; }
.galaxy:hover .galaxy-orb, .galaxy:focus-visible .galaxy-orb { transform: scale(1.05); filter: brightness(1.12) drop-shadow(0 0 32px rgba(255,236,201,.32)); }
.galaxy:focus-visible { outline: none; }
.galaxy:focus-visible .galaxy-orb { outline: 3px solid var(--butter); outline-offset: 10px; border-radius: 50%; }
/* Reserved in the padding above, so revealing the text never shifts the layout. */
.galaxy-text { position: absolute; left: 50%; bottom: .25rem; transform: translate(-50%, 6px); width: min(21rem, 88vw); display: flex; flex-direction: column; gap: .4rem; text-align: center; opacity: 0; pointer-events: none; transition: opacity 300ms var(--ease), transform 400ms var(--ease); }
.galaxy:hover .galaxy-text, .galaxy:focus-visible .galaxy-text { opacity: 1; transform: translate(-50%, 0); }
.galaxy-name { font-family: var(--serif); font-size: 1.18rem; color: var(--butter); }
.galaxy-cm { font-size: .9rem; line-height: 1.5; color: var(--on-dark-soft); }
.galaxy-go { font-size: .85rem; font-weight: 600; letter-spacing: .02em; color: var(--butter); }
.galaxy-text > *, .galaxy-label { text-shadow: 0 1px 3px rgba(14,20,8,.85), 0 2px 18px rgba(14,20,8,.6); }
/* No hover to reveal with: a touch reader must be able to read it. */
@media (hover: none) { .galaxy-text { opacity: 1; transform: translate(-50%, 0); } }

/* ---- Founders, heart-framed, slow cross-fade ----
   Four photos stacked, opacity only, no transform. One turn is 28s: each photo fades
   in over 1.5s, holds 5.5s, fades out over 1.5s, and the next begins 7s after the last.
   The overlap IS the cross-fade. clip-path uses objectBoundingBox units so the heart
   scales with the box. The cream ground shows through only where a contain-fitted
   photo does not reach the edge. */
.heart-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.heart { position: relative; width: min(24rem, 76vw); aspect-ratio: 1; margin: 0 auto; overflow: hidden;
  background: #E7E0CE; clip-path: url(#heartClip); -webkit-clip-path: url(#heartClip); }
.heart img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 38%;   /* keep the couple, not the ceiling */
  opacity: 0; will-change: opacity; animation: heartFade 28s var(--ease) infinite; }
.heart img[data-fit="contain"] { object-fit: contain; }
.heart img:nth-child(1) { animation-delay: 0s; }
.heart img:nth-child(2) { animation-delay: 7s; }
.heart img:nth-child(3) { animation-delay: 14s; }
.heart img:nth-child(4) { animation-delay: 21s; }
@keyframes heartFade {
  0%     { opacity: 0; }
  5.36%  { opacity: 1; }   /* 1.5s in  */
  25%    { opacity: 1; }   /* holds to 7s */
  30.36% { opacity: 0; }   /* 1.5s out, overlapping the next */
  100%   { opacity: 0; }
}

/* ---- FAQ accordion (simple fade, no icon spin) ---- */
.faq { max-width: var(--measure); margin-inline: auto; }
.faq details { border-top: 1px solid var(--sand); padding: .35rem 0; }
.faq details:last-child { border-bottom: 1px solid var(--sand); }
.faq summary { cursor: pointer; list-style: none; padding: 1rem 2.4rem 1rem .8rem; margin-inline: -.8rem; border-radius: 10px; font-family: var(--serif); font-size: 1.12rem; color: var(--forest); position: relative; transition: background 200ms var(--ease), color 200ms var(--ease); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { background: rgba(98,112,68,.07); color: var(--deep-forest); }
.faq summary::after { content: "+"; position: absolute; right: 1rem; top: 50%; transform: translateY(-50%); font-family: var(--sans); font-weight: 400; color: var(--sage); transition: opacity var(--fade-in) var(--ease); }
.faq details[open] summary::after { content: "\2013"; }
.faq .answer { padding: 0 0 1.1rem; color: var(--ink-soft); animation: fade var(--fade-in) var(--ease); }

/* ---- Footer ---- */
.site-footer { background: var(--deep-forest); color: var(--on-dark-soft); padding-block: clamp(2.5rem, 6vw, 4rem); }
.site-footer .thesis { font-family: var(--serif); font-size: 1.15rem; color: var(--on-dark); max-width: 40ch; }
.site-footer .foot-links { display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; margin-top: 1.5rem; }
.site-footer a { color: var(--on-dark-soft); font-size: .92rem; text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: underline; }
.site-footer .fine { margin-top: 1.5rem; font-size: .82rem; color: var(--sage); }

/* ---- Consent banner (calm, two equal buttons, no dark pattern) ---- */
.consent { position: fixed; inset: auto 1rem 1rem 1rem; z-index: 50; max-width: 34rem; margin-inline: auto; background: var(--cream); color: var(--ink); border: 1px solid var(--sand); border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.1rem 1.25rem; }
.consent[hidden] { display: none; }
.consent p { margin: 0 0 .85rem; font-size: .92rem; max-width: none; }
.consent .row { display: flex; gap: .75rem; flex-wrap: wrap; }
.consent .btn { min-height: 42px; padding: .55rem 1.2rem; font-size: .92rem; flex: 1 1 auto; }
/* Equal visual weight, both outline, no dark-pattern nudge toward Allow
   (truth-first applies to consent UX too). Identical hover on both. */
.consent .btn-primary, .consent .btn-secondary { background: transparent; color: var(--forest); border-color: var(--forest); }
.consent .btn-primary:hover, .consent .btn-secondary:hover { background: rgba(98,112,68,.1); color: var(--deep-forest); border-color: var(--deep-forest); }

/* Small print that sits under a form or a CTA. Dark on cream, cream on the realm. */
.note-soft { color: var(--ink-soft); font-size: .95rem; }

/* ---- Motion: reveal on scroll, gentle ---- */
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.reveal { opacity: 0; transform: translateY(12px); transition: opacity var(--fade-in) var(--ease), transform var(--fade-in) var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .card, .btn, .faq .answer, .reveal, .embed .glyph, .embed-thumb, .embed::after,
  .faq summary, .phase-modal[open], .phase-modal[open]::backdrop, .phase-close,
  .galaxy-orb, .galaxy-text, .phase-more::after { transition: none !important; animation: none !important; }
  .reveal { opacity: 1; transform: none; }
  .card:hover, .btn:hover, .btn:active { transform: none; }
  .embed:hover .embed-thumb { transform: none; filter: none; }
  /* The galaxy stands still, and its text is simply there. */
  .galaxy-img { animation: none !important; }
  /* The heart holds one photo rather than cycling. */
  .heart img { animation: none !important; opacity: 0; }
  .heart img:first-child { opacity: 1; }
  .galaxy:hover .galaxy-orb, .galaxy:focus-visible .galaxy-orb { transform: none; }
  .galaxy-text { opacity: 1; transform: translate(-50%, 0); }
}

/* ============================================================
   Rev 1 (2026-07-08): the continuous realm, day-cycle scroll (section 4B).
   One painted canvas per page; all content floats over it; the background
   traverses time of day by scroll (opacity cross-fade, GPU-cheap).
   Built + driven by app.js from body[data-realm="layerA,layerB,..."].
   ============================================================ */
.realm { position: fixed; inset: 0; z-index: -2; overflow: hidden; background: var(--deep-forest); }
.realm-layer { position: absolute; inset: 0; background-size: cover; background-position: 62% center; opacity: 0; will-change: opacity; }
.realm-layer.first { opacity: 1; }
/* Rev 1 polish 3: the left-leaning veil is GONE. A one-sided horizontal wash always
   reads as a vertical shade band, because the eye finds the ramp even when the ramp
   has no edge. What remains is a symmetric, edgeless vignette (darker at the frame,
   clear through the middle) plus a soft top fade so the nav stays legible. Nothing
   here is one-sided, so nothing draws a vertical line. Legibility is carried by the
   per-text halos below. */
.realm-scrim { position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(132% 104% at 50% 46%, transparent 50%, rgba(20,26,12,.16) 76%, rgba(20,26,12,.32) 100%),
    linear-gradient(180deg, rgba(20,26,12,.36) 0%, rgba(20,26,12,.12) 11%, transparent 21%); }

body[data-realm] { background: var(--deep-forest); color: var(--on-dark); }
body[data-realm] .site-nav .brandmark, body[data-realm] .site-nav .nav-links a { color: var(--on-dark); }
body[data-realm] .site-nav .nav-links a:hover { color: #fff; }

/* Hero + sections transparent so the one canvas shows through everywhere.
   Rev 1 polish: tighter vertical rhythm (less dead space), wider measure. */
body[data-realm] .hero { background: none; overflow: visible; position: relative; }
body[data-realm] .hero .wrap { padding-block: clamp(4.5rem, 11vh, 7.5rem) clamp(2rem, 5vw, 3.5rem); }
body[data-realm] .section { background: transparent !important; position: relative; padding-block: clamp(1.75rem, 4vw, 3.25rem); }
body[data-realm] .section .wrap { max-width: 60rem; }
body[data-realm] .section p, body[data-realm] .lede, body[data-realm] .hero .sub { max-width: 46rem; }

/* Rev 1 polish 2: legibility with NO seams anywhere.
   The old per-section scrim was a rectangle: its radial was still ~15% opaque at
   the section's own top edge, so every section boundary drew a step, read as a
   shaded horizontal line. This replaces it with a halo that is centred on the text
   and reaches zero 6rem BEYOND the block it belongs to. Neighbouring halos therefore
   overlap rather than abut, the alpha field is continuous down the whole page, and
   no element edge is ever visible. The canvas stays one unbroken painting. */
body[data-realm] .hero > *, body[data-realm] .section > * { position: relative; z-index: 1; }
body[data-realm] .hero::before, body[data-realm] .section::before {
  content: ""; position: absolute; inset: -6rem 0; z-index: 0; pointer-events: none;
  background: radial-gradient(86% 50% at 38% 50%,
    rgba(20,26,12,.50) 0%, rgba(20,26,12,.40) 34%, rgba(20,26,12,.20) 64%, rgba(20,26,12,.06) 86%, transparent 98%); }
body[data-realm] h1, body[data-realm] h2, body[data-realm] h3 { color: var(--on-dark); }
/* The halo follows the glyphs, not a box. Applies to the hero too (it lives outside
   main), which is where "Lifetime access. Start any day." was washing out. */
body[data-realm] :is(.hero, main) :is(h1,h2,h3,p,.lede,.sub,.underline-note,li,summary,.phase-blurb,.phase-more) {
  text-shadow: 0 1px 2px rgba(14,20,8,.75), 0 2px 16px rgba(14,20,8,.55); }
/* Small, light lines carry a denser halo: they have the least ink to defend themselves. */
body[data-realm] :is(.underline-note, .note-soft) {
  text-shadow: 0 1px 2px rgba(14,20,8,.88), 0 1px 10px rgba(14,20,8,.72), 0 2px 24px rgba(14,20,8,.55); }
body[data-realm] .section p, body[data-realm] .underline-note, body[data-realm] .note-soft { color: var(--on-dark-soft); }
body[data-realm] .lede { color: var(--on-dark); }
/* Prose links go butter on the realm. Buttons must NOT: this selector outranks
   .btn-primary, and it was painting butter text onto the butter purchase button. */
body[data-realm] main a:not(.btn) { color: var(--butter); }
body[data-realm] .section.center { text-align: left; }
body[data-realm] .section.center p, body[data-realm] .section.center .lede { margin-inline: 0; }
body[data-realm] .section.center .cta-row { justify-content: flex-start; }
body[data-realm] .phase-days { color: var(--butter); }

/* Cloud-panels: translucent butter, the only boxed elements. No solid cards. */
body[data-realm] .card { background: rgba(255,236,201,.13); border-color: rgba(255,236,201,.26); box-shadow: none; -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); }
body[data-realm] .card:hover { background: rgba(255,236,201,.19); border-color: rgba(255,236,201,.4); box-shadow: 0 14px 34px rgba(14,20,8,.3); }
body[data-realm] .card h3 { color: var(--on-dark); }
body[data-realm] .card p { color: var(--on-dark-soft); }
body[data-realm] .card a, body[data-realm] .card-link .cue { color: var(--butter); }

/* Phase cards on the realm. The modal is its own lit room: a near-opaque night panel,
   because a list of 21 lines has to be read, not squinted at through a painting. */
body[data-realm] .phase-blurb { color: var(--on-dark-soft); }
body[data-realm] .phase-title { color: var(--on-dark); }
body[data-realm] .phase-more, body[data-realm] .phase-more::after { color: var(--butter); }
body[data-realm] .phase-modal { background: rgba(26,32,17,.96); border-color: rgba(255,236,201,.2); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); }
body[data-realm] .phase-modal :is(h3, li b) { color: var(--on-dark); text-shadow: none; }
body[data-realm] .phase-modal :is(li, .phase-intro) { color: var(--on-dark-soft); text-shadow: none; }
body[data-realm] .phase-modal li { border-top-color: rgba(255,236,201,.18); }
body[data-realm] .phase-close { border-color: rgba(255,236,201,.28); color: var(--on-dark-soft); }
body[data-realm] .phase-close:hover { background: rgba(255,236,201,.14); border-color: var(--butter); color: var(--butter); }

body[data-realm] .faq { background: rgba(255,236,201,.11); border: 1px solid rgba(255,236,201,.2); border-radius: var(--radius); padding: .4rem 1.3rem; -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); }
body[data-realm] .faq details { border-top-color: rgba(255,236,201,.18); }
body[data-realm] .faq details:last-child { border-bottom-color: rgba(255,236,201,.18); }
body[data-realm] .faq summary { color: var(--on-dark); }
body[data-realm] .faq summary:hover { background: rgba(255,236,201,.1); color: #fff; }
body[data-realm] .faq summary::after { color: var(--butter); }
body[data-realm] .faq .answer { color: var(--on-dark-soft); }
body[data-realm] .embed { border-color: rgba(255,236,201,.22); background: rgba(43,51,31,.4); }

/* ---- Legal on the realm: same painting, but the copy sits on a calm reading
   column. Dense legal text does not negotiate its legibility with a background. ---- */
body[data-realm] .legal { padding-block: clamp(6rem, 14vh, 9rem) clamp(3rem, 8vw, 6rem); }
body[data-realm] .legal .wrap {
  max-width: 54rem; padding: clamp(1.75rem, 4vw, 3rem); border-radius: var(--radius);
  background: rgba(26,32,17,.82); border: 1px solid rgba(255,236,201,.16);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: 0 20px 60px rgba(14,20,8,.36); }
body[data-realm] main.legal :is(h1,h2,h3,p,li,strong,.effective) { text-shadow: none; }
body[data-realm] .legal :is(p, li) { color: var(--on-dark-soft); }
body[data-realm] .legal :is(h1, h2, h3, strong) { color: var(--on-dark); }
body[data-realm] .legal .effective { color: var(--sage); }
body[data-realm] .legal a { color: var(--butter); }

/* Footer blends into the realm: transparent at top so the canvas continues, then
   resolves to a night tone at the very bottom. No hard flat block.
   z-index 1 keeps the last section's halo from spilling over the footer text. */
body[data-realm] .site-footer { position: relative; z-index: 1; background: linear-gradient(180deg, transparent 0%, rgba(30,38,20,.42) 34%, rgba(20,26,12,.9) 100%); }
body[data-realm] .site-footer .thesis, body[data-realm] .site-footer a, body[data-realm] .site-footer .fine { text-shadow: 0 1px 8px rgba(14,20,8,.55); }

@media (prefers-reduced-motion: reduce) { .realm-layer { transition: none !important; } }
