/* ===========================================================================
   Section 10's figure: where the money actually goes, and that the default
   guard refuses this run.

   Owned by web-ui, loaded after hero-figure.css - AFTER, because the four
   `fig-*` keyframes it animates with are defined there. Same `--d` / `--len`
   conventions; read that file's head comment once rather than four times.

   WHY THIS EXISTS
     `#cost` had a 611 x 457px void beside its heading at 1920 - the third
     largest on the page - and the honesty argument, which is one of the
     product's two real differentiators, was carried entirely by a prose table.

   WHAT IT SAYS THAT THE PROSE DOES NOT
     Both beats are findings, not restatements. Neither number is anywhere else
     on the page:

       1. 75% of a 14-day seed's projected cost is 469 custom metric series at
          $0.30 per metric-month. Everything priced per gigabyte together comes
          to $1.91 of $187.50 - one percent. The section's caveat about charging
          a full metric-month without prorating is currently a footnote; this is
          the picture that shows why it dominates.
       2. `budget-ceiling` with its default $50 cap REFUSES this run outright on
          an empty ledger. The guard demonstrably has teeth.

     The five policies are deliberately NOT redrawn - `.c-policies` right below
     already lists them, and a matrix of the same five would be decoration.

   EVERY FIGURE DERIVED, AND THE DERIVATION CHECKED AGAINST THE CODE
     The seven priced terms in `_estimate_usd` (proteus/guard/estimate.py) were
     recomputed from `APPROX_RATES_USD` and summed: $187.50, matching
     `Projection.est_usd` to the cent for the same window. `DEFAULT_MONTHLY_CAP_USD
     = 50.0` and `DEFAULT_TTL_SECONDS = 1800` are from proteus/guard/policy.py,
     and the refusal was produced by calling `evaluate(BUDGET_CEILING, ...)`
     against an empty ledger rather than inferred from reading it.

   WHICH QUANTITIES ARE STABLE, MEASURED ACROSS FIVE WINDOW ANCHORS
     Because the projection window is anchored to `now` over a diurnal curve,
     not everything is a constant, and a figure quoted as one when it is not is
     the shape this project keeps getting bitten by:

       new_series      469          STABLE
       spans           7,983,360    STABLE
       est_usd         $187.50 .. $187.70   varies 0.11%
       metric_points   varies 1.96%
       rum_events      varies 4.17%
       requests        varies 1.88%

     So 469 and the span count are printed as constants and the dollar figures
     are one named run's - the same $187.50 the captured `doctor`/`seed`
     transcript on this page already carries.

   PRICED OFFLINE, AND SAID SO. These are built-in-table figures, which is what
   `--dry-run` produces because `PARANOID` makes no network call. Live us-west-2
   pricing is lower; the prose beside the figure gives that number. The graphic
   deliberately carries only figures derived here, so the live total appears
   nowhere in it.

   THE CATEGORY-ERROR TEST, applied rather than asserted. Two axes exist here and
   both are USD:
     - Beat 1's seven-into-four bars are all dollars, one projection, one window,
       one rate source. Legitimately one axis. Record counts appear ONLY as the
       `quantity x rate` text beside each bar, which is the derivation of the
       dollar figure rather than a second quantity sharing its scale.
     - Beat 2's two bars are dollars against dollars, and the comparison is the
       one `_budget_decision` itself performs: `already + est_usd` against
       `monthly_cap_usd`. Their SCOPES differ - one run versus one month - so
       both are labelled with their scope instead of leaving it inferred.
   Nothing here puts a count on a dollar axis, and there is no threshold drawn
   across a bar that measures something a threshold does not apply to.
   =========================================================================== */

/* --- The two-column row -------------------------------------------------- */

.co-row { display: grid; gap: clamp(24px, 3vw, 44px); }

/* 1280px in PIXELS. The figure's rendered text size is
   `figureWidthPx / 520 * 13` and has no relationship to the root font size, so
   `rem` would express the constraint in a unit it does not depend on - and
   misfires, because the harness browser resolves media-query `rem` against a
   12px root. */
@media (min-width: 1280px) {
  .co-row {
    grid-template-columns: minmax(0, 62ch) minmax(0, 1fr);
    align-items: start;
  }
}

@media (max-width: 700px) {
  .co-figure { display: none; }
}

/* The cap lives on the wrapper, not on the `<svg>`. There is no positioned
   child here as there is in the hunt figure, so nothing can currently be thrown
   off by the two boxes disagreeing - but keeping the cap in the same place in
   both files means the next person who adds an overlay does not reintroduce that
   bug. See hunt-figure.css for what it cost to find. */
.co-stage {
  position: relative;
  max-width: 620px;
}

.co {
  display: block;
  width: 100%;
  height: auto;
}

/* --- Ink ----------------------------------------------------------------- */

.co text { font-family: var(--p-mono); }

.co-eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  fill: var(--p-accent);
}
.co-label { font-size: 13px; fill: var(--p-text); }
.co-detail { font-size: 11px; fill: var(--p-muted); }
.co-note { font-size: 12px; fill: var(--p-muted); }
.co-usd { font-size: 13px; font-weight: 600; fill: var(--p-accent); text-anchor: end; }
.co-share { font-size: 11px; fill: var(--p-muted); text-anchor: end; }

/* Bars. `--p-surface` track on the section's `--p-bg`, same as the hunt
   figure's weight bars; the bar itself carries the contrast against the track. */
.co-track { fill: var(--p-surface); }
.co-bar { fill: var(--p-accent); }

/* THE DOMINANT TERM, and the one number a reader should leave with. Amber is
   this page's "the state that matters" token in all three other figures - the
   degraded node, the shared-infrastructure fault, the 70 gate - and here it
   marks the one line item that is three quarters of the bill.

   It is NOT a warning that something is wrong: 469 series at list price is
   correct behaviour. The label beside it says "75% of it", so the colour is a
   pointer and the text is the claim. */
.co-bar--dominant { fill: var(--p-warning); }
.co-label--dominant { fill: var(--p-warning); }
.co-usd--dominant { fill: var(--p-warning); }

/* Beat 2's cap bar. Amber again, for the same "this is the threshold" job the
   hunt figure's 70 line does. */
.co-bar--cap { fill: var(--p-warning); }
.co-usd--cap { fill: var(--p-warning); }

/* REFUSED, as a word. The two bars differ in length and in colour, and neither
   of those says what the guard DID - so the verdict is text. Colour may not be
   the only carrier, and "refused" is the whole point of the beat. */
.co-verdict {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  fill: var(--p-warning);
}

/* A hairline rule between the two beats. Decorative - it separates, it does not
   inform - so `--p-border` at its usual 1.35:1 is right here, the same as every
   `.card` edge on the page. */
.co-rule { fill: none; stroke: var(--p-border); stroke-width: 1; }

/* --- Timeline ------------------------------------------------------------ */

.co-eyebrow,
.co-label,
.co-detail,
.co-note,
.co-usd,
.co-share,
.co-verdict {
  animation: fig-fade 0.5s ease-out var(--d, 0s) both;
}

.co-track,
.co-bar {
  animation: fig-rise 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) var(--d, 0s) both;
}

.co-rule {
  stroke-dasharray: var(--len);
  stroke-dashoffset: 0;
  animation: fig-draw 0.5s ease-in-out var(--d, 0s) both;
}

/* --- Reduced motion ------------------------------------------------------ */

/* The base styles ARE the finished figure - every bar at full length, every
   figure printed, the verdict present - so switching the animations off renders
   a complete static end state with both beats readable. Stated directly rather
   than relying on site.css's global `0.001ms !important`, which lives in a file
   this one does not own. */
@media (prefers-reduced-motion: reduce) {
  .co-eyebrow, .co-label, .co-detail, .co-note, .co-usd, .co-share,
  .co-verdict, .co-track, .co-bar, .co-rule {
    animation: none;
  }
}
