/* Wider than the shared 860px .inner: three side-by-side charts need more
   room than a normal text column. */
section.alt > .inner {
  max-width: 1320px;
}

.article-header + section.alt {
  padding-top: 1.5rem;
}

.charts-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  margin: 2rem 0 0.75rem;
}

.chart-panel h2 {
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
}

/* VCR-style transport row plus scrubber (see spec.md's "Replay controls").
   Landing incrementally: only step-back is wired up so far, index.ts
   enables it and drives the scrubber; the rest stay disabled placeholders
   until their own steps land. Same understated button language as
   cumulative-flow-diagram's own stop-button and scrubber.
   Sized to match one chart panel's own width -- the same (100% - 2 gaps) /
   3 share of .inner that .charts-row's repeat(3, 1fr) columns resolve to
   -- and centered under the row as a block via the auto side margins,
   rather than sized to fit the 5 buttons' own narrower combined width. The
   scrubber below, at width: 100% of this wrapper, then always spans
   exactly as wide as the transport itself, chart-width included. */
.replay-transport {
  width: calc((100% - 2 * 1.5rem) / 3);
  margin: 0 auto 1.5rem;
}

.replay-controls {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.replay-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  background: #fff;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}

.replay-button svg {
  fill: currentColor;
}

.replay-button:not(:disabled):hover {
  border-color: var(--accent);
  color: var(--accent);
}

.replay-button:disabled {
  opacity: 0.35;
  cursor: default;
}

/* The scrubber spans the whole timeline. The band is the 90-day window the
   charts show (drag it to pan), the handle is the playhead inside it (drag
   it to scrub), and the fill is the part of the window drawn so far. index.ts
   positions all three on every change; the values here are only pre-JS
   fallbacks (same resilience pattern as the buttons' own HTML-default
   `disabled`). Same touch-action treatment as cumulative-flow-diagram's own
   scrubber. */
.replay-scrubber {
  position: relative;
  height: 1rem;
  cursor: pointer;
  touch-action: none;
}

.replay-scrubber-dragging,
.replay-scrubber-dragging .replay-scrubber-band,
.replay-scrubber-dragging .replay-scrubber-handle {
  cursor: grabbing;
}

/* No lag while actively dragging -- the band/fill/handle should track the
   pointer 1:1, not ease toward it a beat behind. The transition stays for
   every other move (a button click or a play tick), where a little motion
   reads as "something changed" rather than as input lag. */
.replay-scrubber-dragging .replay-scrubber-band,
.replay-scrubber-dragging .replay-scrubber-fill,
.replay-scrubber-dragging .replay-scrubber-handle {
  transition: none;
}

.replay-scrubber-track {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 6px;
  border-radius: 999px;
  background: var(--border);
  transform: translateY(-50%);
}

.replay-scrubber-band {
  position: absolute;
  top: 50%;
  left: 66%;
  width: 34%;
  height: 14px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--text) 14%, transparent);
  transform: translateY(-50%);
  cursor: grab;
  transition: left 0.15s, width 0.15s;
}

.replay-scrubber-fill {
  position: absolute;
  top: 50%;
  left: 66%;
  width: 34%;
  height: 6px;
  border-radius: 999px;
  background: var(--text);
  transform: translateY(-50%);
  transition: left 0.15s, width 0.15s;
}

.replay-scrubber-handle {
  position: absolute;
  top: 50%;
  left: 100%;
  width: 16px;
  height: 16px;
  margin-left: -8px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--text);
  transform: translateY(-50%);
  cursor: grab;
  transition: left 0.15s;
}

/* Chart basics shared by all three panels. */
.chart {
  width: 100%;
  max-width: 400px;
  height: auto;
}

.chart .axis {
  stroke: var(--border);
  stroke-width: 1;
}

.chart .tick {
  stroke: var(--border);
  stroke-width: 1;
}

.chart .tick-label {
  fill: var(--muted);
  font-size: 8px;
  text-anchor: middle;
}

.chart .tick-label-y {
  text-anchor: end;
}

.chart .axis-label {
  fill: var(--muted);
  font-size: 9px;
  text-anchor: middle;
}

.chart .legend-label {
  fill: var(--muted);
  font-size: 8px;
}

/* Cumulative flow diagram: three cumulative boundary lines with translucent
   fills between them, matching the style of the team's own real dashboard
   tool -- a full bounding box and horizontal gridlines rather than just a
   pair of axes, since that's how that tool frames its own charts too. */
.chart .cfd-border {
  fill: none;
  stroke: var(--border);
  stroke-width: 1;
}

.chart .cfd-gridline {
  stroke: var(--border);
  stroke-width: 1;
}

.chart .cfd-line {
  fill: none;
  stroke-width: 1.75;
}

.chart .cfd-line-todo {
  stroke: #94a3b8;
}

.chart .cfd-line-doing {
  stroke: #f59e0b;
}

.chart .cfd-line-done {
  stroke: var(--accent);
}

.chart .cfd-fill {
  stroke: none;
}

.chart .cfd-fill-doing {
  fill: #f59e0b;
  fill-opacity: 0.18;
}

.chart .cfd-fill-done {
  fill: var(--accent);
  fill-opacity: 0.18;
}

/* Card markers: one card's own history traced across the boundary lines on
   hover -- same styling as cumulative-flow-diagram.css's own card markers. */
.chart .card-marker-circle {
  fill: none;
  stroke: var(--accent-dark);
  stroke-width: 1.75;
}

.chart .card-marker-arrow {
  stroke: var(--accent-dark);
  stroke-width: 1.5;
}

.chart .card-marker-arrowhead {
  fill: var(--accent-dark);
}

/* A white halo (paint-order + stroke) keeps each arrow's duration legible
   over any line or fill it happens to cross. */
.chart .card-marker-label {
  fill: var(--accent-dark);
  font-size: 7.5px;
  font-weight: 600;
  paint-order: stroke;
  stroke: #fff;
  stroke-width: 2.5px;
  stroke-linejoin: round;
}

.chart .legend-swatch-todo {
  stroke: #94a3b8;
}

.chart .legend-swatch-doing {
  stroke: #f59e0b;
}

.chart .legend-swatch-done {
  stroke: var(--accent);
}

.chart .legend-swatch {
  stroke-width: 2;
}

.chart .dot.frozen {
  fill: #16a34a;
  fill-opacity: 1;
  stroke: none;
  cursor: pointer;
}

/* A still-in-Doing item's own dot -- the same orange the CFD's own Doing
   band uses, so the two read as the same "currently in progress" concept
   rather than introducing a third, unrelated color. */
.chart .dot.active {
  fill: #f59e0b;
  fill-opacity: 1;
  stroke: none;
  cursor: pointer;
}

.chart .dot.highlighted {
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(1.6);
  filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.35));
}

/* Hovering a histogram bucket dims every other dot on the scatter plot,
   rather than highlighting that bucket's own -- those dots already read as
   the normal, undimmed color, so the bucket's shape in time stands out by
   everything else fading back instead. */
.chart .dot.dimmed {
  fill-opacity: 0.2;
}

/* Dotted guide lines from a highlighted dot to both axes, plus the pill tag
   on the y-axis carrying that dot's own value -- same styling as
   cycle-time-scatter-plot.css, so a hovered dot here reads the same way. */
.chart .guide {
  stroke: var(--muted);
  stroke-width: 1;
  stroke-dasharray: 2 2;
}

.chart .guide-tag-bg {
  fill: #e6f6ff;
}

.chart .guide-tag-text {
  fill: var(--accent);
  font-size: 8px;
  font-weight: 700;
}

.chart .guide-tag.frozen .guide-tag-bg {
  fill: var(--accent-dark);
}

.chart .guide-tag.frozen .guide-tag-text {
  fill: #fff;
}

/* Cycle time histogram bars. */
.chart .histogram-bar {
  fill: var(--accent);
  fill-opacity: 0.75;
}

/* Hovering a bar dims every other bar, the same treatment the hovered
   bucket's own dots get on the scatter plot above. */
.chart .histogram-bar.dimmed {
  fill-opacity: 0.2;
}

.chart .histogram-percent-label {
  fill: var(--accent-dark);
  font-size: 9px;
  font-weight: 700;
  text-anchor: middle;
}

/* p50/p85/p95 reference lines on the scatter plot and histogram: a fixed
   backdrop rather than a hover effect, so a muted dashed stroke distinct
   from the accent-colored hover .guide. */
.chart .reference-line {
  stroke: var(--muted);
  stroke-width: 1;
  stroke-dasharray: 3 2;
}

/* A white halo (paint-order + stroke) keeps a label legible where a dot or
   bar happens to sit right behind it. */
.chart .reference-line-label {
  fill: var(--muted);
  font-size: 7.5px;
  font-weight: 600;
  paint-order: stroke;
  stroke: #fff;
  stroke-width: 2.5px;
  stroke-linejoin: round;
}

/* CFD hover: dotted, not dashed -- reads distinctly from the solid boundary
   lines and stays visible crossing the Done fill, same reasoning as
   cumulative-flow-diagram.css's own hover-line. mix-blend-mode inverts
   against whatever it's drawn over instead of needing a fixed color that
   would wash out against the translucent fills here. */
.chart .hover-line {
  stroke: #fff;
  stroke-width: 1.25;
  stroke-dasharray: 1 2;
  mix-blend-mode: difference;
}

/* A quiet, near-white chip regardless of which band it sits over -- reads as
   a label sitting on top of the chart, not a badge shouting over it. Same
   as cumulative-flow-diagram.css's own band-tag styling. */
.chart .band-tag-bg {
  fill: rgba(255, 255, 255, 0.82);
}

.chart .band-tag-text {
  fill: var(--text);
  font-size: 7.5px;
  font-weight: 500;
}

/* The scatter plot's own title tooltip gets a border on top of the shared
   band-tag chip styling above -- it can land over a dense cluster of dots,
   and a border keeps its edge legible there instead of just the fill. */
.chart .title-tag .band-tag-bg {
  stroke: var(--border);
  stroke-width: 1;
}

.explanation {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
}

.explanation p {
  max-width: 640px;
  line-height: 1.7;
  color: #374151;
  margin-bottom: 1rem;
}

/* The forecast (see spec.md's "The forecast"): its own chapter under the
   interpretation, the chart across the full width. index.ts draws it in CSS
   pixels at whatever size it's given here, so its labels keep their size on
   any screen: as tall as 3/8 of its width, but never so tall it won't fit on
   one screen with its heading, nor so short its scale gets cramped. Line
   colors as on the Monte Carlo explainer's fan. */
.forecast-chapter {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
}

.forecast-chapter h2 {
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
}

/* The height cap leaves room for the controls under it too, so the whole
   fan stays in view while playing. */
.forecast-chart {
  display: block;
  width: 100%;
  height: clamp(260px, 37.5vw, calc(100svh - 12rem));
}

/* Play/pause beside a scrubber with only a handle on it, centred under the
   chart. Borrows the replay controls' button and scrubber styles. */
.forecast-controls {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  max-width: 480px;
  margin: 0.75rem auto 0;
}

.forecast-scrubber {
  flex: 1;
}

.forecast-scrubber .replay-scrubber-track {
  background: color-mix(in srgb, var(--text) 14%, transparent);
}

.forecast-scrubber.replay-scrubber-dragging .replay-scrubber-handle {
  cursor: grabbing;
  transition: none;
}

.forecast-chart .forecast-frame {
  fill: none;
  stroke: var(--border);
  stroke-width: 1;
}

.forecast-chart .forecast-grid {
  stroke: var(--border);
  stroke-width: 1;
  stroke-opacity: 0.6;
}

.forecast-chart .forecast-tick-label {
  fill: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.forecast-chart .forecast-axis-label {
  fill: var(--muted);
  font-size: 12px;
}

.forecast-chart .forecast-note {
  fill: var(--muted);
  font-size: 11px;
  font-style: italic;
}

.forecast-chart .forecast-not-yet {
  fill: url(#forecast-hatch);
}

.forecast-chart .forecast-hatch-line {
  stroke: var(--border);
  stroke-width: 1.5;
}

.forecast-chart .forecast-playhead {
  stroke: var(--text);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}

.forecast-chart .forecast-playhead-label {
  fill: var(--text);
  font-size: 12px;
  font-weight: 600;
}

/* The past: the CFD's Done line, in its blue with its light fill. */
.forecast-chart .forecast-done {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.75;
}

.forecast-chart .forecast-done-fill {
  fill: var(--accent);
  fill-opacity: 0.18;
  stroke: none;
}

/* Reality, when rewound: the same Done line, dimmed, so it can't be
   mistaken for the 50% line. */
.forecast-chart .forecast-reality {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.75;
  stroke-opacity: 0.4;
}

.forecast-chart .forecast-reality-fill {
  fill: var(--accent);
  fill-opacity: 0.07;
  stroke: none;
}

.forecast-chart .forecast-line {
  fill: none;
  stroke-width: 1.75;
  stroke-linejoin: round;
}

.forecast-chart .forecast-line-50 { stroke: #7cc7f2; }
.forecast-chart .forecast-line-85 { stroke: var(--accent-dark); stroke-width: 3; }
.forecast-chart .forecast-line-95 { stroke: #64748b; }

.forecast-chart .forecast-line-label {
  font-size: 12px;
  font-weight: 700;
  paint-order: stroke;
  stroke: #fff;
  stroke-width: 3px;
  stroke-linejoin: round;
}

.forecast-chart .forecast-line-label-50 { fill: #3b9fd8; }
.forecast-chart .forecast-line-label-85 { fill: var(--accent-dark); }
.forecast-chart .forecast-line-label-95 { fill: #64748b; }

/* Pointing at the fan, as on the Monte Carlo explainer: neutral dotted
   guides, dark tags as on the scatter plot, and the "from now" scale beside
   the "items done" axis. The chart can always be pointed at, so it keeps a
   finger rather than scrolling the page. */
.forecast-chart {
  touch-action: none;
}

.forecast-chart .fan-pointing {
  pointer-events: none;
}

.forecast-chart .fan-guide {
  stroke: var(--text);
  stroke-width: 1;
  stroke-dasharray: 2 2;
  stroke-opacity: 0.7;
}

.forecast-chart .fan-tick-label {
  fill: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.forecast-chart .fan-from-now-zero {
  stroke: var(--muted);
  stroke-width: 1;
  stroke-opacity: 0.35;
}

.forecast-chart .fan-tag-bg {
  fill: var(--accent-dark);
}

.forecast-chart .fan-tag-text {
  fill: #fff;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* The actual tag and its guide: reality's dimmed blue, with dark text. */
.forecast-chart .fan-guide-actual {
  stroke: var(--accent);
  stroke-opacity: 0.7;
  stroke-width: 1.25;
}

.forecast-chart .fan-tag-actual .fan-tag-bg {
  fill: color-mix(in srgb, var(--accent) 40%, #fff);
}

.forecast-chart .fan-tag-actual .fan-tag-text {
  fill: var(--text);
}

/* The likelihood strip: a traffic light from least likely to safest, each
   band clearly lighter than the one before it, so the order still reads
   without telling the hues apart. The "from now" numbers it sits behind
   turn dark to stay readable on it. */
.forecast-chart .fan-strip-under-50 { fill: #d4554e; }
.forecast-chart .fan-strip-50-85 { fill: #e8925a; }
.forecast-chart .fan-strip-85-95 { fill: #efcc62; }
.forecast-chart .fan-strip-95 { fill: #c8f1e8; }

.forecast-chart .fan-strip-on-scale ~ .fan-from-now .fan-tick-label {
  fill: var(--text);
}

@media (max-width: 1024px) {
  .charts-row {
    grid-template-columns: 1fr;
  }

  /* Matches .charts-row's own single-column collapse above -- a chart
     panel is the full column width here, not a third of it, so the
     transport sized to match one should be too. Same 400px cap as
     .chart's own, since a chart itself doesn't stretch past that even in
     a full-width column. position: sticky, not fixed -- scoped to
     .charts-and-transport (see team-northbound.html), not the whole page,
     so it stays pinned to the bottom of the screen while scrolling
     through the charts, then releases back into normal in-flow position
     exactly where that wrapper ends, right as .explanation begins,
     instead of staying stuck in front of the text for the rest of the
     page. Centering stays the same margin: 0 auto already in normal flow
     uses -- sticky keeps an element's own horizontal position, only the
     vertical offset is special, so no left/right centering trick is
     needed the way position: fixed would require. The env() term adds
     clearance for a phone's own home-indicator/safe-area inset, so the
     bar doesn't sit flush under it while stuck. */
  .replay-transport {
    width: 100%;
    max-width: 400px;
    position: sticky;
    bottom: 0;
    margin: 0 auto;
    padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom));
    background: var(--bg-alt);
    border-top: 1px solid var(--border);
    z-index: 50;
  }

  /* Same pinning for the forecast's controls, scoped to the forecast chart
     and its controls: scrolling down the page hands over from the replay
     transport to these, with the interpretation in between pinning
     neither. */
  .forecast-controls {
    max-width: none;
    position: sticky;
    bottom: 0;
    margin: 0;
    padding: 0.75rem max(1rem, (100% - 480px) / 2) calc(0.75rem + env(safe-area-inset-bottom));
    background: var(--bg-alt);
    border-top: 1px solid var(--border);
    z-index: 50;
  }
}

/* ── Presentation mode (see spec.md's "Presentation mode", ../styles.css) ──
   Two slides (presentation.ts shows only the current one): the charts, then
   the forecast. The three charts stay side by side at every wide width and grow as large
   as the screen allows: a third of the width each, or less when the height
   left over by the headings and replay controls is what runs out first (the
   charts are 4:3). The replay controls keep matching one chart's width. */
@media (min-width: 601px) {
  /* Centered when the charts run out of width before height. */
  body[data-presenting] section.alt > .inner {
    justify-content: center;
  }

  body[data-presenting] .charts-and-transport {
    --present-chart-width: min((100% - 3rem) / 3, (var(--present-height) - 14rem - var(--present-title-height)) * 4 / 3);
  }

  body[data-presenting] .charts-row {
    grid-template-columns: repeat(3, var(--present-chart-width));
    justify-content: center;
    margin-top: 0.5rem;
  }

  body[data-presenting] .chart {
    max-width: none;
  }

  body[data-presenting] .replay-transport {
    position: static;
    width: var(--present-chart-width);
    max-width: none;
    margin: 0 auto;
    padding: 0;
    background: none;
    border-top: none;
  }

  /* The forecast's slide: its heading as a label, then the chart across the
     whole width taking all the height left over, its controls centred under
     it. The chart draws itself at whatever size it ends up. Nothing scrolls
     on a slide, so the controls have nothing to stick to. */
  body[data-presenting] .forecast-chapter {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    margin: 0.5rem 0 0;
    padding: 0;
    border-top: none;
  }

  body[data-presenting] .forecast-chapter h2 {
    flex-shrink: 0;
  }

  body[data-presenting] .forecast-chart-and-controls {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  body[data-presenting] .forecast-chart {
    flex: 1;
    min-height: 0;
    height: auto;
  }

  body[data-presenting] .forecast-controls {
    flex-shrink: 0;
    position: static;
    width: 100%;
    max-width: 480px;
    margin: 0.75rem auto 0;
    padding: 0;
    background: none;
    border-top: none;
  }
}
