:root {
  /* Timing (entrance) */
  --sa-dur-enter: 700ms;
  --sa-ease-enter: cubic-bezier(.22, 1, .36, 1);
  --sa-ease-travel: cubic-bezier(.65, 0, .35, 1);   /* scroll-linked travel: every object shares it */
  /* Depth layers of the scattered objects (start state only) */
  --sa-depth-mid: .8;
  --sa-depth-far: .56;
  --sa-blur-far: 2.5px;                             /* the only filter, one object per scene */
  --sa-gap: 16px;                                   /* min distance between objects and zone edges (read by JS) */
  --sa-zone-gap: 56px;                              /* min distance from the copy column to the object zone (read by JS) */
  /* Scene windows — % of the pinned scene (contain range). Copy leaves before any object moves. */
  --sa-copy-out: 12%;
  --sa-gather-from: 13%;
  --sa-gather-to: 52%;
  --sa-skel-from: 44%;
  --sa-skel-to: 52%;
  --sa-text-from: 47%;
  --sa-text-to: 56%;
  --sa-caption-from: 50%;
  --sa-caption-to: 60%;
  --sa-head-from: 54%;
  --sa-head-to: 64%;
  --sa-link-from: 62%;
  --sa-link-to: 74%;
  --sa-scene-h: 250svh;
  --sa-scene-h-narrow: 230svh;
  /* Word scrub */
  --sa-scrub-dim: .16;
  /* Horizontal track */
  --sa-track-intro: 30vw;
  --sa-track-panel: 60vw;
  --sa-track-gap: 5vw;
}

/* ── Static layout helpers (always on) ── */
.sa-rise-line { display: block; overflow: clip; padding-block-end: .08em; margin-block-end: -.08em; }
.sa-rise-line > span { display: block; }
.sa-obj__in { position: relative; }
.sa-skel { position: absolute; opacity: 0; pointer-events: none; }   /* consumer sets inset */
.sa-line-x { transform-origin: left; }
.sa-line-y { transform-origin: top; }
.sa-scrub__vis { display: none; }
.sa-scrub[data-sa-ready] .sa-scrub__vis { display: inline; }
.sa-scrub[data-sa-ready] .sa-scrub__src {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.sa-track__rail { display: none; }

@media (prefers-reduced-motion: no-preference) {
  /* ── Entrance — time-based, once (700ms) ── */
  @keyframes sa-rise   { from { transform: translateY(105%); } to { transform: none; } }
  @keyframes sa-enter  { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
  @keyframes sa-appear { from { opacity: 0; } to { opacity: 1; } }
  .sa-rise-line > span { animation: sa-rise var(--sa-dur-enter) var(--sa-ease-enter) both; animation-delay: calc(120ms + var(--sa-i, 0) * 90ms); }
  .sa-enter { animation: sa-enter var(--sa-dur-enter) var(--sa-ease-enter) both; animation-delay: var(--sa-delay, 360ms); }

  @supports (animation-timeline: view()) {
    @keyframes sa-draw-x   { from { transform: scaleX(0); } to { transform: scaleX(1); } }
    @keyframes sa-draw-y   { from { transform: scaleY(0); } to { transform: scaleY(1); } }
    @keyframes sa-fade-out { from { opacity: 1; } to { opacity: 0; } }
    @keyframes sa-lift     { to { opacity: 0; transform: translateY(-7svh); visibility: hidden; } }
    @keyframes sa-gather {
      from { transform: translate3d(var(--sa-x, 0px), var(--sa-y, 0px), 0) scale(var(--sa-s, 1)); opacity: var(--sa-o, 1); }
      to   { transform: none; opacity: 1; }
    }
    @keyframes sa-gather-far {
      from { transform: translate3d(var(--sa-x, 0px), var(--sa-y, 0px), 0) scale(var(--sa-s, 1)); opacity: var(--sa-o, 1); filter: blur(var(--sa-blur-far)); }
      to   { transform: none; opacity: 1; filter: blur(0); }
    }
    @keyframes sa-lit   { from { opacity: var(--sa-scrub-dim); } to { opacity: 1; } }
    @keyframes sa-slide { to { transform: translateX(calc(-1 * var(--sa-track-d))); } }

    /* ① 조립 — scattered objects gather into the structure. JS measures the start positions and sets data-sa-ready;
       without it the scene stays static (no object can start on top of the copy). */
    [data-sa-scene][data-sa-ready] { view-timeline: --sa-scene block; height: var(--sa-scene-h); }
    [data-sa-scene][data-sa-ready] .sa-stage { position: sticky; top: 0; height: 100svh; display: grid; grid-template-areas: "stack"; align-items: center; overflow: clip; }
    [data-sa-scene][data-sa-ready] .sa-stage > .sa-copy,
    [data-sa-scene][data-sa-ready] .sa-stage > .sa-field { grid-area: stack; }
    [data-sa-scene][data-sa-ready] .sa-field { pointer-events: none; }
    [data-sa-scene][data-sa-ready] .sa-copy { animation: sa-lift linear both; animation-timeline: --sa-scene; animation-range: contain 0% contain var(--sa-copy-out); }
    [data-sa-scene][data-sa-ready] .sa-copy:focus-within { animation: none; }   /* keep the focused copy readable */
    [data-sa-scene][data-sa-ready]:has(.sa-copy:focus-within) .sa-field { visibility: hidden; } /* keep assembling cards clear of focused copy */
    [data-sa-scene][data-sa-ready] .sa-obj { animation: sa-gather var(--sa-ease-travel) both; animation-timeline: --sa-scene; animation-range: contain var(--sa-gather-from) contain var(--sa-gather-to); }
    [data-sa-scene][data-sa-ready] .sa-obj[data-sa-depth="far"] { animation-name: sa-gather-far; }
    [data-sa-scene][data-sa-ready] .sa-obj > .sa-obj__in { animation: sa-appear 900ms var(--sa-ease-enter) both; animation-delay: calc(520ms + var(--sa-k, 0) * 90ms); }
    [data-sa-scene][data-sa-ready] .sa-skel { opacity: 1; animation: sa-fade-out linear both; animation-timeline: --sa-scene; animation-range: contain calc(var(--sa-skel-from) + var(--sa-k, 0) * 1.5%) contain calc(var(--sa-skel-to) + var(--sa-k, 0) * 1.5%); }
    [data-sa-scene][data-sa-ready] .sa-settle { animation: sa-enter linear both; animation-timeline: --sa-scene; animation-range: contain calc(var(--sa-text-from) + var(--sa-k, 0) * 1.5%) contain calc(var(--sa-text-to) + var(--sa-k, 0) * 1.5%); }
    [data-sa-scene][data-sa-ready] .sa-caption { animation: sa-enter linear both; animation-timeline: --sa-scene; animation-range: contain var(--sa-caption-from) contain var(--sa-caption-to); }
    [data-sa-scene][data-sa-ready] .sa-head { animation: sa-enter linear both; animation-timeline: --sa-scene; animation-range: contain var(--sa-head-from) contain var(--sa-head-to); }
    [data-sa-scene][data-sa-ready] .sa-link { animation: sa-draw-y linear both; animation-timeline: --sa-scene; animation-range: contain var(--sa-link-from) contain var(--sa-link-to); }
    @media (max-width: 63.99rem) {
      [data-sa-scene][data-sa-ready] { height: var(--sa-scene-h-narrow); }
    }

    /* ② 선 긋기 — a 1px line drawn by its own position in the viewport */
    .sa-draw-x { animation: sa-draw-x linear both; animation-timeline: view(); animation-range: entry 20% cover 40%; }
    .sa-draw-y { animation: sa-draw-y linear both; animation-timeline: view(); animation-range: entry 15% entry 70%; }
    /* Drawn by an ancestor's timeline: set view-timeline on the ancestor (.sa-view) and use .sa-lit-x/.sa-lit-y */
    .sa-view { view-timeline: --sa-view block; }
    .sa-view .sa-lit-x { animation: sa-draw-x linear both; animation-timeline: --sa-view; animation-range: cover calc(24% + var(--sa-k, 0) * 4%) cover calc(38% + var(--sa-k, 0) * 4%); }
    .sa-view .sa-lit-y { animation: sa-draw-y linear both; animation-timeline: --sa-view; animation-range: cover calc(22% + var(--sa-k, 0) * 4%) cover calc(40% + var(--sa-k, 0) * 4%); }
    .sa-view .sa-lit { animation: sa-enter linear both; animation-timeline: --sa-view; animation-range: cover calc(26% + var(--sa-k, 0) * 4%) cover calc(36% + var(--sa-k, 0) * 4%); }
    /* Opacity + vertical position only, bound to the element's own entry */
    .sa-enter-view { animation: sa-enter linear both; animation-timeline: view(); animation-range: entry 10% cover 30%; }

    /* ③ 단어 스크럽 — words brighten with scroll (opacity only). JS builds .sa-scrub__vis from .sa-scrub__src. */
    .sa-scrub[data-sa-ready] { view-timeline: --sa-scrub block; }
    .sa-scrub[data-sa-ready] .sa-w { animation: sa-lit linear both; animation-timeline: --sa-scrub;
      animation-range: cover calc(20% + var(--sa-i, 0) / var(--sa-n, 1) * 38%) cover calc(26% + var(--sa-i, 0) / var(--sa-n, 1) * 38%); }

    /* ④ 가로 트랙 — vertical scroll becomes a horizontal move. JS sets --sa-count and data-sa-ready (≥ 2 panels)
       and moves the track to follow keyboard focus. */
    @media (min-width: 64rem) and (min-height: 40rem) {
      [data-sa-track][data-sa-ready] {
        --sa-track-pad: max(var(--sa-track-gutter, 24px), (100vw - var(--sa-track-max, 1240px)) / 2);
        --sa-track-w: calc(var(--sa-track-pad) * 2 + var(--sa-track-intro) + var(--sa-count, 2) * (var(--sa-track-gap) + var(--sa-track-panel)));
        --sa-track-d: calc(var(--sa-track-w) - 100vw);
        view-timeline: --sa-track block; height: calc(100svh + var(--sa-track-d));
      }
      [data-sa-track][data-sa-ready] .sa-track__stage { position: sticky; top: 0; height: 100svh; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; overflow: clip; }
      [data-sa-track][data-sa-ready] .sa-track__row { display: flex; gap: var(--sa-track-gap); width: var(--sa-track-w); max-width: none; margin-inline: 0; justify-self: start; padding-inline: var(--sa-track-pad); align-items: center;
        animation: sa-slide linear both; animation-timeline: --sa-track; animation-range: contain 4% contain 96%; }
      [data-sa-track][data-sa-ready] .sa-track__intro { flex: 0 0 var(--sa-track-intro); }
      [data-sa-track][data-sa-ready] .sa-track__panel { flex: 0 0 var(--sa-track-panel); }
      [data-sa-track][data-sa-ready] .sa-track__rail { display: flex; }
      [data-sa-track][data-sa-ready] .sa-track__progress > i { display: block; height: 100%; transform-origin: left; animation: sa-draw-x linear both; animation-timeline: --sa-track; animation-range: contain 4% contain 96%; }
    }
  }
}
