/* ==========================================================================
   R9h — REBUILT TO THE PAGE'S OWN STYLE, by direction: "refer the page style
   from hero to the section above the plate, redo everything after it."

   THE SOURCE IS THE BUILT PAGE (§2–§6), NOT THE DOCUMENTS. What §2–§6
   actually do, read off the stylesheets rather than the plan:

     ground      #000000, always
     container   --color-surface-panel #171717, SQUARE, no border
     accent      violet #6146ED — filled banners, filled circles, 2px rules
                 gold #BE9D4A for the negative side only
     headings    Loos 500, white, section titles CENTRED
     body        Mundial, weight 300, --color-text-body
     rules       1px --color-border-strong
     radius      0 everywhere; 50% only where a circle has no corners
     gradients   NONE. §2–§6 carry no blend shape and no flat fill.

   Every change below follows from that list.
   ========================================================================== */

/* ==========================================================================
   12 — FINAL CTA + HOSTED BY, merged at R12a
   7-5 asymmetric · the ask on the left, the host in a panel on the right.

   R12a — TWO SECTIONS BECAME ONE, by direction, to a supplied reference:
   "combine these 2 sections into one section with the hosted by block on the
   right; use the button from the Hero section; remove the seats rectangle
   bar."

   ⚠ THE PAGE IS NOW 14 SECTIONS, NOT 15, and every number after this one has
   shifted. The stylesheets and comments keep the original numbering so they
   can be traced back to the documents; §17's map is the thing to re-derive
   before it is relied on again.

   ⚠ THE RECEDED CELL FIELD IS GONE. It carried the page's closing argument
   without a sentence — the room that was empty at the top is nearly full at
   the bottom — and it was §12's half of a differentiation the documents state
   twice: the cell field as SUBJECT in §11, as GROUND here. Both halves have
   now been removed by direction (§11 became chip rails at R11c), so the
   pairing does not exist in either direction and the cell motif's page-wide
   budget needs re-deriving with it.

   ⚠ IT IS ALSO THE END OF "centred measure". §17 lists this section's layout
   as centred; it is a left-aligned 7-5 split now, which is what makes the
   two halves read as one section rather than as two stacked ones.

   ⚠ R23a — AND THE 7-5 SPLIT IS GONE TOO, by direction: "redo this section
   without the block on the right." The layout is now a single left-aligned
   column at the prose measure. §17's row for this section is wrong in both
   directions and needs rewriting: not centred, and no longer asymmetric.
   ========================================================================== */

/* R9h — the gradient fill and the blend shape are both gone. */

/* R23j — THE OVERRIDE IS GONE, by direction: "slightly increase the top and
   bottom padding." One step up the scale at every breakpoint is 48/64/80 ->
   64/80/120 — which IS .section's own `--section-padding-block`, so §12 stops
   overriding the page's rhythm rather than restating it with different
   numbers. It is even for free: .section sets `padding-block`, both edges.

   ⚠⚠ THE TRAP R23d FOUND STILL STANDS AND IS THE REASON THIS IS A DELETION
   AND NOT A NEW VALUE. .final once set `padding-block-start` ALONE, so the
   longhand replaced the start and left the end at .section's value — 160 over
   120 at desktop, invisible on black because there was no edge to measure it
   against. The plate drew the edges and it stopped being invisible. Any
   section that sets `padding-block-start` alone inherits the same fault. */
.final {
  /* R23b — the plate's positioning context.
     ⚠⚠ R23r — `overflow: hidden` IS NOW LOAD-BEARING, and the note that stood
     here said the opposite: "nothing overhangs, so no overflow is needed."
     That was true until the two rings arrived. They are deliberately larger
     than the section and anchored past its right edge, so without this they
     would spill across the footer and force a horizontal scrollbar. */
  position: relative;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   THE RINGS — R23r, to a supplied reference
   Two instances of one asset, sized and placed from the reference's own
   geometry rather than by eye. Fitted at 1440 x 694, where the reference's
   arcs give:

       ring          centre          radius
       large         1296, 691        475
       small         1422, -133       288

   ⚠⚠ THE ELEMENT IS NOT THE RING. `Shape Circle.svg` draws its stroke at
   r=449 in a 996 viewBox, so the drawn circle is 90.2% of the box and the
   remaining 9.8% is the glow's margin. Every number below is the ELEMENT box
   — ring diameter x 1.1091 — and reading them as the circle will make both
   rings ~10% too small.

   ⚠ EVERYTHING IS A PERCENTAGE OF THE SECTION'S WIDTH, including the vertical
   placement. `inline-size` and `right` resolve against width already;
   `translate` resolves against the ELEMENT's own box, which is width-derived
   through `aspect-ratio: 1`. A `bottom: %` would have resolved against the
   section's HEIGHT, which changes with the copy — and the rings would drift
   every time a line wrapped differently.
   -------------------------------------------------------------------------- */
/* ⚠⚠ GATED AT 992, AND BOTH REASONS ARE HARD ONES.

   1. THE BUDGET. §16 allows two decorative categories on desktop and ONE on
      mobile. §12 already spends one on the gradient plate, so the rings are
      the second and cannot run at phone width without breaking the limit.

   2. THEY CROSS THE COPY BELOW IT, and that was measured rather than judged.
      The large ring's leftmost point tracks the viewport: at the lead's own
      height the ring reaches x = 0.57W, while the text ends at 48 + 535 = 583
      for any width up to 1376. So:

          >= 1024   ring clears the lead                 (100px clear at 1200)
          992-1023  grazes the tail of line one by <20px
          768       ring reaches x=507 where the text ends at 500 — touching
          390       the arc passes straight through the Apply Now row

      992 is the first breakpoint where it is not a problem, and it is the
      page's own laptop boundary. Gating at 1200 instead would have been safer
      by 176px and would have cost every laptop the entire treatment.

   ⚠ `display: none`, not `opacity: 0` — an image that is merely transparent
   still downloads and still composites. */
.final__circle { display: none; }

@media (min-width: 992px) {
  .final__circle {
    display: block;
    position: absolute;
    z-index: 0;               /* above .final__ground, below .container */
    aspect-ratio: 1;
    block-size: auto;
    /* §13 — a decorative shape is never between the reader and a control. */
    pointer-events: none;
  }

  .final__circle--lg {
    inline-size: 73.2%;
    inset-inline-end: 0;
    inset-block-end: 0;
    translate: 36.3% 49.7%;
  }

  /* ✅ R23u — THE ADDED GLOW IS GONE, by direction: "remove the extra glow
     completely." R23s put four drop-shadows on this ring, R23t cut them to a
     third, and this removes them outright.

     ⚠ THE RING IS NOT UNLIT. `Shape Circle.svg` carries its own glow: a
     25px-wide stroke at 12% blurred 24px, and a 10px stroke at 30% blurred
     10px, both sitting just inside the main 2px line. What has been removed
     is the OUTER bloom this stylesheet was adding on top; the asset's built-in
     edge light is untouched and needs no declaration here.

     ⚠ IF IT IS EVER WANTED BACK, it is a `filter` of stacked `drop-shadow`s
     on this selector and nothing else — drop-shadow follows the asset's alpha,
     so it tracks the arc at any size. The levels that were rendered and
     compared are in design-rules.md §6 R23t. */

  /* ⚠ R23t — THE TWO RINGS BREATHE AGAINST EACH OTHER, not in lockstep.
     `.u-drift` alone would run both on the same 9s diagonal in perfect sync,
     which reads as one rigid object sliding rather than as two things
     floating. Reversing the smaller one costs one declaration and uses the
     same keyframes — no second animation, no second duration. */
  .final__circle--sm { animation-direction: alternate-reverse; }

  .final__circle--sm {
    inline-size: 44.4%;
    inset-inline-end: 0;
    inset-block-start: 0;
    translate: 47.2% -70.8%;
  }
}

/* --------------------------------------------------------------------------
   THE VIOLET PLATE — R23b
   Full-width and edge-to-edge because .final is full-bleed; the container
   above it keeps the content at its measure. Amended in design-rules.md §6
   BEFORE it was built: an eighth gradient, and a gradient behind body copy.
   -------------------------------------------------------------------------- */
.final__ground {
  /* ⚠ THIS OVERRIDES .u-grain's OWN `position: relative` AT EQUAL SPECIFICITY
     — both are (0,1,0), and it lands only because base.css is linked before
     the section stylesheets. Move final-cta.css above base.css and the plate
     snaps into flow as a zero-height block and vanishes. Same coupling
     wall.css records for .wall__glow. */
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--gradient-final-cta);
  /* Decoration is never between the reader and a control, and this one lies
     across the whole section including the CTA. */
  pointer-events: none;
}

/* The content rides above the plate. Without this the container has no
   stacking position of its own and .final__ground — a positioned element
   later in the source — paints over the heading. */
.final > .container {
  position: relative;
  z-index: 1;
}

/* R23a — ONE COLUMN. The host panel is hidden by direction, so the 7-5 grid
   came off the markup with it: a two-track grid holding one child is a phantom
   track, and `align-items: center` on it — the rule that used to sit here,
   relating the shorter pitch to the panel's floor — had nothing left to relate.

   ⚠ THE CAP IS NOT DECORATION. Unconstrained, the block runs the full 1280px
   container and "Find Out if Seats Are Available" sets on ONE line at 48px,
   which is a different headline shape from the one that was approved. 720px is
   within ~12px of the 7-col track it used to occupy (1256 / 12 × 7 = 732), so
   the wrap, the ragging and the 47 all land exactly where they did.

   ⚠ LEFT-ALIGNED, DELIBERATELY. §17 still lists this section as a centred
   measure — R12a left-aligned it to face the panel, and removing the panel
   removes that reason. It is left as it is because that is what the direction
   showed; centring is `margin-inline: auto` plus `text-align: center` and has
   not been asked for. */
.final__inner { max-inline-size: var(--measure-prose); }

.final__pitch { display: grid; align-content: start; }

/* R23c — the eyebrow heads the title group now. --gap-title-group is the
   token for the space INSIDE a title group, which is what this is. */
.final__eyebrow { margin-block-end: var(--gap-title-group); }

.final__lead { margin-block-start: var(--gap-heading-to-paragraph); }

/* R23c — "higher-education professionals", emphasised.
   ⚠⚠ 400, NOT BOLD, AND NOT AN OVERSIGHT. §9 prohibits body at 600+, and
   Mundial at 500 is prohibited outright, so 400 is the only legal step above
   the lead's 300 — the next one after it is 700, which belongs to numerals
   and the primary CTA label. Light -> Regular at 22px is a clear step and a
   smaller one than the reference draws. That is the cost, and it is stated
   rather than absorbed.
   ⚠ reset.css sets NO font-weight on `strong`, so the UA default `bolder`
   resolves to 700. Declaring it here is what stops the prohibited value
   shipping by inheritance. */
/* ⚠ R23j — THE EMPHASIS NOW CARRIES COLOUR AS WELL AS WEIGHT. The lead
   stepped off white, so full white is what marks the phrase — which is the
   page's own convention (§5: "inline emphasis" is a colour event) and it
   costs nothing, because white was already the floor-safe value here. */
.final__emphasis {
  font-weight: var(--font-weight-regular);
  color: var(--color-text-heading);
}

/* R23f — the lead's forced break. Gated, and the reasoning is in index.html:
   a <br> is typesetting hard-coded into content, so it only stands at widths
   where it lands where it is meant to. Below 768 the column cannot hold the
   first half and the break would wrap both. */
.final__break { display: none; }

/* --------------------------------------------------------------------------
   R23h — THE TEXT BLOCK'S OWN LENGTH, by direction: "the text block length
   will be until the 'professionals' end."

   The paragraph's first line ends at "professionals" and its box ran on to
   --measure-prose's 720, which is what let the progress bar overshoot the
   words by 185px. Both now stop at the line's actual end.

   ⚠⚠ 24.4em, NOT A PIXEL VALUE, AND THAT IS THE WHOLE POINT. Measured in a
   browser, the first line is 535.27px at the 22px lead and 486.61px at the
   20px one — and 535.27/22 = 486.61/20 = 24.33. The line is the same length
   in EMS at both sizes, because it is the same string in the same face. A
   pixel cap would have needed one hard-coded number per breakpoint and would
   silently mis-measure the moment the type scale moved; this tracks
   --font-size-lead instead, and 24.4 leaves ~1.5px of cushion so sub-pixel
   rounding can never clip the last "s".

   ⚠ IT IS STILL TUNED TO THIS COPY. Change the sentence and the coefficient
   is wrong — the bar will overshoot or undercut the words. Re-measure the
   first line's width in ems; do not guess.

   ⚠ GATED AT 768, THE SAME BREAKPOINT AS THE BREAK ABOVE, AND FOR THE SAME
   REASON. Below it the <br> is off and the paragraph wraps naturally to the
   full column — capping it there would leave the bar SHORTER than the text it
   describes, which is worse than the overshoot this fixes. The fallback in
   both consumers is --measure-prose, so the narrow case is unchanged.
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .final__break { display: inline; }

  .final__inner { --measure-final-text: calc(var(--font-size-lead) * 24.4); }
}

/* The claimed-seats figure, counting once.
   R23c — `display: block` and its own margin are gone: the figure sits beside
   the total on one line now, and .seats owns the vertical rhythm.
   ⚠ R23i — Display 76 -> H1 48, by direction. The scale runs 76 -> 48 with
   nothing between, so the smallest legal reduction is 37%; 64px would be a
   number answering to no token. See design-rules.md §12a. */
.final__figure {
  font-size: var(--font-size-h1);
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums lining-nums;
  line-height: var(--line-height-display);
  letter-spacing: var(--letter-spacing-display);
  /* R23b — VIOLET -> WHITE, and not a preference. The plate's ground IS
     --color-accent-identity-deep, so the numeral was the ground colour on the
     ground: 1:1, gone. R9h's orange -> violet swap is what put it here. */
  color: var(--color-text-heading);
}

.final__body {
  /* R23h — --measure-prose (720) -> the text's own length. See
     --measure-final-text below. */
  max-inline-size: var(--measure-final-text, var(--measure-prose));
  font-size: var(--font-size-lead);
  font-weight: var(--font-weight-light);   /* R9h */
  line-height: var(--line-height-lead);
  /* R23b — #B4B4B4 measures 2.64:1 on the plate, under the 4.5 body floor,
     which is why this copy went white rather than taking --color-text-body.
     ⚠⚠ R23j — IT STEPS OFF WHITE, by direction, but ONLY as far as the floor
     allows. The plate leaves very little: at the lead's brightest pixel the
     text must stay at or above about #DDDDDD to hold 4.5:1, so a real grey
     token is not available here and never will be on this ground. An 85% mix
     of the page's own white is the whole permitted range — same idiom as
     .seats__total, so the tone re-tints from a token rather than becoming a
     fourth grey. MEASURED VALUE IN design-rules.md §6 R23j. */
  color: color-mix(in srgb, var(--color-text-heading) 85%, transparent);
}

/* ✅ R23c — .final__unresolved IS DELETED, not orphaned. It rendered `XXX`
   because the Hero said 125 and this section said 100 and the page must not
   quietly pick one. The supplied counter reads "/ 125", which settles it in
   the Hero's favour, so the marker has no question left to mark and the gold
   goes with it. Both directions checked per §11 rule 8: no `.final__unresolved`
   remains in the markup, and no rule remains without a consumer. */

/* --------------------------------------------------------------------------
   THE SEATS COUNTER — R23c, to a supplied reference
   Claimed figure · total · caps label · bar. Four elements, one fact.
   -------------------------------------------------------------------------- */
.seats {
  /* R23h — 48/32 -> 24, by direction: "reduce the space between the heading
     and the 50/125 numbers." --gap-title-group, not an arbitrary smaller
     number: it is the token for space INSIDE a title group, and it is already
     the eyebrow's margin-block-end.
     ⚠ R23j — 24 -> 16, by direction, one further step down the scale. The
     numbers now sit CLOSER to the heading than the eyebrow does, which is
     the point: the eyebrow labels the section, the figure continues the
     sentence the heading starts. */
  margin-block-start: var(--space-sm);
  display: grid;
  gap: var(--space-2xs);
  justify-items: start;
  /* R24x — THE STROKE BOX, by direction: "inside a white stroke box aligned
     to the text to give it more attention."
     ⚠ THE BOX'S OUTER EDGES ARE THE ALIGNMENT, not the digits. Its left edge
     sits on the heading's and the lead's left edge, and it takes the lead's
     own measure, so its right edge lands where "professionals" ends — the
     same edge the bar used to hold on its own. The contents are inset by the
     card padding, which is the price of a frame that lines up with the text
     around it rather than one that hangs out into the gutter.
     ⚠ 1px, NOT --border-emphasis. White on the plate is 5.82:1 at the
     darkest stop and far more against the brighter ones, so a hairline reads
     as a deliberate edge here; the 2px token keeps its single job.
     Square, per §4 — radius 0 is inherited, not declared. */
  max-inline-size: var(--measure-final-text, var(--measure-prose));
  padding: var(--gap-card-padding);
  border: var(--border-hairline) solid var(--color-text-heading);
}

/* ⚠ R23j — `center`, NOT `baseline`, by direction: "'/ 125' will center align
   with '50' horizontally." Baseline is the typographic default and was right
   while both figures were the same weight and near the same size; at 48
   against 34 it hangs the total off the bottom of the pair. Centring reads
   as one object. */
.seats__count {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* The total is the quieter half of the pair — it is the constant, and the
   claimed figure is the thing that moves.
   ⚠ IT IS A MIX, NOT AN opacity. `opacity` would fade the whole box including
   anything ever nested in it; a colour stays a colour. Written against the
   token so it re-tints with white rather than becoming a fourth grey.
   ⚠ MEASURED: it is display scale, so the 3:1 large-text floor applies, not
   4.5. At 65% it clears on the brightest plate pixel under it — see
   design-rules.md §6 R23c. Lowering the mix breaks that first. */
/* ⚠⚠ R23i — H2 48 -> H3 34 AND weight 700 -> 400, both by direction, and the
   weight AMENDS §12a's "700" for the first time. The exception is narrow: this
   is the first numeral on the page that is half of a PAIR, and weight is what
   says which half is the news. A numeral standing alone still takes 700.
   ⚠ H3 IS THE FLOOR. §12a permits no numeral below it. */
.seats__total {
  font-size: var(--font-size-h3);
  font-weight: var(--font-weight-regular);
  font-variant-numeric: tabular-nums lining-nums;
  line-height: var(--line-height-heading);
  letter-spacing: var(--letter-spacing-heading);
  color: color-mix(in srgb, var(--color-text-heading) 65%, transparent);
}

/* .t-eyebrow supplies size, weight, case and tracking; only the colour is
   overridden, because .t-eyebrow's own is sand and this is not a sand label. */
/* ⚠ R23h — 14 -> 16, by direction: "slightly bigger". --font-size-small is
   the ONLY step up: §3's scale goes meta 14 -> small 16, and the next after
   that is body 18, which would make this label the same size as the lead it
   sits above. Still uppercase at 600, so still small text under WCAG and
   still held to 4.5:1 — the size change does not move the ratio, which was
   6.39:1 against the brightest plate pixel in its box. */
.seats__label {
  font-size: var(--font-size-small);
  color: var(--color-text-heading);
}

/* THE BAR.
   ⚠⚠ SQUARE ENDS. The reference's are round, and a pill cap is a FOURTH
   radius — proposed and reverted twice already (§7). If a fourth ever
   returns it returns everywhere, not on one bar in one section.

   ⚠ --seats-bar-height is a box dimension, not spacing: §4 is explicit that
   control heights and their like answer to no scale. It is declared here
   rather than as a global token because exactly one thing has this height. */
.seats__bar {
  --seats-bar-height: 8px;
  margin-block-start: var(--space-sm);
  /* R24x — the bar fills the stroke box's inner width. Its own
     max-inline-size (R23h's measure, which stopped it where the paragraph
     does) moved to .seats with the box: the frame now holds that edge, and
     the bar stops one card-padding inside it. */
  inline-size: 100%;
  block-size: var(--seats-bar-height);
  background-color: color-mix(in srgb, var(--color-text-heading) 22%, transparent);
  border-radius: var(--radius-none);
}

/* ⚠ THE WIDTH IS COMPUTED, NEVER TYPED. --seats-claimed and --seats-total are
   declared inline on .seats, beside the digits they duplicate. A literal
   "40%" here would be a fourth copy of one fact, free to disagree with the
   other three the moment the number changes. */
.seats__fill {
  display: block;
  inline-size: calc(var(--seats-claimed) / var(--seats-total) * 100%);
  block-size: 100%;
  background-color: var(--color-text-heading);
  /* R23q — the bar grows from the left, so the origin is the left edge and
     not the default centre. */
  transform-origin: left center;
}

/* --------------------------------------------------------------------------
   R23q — THE FILL DRAWS ITSELF ON ENTRY, by direction: "on scrolling into
   view the line will start from left and end where it is now based on the
   number, like an animation."

   ⚠⚠ scaleX, NOT AN inline-size TRANSITION. The final width stays the
   declarative calc() — one fact, still computed from --seats-claimed and
   --seats-total — and the animation is a transform on top of it. Animating
   the width instead would put the number in two places (the calc and the
   keyframe) and lay out the bar on every frame instead of compositing it.

   ⚠⚠ THE COLLAPSED STATE IS GATED ON `.js` AND ON no-preference, EXACTLY AS
   .reveal IS, AND THAT IS THE WHOLE SAFETY ARGUMENT. The bar's default —
   what a reader gets if the script never runs, or if motion is off — is the
   FINAL width. Nothing here can leave a zero-width bar on screen:
     · script fails   -> no `.js` on <html>, the rule never matches
     · motion is off  -> the media query never matches, and initCounters
                         returns before it could set the flag anyway
   Declaring `scaleX(0)` unconditionally and revealing it with JS would
   invert that, and a script error would hide the fact the bar exists to show.

   ⚠ `is-counting` IS SET BY initCounters, NOT BY THE REVEAL OBSERVER, so the
   fill starts on the frame the figure starts counting — see motion.js.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .js .seats__fill {
    transform: scaleX(0);
    transition: transform var(--duration-count) var(--ease-count);
  }

  .js [data-count-group].is-counting .seats__fill { transform: scaleX(1); }
}

.final__cta {
  margin-block-start: var(--gap-paragraph-to-cta);
  display: flex;
}
