/* ═══════════════════════════════════════════════════════════════════
   EPHEMERIS — shared stylesheet for michellesaya.com
   ───────────────────────────────────────────────────────────────────
   Every page links this file first, then its own style.css.

   What belongs HERE: anything true of the whole site — design tokens,
   type, the topbar, the ephemeris rail, bands, buttons, the sect
   toggle, the threshold, lotus dividers, the seal, footer.

   What belongs in a page's OWN style.css: that page's sections, and
   any override of a rule below (same selector, loaded after, so it
   wins). Do not fork this file per page — a fix here reaches all of
   them, which is the entire point.

   Generated 2026-07-30 from the 303 rules that were byte-identical
   across all 15 stylesheets.
   ═══════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════
   michellesaya.com — workshop template · "Ephemeris"
   Content is centred. The rail floats at the left edge and
   retires when the footer arrives.
   ═══════════════════════════════════════════════════════════════ */

@font-face { font-family:'Heartbreak Eighties'; src:url('/shared/fonts/HeartbreakEighties-Regular.otf') format('opentype'); font-weight:400; font-style:normal; font-display:swap; }

@font-face { font-family:'Heartbreak Eighties'; src:url('/shared/fonts/HeartbreakEighties-Oblique.otf') format('opentype'); font-weight:400; font-style:italic; font-display:swap; }

@font-face { font-family:'Mattone';            src:url('/shared/fonts/mattone.woff') format('woff'); font-weight:400; font-style:normal; font-display:swap; }

@font-face { font-family:'Perfectly Nineties'; src:url('/shared/fonts/perfectlynineties-regular.woff') format('woff'); font-weight:400; font-style:normal; font-display:swap; }

@font-face { font-family:'IM Fell';            src:url('/shared/fonts/imfell-roman.woff') format('woff'); font-weight:400; font-style:normal; font-display:swap; }

@font-face { font-family:'IM Fell';            src:url('/shared/fonts/imfell-italic.woff') format('woff'); font-weight:400; font-style:italic; font-display:swap; }

:root {
  /* ── Brand palette ──
     #7058e0 violet · #d7ceff lilac · #837aab dusk
     #a89b8e stone  · #37312c ink                        */
  --ink:#37312c;
  /* Was #8975ff. That measured 3.27:1 both ways in daylight: parchment
     on it for every primary button, and it as text on parchment for
     every violet link and headline accent. Both are normal-size text
     and both wanted 4.5:1.

     Darkened in OKLCH rather than by scaling toward black, so the hue
     (285) and the chroma (0.197) are untouched and only the lightness
     moves, 65% down to 56%. It is the same violet, nine points darker.
     Both readings land at 4.76:1, with enough headroom that antialiasing
     and a cheap panel cannot push it back under.

     Nocturnal keeps its own lighter #A899FF further down: there the
     button text is dark parchment on light violet, which already
     measured 7.22:1 and does not want changing. */
  --violet:#7058e0;
  --lilac:#d7ceff;
  --dusk:#837aab;
  --stone:#a89b8e;
  --parchment:#FAF8F5;
  --vellum:color-mix(in srgb, var(--lilac) 38%, #FAF8F5);
  --panel:#FFFFFF;
  /* aliases so every rule below stays readable */
  --wine:var(--violet); --gilt:var(--dusk); --ash:var(--lilac);

  /* Type roles */
  --display:'Heartbreak Eighties', Georgia, serif;
  --sub:'Mattone','Helvetica Neue',Arial,sans-serif;
  --body:'Perfectly Nineties','Iowan Old Style',Palatino,Georgia,serif;
  --quote:'IM Fell', Georgia, serif;

  /* Mattone — all caps (3pt down) */
  --caps-xxs: clamp(.46rem, .44rem + .06vw, .5rem);
  --caps-xs: clamp(.53rem, .5rem + .08vw, .57rem);
  --caps-sm: clamp(.58rem, .55rem + .1vw,  .63rem);
  --caps-md: clamp(.66rem, .62rem + .14vw, .72rem);
  /* Mattone — sentence case (2pt down) */
  --sent-sm: clamp(.6rem, .57rem + .1vw, .65rem);
  --sent-md: clamp(.86rem, .8rem + .22vw, .98rem);

  /* IM Fell (2–3pt down) */
  --quote-md: clamp(1rem, .93rem + .32vw, 1.18rem);
  --quote-lg: clamp(1.08rem, .98rem + .45vw, 1.32rem);

  --step-0: clamp(1.02rem, 0.97rem + 0.28vw, 1.14rem);
  --step-1: clamp(1.2rem, 1.06rem + 0.6vw, 1.5rem);
  --step-2: clamp(1.7rem, 1.3rem + 1.8vw, 2.9rem);
  --step-3: clamp(3rem, 2rem + 5vw, 6.6rem);

  --measure:34rem; --shell:66rem; --rail-w:7rem;
  --gutter:clamp(1.25rem, 4vw, 3rem);
  --hair:color-mix(in srgb, var(--stone) 55%, transparent);
  --muted:color-mix(in srgb, var(--ink) 62%, transparent);
}

[data-sect="nocturnal"] {
  /* Three warm blacks stepped off #37312c, so surfaces have depth */
  --ink:#EFEAE3;
  --violet:#A899FF;
  --lilac:#d7ceff;
  --dusk:#A79EC9;        /* was #8F86B5: 3.81:1 on --panel, under AA */
  --stone:#6B6259;
  --parchment:#1C1917;   /* page, deepest */
  --vellum:#272220;      /* alternating bands */
  --panel:#37312c;       /* cards, the brand ink itself */
  --wine:var(--violet); --gilt:var(--dusk); --ash:var(--lilac);
  --hair:color-mix(in srgb, var(--stone) 70%, transparent);
  /* 62%, not 55%. Muting by alpha behaves in opposite directions in the
     two sects: on parchment a lower alpha moves the ink towards white and
     stays legible, but on the nocturnal near-black it moves the text
     towards the background. At 55% every card's body copy sat at 4.42:1
     against --panel, just under AA, and that one value accounted for most
     of the failures on the whole site. 62% puts the same text at 5.3:1
     and reads no louder. */
  --muted:color-mix(in srgb, var(--ink) 62%, transparent);
}

/* ── Film grain + vignette ───────────────────────────────────
   Fixed overlays. Fine fractal noise for tactile paper, plus
   a soft edge fall-off for the cinematic feel.              */
.grain, .vignette { position:fixed; inset:0; pointer-events:none; z-index:40; }

.grain {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px;
  opacity:.075; mix-blend-mode:multiply;
}

.vignette {
  background:radial-gradient(ellipse at 50% 45%, transparent 52%, color-mix(in srgb, #37312c 22%, transparent) 100%);
}

[data-sect="nocturnal"] .grain { opacity:.11; mix-blend-mode:overlay; }

[data-sect="nocturnal"] .vignette { background:radial-gradient(ellipse at 50% 45%, transparent 46%, rgba(0,0,0,.42) 100%); }

/* ── Threshold ───────────────────────────────────────────────
   Temple doors part once per visit. Never blocks the pointer,
   removed from the DOM two seconds after arrival.           */
.threshold { position:fixed; inset:0; z-index:80; display:flex; pointer-events:none; }

.threshold::before {
  content:''; position:absolute; left:50%; top:0; bottom:0; width:3px;
  transform:translateX(-50%); z-index:1;
  background:color-mix(in srgb, var(--gilt) 85%, transparent);
  filter:blur(4px); opacity:0; transition:opacity .4s ease .1s;
}

.threshold.is-open::before { opacity:1; }

.threshold-door {
  flex:1; position:relative;
  background:
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--hair) 40%, transparent) 0 1px, transparent 1px 74px),
    linear-gradient(color-mix(in srgb, var(--vellum) 88%, var(--dusk)), var(--vellum));
  transition:transform 1.25s cubic-bezier(.65,.02,.25,1) .35s;
}

.threshold-door::after {
  content:''; position:absolute; top:50%; width:26px; height:26px;
  border:2px solid color-mix(in srgb, var(--gilt) 70%, transparent); border-radius:50%;
  transform:translateY(-50%);
}

.threshold-door--l { border-right:1px solid color-mix(in srgb, var(--gilt) 45%, transparent); }

.threshold-door--l::after { right:1.6rem; }

.threshold-door--r { border-left:1px solid color-mix(in srgb, var(--gilt) 45%, transparent); }

.threshold-door--r::after { left:1.6rem; }

.threshold.is-open .threshold-door--l { transform:translateX(-102%); }

.threshold.is-open .threshold-door--r { transform:translateX(102%); }

/* ── Base ─────────────────────────────────────────────────── */
*,*::before,*::after { box-sizing:border-box; }

/* The browser's default 8px body margin, killed here rather than in each
   page's own stylesheet. Seventeen of the eighteen pages happened to
   reset it themselves; the one that did not carried an 8px strip of bare
   page down both edges, which stopped every full-bleed band short of the
   glass. Pages that still set margin:0 in their own body rule are simply
   agreeing with this one. */
/* The body defaults, here rather than repeated in each page's own
   stylesheet. Eighteen of the nineteen pages set these themselves; the
   astrocartography guide never did, and the consequences only showed up
   at night. With no `color` it inherited the browser default, pure black,
   which is invisible on the nocturnal near-black: most of that page could
   not be read at all. The same omission also left the browser's 8px body
   margin in place, which stopped every full-bleed band 8px short.

   Pages that still declare these in their own body rule are simply
   agreeing with this one, since theirs load afterwards. */
body {
  margin:0; background:var(--parchment); color:var(--ink);
  font-family:var(--body); font-size:16px; line-height:1.5;
  -webkit-font-smoothing:antialiased; transition:background .35s, color .35s;
}

/* -- No orphans, ever -- universal rule, every page.
   Browser backstop only (support varies by engine) -- real coverage still
   comes from hand-placed &nbsp; between the last two words of every
   heading, paragraph, list item and short line of copy. Never skip that
   step just because this rule exists; add both, always. */
p, li, h1, h2, h3, h4, h5, h6, blockquote, dd, dt, figcaption, summary {
  text-wrap: pretty;
}

html { scroll-behavior:smooth; }

[data-sect="diurnal"] body {
  background:
    radial-gradient(ellipse 100% 60% at 15% -15%, color-mix(in srgb, var(--violet) 20%, transparent) 0%, transparent 55%),
    radial-gradient(ellipse 110% 60% at 50% -10%, color-mix(in srgb, var(--stone) 55%, transparent) 0%, transparent 50%),
    radial-gradient(ellipse 90% 55% at 90% 10%, color-mix(in srgb, var(--violet) 30%, transparent) 0%, transparent 55%),
    var(--parchment);
  background-attachment:fixed, fixed, fixed;
}

[data-sect="nocturnal"] body {
  background:
    radial-gradient(ellipse 100% 60% at 12% -15%, color-mix(in srgb, var(--violet) 8%, transparent) 0%, transparent 55%),
    radial-gradient(ellipse 120% 65% at 50% -10%, color-mix(in srgb, var(--lilac) 4%, transparent) 0%, transparent 50%),
    radial-gradient(ellipse 90% 55% at 92% 12%, color-mix(in srgb, var(--violet) 6%, transparent) 0%, transparent 55%),
    var(--parchment);
  background-attachment:fixed, fixed, fixed;
}

img { max-width:100%; height:auto; display:block; }

a { color:var(--wine); text-underline-offset:.18em; }

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

.skip { position:absolute; left:-9999px; background:var(--ink); color:var(--parchment); padding:.7rem 1.1rem; }

.skip:focus { left:1rem; top:1rem; z-index:100; }

/* ── Type roles ───────────────────────────────────────────── */
.subhead { font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.18em; text-transform:uppercase; color:var(--muted); margin:0 0 .3rem; line-height:1.6; }

.eyebrow { text-align:center; width:100%; font-family:var(--sub); font-size:var(--caps-xxs); color:var(--violet); letter-spacing:.18em; text-transform:uppercase; color:var(--muted); margin:0 0 1.1rem; display:flex; align-items:center; justify-content:center; gap:.75rem; flex-wrap:wrap; }

.eyebrow--left { text-align:left; justify-content:flex-start; margin-bottom:.9rem; }

.display-h2 { font-family:var(--display); font-weight:400; font-size:var(--step-2); line-height:1.04; margin:0 0 .55rem; font-kerning:none; }

.display-h2 em { font-style:normal; color:var(--violet); }

.prose { max-width:var(--measure); }

.prose--center { margin-inline:auto; }

.prose p + p { margin-top:.8em; }

.lead { font-family:var(--quote); font-style:italic; font-size:calc(var(--quote-md) - 2px); line-height:1.32; }

/* ── Header ───────────────────────────────────────────────── */
.topbar { border-bottom:1px solid var(--hair); position:relative; z-index:20; }

.topbar-inner { max-width:var(--shell); margin-inline:auto; display:flex; align-items:center; gap:1.1rem; padding:2.5rem var(--gutter) 1.4rem; }

.wordmark { font-family:var(--display); font-size:var(--step-1); text-decoration:none; color:var(--ink); display:inline-flex; align-items:center; gap:.55rem; font-kerning:none; }

.mark { width:3.3rem; height:auto; flex:none; }

[data-sect="nocturnal"] .mark { filter:invert(1) hue-rotate(180deg); }

.wordmark em { font-style:italic; color:var(--violet); margin-left:-.15em; }

.topbar nav { display:flex; gap:clamp(.8rem,1.8vw,1.6rem); align-items:center; margin-left:auto; }

.topbar nav a { font-family:var(--sub); font-size:var(--caps-xs); letter-spacing:.22em; text-transform:uppercase; text-decoration:none; color:var(--ink); padding-bottom:.25rem; border-bottom:1px solid transparent; }

.topbar nav a:hover, .topbar nav a[aria-current] { border-bottom-color:var(--gilt); }

.nav-cta { color:var(--wine)!important; border-bottom:1px solid var(--wine)!important; }

.sect { margin-left:-3.6px; display:inline-flex; align-items:center; gap:.4rem; font-family:var(--sub); font-size:var(--caps-xs); letter-spacing:.2em; text-transform:uppercase; background:none; border:1px solid var(--hair); color:var(--muted); padding:.38rem .7rem; cursor:pointer; border-radius:999px; }

.sect:hover { border-color:var(--gilt); color:var(--ink); }

.sect-glyph { font-size:.85rem; color:var(--gilt); line-height:1; }

/* ── Singing bowl ─────────────────────────────────────────────
   磬 — struck by hand only. Tone is synthesized on click.    */
.bell {
  all:unset; margin-left:clamp(.6rem,1.4vw,1.1rem); width:2rem; height:2rem;
  display:inline-grid; place-items:center; border:1px solid var(--hair);
  border-radius:50%; cursor:pointer; box-sizing:border-box;
  transition:border-color .2s ease;
}

.bell svg { width:1.05rem; height:1.05rem; overflow:visible; }

.bell .bell-bowl { fill:color-mix(in srgb, var(--gilt) 18%, transparent); stroke:var(--gilt); stroke-width:1.4; }

.bell .bell-rim { stroke:var(--gilt); stroke-width:1.4; stroke-linecap:round; }

.bell .bell-mallet { fill:none; stroke:var(--muted); stroke-width:1.3; stroke-linecap:round; }

.bell:hover, .bell:focus-visible { border-color:var(--violet); }

.bell:hover .bell-bowl, .bell:focus-visible .bell-bowl { stroke:var(--violet); }

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

.bell.is-rung svg { animation:bellStrike .55s cubic-bezier(.2,.7,.3,1); }

@keyframes bellStrike {
  0% { transform:rotate(0); } 25% { transform:rotate(-7deg) scale(1.08); }
  60% { transform:rotate(4deg); } 100% { transform:rotate(0); }
}

.bell-ripple { border-color:color-mix(in srgb, var(--gilt) 62%, transparent); }

.menu-toggle { display:none; font-family:var(--sub); font-size:var(--caps-xs); letter-spacing:.2em; text-transform:uppercase; background:none; border:1px solid var(--ink); color:var(--ink); padding:.38rem .7rem; cursor:pointer; }

/* ── Sky marquee — live sky ticker under the header ─────────── */
.sky-marquee {
  all:unset; display:block; width:100%; cursor:pointer;
  background:var(--vellum); overflow:hidden; border-bottom:1px solid var(--hair);
  padding:.6rem 0; position:relative; z-index:12;
  transition:background .35s, filter .2s ease;
}

.sky-marquee:hover, .sky-marquee:focus-visible { filter:brightness(1.05); }

.sky-marquee:focus-visible { outline:2px solid var(--wine); outline-offset:-2px; }

.sky-marquee-track { display:flex; width:max-content; animation:slide 167s linear infinite; }

.sky-marquee-track span { font-family:var(--sub); font-size:var(--caps-xs); letter-spacing:.22em; text-transform:uppercase; color:var(--gilt); white-space:pre; padding-right:1.6rem; }

/* ── Rail ─────────────────────────────────────────────────── */
.rail {
  position:fixed; left:0; top:50%; transform:translateY(-50%);
  width:var(--rail-w); padding-left:clamp(.9rem,2vw,1.6rem);
  z-index:5; pointer-events:none;
  opacity:1; transition:opacity .4s ease, transform .4s ease;
}

.rail.is-set { opacity:0; transform:translateY(-50%) translateX(-1rem); }

.moon {
  all:unset; display:block; position:relative; width:24px; height:24px; border-radius:50%;
  border:1px solid var(--gilt); overflow:hidden; margin:0 0 1rem .7rem; background:var(--gilt);
  cursor:pointer; pointer-events:auto; transition:box-shadow .2s ease, border-color .2s ease;
}

.moon:hover, .moon:focus-visible { border-color:var(--violet); box-shadow:0 0 0 5px color-mix(in srgb, var(--violet) 16%, transparent); }

.moon:focus-visible { outline:2px solid var(--wine); outline-offset:4px; }

.moon-shadow { position:absolute; inset:0; background:var(--parchment); transform:translateX(calc(var(--p,0) * 100%)); transition:background .35s; }

.rail-scale { position:relative; height:38vh; border-left:1px solid var(--hair); padding-left:.65rem; }

.rail-tick {
  position:absolute; top:calc(var(--at)*100%); transform:translateY(-50%); z-index:2;
  font-family:var(--sub); font-size:var(--sent-sm); letter-spacing:.1em;
  color:var(--muted); font-variant-numeric:tabular-nums;
  opacity:calc(.55 + var(--near,0) * .45);
  text-shadow:0 0 calc(var(--near,0) * 5px) color-mix(in srgb, var(--violet) 65%, transparent);
  transition:color .3s ease, opacity .3s ease;
}

.rail-decan {
  position:absolute; top:calc(var(--at)*100%); transform:translateY(-50%); left:-.42rem; z-index:2;
  font-family:var(--sub); font-size:.5rem; letter-spacing:.06em; text-decoration:none;
  color:var(--gilt); background:var(--parchment); padding:.15rem .3rem;
  opacity:calc(.65 + var(--near,0) * .35); pointer-events:auto; cursor:pointer;
  transition:background .35s, opacity .3s ease, color .18s ease;
}

.rail-decan:hover, .rail-decan:focus-visible { color:var(--violet); }

.rail-decan::after {
  content:attr(data-tip); position:absolute; left:1.5rem; top:50%; transform:translateY(-50%) translateX(-.25rem);
  font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.14em; text-transform:uppercase; white-space:nowrap;
  background:var(--ink); color:var(--parchment); padding:.35rem .6rem;
  opacity:0; pointer-events:none; transition:opacity .18s ease, transform .18s ease;
}

.rail-decan:hover::after, .rail-decan:focus-visible::after { opacity:1; transform:translateY(-50%) translateX(0); }

.rail-progress { position:absolute; left:-1px; top:0; width:2px; height:calc(var(--p,0)*100%); background:var(--gilt); z-index:1; }

.rail-meta {
  all:unset; display:block; cursor:pointer; pointer-events:auto;
  margin:1.3rem 0 0; padding-left:.65rem; font-family:var(--sub); font-size:var(--caps-xxs);
  line-height:2.3; letter-spacing:.16em; text-transform:uppercase; color:var(--muted);
  transition:color .2s ease;
}

.rail-meta:hover, .rail-meta:focus-visible { color:var(--violet); }

.rail-meta:focus-visible { outline:2px solid var(--wine); outline-offset:4px; border-radius:4px; }

/* ── Ephemeris panel ─────────────────────────────────────────
   Live sky positions. Real technique: sun/moon ecliptic
   longitude, plotted on an actual 12-sign wheel.            */
.ephemeris-panel {
  position:fixed; left:calc(var(--rail-w) + clamp(.9rem,2vw,1.6rem) + 1.2rem); top:50%; width:19rem;
  max-height:calc(100vh - 3rem); overflow-y:auto;
  transform:translateY(-50%) translateX(-.4rem) scale(.97);
  background:var(--panel); border:1px solid var(--hair); text-align:left;
  padding:1.3rem 1.4rem 1.5rem; z-index:25;
  visibility:hidden; opacity:0; pointer-events:none;
  transition:opacity .22s ease, transform .22s ease, visibility 0s linear .22s, background .35s, border-color .35s;
  box-shadow:0 20px 44px -16px color-mix(in srgb, var(--ink) 34%, transparent);
}

.ephemeris-panel.is-open {
  visibility:visible; opacity:1; pointer-events:auto;
  transform:translateY(-50%) translateX(0) scale(1);
  transition:opacity .22s ease, transform .22s ease, background .35s, border-color .35s;
}

.ephemeris-panel.is-marquee {
  left:50%; top:7rem;
  transform:translateX(-50%) translateY(-.4rem) scale(.97);
}

.ephemeris-panel.is-marquee.is-open {
  transform:translateX(-50%) translateY(0) scale(1);
}

.eph-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:.9rem; }

.eph-title { font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.2em; text-transform:uppercase; color:var(--muted); margin:0; }

.eph-close { all:unset; cursor:pointer; width:1.5rem; height:1.5rem; display:grid; place-items:center; color:var(--muted); font-size:1.1rem; line-height:1; border-radius:50%; }

.eph-close:hover, .eph-close:focus-visible { color:var(--violet); background:color-mix(in srgb, var(--violet) 12%, transparent); }

.eph-close:focus-visible { outline:2px solid var(--wine); outline-offset:2px; }

.eph-wheel { display:block; width:100%; max-width:11rem; margin:0 auto .9rem; }

.eph-ring { fill:none; stroke:var(--hair); stroke-width:1; }

.eph-sign-glyph { font-size:11px; fill:var(--dusk); text-anchor:middle; dominant-baseline:central; }

.eph-sun-line, .eph-moon-line { stroke-width:1; }

.eph-sun-line { stroke:color-mix(in srgb, var(--violet) 55%, transparent); }

.eph-moon-line { stroke:color-mix(in srgb, var(--gilt) 55%, transparent); }

.eph-sun-mark, .eph-moon-mark { font-size:13px; text-anchor:middle; dominant-baseline:central; }

.eph-sun-mark { fill:var(--violet); }

.eph-moon-mark { fill:var(--gilt); }

.eph-stats { margin:0; }

.eph-stats > div { display:flex; justify-content:space-between; align-items:baseline; gap:1rem; padding:.55rem 0; border-bottom:1px dotted var(--hair); }

.eph-stats > div:last-child { border-bottom:0; }

.eph-stats dt { font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.14em; text-transform:uppercase; color:var(--muted); margin:0; }

.eph-stats dd { font-family:var(--sub); font-size:var(--sent-sm); letter-spacing:.04em; color:var(--ink); margin:0; text-align:right; }

.eph-note { font-family:var(--sub); font-size:var(--sent-sm); letter-spacing:.02em; color:var(--muted); line-height:1.5; margin:1rem 0 0; opacity:.8; }

/* ── Layout ───────────────────────────────────────────────── */
.band { max-width:var(--shell); margin-inline:auto; padding:clamp(3.2rem,7vw,6rem) var(--gutter); }

.band--alt { background:var(--vellum); max-width:none; transition:background .35s; }

.band--alt > * { max-width:var(--shell); margin-inline:auto; }

.centered { text-align:center; }

.centered .hardway, .centered .faq-list { margin-inline:auto; }

.centered .prose--center { margin-inline:auto; }

.split .prose, .split .subhead, .split .display-h2 { margin-inline:0; max-width:34rem; }

.split .display-h2 { max-width:none; }

.centered .module, .centered .split { text-align:left; }

.glyph-rule { border:0; border-top:1px solid var(--hair); margin-inline:auto; max-width:var(--shell); position:relative; height:0; }

.glyph-rule::after { content:attr(data-glyph); position:absolute; left:50%; top:0; transform:translate(-50%,-50%); background:var(--parchment); padding:0 1rem; color:var(--gilt); font-size:1rem; line-height:1; transition:background .35s; }

/* The lotus — real symbol, eight petals as in the cazimi bloom, marking the section that is personal rather than instructional */
/* The lotus stands alone at the seam between bands — no hairline through it,
   so the GIF's transparency reads cleanly in both sects. */
.glyph-rule--lotus { border-top:0; }

.lotus-glyph {
  position:absolute; left:50%; top:0; transform:translate(-50%,-50%);
  height:auto; display:block;
}

.lotus-glyph--bud   { width:4.4rem; aspect-ratio:216 / 194; }

.lotus-glyph--bloom { width:5.6rem; aspect-ratio:248 / 215; }

/* Kindling — labels warm gold once as they enter view */
.eyebrow.is-lit { animation:kindle 1.7s ease-out 1; }

.glyph-rule.is-lit::after { animation:kindle 1.7s ease-out 1; }

.glyph-rule--lotus.is-lit .lotus-glyph { animation:kindleImg 1.7s ease-out 1; }

@keyframes kindle {
  0% { text-shadow:none; }
  35% { color:var(--gilt); text-shadow:0 0 14px color-mix(in srgb, var(--gilt) 85%, transparent); }
  100% { text-shadow:none; }
}

@keyframes kindleImg {
  0% { filter:none; }
  35% { filter:drop-shadow(0 0 10px color-mix(in srgb, var(--gilt) 80%, transparent)); }
  100% { filter:none; }
}

/* ── Hero ─────────────────────────────────────────────────── */
.hero { max-width:var(--shell); margin-inline:auto; padding:clamp(2.6rem,6vw,5rem) var(--gutter); text-align:center; }

.hero-grid { display:grid; grid-template-columns:1.1fr .9fr; gap:clamp(2rem,5vw,4rem); align-items:center; text-align:left; }

.hero h1 { font-family:var(--display); font-weight:400; font-size:clamp(2.3rem, 1.6rem + 3vw, 3.7rem); line-height:1; margin:0 0 .7rem; font-kerning:none; }

.hero h1 em { font-style:normal; color:var(--violet); }

.h1-sub { display:block; letter-spacing:.01em; }

.standfirst { font-family:var(--quote); font-style:italic; font-size:calc(var(--quote-lg) - 2px); line-height:1.3; max-width:28rem; margin:0 0 .8rem; }

.hero-body { max-width:30rem; margin:0 0 1.2rem; }

.hero-actions { display:flex; align-items:baseline; gap:1.3rem; flex-wrap:wrap; }

.hero-figure img { width:100%; filter:grayscale(.06); position:relative; z-index:1; }

.hero-figure { animation:heroLevitate 6.5s ease-in-out infinite; }

.hero-figure > img { transition:transform .4s cubic-bezier(.22,.61,.36,1); will-change:transform; }

@keyframes heroLevitate { 0%, 100% { transform:translateY(0); } 50% { transform:translateY(-10px); } }

/* Soft bloom, sat behind the crisp ring image — same gold sampled from the
   photo itself (243,211,142), not the theme's --gilt, since the ring's own
   colour never shifts between sects and the glow needs to match it exactly. */
.aureole::after {
  content:''; position:absolute; inset:-20%; border-radius:50%; z-index:0;
  background:radial-gradient(circle,
    transparent 34%,
    rgba(243,211,142,.6) 44%,
    rgba(255,196,102,.32) 51%,
    transparent 65%);
  filter:blur(15px);
  animation:aureoleBloom 4.2s ease-in-out infinite alternate;
}

.aureole::before {
  content:''; position:absolute; inset:0; border-radius:50%; z-index:1;
  background:url('images/aureole-halo.webp') center / contain no-repeat;
  opacity:.62; animation:spin 95s linear infinite;
}

@keyframes aureoleBloom { from { opacity:.45; transform:scale(.97); } to { opacity:.85; transform:scale(1.03); } }

[data-sect="nocturnal"] .aureole::before { opacity:.8; }

[data-sect="nocturnal"] .aureole::after { filter:blur(15px) brightness(1.3); }

/* Native fallback (no image request, fully theme-tinted):
.aureole::before {
  background:
    radial-gradient(circle, transparent 53.2%, color-mix(in srgb, var(--gilt) 60%, transparent) 53.8% 54.6%, transparent 55.2%),
    repeating-conic-gradient(color-mix(in srgb, var(--gilt) 55%, transparent) 0deg .7deg, transparent .7deg 6deg);
  -webkit-mask:radial-gradient(circle, transparent 50%, #000 51% 86%, transparent 87%);
  mask:radial-gradient(circle, transparent 50%, #000 51% 86%, transparent 87%);
  opacity:.38;
}
*/

/* Spinning seal */
/* overflow:clip because the svg inside spins: a rotated 220px square
   reports a 311px axis-aligned bounding box, and the browser counts
   that phantom width as real page overflow (it put ~19px of horizontal
   scroll on every page carrying a seal). The artwork is a circle well
   inside the square, so clipping to the box loses nothing visible. */
.seal { position:absolute; right:-2rem; bottom:-1.5rem; width:220px; height:220px; z-index:2; overflow:clip; }

.seal-transition { position:relative; height:0; z-index:5; }

.seal-transition .seal { position:absolute; right:clamp(.9rem,2vw,1.6rem); bottom:auto; top:0; transform:translateY(-50%); }

.seal svg { width:100%; height:100%; animation:spin 26s linear infinite; }

.seal-glyph { position:absolute; inset:0; display:grid; place-items:center; color:var(--violet); font-size:2.4rem; }

@keyframes spin { to { transform:rotate(360deg); } }

/* ── Buttons ──────────────────────────────────────────────── */
.btn { display:inline-block; font-family:var(--sub); font-size:var(--caps-sm); letter-spacing:.22em; text-transform:uppercase; text-decoration:none; color:var(--parchment); background:var(--wine); padding:.95rem 1.9rem; border:1px solid var(--wine); transition:background .18s, color .18s; }

.btn:hover { background:transparent; color:var(--wine); }

.btn--ghost { background:transparent; color:var(--wine); margin-top:2rem; }

.btn--ghost:hover { background:var(--wine); color:var(--parchment); }

.btn--lg { padding:1.15rem 2.6rem; font-size:var(--caps-md); letter-spacing:.16em; position:relative; z-index:2; }

.fineprint { font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.05em; line-height:1.55; color:var(--muted); margin:0; max-width:26rem; }

.centered .fineprint { margin-inline:auto; }

/* ── Square chart ─────────────────────────────────────────── */
.square-chart {
  position:relative; margin:2.5rem auto 0; max-width:52rem;
  display:grid; grid-template-columns:1fr 1fr; gap:1px;
  background:var(--hair); border:1px solid var(--hair); text-align:left;
}

.sc-cell { background:var(--panel); padding:clamp(1.4rem,3vw,2.2rem); }

.sc-cell .glyph { display:block; font-size:1.6rem; color:var(--gilt); line-height:1; margin-bottom:.7rem; }

.sc-cell h3 { font-family:var(--sub); font-size:var(--caps-sm); letter-spacing:.26em; text-transform:uppercase; margin:0 0 .8rem; font-weight:400; }

.sc-cell p { margin:0; font-size:.95em; }

.sc-centre { grid-column:1 / -1; background:var(--parchment); padding:clamp(1.8rem,4vw,3rem); text-align:center; transition:background .35s; }

.sc-centre .display-h2 { margin:0; max-width:26rem; margin-inline:auto; }

.sc-angle { position:absolute; font-family:var(--sub); font-size:var(--caps-xs); letter-spacing:.2em; color:var(--gilt); background:var(--parchment); padding:.2rem .5rem; transition:background .35s; }

.sc-angle--mc  { top:0; left:50%; transform:translate(-50%,-50%); }

.sc-angle--ic  { bottom:0; left:50%; transform:translate(-50%,50%); }

.sc-angle--asc { left:0; top:50%; transform:translate(-50%,-50%); }

.sc-angle--dsc { right:0; top:50%; transform:translate(50%,-50%); }

/* ── Hard way ─────────────────────────────────────────────── */
.hardway { list-style:none; margin:0; padding:0; max-width:44rem; text-align:left; }

.hardway li { position:relative; padding:1.15rem 0 1.15rem 2rem; border-bottom:1px solid var(--hair); }

.hardway li:first-child { border-top:1px solid var(--hair); }

/* Bullets wax as you read down the list — new, crescent, quarter, gibbous, full.
   Lit from the right, the way a waxing moon actually fills. */
.hardway li::before {
  content:''; position:absolute; left:0; top:1.55rem;
  width:9px; height:9px; border-radius:50%;
  border:1px solid var(--gilt);
  background:linear-gradient(to left, var(--gilt) var(--lit,0%), transparent var(--lit,0%));
  transition:background .35s, border-color .35s;
}

.hardway li:nth-child(1)::before   { --lit:0%; }

.hardway li:nth-child(2)::before   { --lit:28%; }

.hardway li:nth-child(3)::before   { --lit:50%; }

.hardway li:nth-child(4)::before   { --lit:76%; }

.hardway li:nth-child(n+5)::before { --lit:100%; }

.link-portal { display:inline-block; margin-top:2.2rem; font-family:var(--sub); font-size:var(--caps-sm); letter-spacing:.22em; text-transform:uppercase; text-decoration:none; border-bottom:1px solid var(--gilt); padding-bottom:.4rem; }

/* ── Opposition ───────────────────────────────────────────── */
.opposition { display:grid; grid-template-columns:1fr auto 1fr; gap:clamp(1.4rem,3.5vw,2.6rem); align-items:start; margin-top:2rem; text-align:left; }

.opp-glyph { font-size:1.5rem; color:var(--gilt); align-self:center; }

.opp-col ul { list-style:none; margin:0; padding:0; }

.opp-col li { padding:.7rem 0 .7rem 1.4rem; position:relative; border-bottom:1px dotted var(--hair); }

.opp-col--yes li::before { content:'+'; position:absolute; left:0; color:var(--gilt); }

.opp-col--no li::before { content:'−'; position:absolute; left:0; color:var(--ash); }

.opp-col--no { color:var(--muted); }

/* ── Quadrants ───────────────────────────────────────────────
   Every chart divides into four quarters. Four modules, four
   equal cells, identical rhythm in every one.               */
.modules { text-align:center; }

.quadrants {
  display:grid; grid-template-columns:repeat(2, 1fr);
  gap:1px; background:var(--hair);
  border:1px solid var(--hair);
  max-width:58rem; margin:2.6rem auto 0; text-align:left;
}

.quad {
  background:var(--panel); padding:clamp(1.6rem,3vw,2.4rem);
  display:flex; flex-direction:column;
}

.quad-mark {
  font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.18em;
  text-transform:uppercase; color:var(--dusk); margin:0 0 1.2rem;
  display:flex; align-items:center; gap:.7rem;
}

.quad-mark span {
  color:var(--violet); border:1px solid color-mix(in srgb, var(--violet) 40%, transparent);
  padding:.22rem .5rem; letter-spacing:.12em;
}

.quad h3 {
  font-family:var(--display); font-weight:400; font-size:var(--step-1);
  margin:0 0 .9rem; line-height:1.12; min-height:2.3em; font-kerning:none;
}

.quad p:not(.quad-mark) { margin:0; }

/* ── Split ────────────────────────────────────────────────── */
.split { display:grid; grid-template-columns:1fr minmax(0,26rem); gap:clamp(2rem,5vw,3.5rem); align-items:center; }

.split--rev { grid-template-columns:minmax(0,26rem) 1fr; }

.split figure { margin:0; }

/* The portrait arrives already masked to an oval with its own border,
   so no border-radius or grayscale is applied over the top of it. */
.oval { position:relative; }

/* ── Water-moon reflection ───────────────────────────────────
   The image is mirrored below itself and clipped to the near
   band, so only what sits closest to the waterline shows.   */
.filter-defs { position:absolute; width:0; height:0; overflow:hidden; }

.reflect { position:relative; }

/* Absolute so the reflection hangs below the figure without moving the seal. */
.reflect-water {
  position:absolute; top:100%; left:0; right:0;
  display:block; overflow:hidden; line-height:0;
  max-height:clamp(3rem, 7vw, 5.5rem);
  opacity:.42;
  filter:url(#waterRipple);
  -webkit-mask-image:linear-gradient(to bottom, #000 0%, transparent 92%);
  mask-image:linear-gradient(to bottom, #000 0%, transparent 92%);
}

.reflect-water img { display:block; width:100%; transform:scaleY(-1); }

[data-sect="nocturnal"] .reflect-water { opacity:.3; }

/* Without the wobble it is just a mirror, which is still the image — keep it, drop the motion. */
@media (prefers-reduced-motion:reduce) { .reflect-water { filter:none; } }

/* ── Marquee ──────────────────────────────────────────────── */
.marquee { background:var(--panel); overflow:hidden; border-top:1px solid var(--hair); border-bottom:1px solid var(--hair); padding:.85rem 0; background:var(--vellum); transition:background .35s; }

.marquee-track { display:flex; width:max-content; animation:slide 44s linear infinite; }

.marquee-track span { font-family:var(--sub); font-size:var(--caps-sm); letter-spacing:.28em; text-transform:uppercase; color:var(--gilt); white-space:pre; padding-right:1.4rem; }

@keyframes slide { to { transform:translateX(-50%); } }

.notes { margin:2.2rem auto 0; }

/* ── Cazimi enrol ─────────────────────────────────────────── */
.enrol-card { position:relative; overflow:hidden; background:var(--panel); color:var(--ink); border:1px solid var(--hair); padding:clamp(2.2rem,5vw,3.6rem); max-width:42rem; margin-inline:auto; transition:background .35s, color .35s; }

/* ── Altar candles ────────────────────────────────────────────
   Two lit candles flank the offering. Flames flicker on their
   own slightly different clocks, as real flames do.         */
.altar { position:relative; max-width:42rem; margin-inline:auto; }

.altar-candle {
  position:absolute; bottom:.2rem; width:.85rem; height:3.4rem;
  background:linear-gradient(color-mix(in srgb, var(--parchment) 82%, var(--gilt)), color-mix(in srgb, var(--parchment) 68%, var(--stone)));
  border:1px solid var(--hair); border-radius:.4rem .4rem .15rem .15rem;
}

.altar-candle--l { left:-2.7rem; }

.altar-candle--r { right:-2.7rem; }

.altar-candle::before { /* wick */
  content:''; position:absolute; left:50%; top:-.2rem; width:1px; height:.25rem;
  background:var(--ink); transform:translateX(-50%);
}

.altar-candle::after { /* pool of light */
  content:''; position:absolute; left:50%; top:-2.6rem; width:5.5rem; height:5.5rem;
  transform:translate(-50%,0);
  background:radial-gradient(circle, rgba(255,178,84,.28) 0%, transparent 62%);
  animation:candleGlow 2.3s ease-in-out infinite alternate;
}

.candle-flame {
  position:absolute; left:50%; top:-1.15rem; width:.52rem; height:1.05rem;
  transform:translateX(-50%);
  border-radius:50% 50% 50% 50% / 62% 62% 38% 38%;
  background:radial-gradient(closest-side at 50% 72%, #ffe9b8 0%, #ffb54d 58%, rgba(255,122,47,0) 100%);
  filter:drop-shadow(0 0 5px rgba(255,160,60,.6));
  animation:flick 1.15s ease-in-out infinite alternate;
}

.altar-candle--r .candle-flame { animation-duration:.94s; animation-delay:.3s; }

.altar-candle--r::after { animation-duration:2.7s; animation-delay:.6s; }

@keyframes flick {
  from { transform:translateX(-50%) scale(1) rotate(-1.5deg); }
  to   { transform:translateX(-53%) scale(.9,1.08) rotate(2.2deg); }
}

@keyframes candleGlow { from { opacity:.75; } to { opacity:1; } }

[data-sect="nocturnal"] .altar-candle::after { background:radial-gradient(circle, rgba(255,178,84,.38) 0%, transparent 62%); }

@media (max-width:900px) { .altar-candle { display:none; } }

/* ── Cazimi lotus ────────────────────────────────────────────
   Two rings of petals — eight outer, eight inner offset by half
   a step — opening from the heart of the sun as the cursor nears.  */
.cazimi {
  /* Heart of the bloom sits on the button, not the price — the button is the cazimi,
     and being opaque it masks the brightest convergence so the type stays readable. */
  position:absolute; left:50%; top:64%; width:34rem; height:34rem;
  transform:translate(-50%,-50%) scale(var(--cazimi-scale,1));
  pointer-events:none; transition:transform .55s cubic-bezier(.2,.7,.3,1);
  --lotus-c:var(--cazimi-color, var(--gilt));
}

.cazimi-lotus {
  position:absolute; inset:0; width:100%; height:100%; overflow:visible;
  opacity:var(--lotus-op, .55);
  transition:opacity .45s ease;
  animation:lotusDrift 150s linear infinite;
}

.lotus-ring { transform-origin:50% 50%; transition:transform .6s cubic-bezier(.2,.7,.3,1); }

.lotus-ring--outer { transform:rotate(var(--ring-out, 0deg)); }

.lotus-ring--inner { transform:rotate(var(--ring-in, 0deg)); }

.lotus-core { transition:opacity .45s ease; }

@keyframes lotusDrift { to { transform:rotate(360deg); } }

.enrol-card[data-zone="beams"] .cazimi {
  --cazimi-scale:1.03; --lotus-op:.72; --ring-out:5deg; --ring-in:-4deg;
}

.enrol-card[data-zone="combust"] .cazimi {
  --cazimi-scale:1.07; --lotus-op:.88; --ring-out:10deg; --ring-in:-8deg;
  --cazimi-color:var(--wine);
}

.enrol-card:has(.btn--lg:hover, .btn--lg:focus-visible) .cazimi,
.enrol-card[data-zone="cazimi"] .cazimi {
  --cazimi-scale:1.13; --lotus-op:.92; --ring-out:16deg; --ring-in:-13deg;
  --cazimi-color:var(--violet);
}

.cazimi-status {
  font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.2em; text-transform:uppercase;
  color:var(--gilt); margin:0 0 1rem; min-height:1.2em; opacity:0; position:relative;
  transition:opacity .3s ease;
}

.enrol-card:has(.btn--lg:focus-visible) .cazimi-status,
.enrol-card[data-zone] .cazimi-status { opacity:1; }

.enrol-card h3 { font-family:var(--display); font-weight:400; font-size:var(--step-2); margin:0 0 1rem; line-height:1.02; position:relative; font-kerning:none; }

.price { font-family:var(--display); font-size:var(--step-2); color:var(--gilt); margin:0 0 1.7rem; line-height:1; position:relative; font-kerning:none; }

.fortune { color:var(--dusk); font-size:.62em; vertical-align:.34em; margin-right:.3em; }

.price .price-sub { display:block; font-family:var(--sub); font-size:var(--caps-xs); letter-spacing:.18em; text-transform:uppercase; color:var(--ink); opacity:.9; margin-top:.7rem; }

.enrol-card .btn { background:var(--violet); color:#FFF; border-color:var(--violet); }

.enrol-card .btn:hover { background:transparent; color:var(--violet); }

.enrol-card .fineprint { color:var(--muted); margin-top:1.5rem; position:relative; }

/* ── FAQ ──────────────────────────────────────────────────── */
.faq-head { display:flex; align-items:center; justify-content:center; gap:2rem; flex-wrap:wrap; margin-bottom:2.5rem; }

.faq-head .display-h2 { margin:0; }

.faq-art { margin:0; width:9rem; }

.faq-art img { border-radius:50%; filter:grayscale(.3); }

.faq-list { max-width:46rem; text-align:left; }

.faq details { border-bottom:1px solid var(--hair); }

.faq details:first-child { border-top:1px solid var(--hair); }

.faq summary { cursor:pointer; list-style:none; padding:1.15rem 2rem 1.15rem 0; position:relative; font-family:var(--sub); font-size:var(--caps-sm); letter-spacing:.14em; text-transform:uppercase; line-height:1.8; }

.faq summary::-webkit-details-marker { display:none; }

.faq summary::after { content:'☌'; position:absolute; right:0; top:1.15rem; color:var(--gilt); }

.faq details[open] summary::after { content:'☍'; }

.faq details p { margin:0 0 1.3rem; }

/* ── Footer ───────────────────────────────────────────────── */
.sitefoot { border-top:1px solid var(--hair); position:relative; z-index:10; background:var(--parchment); transition:background .35s; }

.foot-inner { max-width:var(--shell); margin-inline:auto; padding:clamp(2.6rem,6vw,4rem) var(--gutter) 2rem; display:grid; grid-template-columns:1.5fr repeat(3, 1fr); gap:clamp(1.5rem,3vw,2.5rem); }

.foot-brand .wordmark { display:inline-flex; align-items:center; gap:.55rem; margin:0 0 .25rem; line-height:1.05; }

.tagline { font-family:var(--quote); font-style:italic; font-size:var(--sent-md); line-height:1.15; margin:0 0 .8rem; color:var(--ink); max-width:20rem; }

.foot-blurb { font-size:.78em; line-height:1.4; color:var(--muted); margin:0 0 1.1rem; max-width:22rem; }

.foot-col { display:grid; gap:.55rem; align-content:start; }

.foot-head { font-family:var(--sub); font-size:var(--caps-xs); letter-spacing:.24em; text-transform:uppercase; color:var(--gilt); margin:0 0 .3rem; }

.foot-col a { font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.2em; text-transform:uppercase; text-decoration:none; color:var(--ink); line-height:1.6; }

.foot-col a:hover { color:var(--wine); }

.foot-base { max-width:var(--shell); margin-inline:auto; padding:1.2rem var(--gutter) 2.4rem; border-top:1px solid var(--hair); display:flex; justify-content:space-between; gap:1rem; flex-wrap:wrap; }

.foot-base p { font-family:var(--sub); font-size:var(--caps-xxs); letter-spacing:.14em; text-transform:uppercase; color:var(--muted); margin:0; }

.foot-base a { color:var(--muted); text-decoration:none; }

.foot-base a:hover { color:var(--wine); }

/* ── Responsive ───────────────────────────────────────────── */
@media (max-width:1180px) { .rail { display:none; } .seal-transition { display:none; } }

.mobile-break { display:none; }

@media (prefers-reduced-motion:reduce) {
  html { scroll-behavior:auto; }
  .marquee-track, .sky-marquee-track, .seal svg, .cazimi-lotus, .hero-figure { animation:none; }
  * { transition:none !important; }
}

/* ── Affiliate button ─────────────────────────────────────── */
.affiliate {
  /* Its own line under the blurb, with room to breathe. It is an affiliate
     link rather than a call to action for her own work, so it should read
     as a footnote to the paragraph, not as a competing button. */
  display:table; margin:1.1rem 0 0; text-align:center;
  font-family:var(--sub); font-size:calc(var(--caps-xs) - 2px); letter-spacing:.16em;
  text-transform:uppercase; text-decoration:none !important;
  border:1px solid var(--violet); color:var(--violet) !important;
  padding:.65rem 1.4rem; line-height:1.4; border-radius:999px;
  transition:background .18s, color .18s;
}

.affiliate:hover { background:var(--violet); color:#FFF !important; }

/* ── Star burst on the 1:1 link ───────────────────────────── */
.nav-cta { position:relative; }

.spark {
  position:fixed; pointer-events:none; z-index:60;
  font-size:.7rem; color:var(--violet); line-height:1;
  animation:burst 1.15s cubic-bezier(.2,.7,.3,1) forwards;
}

.spark:nth-child(even) { color:var(--dusk); }

.spark:nth-child(3n) { color:var(--lilac); }

@keyframes burst {
  0%   { transform:translate(0,0) scale(.4) rotate(0deg); opacity:1; }
  100% { transform:translate(var(--dx), var(--dy)) scale(1.15) rotate(160deg); opacity:0; }
}

@media (prefers-reduced-motion:reduce) { .spark { display:none; } }

.sect-ripple {
  position:fixed; border-radius:50%; pointer-events:none; z-index:35;
  border:2px solid color-mix(in srgb, var(--violet) 62%, transparent);
  animation:sectRipple 2.1s cubic-bezier(.22,.61,.36,1) forwards;
}

@keyframes sectRipple {
  0%   { transform:translate(-50%,-50%) scale(0); opacity:.85; }
  70%  { opacity:.32; }
  100% { transform:translate(-50%,-50%) scale(1); opacity:0; }
}

/* ── Petal fall ───────────────────────────────────────────── */
.petal {
  position:fixed; z-index:36; width:14px; height:10px; pointer-events:none;
  background:radial-gradient(ellipse at 32% 40%, #f3d7de 0%, color-mix(in srgb, var(--lilac) 62%, #e9b7c4) 68%, transparent 74%);
  border-radius:60% 40% 55% 45% / 55% 60% 40% 45%;
  opacity:0; animation:petalFall 2.9s ease-in forwards;
}

@keyframes petalFall {
  0%   { transform:translate(0,0) rotate(0deg); opacity:0; }
  12%  { opacity:.9; }
  100% { transform:translate(var(--sx,20px), 130px) rotate(var(--rot,120deg)); opacity:0; }
}

/* ═══════════════════════════════════════════════════════════════════
   ADAPTIVE RAIL v1 — canonical, shared by every page
   The rail is fixed while bands of different luminance slide past it,
   so at any moment it may sit over paper, over a dark full-bleed band,
   or straddling the seam between them. Two mechanisms:

   1. Each discrete mark hit-tests its own midpoint and flips on its own
      via .on-dark, so the top of the rail can stay dark while the
      bottom goes light.
   2. The hairline and its progress fill can't be one colour or the
      other, so each carries a light twin painted through --lum-mask,
      a gradient rebuilt per frame in that element's own pixel space.

   Colours come from the page palette (--rail-lit defaults to --lilac),
   so purple pages stay purple and the Lilith page stays bone.
   Opt any section in on any page with data-lum="dark".
   ═══════════════════════════════════════════════════════════════════ */
:root {
  --rail-lit: var(--lilac);
  --rail-lit-soft: color-mix(in srgb, var(--lilac) 60%, transparent);
}

/* ── Decan markers ───────────────────────────────────────────────────
   Previously a parchment-filled chip, which read as a stray box wherever
   the band behind it wasn't exactly parchment. Now a hollow node sitting
   on the scale with the numeral beside it: no fill, so nothing can box,
   and the node states carry real meaning — hollow for a section you
   haven't reached, filled for the one you're in. */
.rail-decan {
  position:absolute; top:calc(var(--at)*100%); transform:translateY(-50%);
  left:0; z-index:2; display:block; background:none;
  padding:.2rem .2rem .2rem .68rem;
  font-family:var(--sub); font-size:.6rem; letter-spacing:.11em;
  text-decoration:none; color:var(--gilt);
  opacity:calc(.85 + var(--near,0) * .15);
  transition:color .2s ease, opacity .3s ease;
}

.rail-decan::before {
  content:''; position:absolute; left:-1px; top:50%;
  transform:translate(-50%,-50%);
  width:.5rem; height:.5rem; border-radius:50%;
  background:transparent; border:1.6px solid currentColor;
  transition:background .25s ease, transform .25s ease;
}

.rail-decan:hover::before,
.rail-decan:focus-visible::before,
.rail-decan.is-here::before {
  background:currentColor; transform:translate(-50%,-50%) scale(1.22);
}

.rail-decan.is-here { opacity:1; color:var(--violet); }

.rail-decan.is-here.on-dark { color:var(--rail-lit); }

/* ── Light twins for the continuous line and its fill ────────────── */
.rail-scale, .rail-progress { position:relative; }

.rail-scale::before {
  content:''; position:absolute; left:-1px; top:0; width:1px; height:100%;
  background:var(--rail-lit-soft); pointer-events:none; z-index:0;
  -webkit-mask-image:var(--lum-mask, linear-gradient(transparent,transparent));
          mask-image:var(--lum-mask, linear-gradient(transparent,transparent));
}

.rail-progress::before {
  content:''; position:absolute; inset:0; background:var(--rail-lit);
  pointer-events:none;
  -webkit-mask-image:var(--lum-mask, linear-gradient(transparent,transparent));
          mask-image:var(--lum-mask, linear-gradient(transparent,transparent));
}

/* ── Flipped states ──────────────────────────────────────────────── */
.rail-tick.on-dark { color:var(--rail-lit); }

.rail-decan.on-dark { color:var(--rail-lit); }

.rail-meta.on-dark { color:var(--rail-lit-soft); }

.moon.on-dark { border-color:var(--rail-lit); background:var(--rail-lit); }

.moon.on-dark .moon-shadow { background:#0d0b0a; }

.moon.on-dark:hover, .moon.on-dark:focus-visible {
  border-color:var(--rail-lit);
  box-shadow:0 0 0 5px color-mix(in srgb, var(--rail-lit) 20%, transparent);
}

.rail-decan.on-dark::after {
  background:var(--rail-lit); color:#14100e;
}

/* ═══════════════════════════════════════════════════════════════════
   FRESCO BAND — the shared light ground
   A grayscale Baroque ceiling, used at least once on every page so the
   site keeps one recurring texture in common. Three rules:

   1. It bleeds EDGE TO EDGE. A background belongs to the viewport, not
      to the text column, so the section drops its shell width and the
      children take it back. A background that stops at the measure
      reads as a bug — that is why max-width is cleared here.
   2. It is a wash, never a picture: low opacity, and masked so it fades
      out before the copy starts and never competes with the type.
   3. Nocturnal inverts it, so the plate reads as light-on-dark instead
      of a grey smear.
   ═══════════════════════════════════════════════════════════════════ */
.band--fresco {
  position:relative; overflow:hidden;
  max-width:none;
}
.band--fresco::before {
  content:''; position:absolute; left:0; right:0; top:0; pointer-events:none;
  /* The plate keeps its OWN proportions and hangs from the top edge.
     `cover` on a tall section scaled it ~2.5x and showed a blown-up
     fragment; sizing to the full width with a matching aspect-ratio box
     means the fresco always reads at its true scale, whatever the
     section's height, and the fade happens across the image itself. */
  aspect-ratio:1400/933;
  background:url('/shared/images/fresco.png') top center / 100% auto no-repeat;
  opacity:.17;
  -webkit-mask-image:linear-gradient(to bottom, #000 0%, #000 38%, transparent 97%);
          mask-image:linear-gradient(to bottom, #000 0%, #000 38%, transparent 97%);
}
.band--fresco > * {
  position:relative; z-index:1;
  max-width:calc(var(--shell) - 2*var(--gutter)); margin-inline:auto;
}
html[data-sect="nocturnal"] .band--fresco::before { opacity:.09; filter:invert(1); }

/* The lotus dividers deliberately straddle the seam between two sections.
   A background wash on the section BELOW is painted by a positioned
   ::before, which would otherwise cover the lotus's lower half and slice
   it in two. Lifting the divider onto its own layer keeps it whole. */
.glyph-rule { z-index:2; }
.glyph-rule--lotus .lotus-glyph { position:relative; z-index:2; }

/* Degree ticks on the rail sat at 4.43:1 in nocturnal, just under AA. The
   rail is decoration but the numbers on it are real information, and this
   is shared chrome so the fix belongs here rather than on one page. */
html[data-sect="nocturnal"] .rail-tick { color:#e2dcff; }

/* .enrol-card .btn pins its label to white on every page built from the
   workshop template. In daylight that sits on the deep violet and reads
   fine; at night --violet lightens to #A899FF and white on it falls to
   2.42:1. The dark ground is 7.7:1, and is what the shared .btn already
   does through var(--parchment). Here rather than in nine stylesheets. */
html[data-sect="nocturnal"] .enrol-card .btn { color:var(--parchment); }

/* ── Nav collapse, 860px ──────────────────────────────────────
   The topbar holds the wordmark, five nav links and two buttons, and it
   runs out of room well before the old 760px collapse point. Measured on
   /readings: "Book 1:1" wraps onto two lines from 850px down, and below
   810px the right-hand gutter starts collapsing too, until at 768px, the
   iPad's portrait width, the sect button sits 1px from the edge while
   the wordmark keeps its full 32px on the left. Nothing overflowed, so
   the page never scrolled sideways; it just went visibly lopsided.

   860px is the last width measured clean, so the menu button takes over
   at or below it. Only the nav moves. The footer and the seal keep their
   own breakpoints in the page stylesheets.

   This lives in shared because the page stylesheets each carry their own
   copy of the same four rules at 760px, and nineteen copies is how the
   breakpoint got stuck at a stale value in the first place. Those copies
   still fire below 760px and are now redundant, which is harmless: the
   declarations are identical. */
@media (max-width:860px) {
  .menu-toggle { display:block; }
  .topbar-inner { flex-wrap:wrap; }
  .topbar nav {
    display:none; flex-basis:100%; flex-direction:column;
    align-items:flex-start; gap:.9rem; padding-top:1.1rem; margin-left:0;
  }
  .topbar.is-open nav { display:flex; }
}

/* ── Input placeholders ───────────────────────────────────────
   Nobody had ever styled these, so they fell back to the browser's
   default grey (#757575). That happens to clear AA on a white field by
   daylight at 4.61:1, and fails on the dark panel at night at 2.78:1,
   because the browser has no idea the field changed colour underneath
   it.

   It matters more than placeholder text usually does here. The signup
   forms take a first name and an email, their real labels are visually
   hidden, so the placeholder is the only thing on screen telling you
   which field is which. At 2.78:1 a night reader cannot tell them
   apart.

   Tied to --ink so it tracks the sect instead of guessing: 72% clears
   AA on both grounds with room to spare, 5.2:1 by day and 6.3:1 at
   night, and still reads as a hint rather than as typed input. */
input::placeholder,
textarea::placeholder {
  color:color-mix(in srgb, var(--ink) 72%, transparent);
  opacity:1;   /* Firefox dims placeholders by default; undo it */
}

/* ── Honeypot ─────────────────────────────────────────────────
   The signup forms carry a decoy field. It has to be reachable by a
   bot parsing the markup and unreachable by a person, which rules out
   display:none and hidden, since the cruder bots skip those and so do
   some password managers. Pushed off screen instead, with aria-hidden
   and tabindex="-1" on the field so a screen reader never announces it
   and the tab key never lands on it. Anything that arrives with this
   filled in is dropped server side. */
.hp-field {
  position:absolute; left:-9999px; top:auto;
  width:1px; height:1px; overflow:hidden;
}
