/* ═══════════════════════════════════════════════════════════
   SCENE 04 — THE LEGACY TIMELINE

   Sits OVER the full-screen photograph the approach section left
   behind. It draws nothing of its own: the ground is that picture
   and the veil above it, which is why the veil exists at all.

   ABOVE THE PICTURE, NOT INSIDE IT. The picture is a fixed layer at
   z-index 5 (see .tv in core.css). This section is relative and
   above it, so it scrolls up over a background that stays put —
   which is the whole effect. Lower it under 5 and the section
   disappears behind the photograph.
   ═══════════════════════════════════════════════════════════ */

.tl {
  position: relative;
  z-index: 6;
  /* HOW MANY YEARS ARE ON THE AXIS. Declared here rather than in
     the script so the breakpoints below can change it — the count
     is a layout decision, and layout decisions belong to CSS.
     js/sections/timeline.js reads this and sizes the track's
     columns from it, so there is still only one number. */
  --tl-window: 4;
  /* TRANSPARENT, AND THAT TAKES TWO DECLARATIONS. .scene paints
     var(--paper) on every section — which is right for every other
     one and fatal here: the section is above the fixed photograph
     in the stacking order, so its own ground covered the picture
     and the timeline arrived on white paper instead of on the
     image. The stage below needs the same, for the same reason. */
  background: transparent;

  /* PULLED UP BY ONE SCREEN, so it begins exactly where the
     photograph finishes opening.

     The approach section's last viewport of scroll is the stage
     sliding off the top. Nothing is drawn on it by then — the copy
     has faded and the picture is fixed behind it — so it was a full
     screen of scrolling with nothing happening, and the timeline
     only pinned afterwards. That is what read as the content
     arriving after the background section instead of on it.

     Overlapping that dead screen costs nothing and buys the join:
     the image reaches full size and the axis starts drawing on the
     same scroll. */
  margin-top: -100svh;
}

.tl-stage {
  /* NO BACKGROUND. The photograph is the background. Painting
     anything here, even the page's own paper, hides it. */
  background: transparent;
  color: var(--paper);
  display: grid;
  /* ONE ROW THAT FILLS THE STAGE. align-content:space-between here
     sizes the row to its content and leaves the section stacked at
     the top with the bottom half empty — the spreading has to
     happen INSIDE the row, not to it. */
  grid-template-rows: 1fr;
  /* ROOM FOR THE ACTIVE YEAR TO GROW. It scales up from its own
     baseline, so the selected year rises above the row by the whole
     difference — at 4rem it came up level with the logo and the two
     gold marks read as one thing. */
  padding: calc(var(--header-h) + 8.5rem) 0 6rem;
}

/* The axis at the top, the foot at the bottom, the arrows just
   under the axis where they belong to it. */
.tl-inner {
  grid-template-rows: auto auto 1fr;
  align-content: stretch;
  row-gap: 2.4rem;
}
.tl-foot { align-self: end; }

/* ── The axis ────────────────────────────────────────────
   Years along a rule, the way a drawing carries a datum line. The
   rule is the spine of the section and everything else hangs off
   what is selected on it. */
.tl-axis {
  grid-column: content;
  position: relative;
  align-self: start;
}

/* A WINDOW, NOT THE WHOLE ROW. Only a few years are on the axis at
   once; the arrows slide the rest into view. Eight years across one
   screen gave each of them a fifth of the room it needed, and the
   active one had nowhere to grow into.

   The column width comes from js/sections/timeline.js, which also
   does the sliding — one source for how many years are visible, so
   the track cannot be sized for four and slid by five. */
/* clip, NOT hidden, and only on one axis. The window has to cut the
   years that are off to the side, but the SELECTED year grows
   upward out of the row — with overflow:hidden that growth was
   sliced off and the active year lost its top half. overflow:hidden
   also cannot be one-sided: pairing it with overflow-y:visible
   silently computes to auto and hangs a scrollbar off the axis.
   overflow-x:clip is the one that may keep visible on the other
   axis, which is exactly what is needed here. */
.tl-axis { overflow-x: clip; overflow-y: visible; }
.tl-years {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--tl-col, 25%);
  align-items: end;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* SIZED TO THE NUMBER, not to the column. The column is a quarter
   of the axis and the year sits at its left edge, so anything
   centred on the column landed nowhere near the digits. Shrinking
   the item to its own text means the tick below can simply be
   centred on it.

   IT ALSO OWNS THE ENTRANCE. The item's opacity is the year
   arriving and belongs to the scroll; the button's opacity is
   whether it is the selected year and belongs to the arrows. Two
   owners, two elements — see the note in js/sections/timeline.js. */
.tl-item { position: relative; width: max-content; }

.tl-year {
  display: block;
  width: 100%;
  padding: 0 0 1.6rem;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font-family: var(--font-sans);
  /* 400, not 300. A light weight at this size is fine on paper and
     thin on a photograph, where there is texture behind every
     stroke. */
  font-weight: 400;
  /* The inactive size. The active year grows out of this rather
     than being a separate style, so the change reads as one year
     stepping forward and not as two different labels. */
  font-size: 5.45rem;
  line-height: 1;
  letter-spacing: .01em;
  /* The RESTING state of a year that has arrived and is not
     selected. Arriving is the ITEM'''s business (see above), so this
     is never zero — a year at zero here could not be brought back
     by the arrows. */
  opacity: .78;
  color: #fff;
  /* SCALED, NOT RESIZED. Growing the active year by font-size
     reflows the whole row on every frame of the transition, and
     because the row is a grid of equal columns the neighbours shift
     while it happens. A transform costs no layout at all and the
     year grows out of its own baseline, which is also what makes it
     read as one year stepping forward rather than as a label being
     swapped for a bigger one. */
  transition:
    color .55s var(--ease),
    opacity .55s var(--ease),
    transform .55s var(--ease-arch);
  transform-origin: left bottom;
}
/* Revealed by the entrance — see js/sections/timeline.js. Held at
   zero until then so the axis is empty when the section arrives. */
.tl-year:hover { opacity: 1; }

/* THE LOGO'''S SWEEP, PAINTED INTO THE DIGITS. At this size there is
   enough ink for the gradient to read, and the selected year is the
   one place on the page where the brand's gold should be the actual
   brand gold rather than an approximation of it. background-clip
   means the sweep IS the numerals; a gold box behind them would be
   a highlight, which is a different thing. */
.tl-year.is-active {
  opacity: 1;
  /* ~6.89rem against a 5.45rem base — both raised by the same 5px
     again, so the absolute gap between a selected year and its
     neighbours is unchanged and only the ratio moves.

     THAT RATIO IS NOW 1.26x, DOWN FROM 2.08x when this was built.
     Size has almost stopped being what marks the current year; the
     gold and the weight are carrying it. It still reads at a glance
     because the colour does the work — but one more step of this
     and the two sizes are the same thing, and the ratio should be
     retired in favour of a mark that does not shrink: a rule under
     the year, or a heavier cut. */
  transform: scale(1.264);
  color: var(--gold-lift);
  font-weight: 500;
}

/* The rule the years sit on, and the gold length of it that has
   been reached. Two elements rather than one with a gradient: the
   travelled part has to be able to stop at an exact tick. */
.tl-rail {
  position: relative;
  display: block;
  height: var(--hair);
  background: rgba(255, 255, 255, .28);
  /* Drawn left to right by the entrance. */
  transform: scaleX(0);
  transform-origin: left center;
}
.tl-rail i {
  position: absolute;
  inset: 0 auto 0 0;
  display: block;
  width: 100%;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left center;
}

/* A tick under each year, on the rule. */
/* Centred under the digits. The item is sized to its own text (see
   above), so 50% of it is the middle of the number rather than the
   middle of a quarter-width column the number sits at one end of. */
.tl-tick {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  width: var(--hair);
  height: 1.1rem;
  background: rgba(255, 255, 255, .45);
  /* Visible with its year. It used to be revealed by the same class
     that lit the year, and when that class went the tick had
     nothing left to turn it on — the axis drew with no ticks at
     all. The item'''s opacity carries it now, like everything else
     in the column. */
  transition: background .5s var(--ease), height .5s var(--ease);
}
.tl-year.is-active + .tl-tick { background: var(--gold); height: 1.8rem; }

/* ── The arrows ──────────────────────────────────────────
   Under the right end of the rule, where the reference set them —
   the controls belong to the axis, not to the card. */
.tl-nav {
  grid-column: content;
  justify-self: end;
  display: flex;
  gap: .6rem;
  /* CLEAR OF THE RULE. At -2.4rem they cancelled the row gap and sat
     hard against the axis line, which read as part of it rather
     than as a control beside it. */
  margin-top: 1.2rem;
}
/* WHITE, AND SOLID ENOUGH TO FIND. A hairline at 30% white is
   legible on a flat dark ground and disappears on a photograph —
   half of this one is a bright marble floor. These are the only
   control in the section, so they get a full white edge and a
   little ground of their own to sit on rather than relying on
   whatever happens to be behind them. */
.tl-arrow {
  width: 5.2rem;
  height: 5.2rem;
  display: grid;
  place-items: center;
  border: var(--hair) solid rgba(255, 255, 255, .85);
  border-radius: 100vmax;
  background: rgba(19, 25, 38, .3);
  color: #fff;
  cursor: pointer;
  transition: border-color .4s var(--ease), background .4s var(--ease),
              color .4s var(--ease), opacity .4s var(--ease);
}
/* ── The travelling glyph ────────────────────────────────
   The arrow leaves in the direction it points and its replacement
   arrives behind it, rather than the button simply changing colour.
   It is the one flourish on the only control in the section, and it
   says which way the axis is about to move before it moves.

   ONE TRANSITION ON ONE ELEMENT. The pair slides together, so a
   visitor sweeping across the arrows fast reverses a single
   property instead of interrupting a sequence — the same reason
   the menu's per-letter roll had to go. */
.tl-arrow-slot {
  display: block;
  width: 2.1rem;
  height: 2.1rem;
  overflow: hidden;
  position: relative;
}
.tl-arrow-slot svg {
  position: absolute;
  top: 0;
  width: 2.1rem;
  height: 2.1rem;
  display: block;
  stroke-width: 1.9;
  transition: transform .5s var(--ease-arch);
}
/* The visible one, and the one waiting off the other side. */
.tl-arrow-slot svg:first-child { left: 0; }
.tl-arrow-slot svg:last-child  { left: 0; }

[data-prev] .tl-arrow-slot svg:last-child { transform: translateX(100%); }
[data-next] .tl-arrow-slot svg:last-child { transform: translateX(-100%); }

@media (hover: hover) {
  [data-prev]:not([disabled]):hover .tl-arrow-slot svg:first-child { transform: translateX(-100%); }
  [data-prev]:not([disabled]):hover .tl-arrow-slot svg:last-child  { transform: translateX(0); }
  [data-next]:not([disabled]):hover .tl-arrow-slot svg:first-child { transform: translateX(100%); }
  [data-next]:not([disabled]):hover .tl-arrow-slot svg:last-child  { transform: translateX(0); }
}
.tl-arrow:hover { border-color: var(--gold); color: var(--gold); background: rgba(19, 25, 38, .5); }
/* Disabled rather than hidden at the ends — a control that vanishes
   makes the row jump, and the visitor loses the pair. */
.tl-arrow[disabled] { opacity: .3; cursor: default; }
.tl-arrow[disabled]:hover { border-color: rgba(255, 255, 255, .85); color: #fff; background: rgba(19, 25, 38, .3); }

/* ── The foot ────────────────────────────────────────────
   The claim and its way out on the left; the selected year's story
   on the right. */
.tl-foot {
  grid-column: content;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  align-items: end;
}

/* Wide enough for two lines AT THIS SIZE. It has been 22ch and
   34ch; both were set against a smaller title and both broke the
   claim into a stack the moment the type grew. If the title size
   changes again, this is the number that has to move with it. */
.tl-lead { max-width: 42ch; }
.tl-title {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 4.55rem;
  /* 1.26, not 1.12. At the tighter setting the descenders of the
     first line ran into the capitals of the second — fine for a
     display line set once, wrong for a two-line sentence, and
     worse here because it is set in white over a photograph, where
     the eye has less to separate the rows with. */
  line-height: 1.26;
  letter-spacing: -.018em;
  margin-bottom: 2.8rem;
}

/* ── The card ────────────────────────────────────────────
   STACKED, NOT REWRITTEN. Every year's copy is real markup sitting
   in the same grid cell; changing year crossfades between them.
   Writing text into one shared element would have meant the copy
   lived in the script instead of the page — worse to read, worse
   for a screen reader, and the first thing to break when this
   becomes a CMS field. */
.tl-cards {
  display: grid;
  justify-self: end;
  width: 100%;
  max-width: 46rem;
}
/* STACKED AND BOTTOM-ALIGNED. Every year's panel occupies the same
   cell, so the box is as tall as the LONGEST story — and a shorter
   one sat at the top of that box, floating clear of the button it
   is supposed to line up with. Aligning them to the end puts every
   panel's last line on the same baseline whatever its length. */
.tl-panel {
  grid-area: 1 / 1;
  align-self: end;
  opacity: 0;
  visibility: hidden;
}
.tl-panel.is-active { opacity: 1; visibility: visible; }

.tl-panel-ico {
  display: block;
  width: 3.75rem;
  height: 3.75rem;
  margin-bottom: 1.8rem;
  color: var(--gold-lift);
}
.tl-panel-ico svg { width: 100%; height: 100%; display: block; }

.tl-panel-title {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 3.1rem;
  line-height: 1.2;
  letter-spacing: -.008em;
  padding-top: 1.8rem;
  border-top: var(--hair) solid rgba(255, 255, 255, .28);
  margin-bottom: 1.2rem;
}
.tl-panel-body {
  font-family: var(--font-sans);
  font-size: 2.1rem;
  font-weight: 400;
  line-height: 1.62;
  color: rgba(255, 255, 255, .82);
}
/* ── Responsive ────────────────────────────────────────────
   THE NUMBER OF YEARS ON THE AXIS IS THE FIRST DECISION, and every
   size here follows from it. Four years want a wide screen; three
   fit a tablet; two are all a phone can carry without the selected
   year running into its neighbour. --tl-window carries that count
   to the script, which sizes the columns and slides the track.

   These three blocks had drifted badly — a stale 1.8rem left over
   from an earlier size was still overriding the tablet, so the
   years rendered smaller there than on a phone. One size per
   breakpoint now, each one stated once. */
@media (max-width: 1200px) {
  .tl-year  { font-size: 4.6rem; }
  .tl-title { font-size: 3.9rem; }
}

@media (max-width: 991px) {
  /* Three on a tablet. */
  .tl { --tl-window: 3; }

  .tl-stage { padding: calc(var(--header-h) + 6rem) 0 4.5rem; }
  .tl-year  { font-size: 4rem; }
  .tl-title { font-size: 3.4rem; }

  /* ── The stack ────────────────────────────────────────
     Side by side, the claim and the card share the bottom of the
     screen. Stacked, they cannot: the card belongs WITH the axis —
     it is the selected year's story and reading it means looking
     from one to the other — while the claim and its button are
     where the section ends.

     display:contents dissolves the foot so both become rows of the
     section's own grid, which is what lets the card sit directly
     under the years and the claim drop to the bottom with the
     empty space between them rather than after them. As two
     children of one wrapper they could only ever be adjacent. */
  .tl-inner { grid-template-rows: auto auto auto 1fr; }
  .tl-foot  { display: contents; }

  /* ROWS STATED, NOT INHERITED FROM THE DOM. The claim comes first
     in the markup because that is its reading order on a wide
     screen; dissolved into this grid it would land above the card,
     which is the opposite of what the stack needs. */
  .tl-cards {
    grid-row: 3;
    grid-column: content;
    justify-self: start;
    max-width: 52rem;
    margin-top: 3rem;
  }
  .tl-lead {
    grid-row: 4;
    grid-column: content;
    align-self: end;
    max-width: none;
    margin-top: 4rem;
  }
}

@media (max-width: 767px) {
  /* Two on a phone. At three the selected year — half again the
     size of the others — has nowhere to grow into. */
  .tl { --tl-window: 2; }

  .tl-stage { padding: calc(var(--header-h) + 5rem) 0 3.5rem; }
  .tl-year  { font-size: 3.4rem; }
  .tl-title { font-size: 2.8rem; margin-bottom: 2rem; }

  .tl-panel-title { font-size: 2.2rem; }
  .tl-panel-body  { font-size: 1.7rem; }
  .tl-panel-ico   { width: 2.8rem; height: 2.8rem; margin-bottom: 1.4rem; }
  .tl-cards       { margin-top: 2.4rem; }

  /* RIGHT, not left. The arrows move the axis forward, and the axis
     runs left to right — a control for going onward belongs at the
     end of the thing it moves, not in front of it. */
  .tl-nav   { margin-top: 1.4rem; justify-self: end; }
  .tl-arrow { width: 4.6rem; height: 4.6rem; }
}
/* ── The runway ──────────────────────────────────────────
   The scroll that draws the axis, plus a hold after it so the
   visitor can actually use the arrows without the section leaving
   under them. The entrance occupies the first ~74% (see BEATS in
   js/sections/timeline.js); the rest is that hold. */
/* The entrance uses roughly the first three quarters of this; the
   rest is a hold on the finished axis before the section starts to
   leave. 180vh, up from 150 — the years were complete and the
   section was already on its way out, so there was nowhere to just
   look at them. */
.tl-runway { height: 180vh; }

/* ── Frozen, for review ──────────────────────────────────
   ?timeline= sets this. Everything on the axis reaches its state
   through a CSS transition, and a headless capture does not advance
   transitions — so a frozen frame showed the classes correctly
   applied and every one of them still painting its starting value:
   an empty axis that looked like a broken section. Killing the
   transitions makes the captured frame the real one.

   Review-only, scoped to this section, and unreachable without the
   parameter. */
.tl.is-frozen *,
.tl.is-frozen *::before,
.tl.is-frozen *::after { transition: none !important; }

/* ── The button ──────────────────────────────────────────
   Solid white by default, exactly as the header's CTA is and for
   the same reason: this is the one action in the section and it
   sits on a photograph, where an outline pill reads as secondary
   and loses its edge against whatever is behind it.

   .on-dark gives every button a light border and paper text, which
   is right for a button on a flat dark ground and wrong for one on
   an image — so this has to override it rather than inherit it.
   Hover goes gold, the same gesture the header uses, so the two
   buttons on screen behave identically. */
.tl .btn {
  background: var(--paper);
  border-color: var(--paper);
  color: var(--ink);
}
.tl .btn::before { background: var(--gold-grad); }
.tl .btn:hover { color: var(--ink); border-color: var(--gold); }

/* ── The logo's gold, painted into the selected year ─────
   At this size there is enough ink for the mark's own sweep to
   read, and the current year is the one place on the page where the
   brand gold should be the actual brand gold rather than a flat
   approximation of it. background-clip means the sweep IS the
   numerals; a gold box behind them would be a highlight, which is a
   different thing entirely.

   THE GRADIENT IS ON EVERY YEAR, ALWAYS. Only the fill changes —
   white when the year is one of the row, transparent when it is the
   selected one, which lets the gradient through. Putting the
   gradient on .is-active instead meant the change from white to
   gold could not transition at all: text-fill-color:transparent
   cancels the colour property it would have animated, so the year
   snapped. Fading the fill out over the gradient underneath is the
   same effect with the transition intact.

   Guarded, because without background-clip:text a transparent fill
   is an invisible year rather than a gold one. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .tl-year {
    background-image: var(--gold-grad);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: #fff;
    transition:
      -webkit-text-fill-color .55s var(--ease),
      opacity .55s var(--ease),
      transform .55s var(--ease-arch);
  }
  .tl-year.is-active { -webkit-text-fill-color: transparent; }
}

@media (max-width: 991px) {
  /* NO GROUND HERE. The photograph is .ground in core.css — one
     fixed element behind both this section and the approach above
     it, so neither can crop it differently and neither arrives
     carrying its own copy. This section is transparent above it.

     It is still pulled up a screen (see .tl at the top of this
     file) so its stage takes over exactly as the approach's pin
     releases: the claims have finished fading, and the years come
     up in their place over a photograph that never moved. */
  .tl-inner { position: relative; z-index: 1; }
}

@media (max-width: 991px) {
  /* NO RUNWAY, SO NOTHING TO SCROLL THROUGH.

     A runway exists to give a scrubbed entrance somewhere to
     happen. At this width the entrance is played rather than
     scrubbed — see js/sections/timeline.js — so a runway would be
     pure dead scroll: a screen and a half of holding a finished
     section.

     Without it the section is exactly one screen, and because it is
     pulled up by one (see .tl above) it begins where the approach's
     pin releases and ends with the page. So the years arrive, draw
     themselves, and there is nothing left to scroll. */
  /* THE SAME HEIGHT AND THE SAME TOP AS THE APPROACH SECTION.

     Pulled up by a screen plus the shared tail, this section starts
     where that one does and is exactly as tall — so both stages pin
     over the same range and their content occupies the same box.
     Nothing slides in; one block fades out and the other fades in,
     in place. */
  .tl { margin-top: calc(-100svh - var(--fx-tail)); }
  .tl-runway { height: var(--fx-tail); }
}
