/* The sticky canvas (direction D3, rebuilt at 8a): a copy rail of steps on the left, one product window on the right.
   The window is ONE object: a layered composition of the app's own parts that scroll re-forms, never four pictures swapped.
   Builds on tokens.css and components.css (.sx-canvas). Behaviour: sticky-canvas.js. The parts' places and moves: home-d3.css.

   Layouts, decided before first paint (html.sx-js is set by sx-js.js, a synchronous one-line script in <head>):
   - below 1200 px, any: stacked. Each step, then its own still (phone file below 900, desktop file from 900).
   - from 1200 px, scripts off: rows. Each step's copy in columns 1-4, its own still in columns 5-12. No window.
   - from 1200 px, scripts on: the rail in columns 1-4, the window in columns 5-12, sticky, with a "1 2 3 4" row under it.
     The inline stills stay in the accessibility tree (they carry the alts) but are visually hidden; the window is aria-hidden.
   - the same, with reduced motion: the window shows the four poses as stills (.sx-stage-item), swapped instantly.

   One value: sticky-canvas.js sets --p in [0, 3] on .sx-window (and --p1, --p2, --p3, each segment's progress in [0, 1]).
   Every move in the window is a calc() of those (home-d3.css): transforms and opacity only. Nothing here snaps.

   Geometry (scripts on, from 1200): each step is a block --step-h tall (clamp(640px, 80vh, 760px): 720 at a 900 px viewport),
   so one step is --step-h of scroll. Its copy box (--copy-h, not the window's height) is sticky with its centre on the
   window's centre (the focal line); a step's pose is exact when its block's centre crosses the focal line. The rail's
   top and bottom padding make the first copy and the window pin together, and the last copy and the window release together.
   1200 is where the 8-column window first reaches the reading-size floor with the stage files; see system.md, "Imagery". */

/* The base rules (every width: the stacked steps, and .sx-window hidden) are in components.css, "The sticky canvas, base",
   so this file is linked with media="(min-width: 1200px)" and phones don't wait for it (8b: Lighthouse mobile on / held at 93). */

/* Rows: scripts off, wide screens */
@media (min-width: 1200px) {
  .sx-step { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--sx-gutter); align-items: center; }
  .sx-step-copy { grid-column: 1 / span 4; padding-right: var(--sx-s5); }
  .sx-step-fig { grid-column: 5 / -1; margin-top: 0; }
}

/* The window: scripts on, wide screens */
@media (min-width: 1200px) {
  html.sx-js .sx-sticky {
    --stage-w: calc((min(100vw - 2 * var(--sx-pad), var(--sx-content)) - 11 * var(--sx-gutter)) / 12 * 8 + 7 * var(--sx-gutter));
    --stage-h: calc(var(--stage-w) * 962 / 1552);
    --stage-top: max(calc(var(--sx-nav-h) + 24px), calc(50vh + var(--sx-nav-h) / 2 - var(--stage-h) / 2));
    --focal: calc(var(--stage-top) + var(--stage-h) / 2);
    --step-h: clamp(640px, 80vh, 760px);
    --copy-h: 260px;
    --copy-inset: calc(var(--stage-h) * 0.15); /* the step's heading sits level with the first line of the page in the window, under its toolbar */
    --prog-h: 44px;
    display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--sx-gutter); align-items: start;
  }
  html.sx-js .sx-steps {
    grid-column: 1 / span 4; grid-row: 1; gap: 0;
    /* the rail hangs from the window's top edge (Randall, 2026-10-31: "unbalanced"): the first copy and the window pin together,
       the last copy and the window release together */
    padding-top: 0;
    padding-bottom: max(0px, calc(var(--stage-h) + var(--prog-h) - var(--copy-h)));
  }
  /* an anchor (#how-3) lands with that step's block centred on the focal line: its pose exactly */
  html.sx-js .sx-step { display: block; height: var(--step-h); scroll-margin-top: calc(var(--focal) - var(--step-h) / 2 - var(--sx-nav-h) - 16px); }
  html.sx-js .sx-step-copy {
    position: sticky; top: var(--stage-top); min-height: var(--copy-h); box-sizing: border-box;
    display: flex; flex-direction: column; justify-content: flex-start; padding: var(--copy-inset) 0 0;
  }
  /* release 7, the ornament inventory P02 (Randall): no inset accent line beside the step text; the number and heading carry it */
  html.sx-js .sx-step .sx-step-title, html.sx-js .sx-step .sx-num, html.sx-js .sx-step .sx-step-copy p { transition: color var(--sx-dur-2) var(--sx-ease); }
  html.sx-js .sx-step:not(.is-active) .sx-step-title, html.sx-js .sx-step:not(.is-active) .sx-num,
  html.sx-js .sx-step:not(.is-active) .sx-step-copy p { color: var(--sx-muted); } /* 4.8:1 on the release 6 ground, never faded below AA */
  /* a step's number, heading and line arrive when its segment begins (sticky-canvas.js toggles .is-in): a 6 px rise */
  html.sx-js .sx-sticky.is-driven .sx-step:not(.is-in) .sx-step-text { opacity: 0; transform: translateY(6px); }
  html.sx-js .sx-sticky.is-driven .sx-step-text { transition: opacity var(--sx-dur-3) var(--sx-ease), transform var(--sx-dur-3) var(--sx-ease), box-shadow var(--sx-dur-2) var(--sx-ease); }
  /* the inline stills: visually hidden, still announced (they carry the alts) */
  html.sx-js .sx-step-fig { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; box-shadow: none; }

  html.sx-js .sx-window { display: block; grid-column: 5 / -1; grid-row: 1; align-self: start; position: sticky; top: var(--stage-top); }
  html.sx-js .sx-stage {
    position: relative; aspect-ratio: 1552 / 962; border-radius: var(--sx-radius); overflow: hidden; isolation: isolate;
    background: var(--sx-ground-2); box-shadow: var(--sx-surface);
  }
  .sx-progress { list-style: none; margin: 0; padding: 0; height: var(--prog-h); display: flex; align-items: center; justify-content: center; gap: var(--sx-s5);
    font: 500 13px/1 var(--sx-ui); font-variant-numeric: tabular-nums; color: var(--sx-muted); }
  .sx-progress li { position: relative; padding: 6px 2px; transition: color var(--sx-dur-2) var(--sx-ease); }
  .sx-progress li::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; border-radius: 1px; background: currentColor; opacity: 0; transition: opacity var(--sx-dur-2) var(--sx-ease); }
  .sx-progress li.is-active { color: var(--sx-accent); }
  .sx-progress li.is-active::after { opacity: 1; }
}

/* The composition: every part an absolutely placed <img> in frame space (home-d3.css gives each its box and moves) */
.sx-window { --p: 0; --p1: 0; --p2: 0; --p3: 0; }
.sx-comp, .sx-clip { position: absolute; inset: 0; }
.sx-frame { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.sx-comp picture { display: contents; }
.sx-part { position: absolute; display: block; max-width: none; transform-origin: 0 0; pointer-events: none; user-select: none; }
/* the pose stills: shown only with reduced motion (instant swaps), otherwise not displayed (and not downloaded) */
.sx-stage-item { position: absolute; inset: 0; display: none; }
.sx-stage-item img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.sx-stage-item picture { display: contents; }
@media (prefers-reduced-motion: reduce) {
  .sx-comp { display: none; }
  .sx-stage-item { display: block; opacity: 0; }
  .sx-stage-item.is-active { opacity: 1; }
}

/* First paint: the window stays invisible until sticky-canvas.js has set p for the scroll position, so a landing mid-section
   never shows pose 1 first. If the script never runs, the window appears after 3 s anyway. */
@media (min-width: 1200px) {
  html.sx-js .sx-stage:not(.is-ready) { visibility: hidden; animation: sx-stage-fallback 0s linear 3s forwards; }
}
@keyframes sx-stage-fallback { to { visibility: visible; } }
