/* Step back (vision §E1.2, §G2; DECISIONS §12): one sticky sequence, 1:1 with scroll. The hero is its
   first frame; P0155 shrinks from its hero rectangle into the centre slot of a salon wall while its
   neighbours converge from radially expanded positions (×2.4, scale 1.6 → 1, opacity 0 → 1 over their
   first 40%).

   States on .home-sb (js/v3/features/stepback.js, js/v3/pages/home.js):
     (none)          armed: JS on and Full motion. From the first paint the travel is reserved, the stage
                     sticks and the hero's words fade with scroll, so nothing moves when the wall arrives.
     data-sb=live    the wall is built: P0155 and the tiles move too.
     data-sb=static  Calm / reduced motion: the same wall, still, below the hero.
     data-sb=off     no wall (production before the owner approves the picks, or no data).
     No JS: the <noscript> wall (site-images.mjs, once approved) sits still below the hero.
   data-sb-drive  css (animation-timeline: view()) | js (Firefox: scroll-progress.js writes --t and the
                  same keyframes are scrubbed with a negative animation-delay)
   data-sb-state  start | run | wall | end: the hero answers the pointer at start; the tiles (and P0155)
                  as soon as every tile is fully shown (wall); the caption's link once it has formed (end).
                  Everything lands at 0.88 of the travel and holds still for the rest, so the formed wall
                  rests on screen before the page moves on.
   Custom properties: --sb-h (stage height, home.js), --sb-dx/--sb-dy/--sb-s (hero → slot), --sb-spread
   (how far out the neighbours start), --sb-cap (the caption's height, reserved), --wall-ar, --hx/--hy
   (slot centre), --k per cell (salon gutters). Each animated element carries its range in the travel
   as --r0/--r1. */
@layer pages {
  .home-sb { position: relative; --sb-travel: 110vh; }
  @media (orientation: portrait) { .home-sb { --sb-travel: 70vh; } }
  .home-sb__stage { position: relative; }
  .home-sb__travel { display: none; }
  .home-sb__wallarea[hidden] { display: none; }

  /* ------------------------------------------------------------------ the wall (every mode) */
  .home-sb__figure { display: grid; gap: var(--space-4); margin: 0; }
  .home-sb__wall {
    position: relative;
    container-type: size;
    inline-size: 100%;
    aspect-ratio: var(--wall-ar, 1.67);
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .home-sb__cell {
    position: absolute;
    inset-inline-start: calc(var(--x) * 100%);
    inset-block-start: calc(var(--y) * 100%);
    inline-size: calc(var(--w) * 100%);
    block-size: calc(var(--h) * 100%);
    display: grid;
    place-items: center;
  }
  /* Salon gutters: each tile shrinks about its centre by --k (stepback.js), keeping its aspect ratio. */
  .home-sb__tile {
    display: block;
    inline-size: calc(var(--k, 1) * 100%);
    block-size: calc(var(--k, 1) * 100%);
    background: var(--dom, var(--sunken));
    box-shadow: 0 1px 2px var(--hang-contact-color);
    color: inherit;
    text-decoration: none;
  }
  .home-sb__tile img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
  .home-sb__tile:focus-visible { position: relative; z-index: 1; outline-offset: 3px; box-shadow: 0 0 0 5px var(--ground); }

  .home-sb__caption {
    display: grid;
    grid-template-columns: auto auto minmax(0, 1fr);
    align-items: baseline;
    justify-items: start;
    gap: var(--space-2) var(--space-5);
    font-size: var(--step--1);
    line-height: 1.45;
    color: var(--ink-2);
  }
  .home-sb__count { color: var(--ink); font-weight: 500; }
  .home-sb__count [data-count] { font-variant-numeric: tabular-nums; }
  /* The hovered or focused painting's label, at the end of the caption line. */
  .home-sb__now { display: inline-flex; align-items: baseline; gap: 0.7em; justify-self: end; min-block-size: 1.45em; color: var(--ink-2); }
  .home-sb__now .title { color: var(--ink); font-size: var(--step-0); }
  .home-sb__now .mono { font-size: var(--step--2); letter-spacing: 0.08em; }
  .home-sb__caption .draft-note { grid-column: 1 / -1; }
  @media (max-width: 599.98px) {
    .home-sb__caption { grid-template-columns: minmax(0, 1fr); }
    .home-sb__now { display: none; }
  }

  /* "Skip the wall": visible when focused. */
  .home-sb__skip {
    position: absolute;
    inset-block-start: var(--space-4);
    inset-inline-start: var(--margin);
    z-index: 4;
    padding: 10px 16px;
    border-radius: var(--radius-1);
    background: var(--slab);
    color: var(--on-slab);
    font: 600 0.9375rem/1.2 var(--font-ui);
    letter-spacing: 0.02em;
    text-decoration: none;
    pointer-events: auto;
  }
  .home-sb__skip:not(:focus) {
    clip-path: inset(50%);
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
  }

  /* ------------------------------------------------------------------ still: Calm, reduced motion, no JS */
  .home-sb[data-sb="static"] .home-sb__wallarea,
  .home-sb__wallarea--static {
    position: relative;
    padding-block: clamp(32px, 4vw, 72px) 0;
  }
  .home-sb[data-sb="static"] .home-sb__figure,
  .home-sb__wallarea--static .home-sb__figure {
    inline-size: min(100% - 2 * var(--margin), (100svh - 12rem) * var(--wall-ar, 1.67));
    margin-inline: auto;
  }
  @media (orientation: portrait) { .home-sb__figure--desktop { display: none; } }
  @media (orientation: landscape) { .home-sb__figure--phone { display: none; } }

  /* ------------------------------------------------------------------ armed and live: the sequence */
  :root.js:not([data-motion="calm"]) .home-sb:not([data-sb="off"], [data-sb="static"]) {
    timeline-scope: --sb;
  }
  /* The travel is reserved from the first paint, so nothing below moves when the wall arrives. */
  :root.js:not([data-motion="calm"]) .home-sb:not([data-sb="off"], [data-sb="static"]) > .home-sb__travel {
    display: block;
    block-size: var(--sb-travel);
    view-timeline: --sb block;
    /* The page's scroll-padding (base.css) would otherwise inset the timeline by 16 px at each end. */
    view-timeline-inset: 0;
  }
  :root.js:not([data-motion="calm"]) .home-sb:not([data-sb="off"], [data-sb="static"]) > .home-sb__stage {
    position: sticky;
    /* A stage taller than the viewport (phones: painting, label, words) scrolls until its bottom meets
       the viewport bottom, then holds for the travel. home.js measures --sb-h before anyone scrolls. */
    inset-block-start: min(0px, calc(100svh - var(--sb-h, 100svh)));
    min-block-size: 100svh;
    isolation: isolate;
  }
  /* Words and controls sit above the light: the pool is light on the wall, not on words. */
  .home-sb :is(.home-hero__text, .home-hang__label, .home-lamp) { position: relative; z-index: 2; }

  .home-sb[data-sb="live"] .home-sb__wallarea {
    position: absolute;
    inset: auto 0 0;
    block-size: 100svh;
    z-index: 2;
    display: grid;
    place-items: center;
    container-type: size;
    /* The neighbours start beyond the screen's sides; nothing there adds width to the page. */
    overflow-x: clip;
    pointer-events: none;
  }
  /* The formed wall and its caption fit the screen inside the content margins, with --space-7 of wall
     above and below. */
  .home-sb[data-sb="live"] .home-sb__figure {
    inline-size: min(100cqw - 2 * var(--margin), (100cqh - 2 * var(--space-7) - var(--sb-cap, 4.5rem)) * var(--wall-ar, 1.67));
  }
  .home-sb[data-sb="live"] .home-sb__cell[data-hero] { visibility: hidden; }

  /* Who answers the pointer: the hero at the start; the tiles and P0155 once every tile is fully
     shown; the caption's link once it is there. The faded hero never covers the wall. */
  .home-sb[data-sb="live"]:not([data-sb-state="start"]) :is(.home-hero, [data-sb-fade], .home-hang__plate) { pointer-events: none; }
  .home-sb[data-sb="live"]:is([data-sb-state="wall"], [data-sb-state="end"]) :is(.home-hang__plate, .home-sb__cell) { pointer-events: auto; }
  .home-sb[data-sb="live"][data-sb-state="end"] .home-sb__caption a { pointer-events: auto; }
  .home-sb .home-lamp__pop { pointer-events: auto; }

  /* Ranges within the travel (fractions). The label and lamp row clear the way first, then the words;
     P0155 travels to 0.88; the tiles start a little later and settle as it lands; then the formed wall
     holds still to the end of the travel. The neighbours converge on P0155 where it is (−--sb-dx/dy at
     the start), from --sb-spread × their distance out. */
  .home-sb [data-sb-fade] { --r0: 0; --r1: 0.14; }
  .home-sb :is(.home-hang__label, .home-lamp, .home-hang__draft)[data-sb-fade] { --r1: 0.07; }
  .home-sb :is(.home-hang__plate, .home-hang__light) { --r0: 0; --r1: 0.88; transform-origin: 50% 50%; }
  .home-sb .home-sb__cell {
    --r0: 0.12;
    --r1: 0.88;
    /* How much of P0155's way is left when the tiles start: (0.88 − 0.12) / 0.88 (phones: (0.88 − 0.16)
       / (0.88 − 0.05)); both ≈ 0.865, so the wall closes in on the painting wherever it is. */
    --sb-follow: 0.865;
    --ox: calc((var(--cx) - var(--hx, 0.5)) * var(--sb-spread, 1.4) * 100cqw - var(--sb-dx, 0px) * var(--sb-follow));
    --oy: calc((var(--cy) - var(--hy, 0.5)) * var(--sb-spread, 1.4) * 100cqh - var(--sb-dy, 0px) * var(--sb-follow));
  }
  .home-sb .home-sb__caption { --r0: 0.74; --r1: 0.88; }
  @media (orientation: portrait) {
    /* Phones: the painting waits until its label has gone before it moves down over it, and the wall
       gathers only once the words have cleared. */
    .home-sb :is(.home-hang__plate, .home-hang__light) { --r0: 0.05; }
    .home-sb .home-sb__cell { --r0: 0.16; }
  }

  /* Scroll-driven (Chromium, Safari 26+): one view timeline on the travel, shared through timeline-scope.
     Armed, only the words fade (P0155 has nowhere to go yet); live, everything moves. */
  @supports (animation-timeline: view()) and (timeline-scope: --sb) {
    :root.js:not([data-motion="calm"]) .home-sb:not([data-sb="off"], [data-sb="static"], [data-sb-drive="js"]) [data-sb-fade] { animation-name: sb-fade; }
    :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"]:not([data-sb-drive="js"]) :is(.home-hang__plate, .home-hang__light) { animation-name: sb-hero; }
    :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"]:not([data-sb-drive="js"]) .home-sb__cell { animation-name: sb-tile; }
    :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"]:not([data-sb-drive="js"]) .home-sb__caption { animation-name: sb-in; }
    :root.js:not([data-motion="calm"]) .home-sb:not([data-sb="off"], [data-sb="static"], [data-sb-drive="js"]) :is([data-sb-fade], .home-hang__plate, .home-hang__light, .home-sb__cell, .home-sb__caption) {
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --sb;
      animation-range: entry-crossing calc(var(--r0) * 100%) entry-crossing calc(var(--r1) * 100%);
    }
  }
  /* Scrubbed by --t (Firefox, any engine without scroll timelines; only once the wall is live): the same
     keyframes, paused, seeked with a negative delay. */
  :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"][data-sb-drive="js"] [data-sb-fade] { animation-name: sb-fade; }
  :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"][data-sb-drive="js"] :is(.home-hang__plate, .home-hang__light) { animation-name: sb-hero; }
  :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"][data-sb-drive="js"] .home-sb__cell { animation-name: sb-tile; }
  :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"][data-sb-drive="js"] .home-sb__caption { animation-name: sb-in; }
  :root.js:not([data-motion="calm"]) .home-sb[data-sb="live"][data-sb-drive="js"] :is([data-sb-fade], .home-hang__plate, .home-hang__light, .home-sb__cell, .home-sb__caption) {
    animation-duration: 1s;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-play-state: paused;
    animation-delay: calc(clamp(0, (var(--t, 0) - var(--r0)) / (var(--r1) - var(--r0)), 1) * -1s);
  }

  @keyframes sb-hero {
    to { translate: var(--sb-dx, 0px) var(--sb-dy, 0px); scale: var(--sb-s, 1); }
  }
  @keyframes sb-fade {
    to { opacity: 0; translate: 0 -2.5rem; }
  }
  @keyframes sb-tile {
    from { translate: var(--ox, 0px) var(--oy, 0px); scale: 1.6; opacity: 0; }
    40% { opacity: 1; }
    to { translate: 0 0; scale: 1; opacity: 1; }
  }
  @keyframes sb-in {
    from { opacity: 0; translate: 0 0.75rem; }
  }

  /* Belt and braces: whatever happens to the state, Calm never moves. */
  :root[data-motion="calm"] .home-sb * { animation: none !important; }

  @media (forced-colors: active) {
    .home-sb__tile { outline: 1px solid CanvasText; }
  }
}
