/* ===========================================================================
   ribbon.css — leaf 03's line-up as a curved carousel in space.

   THE HANDOVER IS EXPLICIT. band.css ships the line-up as a flat horizontal
   strip: a real `overflow-x: auto` scroller that works with JS off, with the
   keyboard, and under `prefers-reduced-motion`. Everything in this file is
   scoped to `.band--arc`, a class js/ribbon.js adds ONLY once it has decided to
   take the strip over. So the 3D is opt-in progressive enhancement — nothing
   here can strand the flat version, and there is no frame where absolutely
   positioned cards render without a driver.

   Geometry is written per-frame by js/ribbon.js into five custom properties per
   card (--rx / --rz / --ry / --rs / --ro). This file owns the stage, the
   surface treatment and the states. Loaded after band.css so it can take over.
   ======================================================================== */

/* The stage. `perspective` lives HERE, not on the cards: one viewpoint for the
   whole ring is what makes it read as a single curved object rather than nine
   separate cards each with their own vanishing point. */
.band--arc{
  position: relative;
  display: block;                 /* out of band.css's flex row */
  /* THE WHOLE ROW, not band.css's 62svh strip. In arc mode the title is pinned to
     the band's top edge, so every pixel the band gives up at the top is a pixel
     the title sits lower than it needs to — on a 900px window that was some 30px
     of nothing above the words. js/ribbon.js fits the ring to whatever height it
     is given, so the taller box also buys a bigger card at the centre. */
  height: 100%;
  /* CLIPPED ON BOTH AXES, and the bottom edge is now load-bearing: a card whose
     turn has not come waits BELOW it. Clipping is also what keeps that card out
     of the leaf's scroll height — clipped vertical reach used to grow the leaf a
     scrollbar for cards nobody could see yet. Clip is not scroll: nothing is
     unreachable, because every card rises to the centre in turn. */
  overflow: clip;
  padding-inline: 0;
  perspective: 1500px;
  perspective-origin: 50% 46%;
  transform-style: preserve-3d;
  /* The scrub is the scroll position now, so the native scroller stands down.
     Both are switched off together: a programmatic transform plus snap points
     would quantise a continuous sweep into steps. */
  scroll-snap-type: none;
  /* band.css grades the flat strip by progress; on the arc each card carries its
     own falloff, so the blanket filter would double up. */
  filter: none;
}

/* Every card is placed from the centre of the stage. `translate3d` first so it
   moves in the STAGE's space, then `rotateY` about the card's own centre, then
   the extra shrink — order is load-bearing. */
.band--arc .line-card{
  position: absolute;
  top: 50%;
  left: 50%;
  margin: 0;
  transform:
    translate3d(calc(-50% + var(--rx, 0px)), calc(-50% + var(--rv, 0px)), var(--rz, 0px))
    rotateY(var(--ry, 0deg))
    scale(var(--rs, 1));
  transform-origin: 50% 50%;
  opacity: var(--ro, 1);
  transition: none;               /* the clock writes every frame; never tween */
  will-change: transform;
  backface-visibility: hidden;
  scroll-snap-align: none;
}

.band--arc .line-card__plate{
  box-shadow:
    0 1px 0 rgba(27,29,33,.04),
    0 22px 48px -24px rgba(20,22,26,.45);
}

/* The card at the front of the arc is the one being read: it alone is full
   contrast, and its caption is fully present. */
.band--arc .line-card:not([data-front]) .line-card__plate img{
  filter: saturate(0.5) contrast(1.02) brightness(0.97);
}
.band--arc .line-card:not([data-front]) .line-card__range,
.band--arc .line-card:not([data-front]) .line-card__forms,
.band--arc .line-card:not([data-front]) .line-card__go{
  opacity: 0.55;
}
.band--arc .line-card[data-front] .line-card__plate{
  box-shadow:
    0 1px 0 rgba(27,29,33,.05),
    0 38px 76px -28px rgba(20,22,26,.55);
}
.band--arc .line-card__plate img,
.band--arc .line-card__range,
.band--arc .line-card__forms,
.band--arc .line-card__go{
  transition: filter var(--d-ground) var(--e-grade),
              opacity var(--d-ground) var(--e-grade);
}

/* Focus must not be lost inside a 3D transform. js/ribbon.js brings a focused
   card to the front of the arc; this is the ring that proves it arrived. */
.band--arc .line-card:focus-visible{
  outline: none;
  z-index: 200;
}
.band--arc .line-card:focus-visible .line-card__plate{
  outline: 2px solid var(--seal-blue);
  outline-offset: 4px;
}

/* --- no-3D and reduced-motion --------------------------------------------
   js/ribbon.js never adds `.band--arc` under `prefers-reduced-motion`, so the
   flat strip simply stays. This block is the belt to that brace: if the class
   is ever present when motion is not wanted, unwind every 3D declaration and
   fall back to band.css's scroller rather than leaving cards stacked at the
   centre of the stage. */
@media (prefers-reduced-motion: reduce){
  .band--arc{
    perspective: none;
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-inline: var(--card-pad);
  }
  .band--arc .line-card{
    position: relative;
    top: auto; left: auto;
    transform: none;
    opacity: 1;
    will-change: auto;
    scroll-snap-align: start;
  }
  .band--arc .line-card:not([data-front]) .line-card__plate img{ filter: none }
  .band--arc .line-card:not([data-front]) .line-card__range,
  .band--arc .line-card:not([data-front]) .line-card__forms,
  .band--arc .line-card:not([data-front]) .line-card__go{ opacity: 1 }
}

/* --- the label, out of the ring's way ------------------------------------
   In the flat strip the label panel and the closing index panel are two more
   items in the row. In arc mode the CARDS go absolute and the panels do not, so
   they stayed in flow at the top-left and the ring drew straight over them —
   the label read as if it were printed on the photographs. Pin the label into
   the leaf's top-left corner where it belongs, and retire the closing panel: its
   "view all lines" link moves up into the label, because at the end of the arc
   the reader is looking at the last card, not at a panel behind it.

   THE RESERVE IS NOT PADDING, AND USED TO BE. `padding-top` here did nothing at
   all: the cards are positioned from `top: 50%` of the PADDING box, so padding
   moved the ring by exactly zero and the enlarged centre card went on rising into
   the title anyway — it was 509px tall in a 461px stage, printed under the words
   at the top and cut off at "Explore line" along the bottom. js/ribbon.js now
   measures the label, sinks the ring by half its band and shrinks the ring until
   the front pose FITS what is left. Measured every re-layout, so it holds at every
   window size instead of at the one height a clamp was tuned on. */
/* Title and parenthetical on ONE baseline, across the whole top of the leaf. As a
   narrow block in the corner the parenthetical wrapped underneath and the enlarged
   centre card covered it; there is nothing to cover here. */
.band--lineup.band--arc .lineup__intro{
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 300;
  width: auto;          /* out of band.css's 200px flex column */
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  column-gap: clamp(0.6rem, 1.6cqw, 1.4rem);
  row-gap: 0.15em;
  pointer-events: auto;
}
/* Set to be read, not as a caption: this is the section's title. */
.band--lineup.band--arc .lineup__intro .label{
  margin: 0;
  font-size: min(clamp(1.15rem, 2.4cqw, 1.9rem), 4.4svh);
  line-height: 1.05;
}
.band--lineup.band--arc .lineup__intro .sub{
  margin-top: 0;
  max-width: none;
  font-size: min(clamp(0.8rem, 1.15cqw, 1rem), 2.2svh);
  line-height: 1.35;
}
.band--arc .lineup__all{ font-size: min(clamp(0.75rem, 1cqw, 0.9rem), 2svh) }
.band--lineup.band--arc .lineup__end{
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 300;
  width: auto;
}
.band--arc .lineup__end .body{ display: none }
.band--arc .lineup__end .lineup__all{ margin-top: 0 }

@media (prefers-reduced-motion: reduce){
  .band--arc .lineup__intro,
  .band--arc .lineup__end{ position: static; width: auto; z-index: auto }
  .band--arc .lineup__end .body{ display: block }
}


/* ===========================================================================
   testify — the mark on top, the reviews sweeping beneath it.

   Same grammar as the line-up arc above, and deliberately so: the quotes ride
   the same closed ring, left to right, turning and shrinking away from centre.
   The mark sits above them and turns for the whole leaf. Both are advanced from
   one place (js/cube.js) off this leaf's own progress, so the last quote lands
   as the turn completes.

   Written per-frame into --rx / --ry / --rs / --ro, exactly as ribbon.js does.
   ======================================================================== */

#body-07 .testify{
  position: relative;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  /* Both of these are capped against the window HEIGHT as well as the card
     width. On a wide, short window (1512x684) the gap and the top rail alone
     came to 73px and the leaf overran the card by 10px — a scrollbar's worth,
     which is the most conspicuous way to be 10px wrong. */
  row-gap: min(clamp(0.75rem, 2cqw, 2rem), 3.5svh);
  justify-items: center;
  width: 100%;
  height: 100%;
  min-height: 0;
  /* The whole composition sits down off the top rail: the mark was running into
     the card edge, and a 3D object clipped by its own frame reads as a mistake
     rather than as depth. */
  padding-top: min(clamp(1rem, 3cqw, 2.75rem), 4svh);
}
/* The mark is capped against the card HEIGHT as well as its width here, because
   this leaf has to hold the ring underneath it. */
#body-07 .testify .cube{
  grid-row: 1;
  justify-self: center;
  --cube-size: min(clamp(130px, 20cqw, 300px), 26svh);
}
#body-07 .testify__label{
  position: absolute;
  top: 0; left: 0;
  font-family: var(--f-label);
  font-size: var(--t-label);
  font-style: italic;
  color: var(--on-soft);
  margin: 0;
}

/* Without the driver this is a plain readable list — a no-JS or failed-JS
   visitor gets ten quotes they can read, not ten piled in one cell. */
#body-07 .testify__stack{
  grid-row: 2;
  list-style: none;
  margin: 0; padding: 0;
  min-width: 0;
  width: 100%;
  display: grid;
  gap: clamp(0.75rem, 1.8cqw, 1.5rem);
  grid-auto-flow: row;
  grid-auto-columns: auto;
  overflow: visible;
  scroll-snap-type: none;
}

/* --- driven: the ring ---------------------------------------------------- */
#body-07 .testify__stack--live{
  position: relative;
  display: block;
  gap: 0;
  height: 100%;
  perspective: 1600px;
  perspective-origin: 50% 45%;
  transform-style: preserve-3d;
}
#body-07 .testify__stack--live .review{
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(38ch, 34cqw, 420px);
  margin: 0;
  padding: clamp(0.7rem, 1.4cqw, 1.1rem);
  border: 1px solid var(--on-rule);
  border-radius: 2px;
  /* OPAQUE, and that is the point. Transparent cards let three quotes overlap
     into unreadable soup — the one at the front has to occlude the ones behind
     it. White rather than the plate colour so the card being read is the
     brightest thing on the leaf. */
  background: #fff;
  gap: var(--s-3);
  transform:
    translate3d(calc(-50% + var(--rx, 0px)), -50%, var(--rz, 0px))
    rotateY(var(--ry, 0deg))
    scale(var(--rs, 1));
  transform-origin: 50% 50%;
  opacity: var(--ro, 1);
  transition: none;
  will-change: transform, opacity;
  backface-visibility: hidden;
  pointer-events: none;
}
#body-07 .testify__stack--live .review[data-front]{ pointer-events: auto }
#body-07 .testify__stack--live .review blockquote p{
  font-size: clamp(0.95rem, 1.35cqw, 1.25rem);
  line-height: 1.32;
}
/* The quote at the centre is the one being read. */
#body-07 .testify__stack--live .review:not([data-front]) .who,
#body-07 .testify__stack--live .review:not([data-front]) .what{ opacity: 0.6 }
#body-07 .testify__stack--live .review[data-front]{
  box-shadow: 0 26px 60px -30px rgba(20,22,26,.5);
}

@media (max-width: 820px){
  #body-07 .testify .cube{ display: none }
}
@media (prefers-reduced-motion: reduce){
  #body-07 .testify__stack--live{ position: static; display: grid; height: auto; perspective: none; gap: clamp(0.75rem, 1.8cqw, 1.5rem) }
  #body-07 .testify__stack--live .review{
    position: relative; top: auto; left: auto;
    transform: none; opacity: 1; will-change: auto; pointer-events: auto;
  }
}
