/* Homepage chapter transitions: the expression layer, scroll-driven.
   Rules in expression.css. What this file adds, and the limits it keeps:

   - The words never move. Titles, ledes, statements and buttons stay exactly
     where editorial.css puts them. Only the graphics travel: the data plates,
     the tables, the light band, the card groups, the chapter numerals and a
     progress line on the rail.
   - Scroll drives every transition (animation-timeline: view() and scroll()),
     and js/ex-glide.js makes the scroll itself one eased glide per gesture
     instead of the snap's bounce-and-drag. At every stop each graphic is at
     rest in its true, final state.
   - Compositor only: opacity, translate and scale. v1 used filter,
     letter-spacing and an animated clip-path, which repaint large areas on
     every frame and stuttered during the glide. The band's opening is now two
     curtains that scale away.
   - Untouched by these rules: the maturity index (.ed-mi). Its motion is
     js/ex-mi.js, in step with its number.
   - The rotating research cards keep their own transitions; only their group
     moves, so the two never fight over the same property.
   - Reduced motion, or a browser without scroll timelines (Firefox today), gets
     the page exactly as it was. Scoped away from the Current view on the review
     build, and inert on production until Clearer is promoted. */

/* While js/ex-glide.js drives the movement, the CSS snap must not also act. */
html.ex-glide { scroll-snap-type: none !important; scroll-behavior: auto !important; }

/* The promoted headline is longer than the previous two-line headline.
   Measured with Space Grotesk at 1280 and 1440px: the second line needs
   11.1em inside the column's 13% indent. Keep both lines visible and keep
   the hero's height calculation on the same display size. */
@media (min-width: 768px) {
  html:not([data-variant="current"]) .ed {
    --ed-display: clamp(2.4rem, 6.1vw, 6rem);
  }
}

@media (prefers-reduced-motion: no-preference) {
@supports (animation-timeline: view()) {

  /* ---- The opening: the plate settles back as the next chapter arrives -- */
  :root:not([data-variant="current"]) .ed-hero .ed-plate-data {
    animation: ex-h-settle linear both;
    animation-timeline: view();
    animation-range: exit 0% exit 90%;
  }

  /* ---- Chapter numerals: each chapter announces itself ------------------ */
  :root:not([data-variant="current"]) .ed-marker__num {
    animation: ex-h-num linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 30%;
  }

  /* ---- The figures of each chapter arrive with the glide, and settle back
     as it leaves. Long, overlapping ranges so the motion is spread over the
     whole glide instead of happening in a burst. ------------------------- */
  :root:not([data-variant="current"]) :is(.ed-article__figure, .ed-chapter__cards, .ed-band__ladder) {
    animation: ex-h-arrive linear both, ex-h-settle linear both;
    animation-timeline: view(), view();
    animation-range: entry 0% cover 35%, exit 15% exit 100%;
    will-change: transform, opacity;
  }

  /* ---- Table rows cascade: each row has its own timeline. --------------- */
  :root:not([data-variant="current"]) :is(.ed-article__figure, .ed-band__ladder) tr {
    animation: ex-h-row linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 30%;
  }

  /* ---- The light band opens: two curtains of page colour scale away from
     the middle as the band arrives. Transform only. ---------------------- */
  :root:not([data-variant="current"]) :is(.ed-band, .ed-section--alt) { position: relative; }
  :root:not([data-variant="current"]) :is(.ed-band, .ed-section--alt)::before,
  :root:not([data-variant="current"]) :is(.ed-band, .ed-section--alt)::after {
    content: "";
    position: absolute; top: 0; bottom: 0; width: 50%;
    background: var(--bg-page, #111312);
    pointer-events: none; z-index: 3;
    animation: ex-h-curtain linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 30%;
  }
  :root:not([data-variant="current"]) :is(.ed-band, .ed-section--alt)::before { left: 0; transform-origin: left center; }
  :root:not([data-variant="current"]) :is(.ed-band, .ed-section--alt)::after { right: 0; transform-origin: right center; }

  /* ---- On the dark chapters a curtain would be invisible, so the same idea
     builds their structure instead: the rule above each card and each row of
     the model index draws in from the left as it arrives, a little later for
     each column, so a row of cards is built in sequence. ------------------ */
  :root:not([data-variant="current"]) :is(.ed-card, .ed-index__item) { position: relative; border-top-color: transparent; }
  :root:not([data-variant="current"]) :is(.ed-card, .ed-index__item)::before {
    content: "";
    position: absolute; left: 0; right: 0; top: -1px; height: 1px;
    background: var(--ed-rule-strong);
    transform-origin: left center;
    animation: ex-h-draw linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 28%;
    transition: background-color 200ms var(--ed-ease);
  }
  :root:not([data-variant="current"]) .ed-index__item::before { background: var(--ed-rule); }
  :root:not([data-variant="current"]) .ed-card:hover::before { background: var(--ed-accent); }
  :root:not([data-variant="current"]) .ed-cards > .ed-card:nth-child(3n+2)::before,
  :root:not([data-variant="current"]) .ed-index__item:nth-child(4n+2)::before { animation-range: entry 6% cover 32%; }
  :root:not([data-variant="current"]) .ed-cards > .ed-card:nth-child(3n+3)::before,
  :root:not([data-variant="current"]) .ed-index__item:nth-child(4n+3)::before { animation-range: entry 12% cover 36%; }
  :root:not([data-variant="current"]) .ed-index__item:nth-child(4n+4)::before { animation-range: entry 18% cover 40%; }

  /* ---- The rail: a progress line through the whole argument ------------ */
  :root:not([data-variant="current"]) .ed-rail__list { position: relative; }
  :root:not([data-variant="current"]) .ed-rail__list::before {
    content: "";
    position: absolute; left: -1px; top: 0; bottom: 0; width: 2px;
    background: var(--ed-accent);
    transform-origin: top;
    animation: ex-h-progress linear both;
    animation-timeline: scroll(root);
  }

  /* Easing lives inside the keyframes: a scroll timeline maps position to
     progress linearly, so without it every arrival starts and stops hard. */
  @keyframes ex-h-arrive {
    from { opacity: 0; translate: 0 64px; scale: .985; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
    to { opacity: 1; translate: 0 0; scale: 1; }
  }
  @keyframes ex-h-settle {
    from { opacity: 1; scale: 1; animation-timing-function: cubic-bezier(.4, 0, .6, 1); }
    to { opacity: .35; scale: .965; }
  }
  @keyframes ex-h-row {
    from { opacity: 0; translate: -14px 0; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
    to { opacity: 1; translate: 0 0; }
  }
  @keyframes ex-h-num {
    from { opacity: 0; translate: 0 .3em; animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
    to { opacity: 1; translate: 0 0; }
  }
  @keyframes ex-h-curtain {
    from { transform: scaleX(.5); animation-timing-function: cubic-bezier(.7, 0, .3, 1); }
    to { transform: scaleX(0); }
  }
  @keyframes ex-h-draw {
    from { transform: scaleX(0); animation-timing-function: cubic-bezier(.65, 0, .35, 1); }
    to { transform: scaleX(1); }
  }
  @keyframes ex-h-progress { from { transform: scaleY(0); } to { transform: scaleY(1); } }
}
}

/* ===== Homepage instruments, js/ex-home.js. Not scroll-driven. ============== */

/* ---- The opening: one blueprint, three hubs (the proposed system) ---------- */
.ed .ex-port { margin: .8rem 0 0; max-width: 25rem; cursor: pointer; }
.ed .ex-port:focus-visible { outline: 2px solid var(--ed-accent); outline-offset: 6px; }
.ed .ex-port__head { display: flex; justify-content: space-between; gap: 12px; font-family: var(--font-mono); font-size: var(--ed-label); letter-spacing: .14em; text-transform: uppercase; color: var(--ed-quiet); margin-bottom: 4px; }
.ed .ex-port svg { display: block; width: 100%; height: auto; overflow: visible; }
.ed .ex-port__rail { stroke: var(--ed-rule-strong); stroke-width: 1; stroke-dasharray: 3 4; }
.ed .ex-port__hub { fill: var(--bg-page, #111312); stroke: var(--ed-rule-strong); stroke-width: 1.25; }
.ed .ex-port__name { font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; fill: var(--ed-quiet); text-transform: uppercase; }
.ed .ex-port__bp { fill: var(--ed-accent); }
.ed .ex-port__cap { font-family: var(--font-mono); font-size: 12px; letter-spacing: .06em; fill: var(--ed-body); }
.ed .ex-port .ex-port__hub { animation: ex-hub-on 360ms var(--ex-ease-out) both; }
.ed .ex-port .ex-port__hub--a { animation-delay: 1.2s; }
.ed .ex-port .ex-port__hub--b { animation-delay: 2.7s; }
.ed .ex-port .ex-port__hub--c { animation-delay: 4.2s; }
.ed .ex-port .ex-port__tile { animation: ex-bp-travel 4.2s var(--ex-ease) .8s both; }
.ed .ex-port .ex-port__cap--1 { animation: ex-cap-pass 1.5s linear 1.2s both; }
.ed .ex-port .ex-port__cap--2 { animation: ex-cap-pass 1.5s linear 2.7s both; }
.ed .ex-port .ex-port__cap--3 { animation: ex-cap-stay .4s linear 4.2s both; }
.ed .ex-port.is-reset * { animation: none !important; }
@keyframes ex-hub-on { from { fill: var(--bg-page, #111312); stroke: var(--ed-rule-strong); } to { fill: color-mix(in srgb, var(--ed-accent) 22%, transparent); stroke: var(--ed-accent); } }
@keyframes ex-bp-travel {
  0% { opacity: 0; transform: translate(0, 0); }
  9% { opacity: 1; transform: translate(0, 0); }
  21% { transform: translate(0, 0); }
  45% { transform: translate(220px, 0); }
  57% { transform: translate(220px, 0); }
  81%, 100% { opacity: 1; transform: translate(440px, 0); }
}
@keyframes ex-cap-pass { 0% { opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { opacity: 0; } }
@keyframes ex-cap-stay { from { opacity: 0; } to { opacity: 1; } }

/* ---- Chapter 02: the unit strip under the model table ---------------------- */
.ed .ex-pickable { cursor: pointer; }
.ed .ex-pickable.is-picked > * { background: color-mix(in srgb, var(--ed-accent) 10%, transparent); }
.ed .ex-pickable:focus-visible { outline: 2px solid var(--ed-accent); outline-offset: -2px; }
.ed .ex-unit { display: grid; grid-template-columns: repeat(4, 1fr) 6px repeat(2, 1fr); gap: 4px; margin-top: .6rem; }
.ed .ex-unit__cell { display: flex; align-items: center; min-height: 0; padding: 5px 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: var(--font-mono); font-size: 11px; letter-spacing: .04em; line-height: 1.25; color: var(--ed-body); border: 1px solid var(--ed-rule-strong); transition: background-color 240ms var(--ex-ease), border-color 240ms var(--ex-ease), color 240ms var(--ex-ease), opacity 240ms var(--ex-ease); }
.ed .ex-unit__cell--gap { grid-column-start: 6; }
.ed .ex-unit__cell.is-e { background: var(--ed-accent); border-color: var(--ed-accent); color: var(--bg-page, #111312); }
.ed .ex-unit__cell.is-o { opacity: .35; border-style: dashed; }
.ed .ex-unit__say { margin-top: .35rem; min-height: 0; font-size: 12px; }

/* ---- Chapter 04: the rotator's timer line --------------------------------- */
.ed .ex-tick { height: 2px; background: var(--ed-rule); margin: 0 0 1rem; overflow: hidden; }
.ed .ex-tick span { display: block; height: 100%; width: 100%; background: var(--ed-accent); transform: scaleX(0); transform-origin: left; }
.ed .ex-tick.is-running span { animation: ex-tick 4200ms linear both; }
.ed .ex-tick.is-paused span { animation-play-state: paused; }
@keyframes ex-tick { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ---- Chapter 05: the pool teaser, gated like /onboard#ownership ------------ */
.ed .ex-pool { grid-column: 1 / -1; display: grid; gap: .7rem; max-width: 26rem; padding: 18px 20px; border: 1px solid var(--ed-rule-strong); }
.ed .ex-pool__head { display: flex; justify-content: space-between; gap: 12px; font-family: var(--font-mono); font-size: var(--ed-label); letter-spacing: .14em; text-transform: uppercase; color: var(--ed-quiet); }
.ed .ex-pool__stamp { color: var(--mo-warning); }
.ed .ex-pool__meter { display: grid; grid-template-columns: repeat(30, 1fr); gap: 2px; }
.ed .ex-pool__meter i { display: block; aspect-ratio: 1; border: 1px solid color-mix(in srgb, var(--ed-accent) 55%, transparent); }
.ed .ex-pool__meter i.is-g { background: var(--ed-accent); }
.ed .ex-pool__text { margin: 0; color: var(--ed-body); font-size: .95rem; }
@media (min-width: 768px) {
  .ed .ex-pool { grid-column: 1 / span 7; grid-row: 1; align-self: start; margin-top: clamp(4.5rem, 6.5vw, 6rem); }
}
@media (min-width: 960px) {
  .ed .ex-pool { grid-column: 1 / span 6; }
}

@media (prefers-reduced-motion: reduce) {
  .ed .ex-port .ex-port__hub, .ed .ex-port .ex-port__tile, .ed .ex-port [class*="ex-port__cap--"] { animation-delay: 0s !important; }
}

@media (max-width: 959px) {
  .ed .ex-port { margin-bottom: 1.75rem; }
}

/* ---- Chapter 05: the invitation cards show their titles; the descriptions
   are word for word on /onboard, one click away. ---------------------------- */
:root:not([data-variant="current"]) .ed-card--seat .ed-card__excerpt { display: none; }
