/* ==========================================================================
   illus/existing: one-shot reveal motion for the illustrations that were
   already on the site before the illustration pass.

   How it works
   - Every motion rule below sits inside @media (prefers-reduced-motion: no-preference)
     and under .js (the one static rule is the latch-label legibility fix just below), so with no JS or with reduced motion the drawings are the
     finished, static pictures that the page markup already describes.
   - Triggers are the classes the site already sets once:
       .is-in    on any .reveal, added by assets/js/site.js when it scrolls into view
       .is-open  on .hero (assets/js/story.js) and .s-hero (assets/js/start.js)
   - Keyframes use fill-mode "backwards": each part holds its first frame during
     its delay, and when it finishes the animation lets go, so the element falls
     back to its own static style. Every last keyframe equals that static style,
     so nothing jumps, and the settled page renders exactly like the static one.
   - Nothing loops, nothing blinks. The longest sequence settles at about 2.5 s.
   - Scroll-driven and pinned scenes (the 717-day timeline, the prologue, the
     title card, the plates, the morning scene, the memoir's reading ring and
     section breaks) are left to story.js and reader.js on purpose.
   - Flight 811 memorial page and the "nine" marks never animate (memorial tone).

   Index (selectors hook existing markup only; no page edits are needed)
     1. #b-light door figure         .light-figure .lf-*
     2. #b-light view ports          .viewports__fig .vp-*
     3. #b-latch-again latch drawing .latch-state > figure
     4. #b-27 diptych                .diptych__scan mark, .diptych__years
     5. Hero dial and start-page dial .hero__ring/.hero__ticks, .s-port__ring/.s-port__ticks
     6. Ports that mean "checked"    .glance, .entry__rail, .trailer__play, .form__done
   ========================================================================== */

/* (The #b-latch-again drawing was redrawn in the illustration style in story.css; its old label patch is gone.) */

/* Registered so the ring sweep and the 27-year counter interpolate smoothly.
   Browsers without @property simply jump to the end value (still correct). */
@property --il-existing-sweep { syntax: "<angle>"; inherits: false; initial-value: 360deg; }
@property --il-existing-n { syntax: "<integer>"; inherits: false; initial-value: 27; }

@media (prefers-reduced-motion: no-preference) {

  /* ---------- Shared keyframes ---------- */
  @keyframes il-existing-fade { from { opacity: 0; } to { opacity: 1; } }
  @keyframes il-existing-label { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
  /* The motif's unchecked angle (-28deg, site.css .port) swinging level: "looked at, not assumed" */
  @keyframes il-existing-level { from { transform: rotate(-28deg); } to { transform: rotate(0deg); } }

  /* ======================================================================
     1. The door: what the cockpit checked (index.html #b-light, night theme)
     Told in the order NTSB AAR-92/02 §1.17.1 gives for the 1987 Pan Am door:
     "the manual master latch lock handle was stowed, in turn closing the
     pressure relief doors and extinguishing the cockpit cargo door warning
     light", and the latches were "back-driven (opened) ... after the door had
     been closed and locked". So: the handle comes down to stowed -> the relief
     doors swing shut -> the signal runs along the wire -> the lamp goes out
     -> the cockpit reads "secure" -> the eight cams lift off their pins.
     ====================================================================== */
  .js .light-figure.is-in .lf-rivets { animation: il-existing-fade 700ms ease 150ms backwards; }

  /* Relief doors: two flaps swinging shut on their top hinge */
  .js .light-figure.is-in .lf-relief {
    transform-box: fill-box; transform-origin: 50% 0;
    animation: il-existing-flap 600ms cubic-bezier(.3, 1.35, .5, 1) 620ms backwards;
  }
  .js .light-figure.is-in .lf-relief + .lf-relief { animation-delay: 690ms; }
  @keyframes il-existing-flap { from { transform: scaleY(.12); opacity: .35; } to { transform: none; opacity: 1; } }

  /* Lock handle: swings down from open to stowed about its brass pivot (150,196) */
  .js .light-figure.is-in .lf-handle {
    transform-box: view-box; transform-origin: 150px 196px;
    animation: il-existing-handle 800ms cubic-bezier(.25, 1.3, .45, 1) 150ms backwards;
  }
  @keyframes il-existing-handle { from { transform: rotate(-52deg); } to { transform: rotate(0deg); } }

  .js .light-figure.is-in text.lf-label[y="104"] { animation: il-existing-label 450ms var(--ease-out) 940ms backwards; }
  .js .light-figure.is-in text.lf-label[y="236"] { animation: il-existing-label 450ms var(--ease-out) 720ms backwards; }

  /* The wire: the "closed" signal travels from the relief doors to the cockpit lamp.
     A left-to-right reveal (viewBox units: the wire runs x 95 -> 452 of 520) plus
     a short march of its dashes in the direction of travel. */
  .js .light-figure.is-in .lf-wire {
    animation: il-existing-wire 480ms cubic-bezier(.4, 0, .2, 1) 920ms backwards;
  }
  @keyframes il-existing-wire {
    from { clip-path: inset(0 82% 0 0) view-box; stroke-dashoffset: 33; }
    to   { clip-path: inset(0 12% 0 0) view-box; stroke-dashoffset: 0; }
  }

  /* The cockpit lamp: lit while the handle is up, then it goes out when the signal arrives.
     fill swaps discretely (a lamp switching off); the glow decays. */
  .js .light-figure.is-in .lf-lamp { animation: il-existing-lamp 1650ms linear 0ms backwards; }
  @keyframes il-existing-lamp {
    0%, 82% { fill: #efe4c8; filter: drop-shadow(0 0 12px rgba(239, 228, 200, .7)); }
    84%     { fill: url(#lf-lamp); filter: drop-shadow(0 0 7px rgba(239, 228, 200, .35)); }
    100%    { fill: url(#lf-lamp); filter: drop-shadow(0 0 0 rgba(239, 228, 200, 0)); }
  }
  .js .light-figure.is-in .lf-small--muted { animation: il-existing-label 400ms var(--ease-out) 1420ms backwards; }
  .js .light-figure.is-in .lf-label--brass { animation: il-existing-label 450ms var(--ease-out) 1500ms backwards; }
  .js .light-figure.is-in .lf-label--brass + .lf-label--brass { animation-delay: 1580ms; }

  /* The truth under the sill: each cam starts hooked round its pin (closed, neutral steel)
     and lifts off into the open position, turning violet. The end frame equals the markup's
     own transform="translate(-3 -13) rotate(-35)", so the settled drawing is unchanged. */
  .js .light-figure.is-in .lf-cam {
    animation: il-existing-cam 480ms cubic-bezier(.3, 1.25, .5, 1) calc(1600ms + var(--il-existing-k, 0) * 55ms) backwards;
  }
  @keyframes il-existing-cam {
    from { transform: translate(0px, 2px) rotate(0deg); stroke: #8d9099; filter: drop-shadow(0 0 0 rgba(182, 156, 240, 0)); }
    to   { transform: translate(-3px, -13px) rotate(-35deg); stroke: var(--accent); filter: drop-shadow(0 0 6px rgba(182, 156, 240, .45)); }
  }
  .light-figure .lf g > g:nth-child(2) .lf-cam { --il-existing-k: 1; }
  .light-figure .lf g > g:nth-child(3) .lf-cam { --il-existing-k: 2; }
  .light-figure .lf g > g:nth-child(4) .lf-cam { --il-existing-k: 3; }
  .light-figure .lf g > g:nth-child(5) .lf-cam { --il-existing-k: 4; }
  .light-figure .lf g > g:nth-child(6) .lf-cam { --il-existing-k: 5; }
  .light-figure .lf g > g:nth-child(7) .lf-cam { --il-existing-k: 6; }
  .light-figure .lf g > g:nth-child(8) .lf-cam { --il-existing-k: 7; }
  .js .light-figure.is-in .lf-label--accent { animation: il-existing-label 500ms var(--ease-out) 2000ms backwards; }

  /* ======================================================================
     2. The view ports: latched vs open (index.html #b-light, night theme)
     Refines story.css's single swing: the bezels draw, the glass and cams
     settle, the left stripe swings into line with its arrow (brass, latched),
     and only then does the right stripe turn out of line (violet, open).
     ====================================================================== */
  .js .viewports__fig.is-in .vp-bezel { animation: il-existing-bezel 1000ms var(--ease-out) 100ms backwards; }
  .js .viewports__fig.is-in .vp--open .vp-bezel { animation-delay: 240ms; }
  @keyframes il-existing-bezel {
    0%    { stroke-dasharray: 629; stroke-dashoffset: 629; }
    99.9% { stroke-dasharray: 629; stroke-dashoffset: 0; }
    100%  { stroke-dasharray: none; stroke-dashoffset: 0; }
  }

  .js .viewports__fig.is-in .vp-glass { animation: il-existing-fade 700ms ease 80ms backwards; }
  .js .viewports__fig.is-in .vp-cam,
  .js .viewports__fig.is-in .vp-pin { transform-box: fill-box; transform-origin: 50% 50%; animation: il-existing-settle 700ms cubic-bezier(.3, 1.3, .5, 1) 300ms backwards; }
  .js .viewports__fig.is-in .vp--open .vp-cam,
  .js .viewports__fig.is-in .vp--open .vp-pin { animation-delay: 420ms; }
  @keyframes il-existing-settle { from { transform: scale(.82); opacity: 0; } to { transform: none; opacity: 1; } }

  .js .viewports__fig.is-in .vp-arrow,
  .js .viewports__fig.is-in .vp-fitting { animation: il-existing-label 450ms var(--ease-out) 560ms backwards; }
  .js .viewports__fig.is-in .vp--open .vp-arrow,
  .js .viewports__fig.is-in .vp--open .vp-fitting { animation-delay: 680ms; }
  .js .viewports__fig.is-in .vp-glint { animation: il-existing-fade 600ms ease 1050ms backwards; }

  /* Left: the stripe swings into line with the arrow and settles (checked) */
  .js .viewports__fig.is-in .vp--ok .vp-stripe {
    transform-box: view-box; transform-origin: 130px 130px;
    animation: il-existing-inline 900ms cubic-bezier(.25, 1.35, .45, 1) 520ms backwards;
  }
  @keyframes il-existing-inline { from { transform: rotate(-78deg); } to { transform: rotate(0deg); } }

  /* Right: it starts where the left one ended, hesitates, then turns out of line.
     Replaces story.css's 1600 ms transition with a timed keyframe (same start and end angles). */
  .js .viewports__fig.is-in .vp--open .vp-stripe {
    transition: none;
    transform-box: view-box; transform-origin: 390px 130px;
    animation: il-existing-backoff 1100ms cubic-bezier(.5, 0, .2, 1) 1150ms backwards;
  }
  @keyframes il-existing-backoff {
    0%   { transform: rotate(52deg); filter: drop-shadow(0 0 0 rgba(182, 156, 240, 0)); }
    16%  { transform: rotate(47deg); }
    100% { transform: rotate(0deg); filter: drop-shadow(0 0 6px rgba(182, 156, 240, .5)); }
  }

  .js .viewports__fig.is-in .vp--ok .vp-label { animation: il-existing-label 450ms var(--ease-out) 1150ms backwards; }
  .js .viewports__fig.is-in .vp--ok .lf-small { animation: il-existing-label 450ms var(--ease-out) 1260ms backwards; }
  .js .viewports__fig.is-in .vp--open .vp-label { animation: il-existing-label 450ms var(--ease-out) 1950ms backwards; }
  .js .viewports__fig.is-in .vp--open .lf-small { animation: il-existing-label 450ms var(--ease-out) 2010ms backwards; }

  /* ======================================================================
     3. The latch, again (index.html #b-latch-again, ember theme)
     The NTSB Figure 5 drawing assembles: pivot and pin draw, the lock sector
     draws and rotates down into its locked position, then the violet cam
     draws itself closed around the pin.
     ====================================================================== */
  /* The redrawn latch assembles: the cam swings closed around its pin until its stripe meets the arrow,
     then the brass lock sector rotates down over it and settles; labels follow. */
  .js .latch-state > figure.is-in .la-cam { transform-box: view-box; transform-origin: 150px 190px; animation: il-existing-cam 1100ms cubic-bezier(.45, 0, .2, 1) 300ms backwards; }
  @keyframes il-existing-cam { from { transform: rotate(-70deg); } to { transform: rotate(0deg); } }
  .js .latch-state > figure.is-in .la-sector { transform-box: view-box; transform-origin: 258px 72px; animation: il-existing-lock 900ms cubic-bezier(.3, 1.3, .5, 1) 1300ms backwards; }
  @keyframes il-existing-lock { from { transform: rotate(-28deg); opacity: .4; } to { transform: rotate(0deg); opacity: 1; } }
  .js .latch-state > figure.is-in .la-label--pin { animation: il-existing-label 420ms var(--ease-out) 200ms backwards; }
  .js .latch-state > figure.is-in .la-label--cam, .js .latch-state > figure.is-in .la-label--stripe { animation: il-existing-label 450ms var(--ease-out) 1250ms backwards; }
  .js .latch-state > figure.is-in .la-label--sector { animation: il-existing-label 450ms var(--ease-out) 1950ms backwards; }

  /* ======================================================================
     4. Then and now (index.html #b-27, day theme)
     The violet highlighter sweeps across the 1999 line; the two hairlines
     grow from 1999 towards 2026 while the 27 counts up from 0.
     The years block is aria-hidden, so the counter is decoration only.
     ====================================================================== */
  .js .diptych figure.is-in .diptych__scan mark { transform-origin: 0 50%; animation: il-existing-mark 800ms cubic-bezier(.5, 0, .2, 1) 650ms backwards; }
  @keyframes il-existing-mark { from { transform: scaleX(0); } to { transform: none; } }

  .js .diptych__years.is-in .bar { transform-origin: 0 0; animation: il-existing-bar 650ms var(--ease-out) 350ms backwards; }
  .js .diptych__years.is-in .bar ~ .bar { animation-delay: 1450ms; }
  @keyframes il-existing-bar { from { transform: scale(0); } to { transform: none; } }
  .js .diptych__years b { position: relative; color: transparent; }
  .js .diptych__years b::after {
    content: counter(il-existing-years); counter-reset: il-existing-years var(--il-existing-n, 27); /* fallback: without @property the var is unset and the counter would read 0 */
    position: absolute; inset: 0; text-align: center; color: var(--accent);
    font-variant-numeric: tabular-nums lining-nums;
  }
  .js .diptych__years.is-in b::after { animation: il-existing-count 1000ms cubic-bezier(.3, 0, .2, 1) 600ms backwards; }
  @keyframes il-existing-count { from { --il-existing-n: 0; } to { --il-existing-n: 27; } }

  /* ======================================================================
     5. The dials: the hero view port (index.html) and the start pages' port
     story.css / start.css already open them (.is-open): ring scales in,
     notches swing level. Added: the brass ring draws itself clockwise from
     twelve o'clock and the eight ticks light one by one as it passes.
     ====================================================================== */
  .js .hero.is-open .hero__ring,
  .js .s-hero.is-open .s-port__ring {
    -webkit-mask: conic-gradient(#000 var(--il-existing-sweep, 360deg), transparent 0);
            mask: conic-gradient(#000 var(--il-existing-sweep, 360deg), transparent 0);
    animation: il-existing-sweep 1400ms cubic-bezier(.45, .05, .4, 1) 350ms backwards;
  }
  @keyframes il-existing-sweep { from { --il-existing-sweep: 0deg; } to { --il-existing-sweep: 360deg; } }
  /* The tick containers fade in late in story.css/start.css; let the ticks themselves pace it */
  .js .hero.is-open .hero__ticks,
  .js .s-hero.is-open .s-port__ticks { transition-duration: 200ms; transition-delay: 300ms; }
  .js .hero.is-open .hero__ticks i,
  .js .s-hero.is-open .s-port__ticks i { animation: il-existing-fade 420ms ease calc(420ms + var(--k, 0) * 172ms) backwards; }

  /* ======================================================================
     6. Ports that mean "checked": the stripe swings level once, on reveal
     ====================================================================== */
  /* how-we-use-ai.html: the four "At a glance" checks */
  .js .glance li.reveal.is-in .port.is-aligned .port__stripe {
    animation: il-existing-level 900ms var(--ease-out) calc(420ms + var(--i, 0) * 140ms) backwards;
  }
  /* now.html: the first log entry's port (aligned = live now). The rail is not a .reveal,
     so it follows its own heading. Browsers without :has() keep the static drawing. */
  /* Keyed on the heading's .is-in (never on its absence), so if .is-in never arrives the
     stripe simply stays level, which is the page's own static "checked" state. */
  .js .entry:has(> .entry__body > h2.reveal.is-in) .entry__rail .port.is-aligned .port__stripe {
    animation: il-existing-level 1000ms var(--ease-out) 350ms backwards;
  }
  /* index.html trailer: the notched play port levels as the film frame arrives */
  .js .trailer__frame.reveal.is-in .trailer__play .port__stripe { animation: il-existing-level 1100ms var(--ease-out) 650ms backwards; }
  /* speaking.html: the form's confirmation port levels when the message appears */
  .js .form__done:not([hidden]) .port.is-aligned .port__stripe { animation: il-existing-level 900ms var(--ease-out) 200ms backwards; }
}
