/* ==========================================================================
   Empyrean — The Descent (single post template)

   Loaded only on posts using the "Descent Article" template. The page runs
   one continuous gradient from the firmament (marble white) at the top to
   the inferno (--emp-hell-bg) at the bottom, landing seamlessly on the
   black footer.

   IMPORTANT: the gradient itself is NOT defined here. It lives in the STOPS
   table at the top of js/empyrean-descent.js, which paints it and derives every
   ink from it. Text legibility depends on the ink matching the exact background
   luminance behind it, so the two cannot be maintained separately — split them
   and a palette tweak silently makes the prose unreadable mid-article. To
   restyle the descent, edit STOPS. The rule below is only the no-JS fallback.

   Because the gradient is painted on the container rather than fixed to the
   viewport, every block permanently sits on its own patch of background. So
   text colour cannot be a single value — the script measures each top-level
   block and writes:

     --dsc-fg       body ink for that block
     --dsc-fg-head  heading ink for that block
     --dsc-d        0 → 1 realm side, for decorative accents ONLY

   Never colour text from --dsc-d: a mid value lands mid-grey on a mid-grey
   background (measured 1.02:1). --dsc-fg is luminance-derived and safe.

   Progressive enhancement: the dramatic palette only activates once the script
   has added .emp-descent-ready. Without JS you get a light, readable page
   rather than dark ink on a black background.
   ========================================================================== */

.empyrean-descent {
  /* Ink endpoints. These are the no-JS fallback values; the live inks are
     computed by empyrean-descent.js, whose INK_* / HEAD_* constants must match
     these two pairs. */
  --dsc-ink-heaven: #24352b;   /* body text up in the light  (JS: INK_HEAVEN)  */
  --dsc-ink-hell: #c9bdb2;     /* body text down in the dark (JS: INK_HELL)    */
  --dsc-head-heaven: #1c2f24;  /*                            (JS: HEAD_HEAVEN) */
  --dsc-head-hell: #f4ece0;    /*                            (JS: HEAD_HELL)   */

  /* Decorative accents, driven by --dsc-d. Never used for body text. */
  --dsc-link-heaven: color-mix(in srgb, var(--emp-news-accent) 80%, #000);
  --dsc-link-hell: color-mix(in srgb, var(--emp-hell-accent) 65%, #ffb347);
  --dsc-rule-heaven: #7aa15f;
  --dsc-rule-hell: var(--emp-hell-accent);

  position: relative;
  overflow: hidden;
  padding: 128px 24px 96px;

  /* No-JS / pre-hydration fallback: stay light and legible. */
  background: linear-gradient(180deg, #ffffff 0%, #f4efe3 45%, #e6edf0 100%);
}

/* The descent gradient is painted by js/empyrean-descent.js from STOPS. */

/* ---------- set dressing: light above, embers below ---------- */
/* Reuses the parent theme's rayspin / rayglow / emberRise keyframes.
   Sized in px, not vh. These layers sit BEHIND the prose but ON TOP of the
   gradient, so anywhere they reach they lighten the real background the text
   is read against — which the ink calculation does not model. Bound to px they
   stay inside the firmament, where the ink is dark regardless. Sized in vh they
   grow with the window and, on a tall display, wash white light across the dusk
   crossing and destroy the contrast guarantee. */
.dsc-sky {
  position: absolute; top: 0; left: 0; right: 0;
  height: min(90vh, 780px);
  pointer-events: none; z-index: 0; overflow: hidden;
  opacity: 0; transition: opacity .6s ease;
}
.emp-descent-ready .dsc-sky { opacity: 1; }

.dsc-rays {
  position: absolute; top: -120px; left: 50%; transform: translateX(-50%);
  width: 1400px; height: 1400px; overflow: hidden; opacity: .55;
  -webkit-mask-image: radial-gradient(closest-side, rgba(0,0,0,1) 10%, rgba(0,0,0,.7) 36%, rgba(0,0,0,0) 72%);
  mask-image: radial-gradient(closest-side, rgba(0,0,0,1) 10%, rgba(0,0,0,.7) 36%, rgba(0,0,0,0) 72%);
}
.dsc-ray1 {
  position: absolute; inset: 0; animation: rayspin 180s linear infinite;
  background: repeating-conic-gradient(from 0deg at 50% 50%, rgba(255,251,236,0) 0deg, rgba(255,250,230,.85) 1.6deg, rgba(255,251,236,0) 3.4deg, rgba(255,251,236,0) 16deg);
}
.dsc-ray2 {
  position: absolute; inset: 0; animation: rayspinRev 260s linear infinite; opacity: .6;
  background: repeating-conic-gradient(from 8deg at 50% 50%, rgba(255,248,224,0) 0deg, rgba(255,246,216,.65) 1deg, rgba(255,248,224,0) 2.6deg, rgba(255,248,224,0) 22deg);
}
.dsc-glow {
  position: absolute; top: -220px; left: 50%; transform: translateX(-50%);
  width: 620px; height: 620px; border-radius: 50%;
  animation: rayglow 7s ease-in-out infinite;
  background: radial-gradient(closest-side, rgba(255,252,242,1), rgba(255,248,228,.45) 42%, transparent 72%);
}

/* Also px-bound: embers only belong in the inferno. */
.dsc-embers {
  position: absolute; bottom: 0; left: 0; right: 0;
  height: min(60vh, 560px);
  pointer-events: none; z-index: 0; overflow: hidden;
  opacity: 0; transition: opacity .6s ease;
}
.emp-descent-ready .dsc-embers { opacity: 1; }
.dsc-hellglow {
  position: absolute; bottom: -180px; left: 50%; transform: translateX(-50%);
  width: 780px; height: 420px; border-radius: 50%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--emp-hell-accent) 34%, transparent), transparent 70%);
}

/* ---------- the column ---------- */
.dsc-wrap {
  position: relative; z-index: 2;
  max-width: 820px; margin: 0 auto;
}

/* ---------- header ---------- */
.dsc-header { text-align: center; margin-bottom: 44px; }
.dsc-kicker {
  font-size: 12px; letter-spacing: .42em; font-weight: 700;
  color: var(--emp-heaven-accent);
}
.dsc-title {
  margin: 16px 0 0; font-family: var(--emp-serif); font-weight: 300;
  font-size: clamp(38px, 6.5vw, 72px); line-height: 1.02; letter-spacing: -.015em;
  color: var(--emp-heaven-text);
}
.dsc-divider {
  width: 64px; height: 1px; margin: 26px auto;
  background: color-mix(in srgb, var(--emp-heaven-accent) 45%, #fff);
}
.dsc-meta {
  margin: 0; font-size: 11px; letter-spacing: .34em; font-weight: 600;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--emp-heaven-accent) 80%, #fff);
}
.dsc-featured { margin: 0 0 44px; }
.dsc-featured img { width: 100%; border-radius: 4px; }

/* ---------- prose: colour derived from depth ---------- */
.empyrean-descent .empyrean-prose {
  font-size: 16.5px; line-height: 1.8;
  color: var(--dsc-ink-heaven);
}

/* No transition on colour. Depth is derived from layout, not scroll, so it only
   ever changes on a (debounced) resize — and transitioning a colour driven by an
   unregistered custom property leaves the text pinned at the start value until
   the compositor advances it, which reads as unstyled text on first paint. */
.emp-descent-ready .empyrean-prose > * {
  color: var(--dsc-fg, var(--dsc-ink-heaven));
}

.emp-descent-ready .empyrean-prose > h1,
.emp-descent-ready .empyrean-prose > h2,
.emp-descent-ready .empyrean-prose > h3,
.emp-descent-ready .empyrean-prose > h4 {
  color: var(--dsc-fg-head, var(--dsc-head-heaven));
}
.empyrean-descent .empyrean-prose h1,
.empyrean-descent .empyrean-prose h2,
.empyrean-descent .empyrean-prose h3,
.empyrean-descent .empyrean-prose h4 {
  font-family: var(--emp-serif); font-weight: 400; line-height: 1.15;
  margin: 1.9em 0 .5em;
}
.empyrean-descent .empyrean-prose h2 { font-size: clamp(28px, 3.6vw, 38px); }
.empyrean-descent .empyrean-prose h3 { font-size: clamp(22px, 2.6vw, 27px); }

/* Links carry the realm accent in the underline rather than the text.
   An accent-coloured link is unreadable across the dusk crossing (an ember on
   mid-dusk measures ~1.2:1), so the text keeps the block's safe ink and the
   accent moves to the underline, which carries no contrast requirement. */
.emp-descent-ready .empyrean-prose a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--dsc-link-hell) calc(var(--dsc-d, 0) * 100%), var(--dsc-link-heaven));
}
.emp-descent-ready .empyrean-prose a:hover {
  text-decoration-thickness: 2px;
}

.empyrean-descent .empyrean-prose blockquote {
  margin: 32px 0; padding: 4px 0 4px 22px;
  border-left: 3px solid var(--dsc-rule-heaven);
  font-family: var(--emp-serif); font-style: italic;
  font-size: clamp(19px, 2.2vw, 23px); line-height: 1.55;
}
.emp-descent-ready .empyrean-prose > blockquote {
  border-left-color: color-mix(in srgb, var(--dsc-rule-hell) calc(var(--dsc-d, 0) * 100%), var(--dsc-rule-heaven));
}

.empyrean-descent .empyrean-prose img { border-radius: 4px; }
.empyrean-descent .empyrean-prose hr {
  border: 0; height: 1px; margin: 48px 0;
}
.emp-descent-ready .empyrean-prose > hr {
  background: color-mix(in srgb,
    color-mix(in srgb, var(--emp-hell-accent) calc(var(--dsc-d, 0) * 100%), var(--emp-heaven-accent))
    40%, transparent);
}

/* ---------- entry footer: always deep in the inferno ---------- */
.dsc-entry-footer {
  margin-top: 64px; padding-top: 28px;
  border-top: 1px solid var(--emp-hell-border);
  display: flex; flex-wrap: wrap; gap: 16px;
  align-items: center; justify-content: space-between;
}
.dsc-entry-footer .empyrean-entry-tags {
  font-size: 12px; letter-spacing: .1em; color: #8a7f76;
}
.dsc-entry-footer a { color: var(--emp-hell-accent); }
.dsc-backlink {
  font-size: 12px; letter-spacing: .24em; font-weight: 700;
  text-transform: uppercase; color: var(--emp-hell-accent);
}
.dsc-backlink:hover { color: #ffb347; }

/* ---------- comments: bottom of the descent, so styled for the dark ---------- */
.dsc-comments { margin-top: 72px; }
.dsc-comments,
.dsc-comments p,
.dsc-comments li,
.dsc-comments label { color: #b8aca0; }
.dsc-comments h2, .dsc-comments h3 {
  font-family: var(--emp-serif); font-weight: 400; color: #f4ece0;
}
.dsc-comments a { color: var(--emp-hell-accent); }
.dsc-comments a:hover { color: #ffb347; }
.dsc-comments .comment-list { list-style: none; margin: 0; padding: 0; }
.dsc-comments .comment-list li { padding: 18px 0; border-top: 1px solid rgba(244,236,224,.08); }
.dsc-comments input[type="text"],
.dsc-comments input[type="email"],
.dsc-comments input[type="url"],
.dsc-comments textarea {
  width: 100%; padding: 12px 14px;
  background: rgba(244,236,224,.05);
  border: 1px solid var(--emp-hell-border);
  border-radius: 3px; color: #f4ece0;
}
.dsc-comments input::placeholder,
.dsc-comments textarea::placeholder { color: #6b6058; }
.dsc-comments .submit {
  padding: 13px 26px; border: 0; border-radius: 3px; cursor: pointer;
  background: var(--emp-hell-accent); color: #fff;
  font-size: 12px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
}
.dsc-comments .submit:hover { background: #ffb347; color: #2a0d09; }

/* ==========================================================================
   The Turn — the pivot in a dual-nature article
   --------------------------------------------------------------------------
   Rendered by [the_turn from="…" to="…"] (inc/empyrean-descent-turn.php).
   A separating rule broken by a taijitu: two opposites, each carrying a seed
   of the other, which is the shape these articles argue for.

   empyrean-descent.js remaps the gradient so the light→dark crossing lands on
   this rule, and writes --turn-t (0→1) as the rule rises up the viewport.
   Every colour below is mixed from that one number, so scrolling back up runs
   the whole thing backwards. Nothing here fires once.

   COLOUR: nothing here invents a value. The script samples the descent and
   hands down three colours straight out of STOPS —

     --turn-sky    the firmament, bgAt(0.05)
     --turn-pit    the inferno,   bgAt(0.97)
     --turn-here   the exact dusk the rule sits on, bgAt(CROSS_P)

   — and both halves are lifted or deepened out of --turn-here rather than set
   to fixed hexes. That is what keeps the disc reading as the page thinning
   into a symbol instead of a sticker laid over it, and it means editing STOPS
   re-keys the rule automatically. The fallbacks below only stand in for the
   frame before the script measures.
   ========================================================================== */
.dsc-turn {
  --turn-t: 0;
  --turn-sky: #fdfaf3;
  --turn-pit: #0a0a0c;
  --turn-here: #7d8c82;

  /* Ink walks from the firmament's gold to the inferno's ember, then settles
     back toward the local ground so the hairline never outshines its page. */
  --turn-ink: color-mix(in srgb,
    color-mix(in srgb, var(--emp-hell-accent) calc(var(--turn-t) * 100%), var(--emp-heaven-accent))
    calc(70% + var(--turn-t) * 28%), var(--turn-here));

  /* The light half sets toward the ground as the reader descends; the dark
     half catches fire out of it. */
  --turn-light: color-mix(in srgb, var(--turn-sky) calc(92% - var(--turn-t) * 44%), var(--turn-here));
  --turn-dark: color-mix(in srgb,
    color-mix(in srgb, var(--emp-hell-accent) calc(var(--turn-t) * 88%), var(--turn-pit))
    calc(64% + var(--turn-t) * 36%), var(--turn-here));

  margin: 76px 0;
}

/* A soft dusk breath behind the rule, so the crossing reads as the page
   opening rather than a line cutting it. Its colour is the background it sits
   on, so it only ever softens — it cannot tint. */
.dsc-turn-line {
  position: relative;
  display: flex;
  align-items: center;
  gap: clamp(12px, 3vw, 24px);
}
.dsc-turn-line::before {
  content: "";
  position: absolute;
  left: -8%; right: -8%; top: 50%;
  height: 150px;
  transform: translateY(-50%);
  pointer-events: none;
  background: radial-gradient(60% 50% at 50% 50%,
    color-mix(in srgb, var(--turn-here) 55%, transparent), transparent 72%);
  opacity: calc(.35 + var(--turn-t) * .3);
}

/* Hairlines, dissolving into the column edges rather than stopping. */
.dsc-turn-rule {
  position: relative;
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--turn-ink) 88%);
  opacity: calc(.5 + var(--turn-t) * .5);
  /* The seam catches: a heat haze along the hairline that comes up with the
     ember and goes back down on the way up. */
  box-shadow: 0 0 calc(var(--turn-t) * 9px)
    color-mix(in srgb, var(--emp-hell-accent) calc(var(--turn-t) * 62%), transparent);
}
.dsc-turn-line .dsc-turn-rule:last-child {
  background: linear-gradient(90deg, var(--turn-ink) 12%, transparent);
}

/* Embers off the rule. Ambient and always running, but only visible in
   proportion to --turn-t — so they kindle as the reader crosses and settle
   back to nothing on the way up. Nothing here fires once. */
.dsc-turn-embers {
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 0;
  pointer-events: none;
  opacity: var(--turn-t);
}
.dsc-turn-embers span {
  position: absolute;
  bottom: 0;
  border-radius: 50%;
  opacity: 0;
  animation-name: turnEmber;
  animation-timing-function: ease-in;
  animation-iteration-count: infinite;
}
@keyframes turnEmber {
  0%   { transform: translateY(0) scale(1); opacity: 0; }
  18%  { opacity: .85; }
  100% { transform: translateY(-72px) scale(.28); opacity: 0; }
}

/* The two topics, set as quiet marks on the rule rather than a card. */
.dsc-turn-mark {
  position: relative;
  font-size: 10px;
  letter-spacing: .3em;
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--turn-ink);
}
.dsc-turn-mark--from { opacity: calc(1 - var(--turn-t) * .5); }
.dsc-turn-mark--to { opacity: calc(.5 + var(--turn-t) * .5); }

/* ---------- the taijitu ---------- */
.dsc-turn-sigil {
  position: relative;
  flex: none;
  display: block;
  line-height: 0;
  /* Half a turn across the descent: the dark head rises as the light sets.
     Driven by --turn-t, so it unwinds on the way back up. */
  transform: rotate(calc(var(--turn-t) * 180deg));
  filter: drop-shadow(0 0 calc(var(--turn-t) * 12px)
          color-mix(in srgb, var(--emp-hell-accent) calc(var(--turn-t) * 55%), transparent));
}
.dsc-turn-sigil svg { display: block; overflow: visible; }

.yy-light { fill: var(--turn-light); }
.yy-dark { fill: var(--turn-dark); }
/* Each half carries the other's seed, so the dots take the opposite fill. */
.yy-dot-light { fill: var(--turn-light); }
.yy-dot-dark { fill: var(--turn-dark); }
/* The rim is barely there — it only needs to close the disc, not outline it. */
.yy-ring { stroke: var(--turn-ink); opacity: .28; }

.dsc-turn-note {
  position: relative;
  margin: 20px 0 0;
  text-align: center;
  font-family: var(--emp-serif);
  font-style: italic;
  font-size: 16px;
  color: var(--dsc-fg, #5a5346);
}

/* No JS: --turn-t never moves off 0 and the fallbacks above stand, which is a
   valid light-side rule. The descent stays light throughout in that case, so
   the two agree. */

/* ---------- responsive ---------- */
@media (max-width: 782px) {
  .empyrean-descent { padding: 104px 18px 72px; }
  .dsc-header { margin-bottom: 32px; }
  .dsc-turn { margin: 56px 0; }
  /* The rule needs its full width more than the labels do. */
  .dsc-turn-mark { font-size: 9px; letter-spacing: .2em; }
}
@media (max-width: 480px) {
  .dsc-turn-mark { display: none; }
}

/* ---------- reduced motion ---------- */
/* Mirrors the parent theme's rule at style.css: the descent itself is a
   static gradient, so only the animated set dressing is suppressed. */
@media (prefers-reduced-motion: reduce) {
  .dsc-ray1, .dsc-ray2, .dsc-glow { animation: none !important; }
  .dsc-embers span { animation: none !important; }
  .dsc-embers { display: none; }
  /* The turn's colour still tracks the reader — that is the point of it, and a
     colour shift is not motion. The rotation and the embers are held still. */
  .dsc-turn-sigil { transform: none !important; }
  .dsc-turn-embers { display: none; }
}
