/* ============================================================
   Hurtorius.com — visual-effects toolkit
   Reusable, opt-in effects that extend the candlelit aesthetic.
   Synthesized from a judged design panel; every effect is
   transform/opacity-only, accessible, and degrades gracefully.

   PROGRESSIVE ENHANCEMENT CONTRACT:
   effects.js sets <html class="js"> as its first action. Every rule
   that HIDES content for an entrance is scoped to `.js`, so if the
   script is blocked or fails, nothing is hidden — the page renders
   fully with the normal prose glow.

   LOAD ORDER:  styles.css → effects.css → (markup) → effects.js (defer)
   ============================================================ */

/* ------------------------------------------------------------
   1. SCROLL REVEAL  ·  .reveal  (+ wrap siblings in .reveal--stagger)
   Content fades + rises once as it enters the viewport.
   ------------------------------------------------------------ */
.js .reveal {
  opacity: 0;
  transform: translateY(1.2rem);
  transition:
    opacity 0.9s ease,
    transform 0.9s cubic-bezier(0.2, 0.6, 0.3, 1);
  will-change: opacity, transform;
}
.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}
/* staggered cascade: JS sets --i (child index) on .reveal--stagger > * */
.js .reveal--stagger > * { transition-delay: calc(var(--i, 0) * 90ms); }

/* ------------------------------------------------------------
   2. READING PROGRESS  ·  <div class="read-progress">  (first in body)
   A thin glowing line that fills with scroll depth. JS sets scaleX.
   ------------------------------------------------------------ */
.read-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, rgba(255, 236, 196, 0.85), rgba(255, 247, 230, 0.95));
  box-shadow: 0 0 8px rgba(255, 236, 196, 0.6), 0 0 18px rgba(255, 236, 196, 0.35);
  z-index: 10;
  pointer-events: none;
  will-change: transform;
}

/* ------------------------------------------------------------
   3. CANDLELIGHT CURSOR  ·  <div class="candle-glow">  (once in body)
   A soft warm pool that follows the reader, as if they carry a candle.
   JS translates it (transform-only) and toggles .is-lit. Auto-disabled
   on touch + reduced-motion (JS never attaches).
   ------------------------------------------------------------ */
.candle-glow {
  position: fixed;
  top: 0;
  left: 0;
  width: 44rem;
  height: 44rem;
  margin: -22rem 0 0 -22rem;        /* centre the gradient on the origin */
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: opacity 0.6s ease;
  mix-blend-mode: screen;
  background: radial-gradient(closest-side,
    rgba(255, 236, 196, 0.10),
    rgba(255, 236, 196, 0.04) 42%,
    transparent 70%);
  will-change: transform, opacity;
}
.candle-glow.is-lit { opacity: 1; }

/* ------------------------------------------------------------
   4. DROP CAP  ·  .dropcap  (on the opening paragraph)
   The brightest object on the page — literally the candle flame.
   ::first-letter only, so the serif stays crisp.
   ------------------------------------------------------------ */
.dropcap::first-letter {
  float: left;
  font-size: 3.4em;
  line-height: 0.82;
  padding: 0.02em 0.09em 0 0;
  font-weight: 700;
  color: var(--ink);
  text-shadow:
    0 0 0.02em rgba(255, 251, 244, 0.5),
    0 0 0.4em  rgba(255, 243, 214, 0.30),
    0 0 1.2em  rgba(255, 236, 196, 0.14);
}

/* ------------------------------------------------------------
   5. PULL-QUOTE  ·  <blockquote class="pullquote"> (optional <cite>)
   A line worth enlarging — brighter, centred, pulls the eye like a flame.
   ------------------------------------------------------------ */
.pullquote {
  font-size: clamp(1.4rem, 3.5vw + 0.5rem, 1.85rem);
  line-height: 1.32;
  font-style: italic;
  text-align: center;
  color: var(--ink);
  margin: 2.6em auto;
  max-width: 30rem;
  border: 0;
  padding: 0;
  text-shadow: var(--text-glow-strong);
}
.pullquote cite {
  display: block;
  margin-top: 0.7em;
  font-size: 0.95rem;
  font-style: normal;
  letter-spacing: 0.04em;
  color: var(--ink-dim);
}

/* ------------------------------------------------------------
   6. ASTERISM DIVIDER  ·  <hr class="asterism">
   ------------------------------------------------------------ */
.asterism {
  border: 0;
  height: auto;
  text-align: center;
  margin: 2.8em 0;
  line-height: 1;
}
.asterism::before {
  content: "\2042";                 /* the asterism glyph */
  font-size: 1.4rem;
  letter-spacing: 0.4em;
  color: var(--ink-dim);
  text-shadow: 0 0 0.6em rgba(255, 236, 196, 0.4);
}

/* ------------------------------------------------------------
   7. LUMINOUS HEADING  ·  .heading-lum  (on an h2/h3)
   Crisp glowing text + a warm->cool glowing underline accent.
   (Glow stays on the text; the gradient lives on the rule, never the
   glyph — background-clip:text would kill the candle glow.)
   ------------------------------------------------------------ */
.heading-lum { position: relative; display: inline-block; }
.heading-lum::after {
  content: "";
  display: block;
  height: 1px;
  margin-top: 0.28em;
  background: linear-gradient(90deg,
    rgba(255, 236, 196, 0.75), rgba(200, 210, 255, 0.28), transparent);
  box-shadow: 0 0 8px rgba(255, 236, 196, 0.4);
}

/* ------------------------------------------------------------
   8. TURING'S VOICE  ·  .mono (inline) / .aside-tech (block)
   A deliberately cool, exact monospace register against the warm prose.
   text-shadow:none — the one place the page goes cold on purpose.
   ------------------------------------------------------------ */
.mono {
  font-family: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas,
    "Liberation Mono", monospace;
  font-size: 0.92em;
  letter-spacing: 0;
  color: #dfe6f2;
  text-shadow: none;
}
.aside-tech {
  font-family: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas,
    "Liberation Mono", monospace;
  font-size: 0.92rem;
  line-height: 1.55;
  color: #dbe2ee;
  text-shadow: none;
  background: rgba(200, 210, 235, 0.02);
  border: 1px solid rgba(200, 210, 235, 0.12);
  border-radius: 6px;
  padding: 1rem 1.15rem;
  margin: 1.8em 0;
}
.aside-tech .tag {
  display: block;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(200, 210, 235, 0.5);
  margin-bottom: 0.5em;
}

/* ------------------------------------------------------------
   9. REFRACTION FOOTNOTE  ·  <a class="fn-ref" id="refN" href="#fnN">N</a>
   Newton's prism made literal: the reference is one wavelength bent out
   of the reading line. A real, focusable anchor — cleverness costs no a11y.
   Pair with:
     <li class="footnote" id="fnN">... <a class="fn-back" href="#refN">&#8617;</a></li>
   ------------------------------------------------------------ */
.fn-ref {
  position: relative;
  font-size: 0.62em;
  vertical-align: super;
  line-height: 0;
  margin-left: 0.12em;
  padding: 0 0.1em;
  text-decoration: none;
  color: var(--ink);
  text-shadow: var(--text-glow);
}
.fn-ref::after {                    /* the refracted spectral glint */
  content: "";
  position: absolute;
  left: 50%;
  top: -0.15em;
  width: 0.9em;
  height: 0.18em;
  transform: translateX(-50%) scaleX(0);
  transform-origin: 50% 50%;
  border-radius: 1px;
  background: linear-gradient(90deg,
    rgba(255, 120, 120, 0.0), rgba(255, 210, 140, 0.9),
    rgba(180, 220, 255, 0.9), rgba(160, 160, 255, 0.0));
  opacity: 0;
  transition: transform 0.3s ease, opacity 0.3s ease;
  pointer-events: none;
}
.fn-ref:hover::after,
.fn-ref:focus-visible::after { transform: translateX(-50%) scaleX(1); opacity: 0.9; }
.fn-ref:focus-visible { outline: 2px solid rgba(247, 233, 205, 0.7); outline-offset: 2px; border-radius: 2px; }
.fn-back { margin-left: 0.4em; text-decoration: none; color: var(--ink-dim); }

/* a brief candle-flare when a footnote is jumped to */
.footnote:target { animation: fn-flare 1.8s ease; border-radius: 4px; }
@keyframes fn-flare {
  0%   { background: rgba(255, 236, 196, 0.12); box-shadow: 0 0 18px rgba(255, 236, 196, 0.18); }
  100% { background: transparent; box-shadow: 0 0 0 transparent; }
}

/* ------------------------------------------------------------
   10. GRID FADE  ·  <div class="gridfade"> inside a position:relative box
   Hairline graph-paper (Newton's rule lines / Turing's grid), radial-masked
   so it pools rather than tiling to hard edges. Decorative.
   ------------------------------------------------------------ */
.gridfade {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(200, 210, 235, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(200, 210, 235, 0.05) 1px, transparent 1px);
  background-size: 2.2rem 2.2rem;
  -webkit-mask-image: radial-gradient(72% 60% at 50% 45%, #000 28%, transparent 100%);
          mask-image: radial-gradient(72% 60% at 50% 45%, #000 28%, transparent 100%);
}

/* ------------------------------------------------------------
   11. CONSTELLATION FIELD  ·  <canvas class="constellation"> in .constellation-wrap
   NOVEL: sparse warm stars drift; near neighbours link into a graph
   (Turing: computation as connection); stars lean toward the cursor
   (Newton: attention has mass). Decorative, paused off-screen, absent
   under reduced-motion / no-JS. JS-driven (see effects.js).
   ------------------------------------------------------------ */
.constellation-wrap { position: relative; }
canvas.constellation {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.2s ease;
}
canvas.constellation.is-lit { opacity: 1; }

/* ------------------------------------------------------------
   12. ORRERY DIVIDER  ·  the section break as celestial mechanics
   NOVEL: faint points orbit a glowing candle-sun. Pure CSS, transform-only.
   Correct composition: each .orrery__orbit is a centred ring that rotates;
   its planet rides the ring. (No base-transform clobbering.)
   <div class="orrery" role="separator" aria-hidden="true">
     <span class="orrery__sun"></span>
     <span class="orrery__orbit orrery__orbit--1"><i class="orrery__planet"></i></span>
     <span class="orrery__orbit orrery__orbit--2"><i class="orrery__planet"></i></span>
     <span class="orrery__orbit orrery__orbit--3"><i class="orrery__planet"></i></span>
   </div>
   ------------------------------------------------------------ */
.orrery {
  position: relative;
  width: 7rem;
  height: 7rem;
  margin: 3.2em auto;
}
.orrery__sun, .orrery__orbit, .orrery__planet { position: absolute; }
.orrery__sun {
  top: 50%; left: 50%;
  width: 0.5rem; height: 0.5rem;
  margin: -0.25rem 0 0 -0.25rem;
  border-radius: 50%;
  background: rgba(255, 238, 200, 0.95);
  box-shadow: 0 0 8px rgba(255, 236, 196, 0.8), 0 0 18px rgba(255, 236, 196, 0.4);
}
.orrery__orbit {
  top: 50%; left: 50%;
  border: 1px solid rgba(255, 236, 196, 0.14);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  animation: orbit 18s linear infinite;
}
.orrery__orbit--1 { width: 2.6rem; height: 2.6rem; animation-duration: 9s; }
.orrery__orbit--2 { width: 4.6rem; height: 4.6rem; animation-duration: 15s; }
.orrery__orbit--3 { width: 6.8rem; height: 6.8rem; animation-duration: 24s; }
.orrery__planet {
  top: -0.16rem; left: 50%;
  width: 0.32rem; height: 0.32rem;
  margin-left: -0.16rem;
  border-radius: 50%;
  background: rgba(247, 233, 205, 0.92);
  box-shadow: 0 0 6px rgba(255, 236, 196, 0.6);
}
@keyframes orbit { to { transform: translate(-50%, -50%) rotate(360deg); } }

/* ============================================================
   REDUCED MOTION — every effect collapses to the finished static page.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .read-progress, .candle-glow { display: none; }
  canvas.constellation { display: none; }
  .orrery__orbit { animation: none; }
  .footnote:target { animation: none; }
  .fn-ref::after { transition: none; }
}

/* ============================================================
   FORCED COLORS (Windows high-contrast) — keep meaning without the glow.
   ============================================================ */
@media (forced-colors: active) {
  .read-progress { background: Highlight; box-shadow: none; }
  .candle-glow, canvas.constellation, .gridfade { display: none; }
  .article a { text-decoration: underline; }
  .orrery__sun, .orrery__planet { background: CanvasText; box-shadow: none; }
  .aside-tech { border-color: CanvasText; }
}
