/* ==========================================================================
   Feature story deck
   ==========================================================================
   Shared frame for every scroll-led story that turns: three narrative beats
   scroll past a stage that stays put, and the beat on the reading line is the
   view the deck turns to the front. The copy column wears the family's story
   grammar (StoryScaffold.css); this file owns the beat rhythm, the sticky
   stage, the ring the views are set on, the pager, and how the whole thing
   re-cuts itself on a phone.

   What is ON the deck is never here: a ring of phone renders on the advice
   turntable, a deck of built panels on the meeting-prep sources. A section
   brings its own light, its own views and its own three hues, and tunes the
   ring through the custom properties named below.

   The turn itself is driven by `initStoryDeck` (Features/shared/runtime.js),
   which writes `data-position` on each view and `is-enhanced` on the section
   while the deck — rather than the stacked sequence — is the thing driving.
   ========================================================================== */

.feat-deck {
  /* The scaffold's copy grammar reads its accent from these two; a deck is a
     violet story like the rest of the family. */
  --story-accent: var(--feat-violet-soft);
  --story-accent-rgb: 169, 144, 255;
  --deck-turn: 950ms;
  --deck-ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* How far the two views behind sit, how small they are drawn, and how they
     are dimmed. A section whose views are live markup rather than photographs
     needs more of all three — see the ring below. */
  --deck-back-x: 40%;
  --deck-back-scale: 0.42;
  --deck-back-right-filter: brightness(0.58);
  --deck-back-left-filter: brightness(0.5);
  position: relative;
  /* Sticky descendants must keep the page itself as their scroll container. */
  overflow: visible;
}

.feat-deck__layout {
  display: grid;
  /* The stage takes the larger share: the views are the section's subject. */
  grid-template-columns: minmax(27rem, 1.25fr) minmax(0, 0.85fr);
  gap: clamp(2.25rem, 4vw, 4.5rem);
  align-items: start;
}

/* --- Three scroll beats -------------------------------------------------- */

.feat-deck__copy {
  min-width: 0;
}

/* One viewport per beat, the last one included. The reserve is not decoration:
   a beat is "settled" when its own centre reaches the reading line (the middle
   of the viewport, see createBeatPager in runtime.js), and it can only get
   there if the column keeps scrolling for half a viewport underneath it.
   Shorten the last beat and the section hands over while it is still on its way
   up — it lights as active, but its copy never centres and the deck is already
   leaving. */
.feat-deck__step {
  display: grid;
  align-items: center;
  min-height: 92svh;
  padding: clamp(4rem, 10vh, 7rem) 0;
}

.feat-deck__step-inner {
  max-width: 34rem;
  transition:
    opacity 420ms ease,
    transform 620ms cubic-bezier(0.16, 1, 0.3, 1);
}

.feat-deck.is-enhanced .feat-deck__step:not(.is-active) .feat-deck__step-inner {
  opacity: 0.28;
  transform: translateY(1.6rem);
}

.feat-deck__step-count {
  display: flex;
  gap: 0.8rem;
  align-items: center;
  margin: 0 0 1.1rem;
  color: rgba(225, 220, 247, 0.5);
  font-family: var(--feat-mono);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.14em;
}

.feat-deck__step-count::after {
  width: 2.8rem;
  height: 1px;
  background: var(--feat-line);
  content: '';
}

/* --- Where a deck story departs from the shared grammar ------------------- */

/* One notch tighter than the scaffold default: three headlines must each fit a
   viewport in the narrow column left by the stage. */
.feat-deck .feat-story__title {
  font-size: var(--feat-title-deck-size);
}

/* The accent rides the sitewide title gradient; the scaffold's own violet→cyan
   ramp belongs to the banded story sections. `background-image`, never the
   `background` shorthand: the shorthand resets background-clip to border-box
   and the scaffold's `background-clip: text` would be wiped, painting the
   gradient as a solid block behind the words. */
.feat-deck .feat-story__title-accent {
  background-image: var(--brand-title-gradient);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Forced colours remove the gradient these words are painted with, and the
   glyphs are transparent without it. Give the system its own ink back. */
@media (forced-colors: active) {
  .feat-deck .feat-story__title-accent {
    color: CanvasText;
    background: none;
  }
}

/* --- The sticky stage ----------------------------------------------------- */

.feat-deck__visual {
  position: sticky;
  top: clamp(5.8rem, 9vh, 7.5rem);
  z-index: 2;
  height: calc(100svh - clamp(6.5rem, 11vh, 9rem));
  min-height: 40rem;
  max-height: 56rem;
  margin: 0;
}

.feat-deck__stage {
  position: relative;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  width: 100%;
  height: 100%;
}

/* No `isolation` here: a section whose views are glass reads the page through
   them, and a backdrop root would leave them nothing to pick their colour up
   from. Sections that need one declare it themselves. */
.feat-deck__scene {
  position: relative;
  min-height: 0;
}

/* --- Ring positions -------------------------------------------------------
   The transform keeps one fixed function list so every swap interpolates
   smoothly. z-index is in the transition on purpose: integer interpolation
   makes the incoming view overtake the outgoing one mid-turn.

   The recede is tuned through the `--deck-back-*` properties above rather than
   overridden per section: `filter` and `transform` are the two things the
   stacked layout has to take back, and they are only guaranteed to be taken
   back if every declaration of them lives in this sheet. A section states its
   own WIDTH, which is its own business at any width. */
.feat-deck__slot {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate3d(calc(-50% + var(--pos-x)), calc(-50% + var(--pos-y)), 0)
    rotate(var(--pos-rz)) scale(var(--pos-s));
  transform-origin: 50% 54%;
  transition:
    transform var(--deck-turn) var(--deck-ease),
    filter var(--deck-turn) var(--deck-ease),
    z-index var(--deck-turn) var(--deck-ease);
}

.feat-deck__slot[data-position='front'] {
  --pos-x: 0%;
  --pos-y: 0%;
  --pos-rz: 0deg;
  --pos-s: 1;
  z-index: 3;
  filter: none;
}

.feat-deck__slot[data-position='back-right'] {
  --pos-x: var(--deck-back-x);
  --pos-y: -6%;
  --pos-rz: 2.2deg;
  --pos-s: var(--deck-back-scale);
  z-index: 2;
  filter: var(--deck-back-right-filter);
}

.feat-deck__slot[data-position='back-left'] {
  --pos-x: calc(-1 * var(--deck-back-x));
  --pos-y: -6%;
  --pos-rz: -2.2deg;
  --pos-s: var(--deck-back-scale);
  z-index: 1;
  filter: var(--deck-back-left-filter);
}

/* --- Pill pager ------------------------------------------------------------ */

.feat-deck__pager {
  position: relative;
  z-index: 4;
  display: flex;
  gap: 0.1rem;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
}

/* The button keeps a usable touch target; the visible dot stays small, so the
   three sit close together. */
.feat-deck__pill {
  display: grid;
  width: 1.55rem;
  height: 2.2rem;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  place-items: center;
}

/* App-style pagination: resting views are dimmed dots, the active one stretches
   into a capsule. No glow — the colour alone carries the state, and the three
   hues are the section's own. */
.feat-deck__pill::before {
  width: 0.42rem;
  height: 0.42rem;
  border-radius: var(--feat-radius-pill);
  content: '';
  opacity: 0.4;
  transition:
    width 320ms var(--deck-ease),
    opacity 260ms ease;
}

.feat-deck__pill:hover::before {
  opacity: 0.75;
}

.feat-deck__pill.is-active::before {
  width: 1.25rem;
  opacity: 1;
}

.feat-deck__pill:focus-visible {
  outline: 2px solid var(--feat-text);
  outline-offset: -0.3rem;
}

/* --- Stacked: no deck at all -----------------------------------------------
   A phone screen cannot hold three views AND a paragraph, so the story is
   re-cut as a sequence: claim, then view, three times. Each beat says its piece
   and hands over to its own view, shown whole and as wide as the measure
   allows. The sticky stage, the ring and the pager all go — none of them means
   anything once there is one view per beat.

   Mechanically this is one flex column. `display: contents` dissolves the three
   wrappers the desktop composition needs (the sticky figure, the stage and the
   copy column) so the views and the beats become siblings, and `order`
   interleaves them. Nothing about the markup or the desktop layout changes.

   Motion: the views arrive on the sitewide scroll reveal, which the section's
   script hooks up for this layout only. With no JS at all there is no
   `scroll-observer-prepared` marker, so nothing is held back and every view is
   simply already there.
   ========================================================================== */

@media (max-width: 960px) {
  .feat-deck {
    /* The views and the copy do not read at the same width; a section that
       needs other measures overrides these two. */
    --deck-copy-w: min(100%, 34rem);
    --deck-view-w: min(100%, 30rem);
    /* A beat holds together and the next one stands clear: the copy sits near
       its own view, the pair sits far from the following one. */
    --deck-pair-gap: clamp(1.9rem, 5.5vw, 2.6rem);
    --deck-beat-gap: clamp(3.5rem, 11vw, 5.5rem);
  }

  .feat-deck__layout {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
  }

  /* The desktop composition's shells step out of the way so their contents can
     interleave: three views and three beats, alternating. */
  .feat-deck__visual,
  .feat-deck__stage,
  .feat-deck__scene,
  .feat-deck__copy {
    display: contents;
  }

  /* A ring's furniture: a pager for views that no longer turn, and the stage
     light, positioned against a stage that no longer exists. */
  .feat-deck__pager,
  .feat-deck__halo,
  .feat-deck__floor {
    display: none;
  }

  /* Claim, then view. The pairs are spelled out because CSS cannot derive an
     order from an index; a deck is a three-beat structure by contract (its
     script refuses to run on any other count), so a fourth pair would be a
     change of shape here and there. */
  .feat-deck__step[data-step-index='0'] {
    order: 1;
  }

  .feat-deck__slot[data-slot-index='0'] {
    order: 2;
  }

  .feat-deck__step[data-step-index='1'] {
    order: 3;
  }

  .feat-deck__slot[data-slot-index='1'] {
    order: 4;
  }

  .feat-deck__step[data-step-index='2'] {
    order: 5;
  }

  .feat-deck__slot[data-slot-index='2'] {
    order: 6;
  }

  /* --- The beat ----------------------------------------------------------- */

  .feat-deck__step {
    display: block;
    width: var(--deck-copy-w);
    min-height: 0;
    padding: 0;
    margin: 0 0 var(--deck-pair-gap);
  }

  /* The measure is the beat's own here, not a column's share of the layout.
     (The dimming of the beats the reader is not on is not switched off in this
     sheet: the script only marks a section enhanced while the deck is the one
     driving.) */
  .feat-deck__step-inner {
    max-width: none;
  }

  /* The scaffold reshapes its own type inside a .feat-stories band only, so the
     borrowed copy grammar keeps its desktop scale here unless it is restated. */
  .feat-deck .feat-story__title {
    font-size: var(--feat-title-deck-size-mobile);
    letter-spacing: -0.058em;
    line-height: 1.02;
  }

  .feat-deck .feat-story__body {
    margin-top: 1.15rem;
    font-size: 1rem;
    line-height: 1.64;
  }

  .feat-deck .feat-story__notes {
    margin-top: 1.5rem;
  }

  /* --- The view ----------------------------------------------------------- */

  /* The scroll still names a view "front" and the other two "back": that is the
     ring's vocabulary, and the ring is gone. Every state it dresses — the
     recede transform, the dimming, the stacking order — has to be undone at the
     same specificity, or a view darkens on its way past the reading line. Kept
     on [data-position] so it outranks the ring's own rules. */
  .feat-deck__slot[data-position] {
    position: relative;
    top: auto;
    left: auto;
    width: var(--deck-view-w);
    min-height: 0;
    margin: 0 0 var(--deck-beat-gap);
    z-index: auto;
    opacity: 1;
    filter: none;
    transform: none;
    /* The ring's turn is not this layout's motion: what a view does here is
       arrive once, on the sitewide reveal's own tokens — and on nothing at all
       when the hooks are absent, since the two element-level properties resolve
       to unset, which is what a page without JS wants. Every declaration here
       sits under the shared contract's specificity, so the hidden state still
       wins while the element waits for .is-visible. */
    transition:
      opacity var(--animation-duration) var(--scroll-reveal-easing-opacity) var(--animation-delay),
      transform var(--animation-duration) var(--scroll-reveal-easing-transform)
        var(--animation-delay);
  }

  .feat-deck__slot:last-child {
    margin-bottom: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .feat-deck__slot,
  .feat-deck__step-inner,
  .feat-deck__pill::before {
    transition: none;
  }
}
