/* =========================================================
   PANTRY principle section
   Part 1: pinned image comparison. Part 2: column wipe to dark.
   Part 3: horizontal statement. All three share one pinned stage.
   Motion lives in scripts/principle.js. Every value comes from tokens.css.
   ========================================================= */

.section.principle {
  padding: 0;
}

/* ---------- Pinned stage ----------
   One track holds the swap, the wipe and the statement. JS sets its
   height from the statement's width; this is the fallback. */

.principle-track {
  position: relative;
  height: calc(var(--compare-scroll) + var(--wipe-scroll) + var(--statement-hold) + var(--stage-height) * 2);
}

/* Once the wipe is done, the whole track is ink: nothing light shows
   between the bars or below the stage. */
.principle-track.is-dark {
  background: var(--color-ink);
}

/* Invisible boxes JS reads to turn the scroll lengths into px. */
.distance {
  position: absolute;
  top: 0;
  width: 0;
  visibility: hidden;
}

.distance--compare {
  height: calc(var(--compare-scroll) - var(--stage-height));
}

.distance--wipe {
  height: var(--wipe-scroll);
}

.distance--hold {
  height: var(--statement-hold);
}

.principle-stage {
  position: sticky;
  top: 0;
  height: var(--stage-height);
  display: flex;
  align-items: center;
  overflow: clip;
}

.grid-12.compare-grid {
  row-gap: 0;
}

.compare-figure {
  margin-top: var(--space-label-title);
  /* Title, frame and caption sit on rows shared by both figures, so the
     frames stay level when one title wraps to two lines. */
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
}

/* A figure is two bays wide on desktop (one below that). The title is a
   big heading, so like a wide cell it spans the whole figure and the line
   runs behind it. From tablet up both titles break before the last word,
   so "chooses." sits on the same row in both. On mobile they wrap freely. The frame is an image: it
   fills both bays and the line runs behind it too. */
.compare-title {
  padding-inline: var(--cell-pad);
  margin-bottom: var(--space-16);
}

@media (min-width: 640px) {
  .compare-title-end {
    display: block;
  }
}

.compare-frame {
  position: relative;
  align-self: start;
  margin-inline: var(--cell-pad);
  aspect-ratio: var(--compare-frame-ratio);
  max-height: calc(var(--stage-height) - var(--compare-chrome));
  overflow: hidden;
  background: var(--color-surface-subtle);
  border: var(--line-width) solid var(--color-rule);
  border-radius: var(--radius);
}

/* All slides sit on top of each other; only the active one shows. */
.compare-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  visibility: hidden;
}

.compare-slide.is-active {
  visibility: visible;
}

img.compare-slide {
  object-fit: cover;
}

.compare-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-surface-subtle);
}

.compare-number {
  font-family: var(--font-mono);
  font-size: var(--text-item-size);
  font-weight: var(--text-label-weight);
  color: var(--color-text-secondary);
}

.compare-meta {
  display: flex;
  justify-content: space-between;
  gap: var(--space-16);
  margin-top: var(--space-8);
  padding-inline: var(--cell-pad);
}

/* Caption and counter each stay on one line, the same in both figures. */
.compare-meta > * {
  white-space: nowrap;
}

.compare-counter {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

/* Mobile: frames stack, each takes half of what's left of the screen. */
@media (max-width: 639px) {
  .compare-frame {
    aspect-ratio: auto;
    height: calc((var(--stage-height) - var(--compare-chrome-mobile)) / 2);
    max-height: none;
  }
}

/* ---------- Structure lines on dark ---------- */

.ink-lines {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.ink-lines .container,
.wipe .container {
  height: 100%;
}

.ink-lines .vline {
  background: var(--color-guide-on-ink);
}

/* ---------- Part 2: wipe ----------
   One bar per bay, rising from the bottom. The outer bars bleed past the
   container to the screen edges so the whole screen ends up dark. */

.wipe {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: clip;
  pointer-events: none;
  visibility: hidden;
}

.wipe-bar {
  --bleed-left: 0px;
  --bleed-right: 0px;
  position: absolute;
  bottom: 0;
  height: 100%;
  left: calc(var(--from) - var(--bleed-left));
  width: calc(var(--to) - var(--from) + var(--bleed-left) + var(--bleed-right));
  background: var(--color-ink);
  transform: scaleY(0);
  transform-origin: bottom;
}

.bay-1 { --from: 0%; --to: 25%; --bleed-left: 100vw; }
.bay-2 { --from: 25%; --to: 50%; }
.bay-3 { --from: 50%; --to: 75%; }
.bay-4 { --from: 75%; --to: 100%; --bleed-right: 100vw; }

/* Tablet: 2 bays, like the structure lines. Mobile: 1. */
@media (max-width: 1023px) {
  .bay-2,
  .bay-4 {
    display: none;
  }

  .bay-1 { --to: 50%; }
  .bay-3 { --from: 50%; --to: 100%; --bleed-right: 100vw; }
}

@media (max-width: 639px) {
  .bay-3 {
    display: none;
  }

  .bay-1 { --to: 100%; --bleed-right: 100vw; }
}

/* ---------- Part 3: statement ----------
   Sits on top of the stage and shows once the wipe is done. */

.statement-layer {
  position: absolute;
  inset: 0;
  z-index: 2;
  visibility: hidden;
  color: var(--color-canvas);
}

/* The wipe already draws the lines while pinned; these are for reduced motion. */
.statement-layer > .ink-lines {
  display: none;
}

/* Positioned against the stage, not the container, so it can travel
   from edge to edge. */
.statement {
  position: absolute;
  top: 50%;
  left: 0;
  width: max-content;
  white-space: nowrap;
  transform: translate3d(0, -50%, 0);
  font-size: var(--statement-size, var(--text-statement-size));
  font-weight: var(--text-display-weight);
  line-height: var(--text-statement-lh);
  letter-spacing: var(--text-statement-ls);
  word-spacing: var(--text-statement-ws);
}

/* "That's why:" holds still in the first bay while the line passes under
   it. Letters are always on the baseline by the time they reach the first
   bay, so it sits one step above the line. It fades in as the screen turns
   dark. --statement-size is the fitted size principle.js sets. */
.statement-bridge {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(50% + var(--statement-size, var(--text-statement-size)) * var(--text-statement-lh) / 2 + var(--space-32));
  opacity: 0;
  transition: opacity var(--duration) var(--ease);
}

.statement-layer.is-on .statement-bridge {
  opacity: 1;
}

.statement-word {
  white-space: nowrap;
}

.statement-char {
  display: inline-block;
  will-change: transform;
}

/* ---------- Reduced motion: no pinning, no wipe, no letter offsets ---------- */

@media (prefers-reduced-motion: reduce) {
  .principle-track {
    height: auto;
  }

  .principle-stage {
    position: static;
    height: auto;
    display: block;
    overflow: visible;
  }

  .principle-stage > .container {
    padding-top: var(--section-pad);
    padding-bottom: var(--section-pad);
  }

  .compare-frame {
    max-height: none;
  }

  .wipe,
  .distance {
    display: none;
  }

  .statement-layer {
    position: relative;
    inset: auto;
    visibility: visible;
    padding: var(--section-pad) 0;
    background: var(--color-ink);
  }

  .statement-layer > .ink-lines {
    display: block;
  }

  .statement-bridge {
    position: relative;
    bottom: auto;
    margin-bottom: var(--space-24);
    opacity: 1;
    transition: none;
  }

  /* One clause per line ("Humans must decide," / "AI only builds."). */
  .statement-sentence {
    display: block;
  }

  .statement {
    position: relative;
    width: auto;
    white-space: normal;
    transform: none;
    /* One clause per line: 2 lines on desktop, 3 on mobile. */
    font-size: var(--text-statement-still-size);
    line-height: var(--text-display-lh);
    /* Keep clear of the outer lines. The lines run behind it. */
    padding-inline: var(--cell-pad);
  }

  .statement-char {
    will-change: auto;
  }
}
