/*
 * figure-embed.css — the child half of the paperHTML responsive-figure system.
 *
 * Include in any interactive figure page that gets embedded in a paper:
 *   <html lang="en" data-figure-sizing="flow">        <- or "fill"
 *   <link rel="stylesheet" href="/paperHTML/figure-embed.css">
 *
 * THE INVARIANT THIS FILE ENFORCES
 * --------------------------------
 * A figure's height must be a pure function of its WIDTH — never of its own
 * animation state, and never of the height it was given. Hold that and the
 * parent's height binding cannot oscillate; break it and no amount of
 * debouncing saves you.
 *
 * TWO SIZING MODES, declared by the figure itself on <html>:
 *
 *   data-figure-sizing="flow"  the figure has a natural height that follows from
 *                              its content at a given width (a stepped explainer,
 *                              stacked cards). The parent MEASURES it.
 *
 *   data-figure-sizing="fill"  the figure is a viewport-filling canvas with
 *                              overlaid chrome; it has no natural height and
 *                              adopts whatever box it is given. The parent
 *                              IMPOSES a height from an aspect ratio. Measuring
 *                              one of these reads back the imposed height and
 *                              locks — so the parent must not.
 *
 * WHY "flow" MUST DROP min-height:100%
 * ------------------------------------
 * With min-height:100% the root box is max(content, viewport). The parent sets
 * the iframe height, that becomes the child viewport, the root box grows to
 * match, the parent measures its own value back and the figure can never shrink.
 * Flow figures therefore size to content only.
 */

/* ---- both modes ---------------------------------------------------------- */

/* The child must never produce its own scrollbar. A scrollbar steals ~15px of
 * width, which rewraps the content, which changes the height, which resizes the
 * frame, which removes the scrollbar — the classic "iframe dance". Severing the
 * height->width path here means the parent never needs to damp anything. */
html {
  overflow-y: hidden;
  scrollbar-gutter: stable;
}

body {
  margin: 0;
}

/* Every drawing surface declares a ratio so its height follows from its width
 * rather than from a JS measurement of something else. Figures may override with
 * a specific ratio; the point is that one is always set. */
canvas,
svg {
  max-width: 100%;
}

/* The figure is its own layout context. Everything inside should size off
 * container query units (cqi/cqw) and @container rules — never off viewport
 * units, which are wrong inside an iframe and jump on iOS as the URL bar
 * collapses. inline-size, never size: `size` applies block containment, which
 * stops the element sizing from its content and re-breaks the height binding. */
.figure-root {
  container-type: inline-size;
  container-name: figure;
}

/* ---- flow mode ----------------------------------------------------------- */

html[data-figure-sizing="flow"],
html[data-figure-sizing="flow"] body {
  height: auto;
  min-height: 0;
}

/* Stepped figures: stack every panel in ONE grid cell so the container's height
 * is the tallest panel and does not change when the reader switches steps. A
 * height that changes per step is a height that changes per interaction, which
 * is a second-order violation of the invariant — the frame would resize under
 * the reader's finger. Panels are hidden by visibility, not display, so they
 * keep contributing their size. */
.figure-steps {
  display: grid;
}
.figure-steps > .figure-step {
  grid-area: 1 / 1;
  visibility: hidden;
}
.figure-steps > .figure-step[data-active="true"] {
  visibility: visible;
}

/* ---- fill mode ----------------------------------------------------------- */

html[data-figure-sizing="fill"],
html[data-figure-sizing="fill"] body {
  height: 100%;
}

/* ---- touch affordances --------------------------------------------------- */

/* pointer:coarse is the ONE thing a media query should decide here — it asks
 * about the input device, not the layout. Layout decisions belong to container
 * queries, because a figure in a 600px column inside a 1024px tablet is narrow
 * regardless of what the viewport says. */
/* ---- touch affordances — OPT-IN ONLY -------------------------------------
 *
 * Everything below is keyed to classes a figure adds DELIBERATELY. An earlier
 * version of this file matched generic names — .chip, .chips, .steps, button —
 * on the reasonable-sounding theory that a chip is a chip. It is not: one of
 * these figures had already solved narrow screens by shrinking its chips to
 * 25px and showing only their first letter, and a blanket `min-width: 44px`
 * overrode that authored width while `flex-wrap` broke the four oversized
 * chips into a vertical column across the middle of the drawing.
 *
 * A shared stylesheet cannot know what a class means in a document it did not
 * write. So it asks, and the figure answers. Rules that cost no layout — the
 * sizing modes, the hit-area expansion below — stay automatic; anything that
 * can move a box is opt-in. */

@media (pointer: coarse) {
  /* Put .figure-touch on a control ROW to size its children for fingers. */
  .figure-touch button:not(.progress-dot),
  .figure-touch [role="tab"],
  .figure-touch a,
  .figure-touch-self {
    min-height: 44px;
    min-width: 44px;
  }

  /* Small round step indicators can't grow to 44px without looking absurd, and
   * can't reserve 44px of width without overflowing their strip. Grow the HIT
   * AREA instead of the ink: the pseudo-element is out of flow, so it costs no
   * layout width at all — which is why this one is safe to apply unasked. */
  .progress-dot {
    position: relative;
  }
  .progress-dot::after {
    content: "";
    position: absolute;
    inset: -18px;
  }
}

/* Put .figure-tabstrip on a horizontal tab row that should wrap rather than
 * overflow. Only for strips laid out in normal flow — a floating overlay panel
 * wants its own narrow-screen treatment, not this one. */
.figure-tabstrip {
  flex-wrap: wrap;
}
