/* chapters.css: full-screen chapters, snap scrolling, focus fades and smooth reveals.
   Spec: docs/chapters.md. Owner: orchestrator. Loaded on every page after chrome.css.

   Without JS: native scroll snap moves one chapter per scroll, and every chapter is fully visible.
   With JS (chapters.js adds .chapters-live): the chapter at the centre line is .is-current;
   the others fade back so attention lands on the new heading. */

/* ---------- Snap ---------- */
html:has([data-chapter]) {
  scroll-snap-type: y mandatory;
}
[data-chapter] {
  box-sizing: border-box;
  min-height: 100vh;
  min-height: 100svh;
  /* The fixed header overlays the top of every chapter. */
  padding-block: calc(var(--header-h, 64px) + var(--space-6)) var(--space-7);
  display: flex;
  flex-direction: column;
  justify-content: center;
  scroll-snap-align: start;
  scroll-snap-stop: always; /* one gesture never skips a chapter */
}
/* Short laptop screens (e.g. 1080p at 125% scaling): less padding, so a chapter's last line stays on screen. */
@media (min-width: 1024px) and (max-height: 780px) {
  [data-chapter] {
    padding-block: calc(var(--header-h, 64px) + var(--space-4)) var(--space-5);
  }
}
/* A second snap point at each chapter's end (chapters.js adds the marker), so PageDown and Space
   stop at the end of a tall chapter instead of skipping its tail. On a chapter exactly one screen
   tall it coincides with the start, so it adds no extra stop. */
[data-chapter] {
  position: relative;
}
.chapter-end {
  position: absolute;
  inset: auto 0 0 auto;
  width: 1px;
  height: 1px;
  pointer-events: none;
  scroll-snap-align: end;
}
/* Focus moved by keyboard (including Shift+Tab back up) always lands clear of the fixed header. */
[data-chapter] :is(a[href], button, summary, input, select, textarea, [tabindex]) {
  scroll-margin-block: calc(var(--header-h, 64px) + var(--space-4)) var(--space-4);
}
/* A chapter taller than the screen scrolls freely inside its snap area (CSS Scroll Snap spec),
   so the visitor reads to its end before the next scroll pulls the next chapter in.
   Its content starts at the top rather than centring. */
[data-chapter][data-chapter-tall] {
  justify-content: flex-start;
}
/* The footer sits after the last chapter. It must be a snap target or mandatory snap can't reach it. */
body > footer {
  scroll-snap-align: end;
}

/* ---------- Focus fades (JS only) ---------- */
.chapters-live [data-chapter] > * {
  transition:
    opacity var(--dur-chapter, 520ms) var(--ease-chapter, cubic-bezier(.22, .61, .36, 1)),
    transform var(--dur-chapter, 520ms) var(--ease-chapter, cubic-bezier(.22, .61, .36, 1));
  transition-delay: 0ms;
}
/* Arriving: the heading lands first, then the rest follows. */
.chapters-live [data-chapter].is-current > :nth-child(2) { transition-delay: 70ms; }
.chapters-live [data-chapter].is-current > :nth-child(3) { transition-delay: 140ms; }
.chapters-live [data-chapter].is-current > :nth-child(n + 4) { transition-delay: 200ms; }

.chapters-live [data-chapter]:not(.is-current) > *:not(.chapter-end, .deco-shapes) {
  opacity: .14;
  transform: translateY(28px);
}
/* Chapters already passed drift up and away instead of down. */
.chapters-live [data-chapter].is-past:not(.is-current) > *:not(.chapter-end, .deco-shapes) {
  transform: translateY(-28px);
}
/* A chapter reached by keyboard focus appears at once: the focused control is never shown faded. */
.chapters-live [data-chapter].is-current:focus-within > * {
  transition-duration: 0ms;
  transition-delay: 0ms;
}
/* No transition on the very first paint: the opening chapter is simply there. */
.chapters-live:not(.chapters-ready) [data-chapter] > * {
  transition: none;
}

/* ---------- Smooth reveal for <details data-smooth> ----------
   Native path: ::details-content plus interpolate-size (Chromium 131+).
   Other browsers: chapters.js animates .details-body with the Web Animations API. */
:root {
  interpolate-size: allow-keywords;
}
details[data-smooth]::details-content {
  block-size: 0;
  overflow: hidden;
  opacity: 0;
  transition:
    block-size 380ms cubic-bezier(.22, .61, .36, 1),
    opacity 300ms ease,
    content-visibility 380ms allow-discrete;
}
details[data-smooth][open]::details-content {
  block-size: auto;
  opacity: 1;
}

/* ---------- Decorative shapes (.deco-shapes, desktop only) ----------
   Flat circles and shapes in a chapter's empty right side (the Projects intro on Home, and the "Next project"
   door on project pages). They rise into view from the bottom of the screen when the chapter becomes current
   and lift away upward once it is passed. Colours follow the chapter's palette. Without JS they simply sit in
   place; with reduced motion they don't move. */
.deco-shapes { display: none; }
@media (min-width: 1100px) {
  .deco-shapes {
    display: block; position: absolute; inset: 0 0 0 max(52%, 800px); overflow: hidden;
    pointer-events: none; z-index: 0;
  }
  [data-chapter]:has(> .deco-shapes) > :not(.deco-shapes, .chapter-end) { position: relative; z-index: 1; }
}
.deco-shape {
  --k: 1; --d: 0ms; --r: 0deg; --off: 0px;
  position: absolute; display: block;
  translate: 0 calc(var(--k) * var(--off));
  transition:
    translate 1100ms cubic-bezier(.16, 1, .3, 1) var(--d),
    opacity 700ms ease var(--d);
  animation: deco-drift 9s ease-in-out infinite alternate;
}
.deco-shape--disc   { --k: 1.15; --d: 0ms;   width: 34vmin; aspect-ratio: 1; border-radius: 50%; background: var(--accent); right: 9%; top: 17%; }
.deco-shape--ring   { --k: 0.85; --d: 140ms; width: 22vmin; aspect-ratio: 1; border-radius: 50%; border: 3px solid var(--ink); left: 6%; top: 50%; }
.deco-shape--dot    { --k: 1.35; --d: 260ms; width: 5vmin;  aspect-ratio: 1; border-radius: 50%; background: var(--ink); left: 30%; top: 22%; }
.deco-shape--half   { --k: 0.7;  --d: 80ms;  width: 20vmin; aspect-ratio: 2; border-radius: 20vmin 20vmin 0 0; background: var(--surface-2); right: 26%; bottom: 7%; }
.deco-shape--square { --k: 1.25; --d: 320ms; --r: 14deg; width: 9vmin; aspect-ratio: 1; border: 3px solid var(--accent); left: 14%; top: 14%; }
.deco-shape--pill   { --k: 0.95; --d: 200ms; --r: -18deg; width: 24vmin; height: 7vmin; border-radius: 7vmin; background: color-mix(in srgb, var(--accent) 35%, var(--bg)); right: 4%; bottom: 22%; }
@keyframes deco-drift {
  from { transform: translateY(0) rotate(var(--r)); }
  to   { transform: translateY(-14px) rotate(calc(var(--r) + 8deg)); }
}
/* Waiting below the screen before the chapter arrives… */
.chapters-live [data-chapter]:not(.is-current) .deco-shape { --off: 80vh; opacity: 0; }
/* …and lifting up and away once it has been passed, faster than they arrived. */
.chapters-live [data-chapter].is-past:not(.is-current) .deco-shape {
  --off: -80vh;
  transition-duration: 750ms, 500ms;
  transition-delay: calc(var(--d) / 3);
}
.chapters-live:not(.chapters-ready) .deco-shape { transition: none; }

/* ---------- Reduced motion ----------
   Snapping stays because it is navigation, not decoration. Fades and reveals become instant,
   and every chapter stays fully visible. */
@media (prefers-reduced-motion: reduce) {
  html:has([data-chapter]) {
    scroll-snap-type: y proximity;
  }
  /* Selectors match the fade rules' specificity so this override wins. */
  .chapters-live [data-chapter] > *,
  .chapters-live [data-chapter]:not(.is-current) > *:not(.chapter-end, .deco-shapes),
  .chapters-live [data-chapter].is-past:not(.is-current) > *:not(.chapter-end, .deco-shapes) {
    transition: none;
    opacity: 1;
    transform: none;
  }
  details[data-smooth]::details-content {
    transition: none;
  }
  .deco-shape,
  .chapters-live [data-chapter]:not(.is-current) .deco-shape,
  .chapters-live [data-chapter].is-past:not(.is-current) .deco-shape { transition: none; animation: none; --off: 0px; opacity: 1; }
}

/* Printing: no snap, no fades. */
@media print {
  html:has([data-chapter]) { scroll-snap-type: none; }
  [data-chapter] { min-height: 0; padding-block: var(--space-6); }
  .chapters-live [data-chapter] > * { opacity: 1 !important; transform: none !important; }
}
