/*
    The public marketing site's page-level stylesheet (ratified Phase 17 plan Section 3.6, slice 17H;
    the chrome extracted by the ratified Phase 18 plan Section 3.2, slice 18A).

    IT IS NO LONGER THE ONLY ONE, AND THE SPLIT IS EXACTLY ONE FILE DEEP. wwwroot/css/chrome.css
    holds the header, the footer, the navigation and the type scale, because those are what the
    Identity Razor Pages need in order to stop being a third look and a .cshtml page cannot call into
    a Blazor layout. This file keeps everything that is page-level: the reset, the body, the bands,
    the marketing sections, /pricing, the legal shell and the contact form. Phase 18's Section 5.99
    rejects any further split - each <link> is one more request on a site designed as one document,
    and chrome.css earns its request by serving a second area.

    NOT ONE LITERAL COLOUR. Every colour here is a --forge-* custom property emitted by
    Forge.Web/Public/PublicPalette.cs, which reads AppTheme's two palettes in C#. That is the whole
    reason the public site lives inside the application: a static site would have to restate the
    palette, and a restated palette is a palette that drifts. PublicPaletteTests asserts the emitted
    values against the live theme, and this file cannot introduce a colour of its own without
    somebody typing a hex into it.

    THE BREAKPOINT IS 768 px AND THERE IS NO OTHER ONE. Section 9.3 asks the header nav to collapse
    below it; every other collapsing surface in this product decides that in C# through
    IViewportWidthWatcher, which reports the width over JS interop on a circuit - and this page has
    neither. The nav's own rules moved to chrome.css with the nav; what remains here is the section
    grid. Every step BETWEEN the matrix widths comes from clamp() rather than from a second
    breakpoint, and LandingPageTests' allow-set rule permits exactly two media features across both
    served stylesheets: (min-width: 768px) and (prefers-reduced-motion: reduce).

    TOUCH TARGETS ARE 44 px, INCLUDING THE ONES THAT LOOK LIKE TEXT, because on a phone these links
    ARE the page's controls. PublicTouchTargetTests parses the floor-bearing classes out of EVERY
    served stylesheet rather than out of this one by name, so a control whose rule lives in
    chrome.css is checked and an extraction cannot silently empty the set.

    NOTHING HERE FETCHES. No @import, no url(), no web font: the system font stack is the same one
    the opt-out page uses, for the same reason - the page must render identically with no external
    network access at all.
*/

*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    background-color: var(--forge-background);
    color: var(--forge-text);

    /* AppTheme.FontStack, CHARACTER FOR CHARACTER, WHICH IT WAS NOT (Round 1 audit finding
       F18-A2-10). The Identity layout's body already declares this stack and its comment says why -
       "the shell and the login page are one product" - and this file declared a different one, so on
       Windows 11, which ships Segoe UI Variable, /features rendered in Segoe UI and
       /Identity/Account/Login rendered in Segoe UI Variable Text: the same shared header and the
       same shared footer in two typefaces, one click apart. chrome.css declares no font-family at
       all, so the one header component and the one footer component inherit whichever body rule
       their area writes, which is what made the two areas disagree about a component they share.
       A stylesheet is a static file and cannot call into AppTheme, so the stack is written out in
       both places and SharedFontStackTests compares each of them against
       AppTheme.Theme.Typography.Default.FontFamily rather than against the other. */
    font-family: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, Roboto,
        "Helvetica Neue", Arial, sans-serif;
    font-size: 1rem;
    line-height: 1.6;

    /* The document never scrolls horizontally (Section 9.3). Wide content scrolls inside its own
       container; nothing on this site is wider than its column. */
    overflow-x: hidden;
}

.forge-public {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* ---------------------------------------------------------------------------------------------
   Body.
   --------------------------------------------------------------------------------------------- */

.forge-public-main {
    flex: 1 1 auto;
    width: 100%;
    max-width: 64rem;
    margin: 0 auto;
    padding: 24px 16px 48px;
}

/* THE TYPE SCALE'S CONSUMING RULES ALL LOOK LIKE THIS (Section 5.1, and chrome.css's own header
   for what each half covers): a plain size, then the token with THAT SAME plain size as its var()
   fallback argument. The fallback fires when chrome.css has not loaded - a real failure mode now
   that a public page links two stylesheets - and it substitutes at parse time, so the resulting
   declaration is valid rather than invalid at computed-value time. It is deliberately NOT claimed
   to rescue an engine that lacks clamp(); Section 12 R9 is settled by 18G's walkthrough instead of
   by a comment here promising a fallback that cannot exist. */
/* THE HERO HEADLINE IS THE SCALE'S DISPLAY STEP, AND UNTIL NOW NOTHING WAS (Round 1 audit finding
   F18-A2-3). chrome.css declares --forge-text-display and describes it as "a display size for a
   hero"; a grep for the token across src/ and tests/ returned exactly one hit, its own declaration.
   Section 5.1 buys the ramp INSTEAD of a second typeface, and the ramp shipped one step short: every
   heading on the site, hero and legal title alike, read --forge-text-h1 and topped out at 2.6rem.
   The five hero headlines are the display headings on this site - a legal document's title is a
   title, not a poster - so this is the rule the token was written for, and pointing it here is what
   gives the first screen the step the plan describes. */
.forge-public-hero h1 {
    margin: 8px 0 12px;
    font-size: 2rem;
    font-size: var(--forge-text-display, 2rem);
    line-height: 1.2;
}

.forge-public-lede {
    margin: 0 0 8px;
    max-width: 42rem;
    color: var(--forge-text-muted);
    font-size: 1.05rem;
    font-size: var(--forge-text-lede, 1.05rem);
    line-height: var(--forge-leading-prose, 1.6);
}

/* The landing hero's two calls to action (Section 9.3: "stacked, one CTA per row" at 320 and 360,
   "two CTAs on one row" at 600 and above; slice 17I).

   NO SECOND MEDIA QUERY, AND THAT IS THE POINT. The matrix wants the pair stacked on a phone and on
   one row from 600 up, and a flex-basis does that arithmetically rather than by naming a second
   breakpoint: each action asks for 12rem, so the pair needs 24rem plus the 12px gap - 396px. At 320
   and 360 the main column offers 288px and 328px, so the second action wraps and each then takes the
   full width; at 600 it offers 568px, so both fit. There is one breakpoint on this site, which the
   768px block below states, and this rule does not add another.

   THE BASIS IS 12rem RATHER THAN 14rem BECAUSE THE HERO'S SECOND COLUMN HAS TO PAY FOR ITSELF
   (Round 1 audit findings F18-A2-8 and F18-A2-13). Above the breakpoint the pair shares the copy
   column with the illustration, and at 768px there are only 712px to divide: a pair asking 460px
   left the picture 220px, which is SMALLER than the 288px it gets on the narrowest phone in the
   matrix. A 396px pair leaves the picture 296px at the breakpoint, so it never shrinks as the
   viewport grows, and the pair still shares a row at every width from 600 up. */
.forge-public-hero-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
}

.forge-public-hero-actions > * {
    flex: 1 1 12rem;
}

/* AN ACTION IN A HERO IS NOT A ROW OF THE NAVIGATION PANEL (Round 1 audit finding F18-A2-9). The
   landing's secondary action wears .forge-public-nav-link, which is not a link style at all: it is
   the OPEN MOBILE PANEL's row style. Below 768px that rule puts a 1px full-width divider under the
   action, indents its text by the chrome's 16px gutter away from an h1 and a lede that start at 0,
   and paints its hover state in --forge-surface - which is the hero band's own ground, so hovering
   it changed nothing. It read as one row of the menu that had escaped into the hero, at three of the
   five matrix widths and not at the two a desktop reviewer looks at, because chrome.css's own 768px
   block cancels the same declarations.

   These two rules undo the panel treatment wherever a nav link is used as a hero action and give it
   the in-body link's appearance instead, at every width. They are written about the hero rather than
   about the landing so a second page borrowing the class is covered by existing. */
.forge-public-hero-actions .forge-public-nav-link {
    justify-content: center;
    padding: 0;
    border-bottom: 0;
    color: var(--forge-primary);
    font-weight: 600;
    text-decoration: underline;
    text-decoration-color: transparent;
    text-underline-offset: 0.2em;
}

.forge-public-hero-actions .forge-public-nav-link:hover,
.forge-public-hero-actions .forge-public-nav-link:focus-visible {
    background-color: transparent;
    text-decoration-color: currentColor;
}

/* minmax(0, 1fr) RATHER THAN A BARE 1fr, WHICH IS A CLIPPING FIX RATHER THAN A TIDY-UP (Round 1
   audit finding F18-A2-1). A bare 1fr is minmax(auto, 1fr), and an auto minimum is the largest
   min-content contribution among the track's items - so a card holding an unbreakable token GROWS
   the track past the band's measure, and body's overflow-x: hidden then clips the right-hand edge of
   every card in the grid with no scrollbar to say so. The one grid on this site that holds
   owner-supplied text was the one still written as a bare 1fr: /contact renders
   PublicSite:ContactAddress as its own link text, and an address is one unbreakable token with no
   bound. The three grids 18C wrote were already minmax(0, 1fr) for exactly this reason. */
.forge-public-sections {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    margin-top: 24px;
}

.forge-public-section {
    padding: 16px;
    border: 1px solid var(--forge-divider);
    border-radius: 10px;
    background-color: var(--forge-surface);
}

.forge-public-section h2 {
    margin: 0 0 8px;
    font-size: 1.15rem;
    font-size: var(--forge-text-h2, 1.15rem);
}

.forge-public-section p {
    margin: 0 0 8px;
}

.forge-public-badge {
    display: inline-block;
    margin: 0 0 8px;
    padding: 2px 10px;
    border: 1px solid var(--forge-divider);
    border-radius: 999px;
    color: var(--forge-text-muted);
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    font-weight: 600;
}

.forge-public-list {
    margin: 0;
    padding-left: 20px;
    color: var(--forge-text-muted);
}

/* AND IT WRAPS, BECAUSE ITS TEXT IS SOMETIMES A SETTING (Round 1 audit finding F18-A2-1). /contact
   renders PublicSite:ContactAddress as this class's own link text. An email address is one
   unbreakable token, and an inline-flex box's min-content width is that token - so a long address
   floors the box, floors the grid track above it, and the page is clipped rather than scrolled.
   overflow-wrap: anywhere is the value that reduces the min-content size (break-word does not), and
   min-width: 0 is what lets the box itself shrink when it is laid out as a flex item. */
.forge-public-link {
    display: inline-flex;
    align-items: center;
    min-width: 0;
    min-height: 44px;
    overflow-wrap: anywhere;
    color: var(--forge-primary);
    font-weight: 600;
}

/* ---------------------------------------------------------------------------------------------
   768 px and up: the marketing sections become two columns.

   THIS IS THE ONE BREAKPOINT ON THE PUBLIC SITE, and after 18A it is the only thing this block
   still decides here. The disclosure's four rules - the summary turned off, the nav's width, the
   ::details-content reveal the whole desktop navigation rests on, and the link row - moved to
   chrome.css with the header they describe, and PublicLayoutTests' pins moved with them: the pins
   read whichever served stylesheet declares .forge-public-nav (plan Section 3.3), so the extraction
   carried the assertion rather than emptying it.

   THE HERO HEADING'S OLD 2.1rem OVERRIDE IS GONE, AND THAT IS THE TYPE SCALE DOING ITS JOB. The
   heading now reads --forge-text-h1, which is a clamp: 1.7rem at 320 px, about 2.19rem at this
   breakpoint and 2.6rem at the top. A fixed override here would flatten the ramp back into a step
   and would be a second place to decide a font size.
   --------------------------------------------------------------------------------------------- */

@media (min-width: 768px) {
    .forge-public-sections {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    /* A LONE CALL TO ACTION TAKES ITS OWN WIDTH FROM HERE UP (Round 1 audit finding F18-A2-8). The
       basis above is written for a PAIR, and flex-grow: 1 on a single item means it absorbs every
       pixel of free space: four of the five heroes render exactly one action, so /about's "See what
       it does" was a 665 px pill at 1024 with a 100 px label centred in it. Turning the growth off
       above the breakpoint leaves the 320 and 360 stacking exactly as it is - each action still
       fills its own row there, which is Section 9.3's phone row - and lets an action take its
       12 rem basis on a laptop. */
    .forge-public-hero-actions > * {
        flex-grow: 0;
    }
}

/* ---------------------------------------------------------------------------------------------
   /pricing (ratified Phase 17 plan Sections 3.10, 5.14 and 9.3, slice 17K).

   THE RULES LIVE HERE RATHER THAN IN A Pricing.razor.css, AND THAT IS A CORRECTION RATHER THAN A
   PREFERENCE. App.razor's [PublicPage] branch serves this stylesheet and DELIBERATELY omits
   Forge.Web.styles.css, the scoped-CSS bundle - so a component-scoped stylesheet next to the page
   would compile, ship, parse cleanly and be fetched by nobody. That is the ScopedStylesheetReachTests
   defect class in its most complete form: not a selector that reaches nothing, but a whole file.

   THE INTERVAL TOGGLE IS CSS ONLY. There is no circuit on this site and no script, so the monthly
   and yearly figures are BOTH rendered and one set is hidden: the two radio inputs are the first
   children of .forge-pricing and the sibling combinator below reaches forward from whichever one is
   checked. The inputs themselves are off-screen rather than display:none, because a hidden input
   cannot be reached by a keyboard and the labels are what a reader clicks.

   THE TABLE SCROLLS INSIDE ITS OWN CONTAINER at every width, which is how the six-column comparison
   fits a 320 px phone while the DOCUMENT still never scrolls sideways (Section 9.3). Above the
   breakpoint it simply fits and no scrollbar appears.
   --------------------------------------------------------------------------------------------- */

.forge-pricing {
    margin-top: 24px;
}

.forge-pricing-choice {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.forge-pricing-toggle {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}

/* THE UNCHECKED LABEL'S EDGE IS --forge-control-edge, NOT --forge-divider (Section 3.8). A toggle
   is a user interface component, so its visual boundary owes WCAG 2.2 SC 1.4.11 a 3:1 ratio against
   the surface it sits on; the divider computed to 1.27:1 in light and 1.28:1 in dark, which is a
   control whose edge a reader cannot see. PublicContrastTests reads whichever token THIS
   declaration names and computes the ratio, so reverting this line fails the build rather than
   quietly restoring the defect. */
.forge-pricing-toggle-label {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 16px;
    border: 1px solid var(--forge-control-edge);
    border-radius: 999px;
    background-color: var(--forge-surface);
    color: var(--forge-text-muted);
    font-weight: 600;
    cursor: pointer;
}

/* THE HOVERED LABEL. It is a separate rule from the focus one below because the two want different
   treatments: hover is a pointer hint on a label the reader has not chosen, and focus has to survive
   the :checked rule underneath it. */
.forge-pricing-toggle-label:hover {
    border-color: var(--forge-primary);
    color: var(--forge-text);
}

/* THE FOCUSED LABEL. It is the same shape as the checked rule below, and for the same reason
   (finding F17M-4-2): "+" is the ADJACENT sibling combinator, so
   #forge-pricing-monthly:focus-visible + .forge-pricing-toggle matched nothing at all - the element
   immediately after the monthly radio is the annual radio - and a descendant selector with no
   [for=] filter would have highlighted both labels rather than the focused one. The inputs are
   deliberately off-screen rather than display:none, precisely so a keyboard reader can reach them,
   and the reader lands on the CHECKED one first: with no focus indicator that is the page's only
   interactive control giving no sign it has focus.

   AND THE OUTLINE IS WHAT MAKES IT VISIBLE, WHICH THE BORDER AND THE COLOUR NEVER WERE (Round 1
   audit findings F18-A2-2 and F18-A1-1; the SECOND remediation on this one control). This rule and
   the :checked rule below are the same selector shape and therefore the same specificity, and the
   checked rule is declared later, so on the label a reader is actually on it wins BOTH declarations
   they share: border-color is the value :checked already sets, and color loses outright. Focused
   and unfocused computed to identical pixels, on the only state a reader can be in - a radio cannot
   be focused without being checked, because an arrow key moves selection with focus - and the
   radios' own user-agent ring is clipped away by clip-path: inset(50%) above.

   An outline is the fix rather than a stronger colour because the checked rule DOES NOT DECLARE ONE:
   a property the later rule never mentions cannot be overridden by it, whatever the specificity.
   It is drawn outside the border box, so it does not move the label, and nothing else on this page
   declares an outline. PricingControlAffordanceTests resolves the two rules against each other rather
   than asserting either one's text. */
#forge-pricing-monthly:focus-visible ~ .forge-pricing-toggle .forge-pricing-toggle-label[for="forge-pricing-monthly"],
#forge-pricing-annual:focus-visible ~ .forge-pricing-toggle .forge-pricing-toggle-label[for="forge-pricing-annual"] {
    border-color: var(--forge-primary);
    color: var(--forge-text);
    outline: 2px solid var(--forge-primary);
    outline-offset: 2px;
}

/* THE CHECKED LABEL. Each radio reaches its own label through the toggle row that follows it. */
#forge-pricing-monthly:checked ~ .forge-pricing-toggle .forge-pricing-toggle-label[for="forge-pricing-monthly"],
#forge-pricing-annual:checked ~ .forge-pricing-toggle .forge-pricing-toggle-label[for="forge-pricing-annual"] {
    border-color: var(--forge-primary);
    background-color: var(--forge-primary);
    color: var(--forge-primary-contrast);
}

/* THE TWO SETS OF FIGURES AND CALLS TO ACTION. Both are in the markup; one is shown. */
#forge-pricing-monthly:checked ~ .forge-pricing-cards .forge-pricing-annual,
#forge-pricing-annual:checked ~ .forge-pricing-cards .forge-pricing-monthly {
    display: none;
}

.forge-pricing-cards {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

.forge-pricing-card {
    display: flex;
    flex-direction: column;
    padding: 16px;
    border: 1px solid var(--forge-divider);
    border-radius: 10px;
    background-color: var(--forge-surface);
}

.forge-pricing-card-raised {
    border-color: var(--forge-primary);
    border-width: 2px;
}

.forge-pricing-name {
    margin: 0 0 8px;
    font-size: 1.15rem;
    font-size: var(--forge-text-h3, 1.15rem);
}

.forge-pricing-price {
    margin: 0 0 4px;
}

.forge-pricing-figure {
    font-size: 1.6rem;
    font-weight: 700;
}

.forge-pricing-unit {
    color: var(--forge-text-muted);
}

.forge-pricing-note {
    margin: 0 0 4px;
    color: var(--forge-text-muted);
    font-size: 0.9rem;
}

.forge-pricing-description {
    margin: 8px 0 16px;
    color: var(--forge-text-muted);
}

.forge-pricing-current {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    margin: auto 0 0;
    color: var(--forge-text-muted);
    font-weight: 600;
}

.forge-pricing-comparison {
    margin-top: 24px;
}

.forge-pricing-table-scroll {
    overflow-x: auto;
}

.forge-pricing-table {
    width: 100%;
    border-collapse: collapse;
    text-align: left;
}

.forge-pricing-caption {
    margin-bottom: 8px;
    color: var(--forge-text-muted);
    text-align: left;
}

.forge-pricing-table th,
.forge-pricing-table td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--forge-divider);
    white-space: nowrap;
}

/* THE ACCESSIBLE NAME OF A TICK OR A CROSS. The glyph is aria-hidden and this is what a screen
   reader announces, so a cell is never read out as an unlabelled symbol. */
.forge-pricing-reader {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.forge-pricing-ai {
    margin-top: 24px;
}

.forge-pricing-faq {
    margin-top: 24px;
}

.forge-pricing-question {
    border-top: 1px solid var(--forge-divider);
}

.forge-pricing-question:first-of-type {
    border-top: 0;
}

/* THE DISCLOSURE SAYS THAT IT OPENS (Round 1 audit finding F18-A2-6). A <summary> draws the
   browser's triangle because the user agent stylesheet gives it display: list-item, and overriding
   display removes the marker generation - the same thing .forge-public-nav-toggle does, which is why
   that rule declares list-style: none and says so. This one declared nothing, because the marker was
   already gone: four questions were four lines of bold body text whose only affordance was
   cursor: pointer, and a phone has no pointer. list-style: none is restated here for the reader
   rather than for the browser. */
.forge-pricing-summary {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 44px;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}

/* THE CARET, DRAWN RATHER THAN FETCHED OR INLINED, exactly as chrome.css draws the navigation's.
   Two borders on an empty pseudo-element: no glyph, because a glyph is a font's opinion about a
   shape and this site ships no font; no url(), no asset, and no markup for a sweep to make an
   exception for. It rotates on open, so the control says what it will DO rather than only what it
   is - and because the rule is on the class every question's summary already wears, a fifth question
   is covered by existing rather than by being remembered. */
.forge-pricing-summary::after {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    margin-left: auto;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    transition: transform var(--forge-motion, 160ms) var(--forge-motion-ease, ease-out);
}

.forge-pricing-question[open] .forge-pricing-summary::after {
    transform: rotate(225deg);
}

@media (min-width: 768px) {
    .forge-pricing-cards {
        grid-template-columns: repeat(3, 1fr);
    }

    .forge-pricing-table th,
    .forge-pricing-table td {
        white-space: normal;
    }
}

/* ---------------------------------------------------------------------------------------------
   Legal documents (slice 17J: /privacy, /terms, /acceptable-use, /subprocessors).

   ONE COLUMN AT EVERY WIDTH, WITH A MEASURE. Section 9.3's row for these pages asks for "one
   column, 70ch measure", and the reason is the rule above it: .forge-public-sections becomes two
   columns at 768 px, which is right for marketing cards and wrong for prose. A legal document read
   at 64 rem is a document people lose their place in. So these pages use their own container, it
   never changes column count, and the measure is capped in ch rather than rem so it follows the
   reader's own font size.

   THE ONLY THING THAT SCROLLS SIDEWAYS IS THE SUB-PROCESSOR TABLE, AND IT SCROLLS INSIDE ITSELF.
   The document never scrolls horizontally (Section 9.3's standing rule, held on body above), so a
   six-column table on a 320 px phone is given its own overflow container rather than being allowed
   to widen the page.

   NOT ONE LITERAL COLOUR, like the rest of this file: every value is a --forge-* property emitted
   from AppTheme in C#.
   --------------------------------------------------------------------------------------------- */

.forge-legal {
    max-width: 70ch;
    margin: 0 auto;
}

.forge-legal-header {
    padding-bottom: 16px;
    border-bottom: 1px solid var(--forge-divider);
}

.forge-legal-eyebrow {
    margin: 0;
    color: var(--forge-text-muted);
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    font-weight: 600;
    letter-spacing: 0.08em;
    letter-spacing: var(--forge-tracking-wide, 0.08em);
    text-transform: uppercase;
}

.forge-legal-header h1 {
    margin: 4px 0 12px;
    font-size: 1.7rem;
    font-size: var(--forge-text-h1, 1.7rem);
    line-height: 1.25;
}

.forge-legal-lede {
    margin: 0 0 16px;
    color: var(--forge-text-muted);
    font-size: 1.05rem;
    font-size: var(--forge-text-lede, 1.05rem);
    line-height: var(--forge-leading-prose, 1.6);
}

/* The dates, side by side where there is room and stacked where there is not. A definition list
   because that is what they are: a label and the one value that answers it. */
.forge-legal-dates {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 24px;
    margin: 0;
}

.forge-legal-date dt {
    color: var(--forge-text-muted);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.forge-legal-date dd {
    margin: 0;
    font-weight: 600;
}

.forge-legal-section {
    margin-top: 28px;
}

.forge-legal-section h2 {
    margin: 0 0 8px;
    font-size: 1.15rem;
    font-size: var(--forge-text-h2, 1.15rem);
}

/* A legal document is the one thing on this site anybody reads at length, so it takes the wider
   leading. The 70ch measure above is unchanged. */
.forge-legal-section p {
    margin: 0 0 12px;
    line-height: var(--forge-leading-prose, 1.6);
}

/* The sub-processor table. Its own scroller, so the six columns never widen the document. */
.forge-legal-table-scroll {
    overflow-x: auto;
}

.forge-legal-table {
    width: 100%;
    border-collapse: collapse;
    text-align: left;
}

.forge-legal-table caption {
    margin-bottom: 8px;
    color: var(--forge-text-muted);
    font-size: 0.85rem;
    font-size: var(--forge-text-sm, 0.85rem);
    text-align: left;
}

.forge-legal-table th,
.forge-legal-table td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--forge-divider);
    vertical-align: top;

    /* Wide enough to read a sentence in, narrow enough that six of them fit a laptop. Below the
       table breakpoint the container above is what scrolls. */
    min-width: 14ch;
}

.forge-legal-table thead th {
    background-color: var(--forge-surface);
    font-size: 0.85rem;
    letter-spacing: 0.02em;
}

.forge-legal-table tbody th {
    font-weight: 600;
}

/* Each link in the last column is its own row of the cell, so two of them never share a line and
   lose the 44 px floor .forge-public-link carries. */
.forge-legal-table td .forge-public-link {
    display: flex;
}

/* ---------------------------------------------------------------------------------------------
   The contact form (slice 17L: /contact behind Feature:PublicSiteContactForm).

   A NATIVE FORM, AND THE RULES HERE ARE THE ONLY STYLING IT GETS. The page is static SSR with no
   script and no MudBlazor, so an input is an <input>: these rules give it the same surface, border
   radius and 44 px floor every other control on this site carries, and nothing else. The form is
   usable with CSS disabled entirely, which is the property the whole public shell is built for.

   IT SPANS BOTH COLUMNS AT AND ABOVE 768 px. .forge-public-sections becomes two columns there,
   which is right for the short channel cards beside it and wrong for a message box: a textarea in
   a half-width card is a box people write one line in. The span is a separate media block at the
   end of this file rather than an edit to the one above, which is the append-only discipline
   Section 6.0 asks of every slice that touches this stylesheet after 17H.

   NOT ONE LITERAL COLOUR, like the rest of this file. The refusal line is marked by weight and a
   rule down its edge in --forge-error, which Phase 18's widened emission supplies from AppTheme's
   Error slot; before that the emission carried no error colour at all - AppTheme always had one -
   and the rule borrowed the primary. It still carries role="alert" in the markup, which is what a
   screen reader acts on: the colour was never the accessible part.

   AND THE INPUTS' EDGE IS --forge-control-edge, WHICH IS A CONFORMANCE FIX RATHER THAN A RESTYLE
   (Section 3.8). --forge-divider on this card computed to 1.27:1 in light and 1.28:1 in dark
   against WCAG 2.2 SC 1.4.11's 3:1 for a user interface component.
   --------------------------------------------------------------------------------------------- */

.forge-public-form {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-top: 8px;
}

.forge-public-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.forge-public-field label {
    color: var(--forge-text-muted);
    font-size: 0.9rem;
    font-weight: 600;
}

/* THE SAME EDGE, ON THE ONE PUBLIC PAGE WHERE A STRANGER TYPES. This was 1px of --forge-divider on
   --forge-background inside a --forge-surface card: 1.27:1 light and 1.28:1 dark against SC
   1.4.11's 3:1. It was found by computing the numbers rather than by looking at the page, which is
   exactly why the guard computes rather than looks. */
.forge-public-input {
    width: 100%;
    min-height: 44px;
    padding: 10px 12px;
    border: 1px solid var(--forge-control-edge);
    border-radius: 8px;
    background-color: var(--forge-background);
    color: var(--forge-text);
    font-family: inherit;
    font-size: 1rem;
    line-height: 1.4;
}

.forge-public-input:focus-visible {
    border-color: var(--forge-primary);
    outline: 2px solid var(--forge-primary);
    outline-offset: 1px;
}

.forge-public-textarea {
    min-height: 8rem;
    resize: vertical;
}

/* The submit control is the site's own call to action, so it is a <button> wearing that class and
   needs only the things a button does not inherit from an <a>. */
.forge-public-form .forge-public-cta {
    align-self: flex-start;
    border: 0;
    font-family: inherit;
    font-size: 1rem;
    cursor: pointer;
}

.forge-public-form-error {
    margin: 0;
    padding: 8px 12px;
    border-left: 4px solid var(--forge-error);
    background-color: var(--forge-background);
    font-weight: 600;
}

.forge-public-form-note {
    margin: 0;
    color: var(--forge-text-muted);
    font-size: 0.85rem;
    font-size: var(--forge-text-sm, 0.85rem);
}

.forge-public-form-sent {
    margin: 0 0 8px;
    font-weight: 600;
}

@media (min-width: 768px) {
    /* Both columns, for the reason in this block's header: a message box is not a card. The span is
       carried by a class on the section rather than by :has(), because this stylesheet is parsed and
       compared rule by rule by StylesheetParseTests and a selector the parser models differently is
       a rule a reader may never get. */
    .forge-public-form-section {
        grid-column: 1 / -1;
    }

    .forge-public-input {
        max-width: 32rem;
    }

    .forge-public-textarea {
        max-width: 44rem;
    }
}

/* ---------------------------------------------------------------------------------------------
   The band model (ratified Phase 18 plan Section 5.2, slice 18A).

   PRIMITIVES ONLY: NO PAGE ADOPTS THESE YET, AND THAT IS THE PLAN'S OWN SEQUENCING. 18A owns this
   stylesheet outright and defines the system; 18C is the first slice to render a band, and 18D and
   18E follow it in strict order (Section 6.0). Shipping the rules ahead of the markup is what lets
   those three slices append markup without appending a design.

   WHAT A BAND IS. "Plain and bland" was largely nine pages built from one 64rem container and one
   card style, so the answer is not a palette edit: a band is a full-bleed <section> carrying its own
   ground, with an inner element that restores the measure. .forge-public-main caps itself at 64rem,
   which is right for a document and wrong for a band, so a page that uses bands puts
   .forge-public-main-bands on the main element and lets each band own its padding. A page that does
   not is completely unaffected, which is why this can land a slice early.

   THEY ALTERNATE, AND THE ALTERNATION IS THE WHOLE POINT. --forge-surface and --forge-band are one
   step apart in each theme independently - the band recedes in light and lifts in dark, because the
   emission reads a different slot per theme for exactly this reason - so a stack of bands reads as
   sections rather than as one long page.

   TWO COLOURED TREATMENTS, EACH DECLARING ITS OWN TEXT COLOUR. PublicContrastTests computes both
   against WCAG 2.2 SC 1.4.3's 4.5:1 in both themes, reading whichever tokens THESE declarations
   name rather than a pair written down in the test, so a band cannot be re-tinted into an
   unreadable one without failing the build.
   --------------------------------------------------------------------------------------------- */

.forge-public-main-bands {
    max-width: none;
    padding: 0;
}

.forge-band {
    width: 100%;
    padding: 40px 16px;
    background-color: var(--forge-surface);
}

.forge-band-inner {
    width: 100%;
    max-width: 64rem;
    margin: 0 auto;
}

.forge-band-alt {
    background-color: var(--forge-band);
}

.forge-band-accent {
    background-color: var(--forge-accent);
    color: var(--forge-accent-contrast);
}

.forge-band-proof {
    background-color: var(--forge-secondary);
    color: var(--forge-secondary-contrast);
}

/* A link on a coloured band inherits the band's own text colour rather than keeping the page's
   primary, which on the accent would be a blue on a violet that neither theme makes legible. It
   needs no ratio of its own: it is the colour PublicContrastTests already computes for the band. */
.forge-band-accent a,
.forge-band-proof a {
    color: inherit;
}

/* ---------------------------------------------------------------------------------------------
   Motion, tier 1 (Section 5.8), and the reduced-motion arm this stylesheet owes.

   ONLY THE TWO CONTROLS THIS FILE GIVES A STATE RULE TO. .forge-public-input changes its border on
   focus and .forge-pricing-toggle-label changes its border, ground and text on hover and on
   :checked; everything else on these pages is static, and transitioning a property nothing changes
   is a declaration with no reader. Nothing here decides whether an element is visible, which is
   Section 12 R3's failure mode in its cheapest form: remove every line below and the pages are
   correct, just instant.

   ONE ARM PER STYLESHEET, NAMING THE CLASSES THIS FILE ANIMATES. A universal-selector arm would
   satisfy 18E's coverage guard by construction, and a guard that cannot fail is not protecting the
   reader who asked their operating system to stop things moving.
   --------------------------------------------------------------------------------------------- */

.forge-public-input,
.forge-pricing-toggle-label {
    transition:
        background-color var(--forge-motion, 160ms) var(--forge-motion-ease, ease-out),
        border-color var(--forge-motion, 160ms) var(--forge-motion-ease, ease-out),
        color var(--forge-motion, 160ms) var(--forge-motion-ease, ease-out);
}

/* THE ARM NAMES THE PSEUDO-ELEMENT, NOT ITS OWNER. The FAQ caret's transition is declared on
   .forge-pricing-summary::after, and transition properties are not inherited, so switching the
   summary off would leave the caret spinning for a reader who asked their operating system to stop
   things moving. */
@media (prefers-reduced-motion: reduce) {
    .forge-public-input,
    .forge-pricing-toggle-label,
    .forge-pricing-summary::after {
        animation: none;
        transition-duration: 0.01ms;
    }
}

/* ---------------------------------------------------------------------------------------------
   The landing's bands, its hero, its capability rows and the AI showcase (ratified Phase 18 plan
   Sections 4, 5.2, 5.3 and 9.3, slice 18C).

   ONE APPENDED BLOCK AT THE END OF THE FILE, which is Section 6.0's ordering rule rather than a
   habit: 18C, 18D and 18E each add one block to this stylesheet, strictly in that order and never
   in parallel, so no earlier rule is reordered and no two slices ever edit the same lines. Nothing
   above this comment was touched.

   HOW A BAND ESCAPES THE 64 rem COLUMN, AND WHY IT IS NOT THE CLASS 18A SHIPPED FOR IT. 18A defined
   .forge-public-main-bands to be put on the <main> element, and PublicLayout.razor - the file that
   writes that element - belongs to 18B, which is being built at the same time as this slice. So the
   escape is asked for by the page instead of by the layout: the landing renders .forge-bands, and
   the rule below removes the cap and the padding from whichever main contains it. The declarations
   are the same two 18A wrote, and LandingPageTests compares the two rules declaration for
   declaration, so the pair cannot drift into disagreeing about what a band page is.

   EVERY STEP BETWEEN THE MATRIX WIDTHS IS ARITHMETIC, NOT A SECOND BREAKPOINT. There is one
   breakpoint on this site and the allow-set rule permits exactly two media features across both
   served stylesheets, so the proof strip's one, two and three columns come from an auto-fit track
   whose minimum is the number that produces the Section 9.3 row, and the hero's two calls to action
   keep the flex-basis arithmetic 17I wrote. Each is worked out in the comment above its rule.

   NO MOTION IN THIS SLICE, DELIBERATELY. Tier 1 is already carried by the two files' existing
   transition rules and their reduced-motion arms; tier 2's keyframes belong to 18E, which owns
   PublicMotionTests. A keyframe written here would ship referenced by an animation nobody asserts,
   which is the "a rule that ships asserted by nothing is a defect rather than a head start" class.

   NOT ONE LITERAL COLOUR, like the rest of this file. The ornament is two gradients over palette
   tokens: color-mix() is Baseline widely available (May 2023, plan Section 3.1), and an engine that
   cannot parse it drops the background-image declaration and keeps the plain background-color
   before it, which is a solid panel rather than an empty box.
   --------------------------------------------------------------------------------------------- */

.forge-public-main:has(.forge-bands) {
    max-width: none;
    padding: 0;
}

/* ---- The hero band --------------------------------------------------------------------------

   THE COPY COLUMN IS 1.4fr AGAINST THE VISUAL'S 1fr, AND THE ARITHMETIC IS STATED FOR BOTH COLUMNS
   RATHER THAN FOR THE COPY ALONE (Round 1 audit finding F18-A2-13). The ratio shipped at 2.2:1,
   worked out from the copy column's needs and nothing else, and what paid for it was the picture:
   at 768 px the figure was 220 px, a quarter narrower than the 288 px it gets at 320 px, so one
   pixel of viewport shrank the hero illustration by two thirds.

   Both columns, at the breakpoint: the band's inner measure is 736 px (768 less this band's own
   16 px sides) and the hero grid's 24 px gap leaves 712 px to divide.
     Copy    1.4 of 2.4 of 712 = 415 px, and Section 9.3 asks for the two calls to action on ONE row
             from 600 upwards - which, at the 12 rem basis above, needs 396 px. 415 >= 396.
     Visual  1.0 of 2.4 of 712 = 296 px, against the 288 px the same figure takes at 320 px where the
             grid is one column. 296 >= 288, so the picture never shrinks as the viewport grows.
   At 1024 px the inner measure is 992 px, so the copy takes 565 px and the visual 403 px.

   Below the breakpoint the grid is one column, so the visual sits BELOW the text, which is the
   hero's own row of the matrix and the opposite of the capability bands below. */

.forge-hero {
    padding-top: 48px;
    padding-bottom: 48px;
}

.forge-hero-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
    align-items: center;
}

/* ---- The capability bands -------------------------------------------------------------------

   THE FIGURE COMES FIRST IN THE MARKUP AND THAT IS THE MOBILE LAYOUT (Section 9.3: "single column,
   image above text"). Ordering it any other way below the breakpoint would need a max-width query,
   which this site does not have, so the DOM carries the phone's order and the block below places
   the two columns at and above 768 px. The figure is aria-hidden, so a screen reader meets the
   heading first whichever side the picture is on. */

.forge-capability {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
    align-items: center;
}

.forge-capability-copy h2 {
    margin: 0 0 8px;
    font-size: 1.15rem;
    font-size: var(--forge-text-h2, 1.15rem);
}

.forge-capability-copy p {
    margin: 0;
    color: var(--forge-text-muted);
    line-height: var(--forge-leading-prose, 1.6);
}

/* ---- The AI showcase (Section 5.3) -----------------------------------------------------------

   EVERYTHING ON THIS BAND READS THE BAND'S OWN TEXT COLOUR. The accent ground is a violet, and the
   muted grey that carries a summary on a plain band would fail SC 1.4.3 against it - so nothing
   here declares a colour at all except the claim rule's edge, which takes currentColor and is
   therefore the pair PublicContrastTests already computes for this band. A second line set apart by
   opacity would be the same mistake wearing a different hat: it would change the contrast and no
   guard could see it, so the second line is set apart by size and weight instead. */

.forge-ai {
    display: grid;
    gap: 20px;
}

/* A BAND HEADLINE IS A STEP ABOVE A CARD HEADING, AND SAYING SO TWICE IN THE SAME RULE DID NOT MAKE
   IT ONE (Round 1 audit finding F18-A2-4). This rule and .forge-closing h2 declared font-size:
   1.5rem and then font-size: var(--forge-text-h2, 1.5rem), and the second declaration always wins
   whenever chrome.css loads - which is every real page load. --forge-text-h2 is
   clamp(1.15rem, 1.02rem + 0.65vw, 1.5rem), so on a phone the AI showcase's headline, the closing
   call to action's headline, a capability heading, a marketing card heading and a legal section
   heading were all 18.4px: five levels at one size, and the hierarchy the 1.5rem declaration was
   written to state existed at no width in the matrix.

   The answer is to pick the step rather than to write the number twice. A full-bleed band's headline
   is the second level on this site, under the hero's display step and above the card headings, so it
   reads --forge-text-h1 - 27.2px on a phone, 39.5px at 1024 - and the plain declaration in front of
   it is that token's own floor, which is the convention chrome.css states for itself. */
.forge-ai h2 {
    margin: 0 0 12px;
    font-size: 1.7rem;
    font-size: var(--forge-text-h1, 1.7rem);
}

.forge-ai-lead {
    margin: 0 0 12px;
    font-size: 1.15rem;
    font-size: var(--forge-text-h3, 1.15rem);
    font-weight: 600;
    line-height: 1.35;
}

.forge-ai-second {
    margin: 0;
    line-height: var(--forge-leading-prose, 1.6);
}

.forge-ai-claims {
    display: grid;
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.forge-ai-claim {
    margin: 0;
    padding-left: 12px;
    border-left: 2px solid currentColor;
}

.forge-ai-more {
    margin: 0;
}

/* ---- The closing band ------------------------------------------------------------------------ */

.forge-closing {
    display: grid;
    justify-items: center;
    gap: 12px;
    text-align: center;
}

/* The closing band's headline is the same level as the AI band's, for the reason stated there. */
.forge-closing h2 {
    margin: 0;
    font-size: 1.7rem;
    font-size: var(--forge-text-h1, 1.7rem);
}

.forge-closing p {
    margin: 0;
    max-width: 42rem;
    color: var(--forge-text-muted);
}

/* ---- The visual frame and its ornament (Section 3.7, decision Q5) ----------------------------

   THE FRAME IS SHIPPED AND THE PICTURE IS NOT, WHICH IS THE WHOLE POINT OF A NAMED SLOT. Each frame
   declares which slot it is through data-visual-slot, and 18E replaces the ornament inside it with
   an illustration and the reserved <picture> screenshot source. Until then the ornament is drawn
   here: no url(), no CSS mask, no inline SVG and no image file that does not exist.

   THE ASPECT RATIO IS WHAT KEEPS THE PAGE FROM MOVING. A frame with a declared ratio reserves its
   height before anything is painted, so the illustration 18E drops in lands in a box the reader has
   already seen rather than pushing the band below it down the page. */

/* THE FRAME'S EDGE IS --forge-control-edge, AND THAT IS A VISIBILITY FIX RATHER THAN A RESTYLE
   (Round 1 audit finding F18-A2-5). --forge-divider computes to 1.09:1 in light and 1.21:1 in dark
   against --forge-band, which is BOTH the alternating band's ground AND the colour the illustration
   paints its own backing rect in. So on every alternating band there was no visible frame, no
   visible edge between the picture and the page, and the "framed panel" 18C and 18E both describe in
   their comments was not on the page at all. The control edge clears 3:1 against every neutral
   ground in both themes, computed rather than eyeballed by PublicIllustrationContrastTests. */
.forge-band-visual {
    margin: 0;
    padding: 0;
    border: 1px solid var(--forge-control-edge);
    border-radius: 14px;
    overflow: hidden;
}

/* EXCEPT ON A COLOURED BAND, WHERE THE SAME GREY WOULD BE 1.08:1. The AI showcase's ground is the
   accent violet and the product-proof band's is the second hue; a neutral edge disappears into
   either. currentColor is the band's own declared text colour, which is the pair
   PublicContrastTests already computes for that band, so the frame is legible on all four grounds
   without introducing a fifth token. */
.forge-band-accent .forge-band-visual,
.forge-band-proof .forge-band-visual {
    border-color: currentColor;
}

.forge-band-ornament {
    aspect-ratio: 16 / 10;
    background-color: var(--forge-primary);
    background-image:
        linear-gradient(135deg, color-mix(in srgb, var(--forge-secondary) 70%, transparent) 0%, transparent 58%),
        linear-gradient(205deg, color-mix(in srgb, var(--forge-accent) 60%, transparent) 0%, transparent 62%);
}

/* ---------------------------------------------------------------------------------------------
   768 px and up: the bands take their second column, and the capability rows alternate sides.

   THE SIDE ALTERNATES BY PLACEMENT RATHER THAN BY nth-child, because how many capability bands
   render depends on how many flags are on: the page counts the bands and puts .forge-capability-flip
   on every other one, so the alternation survives a flag being flipped. Both halves are placed
   explicitly on row 1, so the two columns cannot be dealt into two rows by the auto-placement
   algorithm when a copy block grows.
   --------------------------------------------------------------------------------------------- */

@media (min-width: 768px) {
    .forge-hero .forge-hero-inner {
        grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    }

    .forge-band .forge-capability {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .forge-capability .forge-band-visual {
        grid-column: 1;
        grid-row: 1;
    }

    .forge-capability-copy {
        grid-column: 2;
        grid-row: 1;
    }

    .forge-capability-flip .forge-band-visual {
        grid-column: 2;
    }

    .forge-capability-flip .forge-capability-copy {
        grid-column: 1;
    }
}

/* ---------------------------------------------------------------------------------------------
   The illustrations in their frames, the motion tiers, and the two items 18D carried here
   (ratified Phase 18 plan Sections 3.5, 3.7, 5.7, 5.8 and 9.2, slice 18E).

   ONE APPENDED BLOCK AT THE END OF THE FILE, which is Section 6.0's ordering rule: 18C, 18D and 18E
   each add one block to this stylesheet, strictly in that order. 18D's block was empty - its
   acceptance's own success case - so this follows 18C's directly and nothing above it was touched.

   HOW THE PICTURE SITS IN THE FRAME, AND WHY THE ORNAMENT IS STILL HERE. 18C shipped
   .forge-band-visual as the frame and .forge-band-ornament as a gradient panel inside it, with a
   16:10 aspect-ratio holding the height before anything is painted. This slice does NOT delete the
   ornament: the class moves onto the <picture> element, so the gradient becomes the GROUND the
   illustration is drawn on. That keeps three things at once - the reserved height, a painted panel
   in the frame in the moment before an image decodes, and something to look at if an image ever
   fails - and it means the rule 18C wrote is still the rule that reserves the box rather than a
   declaration nothing reaches. A picture element is an inline box by default, which is why
   display: block is the one thing that has to be added: aspect-ratio on an inline box does nothing.

   THE TWO SOURCES ARE A prefers-color-scheme QUERY IN THE MARKUP, NOT IN THIS FILE. The picture
   element's own media attribute is what selects the dark drawing, so the media-query allow-set
   (LandingPageTests) still sees exactly two features across both served stylesheets. There is a
   limit worth stating rather than hiding: a reader whose theme COOKIE disagrees with their operating
   system gets the other theme's illustration, because markup cannot ask about data-theme and a third
   media feature in this file is forbidden. Both drawings are palette-correct, self-contained panels,
   so the worst case is a light panel on a dark page rather than anything unreadable.

   MOTION, TIERS 1 AND 2. Tier 1 is a transition on a property a state rule already changes - the
   rule 18A wrote for this file and 18B for chrome.css - and this block adds the one interactive
   element on these pages that had no state at all: an in-body link. Tier 2 is the entrance, and it
   is written under the two rules Section 3.5 binds every keyframe with: the END STATE IS THE
   DEFAULT, so an engine that skips keyframes entirely renders a correct, complete page and the
   animation only moves an element into a position it already occupies; and no animated class sets
   opacity: 0 outside a keyframe, which is Section 12 R3's failure mode written down as something
   PublicMotionTests can read.

   THE SECOND REDUCED-MOTION ARM IS AT THE END OF THIS BLOCK, and it is a second arm rather than an
   edit to 18A's because this file is append-only below 18C's block. It names the classes THIS block
   animates and transitions; 18A's names the two controls that file animates. PublicMotionTests folds
   the animated-class set out of the whole stylesheet and compares it against the union of both arms,
   so neither arm can fall behind the rules above it, and neither may reach for the universal
   selector - a * arm satisfies a coverage check by construction and protects nobody.

   NOTHING ON A LEGAL DOCUMENT ANIMATES. Those four routes are live for a stranger today with the
   master flag off (Section 12 R1), and they are the one part of this site somebody reads rather than
   scans. They get the mark and no motion.

   NOT ONE LITERAL COLOUR, like the rest of this file.
   --------------------------------------------------------------------------------------------- */

:root {
    /* The entrance duration, named here for the same reason chrome.css names --forge-motion: so
       "everything on this site arrives the same way" is a fact rather than a habit, and so the arm
       below has one thing to switch off. Longer than tier 1's 160 ms because an entrance travels
       further than a colour does, and short enough that a reader who scrolls at once is not waiting
       for the page to finish assembling itself. */
    --forge-motion-entrance: 320ms;
}

/* ---- The picture inside the frame ------------------------------------------------------------ */

.forge-band-visual .forge-band-ornament {
    display: block;
}

.forge-band-image {
    display: block;
    width: 100%;
    height: auto;
}

/* ---- The legal shell's compact mark (Section 5.7, carried here by 18D) ------------------------

   A COMPACT MARK RATHER THAN A HERO, which is Section 5.2's own addendum for this surface: the four
   legal documents open with an eyebrow, a title and a lede at a 70ch measure, and a full-width 16:10
   panel above that would turn a document into a landing page. This is the sizing rule 18D reported
   it could not write, because .forge-band-visual is the wrong box and public.css was not 18D's file
   to append to. */

.forge-legal-mark {
    display: block;
    width: 40px;
    height: 40px;
    margin: 0 0 10px;
}

.forge-legal-mark-image {
    display: block;
    width: 100%;
    height: auto;
}

/* ---- 18D's second carried item: the legal date label reads the scale --------------------------

   .forge-legal-date dt states font-size: 0.8rem above, where every other rule on this shell reads
   --forge-text-xs. 18D flagged it and correctly declined to fix it: the rule is above that slice's
   append point and this file is append-only, so the only way to reach it is a second declaration of
   the same selector - which is what this is, and it is said out loud rather than left for a reader
   to find. The cascade takes the later one, and the var() fallback repeats the value that was
   already there, so a chrome.css that failed to load changes nothing.

   THE TRACKING IS DELIBERATELY LEFT ALONE. The rule above declares letter-spacing: 0.04em and the
   token --forge-tracking-wide is 0.08em, so pointing this at the token would DOUBLE the tracking on
   these labels. That is a visual change nobody asked for, and 18D's note named the font size. */

.forge-legal-date dt {
    font-size: var(--forge-text-xs, 0.8rem);
}

/* ---- Motion, tier 1: the one interactive element on these pages with no state rule ------------

   An in-body link had no hover and no focus response at all: the chrome's links and calls to action
   got theirs in 18A and 18B, and .forge-public-link was the gap. The state is a rule under the text
   rather than a colour change, deliberately - a second colour would be a new pair somebody has to
   compute a contrast ratio for, and PublicContrastTests belongs to 18A. currentColor is the colour
   the link already is, so the edge is a pair that has already been computed.

   AND IT IS text-decoration RATHER THAN border-bottom, WHICH IS WHERE THE RULE ACTUALLY LANDS
   (Round 1 audit finding F18-A2-11). A border is painted on the BORDER BOX, and this class is
   display: inline-flex with min-height: 44px - so on a 16px body at line-height 1.6 the line box is
   25.6px centred in a 43px content box and the border came out about 14px below the baseline: a
   detached line floating under the words rather than an underline. On /subprocessors it was worse,
   because .forge-legal-table td .forge-public-link is display: flex and the rule then spanned the
   whole column. text-decoration is drawn on the TEXT, so it lands where a reader expects it at every
   width, and transitioning text-decoration-color from transparent keeps 18E's argument intact: one
   colour, currentColor, and no new pair to compute. */

.forge-public-link {
    text-decoration: underline;
    text-decoration-color: transparent;
    text-underline-offset: 0.2em;
    transition: text-decoration-color var(--forge-motion, 160ms) var(--forge-motion-ease, ease-out);
}

.forge-public-link:hover,
.forge-public-link:focus-visible {
    text-decoration-color: currentColor;
}

/* ---- Motion, tier 2: the entrance -------------------------------------------------------------

   THE END STATE IS THE DEFAULT AND THAT IS THE WHOLE SAFETY ARGUMENT. opacity: 1 and transform: none
   are the initial values of both properties, so this animation moves an element into the position it
   already occupies. Delete the rule, or meet an engine that does not implement keyframes, and every
   page renders complete and correct; all that is lost is 320 ms of arrival.

   animation-fill-mode: both, and not the default. Without it an element sits at its default value
   through its own animation-delay and then jumps to the keyframe's start - a flash rather than an
   entrance - which is the defect a stagger makes visible. "both" holds the start value through the
   delay and the end value afterwards, and the end value is the default. */

@keyframes forge-rise {
    from {
        opacity: 0;
        transform: translateY(10px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

.forge-public-hero,
.forge-band-visual,
.forge-capability-copy,
.forge-ai-copy,
.forge-ai-claim,
.forge-closing {
    animation: forge-rise var(--forge-motion-entrance, 320ms) var(--forge-motion-ease, ease-out) both;
}

/* THE STAGGER, AND WHY IT IS WRITTEN AS DESCENDANT AND PSEUDO-CLASS SELECTORS. Each of these has to
   be a selector string that occurs exactly once in this file, so a guard scoping to a rule finds the
   rule it means rather than whichever came first - the same care 18C took with its breakpoint block.
   The SUBJECT of each selector is still the animated class, which is what the reduced-motion arm
   covers and what PublicMotionTests folds out of the file. */

.forge-band-inner .forge-band-visual {
    animation-delay: 90ms;
}

.forge-ai-claim:nth-child(2) {
    animation-delay: 60ms;
}

.forge-ai-claim:nth-child(3) {
    animation-delay: 120ms;
}

/* ---- The reduced-motion arm this block owes -------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .forge-public-link,
    .forge-public-hero,
    .forge-band-visual,
    .forge-capability-copy,
    .forge-ai-copy,
    .forge-ai-claim,
    .forge-closing {
        animation: none;
        transition-duration: 0.01ms;
    }
}

/* ---------------------------------------------------------------------------------------------
   The depth recipe, the type hierarchy and the stat strip (ratified Phase 21 plan Sections 3.4,
   3.5, 5.1 and 5.4, decision Q8; slice 21A).

   ONE APPENDED BLOCK AT THE END OF THE FILE, which is Section 6.0's rule for this stylesheet: it is
   the hotspot every slice of the phase grows, so 21A appends and 21B, 21C, 21D and 21G append after
   it in turn, and nothing above this comment was touched. No page wears any of these classes yet;
   21C is the first re-cut, and the two components this slice ships (ForgeStatStrip, ForgeEyebrow)
   are what PublicContrastTests renders so every colour pair below is computed on the day it is
   written rather than on the day a page reaches for it.

   EVERY COLOUR IS A TOKEN, A MIX OF A TOKEN TOWARDS transparent, OR A GRADIENT OF TOKENS. There is
   still not one literal colour in this file: color-mix() is Baseline widely available (May 2023,
   plan Section 3.1) and the literal-colour sweep in PublicPaletteTests already lets it and
   transparent through, so the whole recipe is written from --forge-* names and nothing else.

   THE ONE STRUCTURAL RULE: A TRANSLUCENT SURFACE IS A FRAME, AND TEXT NEVER SITS ON IT. A glass
   card has no single background colour to compute contrast against, so .forge-glass is the rim and
   .forge-glass-body - solid, from the two raised tokens PublicPalette emits for exactly this - is
   where the words go. PublicContrastTests' translucent leg walks every element with text of its
   own up to the ground it is painted on and fails the build if that ground is a mix towards
   transparent, so the rule cannot be broken quietly by a later band.

   backdrop-filter SITS BEHIND @supports AND THE SOLID FALLBACK IS THE DESIGN, NOT A DEGRADED ONE.
   The feature is Baseline 2024 (September 2024, inside this site's engine floor); an engine without
   it renders the 72% surface over the page ground with no blur, which is a flat translucent card
   and reads correctly. Likewise the gradient headline: background-clip: text wants a feature query
   (MDN, plan Section 3.1), so the PLAIN colour rule is written first, outside the query, and the
   gradient arm only ever ADDS to it. An engine that fails the query paints --forge-text; one that
   takes it and then loses the gradient paints transparent text - which is why the two are never
   written the other way round, and why a test asserts the order rather than a comment promising it.

   TWO AT-RULES ARE NEW TO THIS SITE, BOTH @supports FEATURE QUERIES. They are NOT media queries -
   the media-feature allow-set is still exactly (min-width: 768px) and (prefers-reduced-motion:
   reduce) - and LandingPageTests' at-rule allow-set names both preludes by their exact spelling,
   with the rule that a feature query may nest no at-rule of its own, so a second breakpoint cannot
   be smuggled in under one.

   NO MOTION IN THIS BLOCK. Nothing here animates or transitions, so the block owes no reduced-motion
   arm; a glow is a static shadow and a glass rim is a static gradient. 18E's arm above still covers
   every selector this file animates.
   --------------------------------------------------------------------------------------------- */

/* ---- The glass frame and its solid body -------------------------------------------------------

   THE RIM IS THE SURFACE AT 72% OVER A RADIAL OF THE GLOW. Both mixes go towards transparent, so
   what shows through is whatever the frame sits on - the page, a band, the accent - and the rim
   reads as glass on every one of them without a variant per ground. The 6px padding is the whole
   width of the rim: the body fills the rest, so a reader sees a thin luminous edge around a solid
   card and never a word on the glass itself.

   THE EDGE IS THE DECORATIVE TOKEN, deliberately and by the same argument as every section card:
   --forge-divider is below the 3:1 non-text bar on every ground on this site and is exempt from
   that arithmetic because a card's edge is not a user interface component. A control may never
   take its boundary from it, and PublicContrastTests holds that separately. */

/* AND THE CARD REALLY HAS THE SHADOW ITS OWN COMMENT PROMISED (round-1 audit finding F21-R1-15).
   The paragraph below used to retire the light half of the lift by pointing at "the shadow below",
   and there was exactly one box-shadow declaration in either public stylesheet - the primary
   action's glow. In light the page, a plain band and a card are all at or near the ceiling, so the
   only thing that can separate a card from the band it sits on is a shadow; it is a mix of the text
   colour towards transparent, so it reads in both themes and no literal colour is written. */

.forge-glass {
    position: relative;
    padding: 6px;
    border: 1px solid var(--forge-divider);
    border-radius: 14px;
    background-color: color-mix(in srgb, var(--forge-surface) 72%, transparent);
    background-image: radial-gradient(
        120% 80% at 20% 0%,
        color-mix(in srgb, var(--forge-glow) 22%, transparent),
        transparent 60%);
    box-shadow: 0 2px 6px -2px color-mix(in srgb, var(--forge-text) 18%, transparent);
}

@supports (backdrop-filter: blur(1px)) {
    .forge-glass {
        backdrop-filter: blur(12px);
    }
}

.forge-glass-body {
    border-radius: 10px;
    padding: 16px;
    background-color: var(--forge-raised);
}

/* THE SECOND RAISED STEP IS TAKEN BY THE BAND RATHER THAN BY A CLASS ON THE CARD (round-1 audit
   finding F21-R1-13).

   THE DEFECT. In dark --forge-raised and --forge-band read the SAME slot - PaletteDark.DarkLighten,
   #1e252d - so every glass card standing on an alternating band had an interior byte-identical to
   the band behind it, and the whole card was the 1.21:1 hairline its own border draws. The stat
   strip is deterministic about it: it takes band index 1 on every landing render, so in dark all
   four of its cells vanished into the band. The answer was already written and simply never wired -
   .forge-glass-strong was applied by no .razor in the repository at all, which is the
   ships-referenced-by-nothing class F13-10 named.

   WHY A TOKEN OVERRIDE AND NOT THE CLASS. A class has to be put on each card by the component that
   draws it, and glass cards are drawn by five components across three pages, each of which would
   have had to learn its band's parity. A custom property inherits: redefining --forge-raised on the
   band re-points every .forge-glass-body inside it, with nothing plumbed and no surface able to
   forget. The coloured bands need no entry - their grounds are the accent and the second hue, which
   no raised step resembles. */
.forge-band-alt {
    --forge-raised: var(--forge-raised-strong);
}

/* ---- The grid texture -------------------------------------------------------------------------

   TWO REPEATING GRADIENTS, ONE PER AXIS, A 1px LINE EVERY 32px. The line is the TEXT colour mixed
   to 4% rather than the divider token, and the arithmetic is why: --forge-divider is itself only
   1.09:1 against the light page, so 4% of it would be 4% of almost nothing and the texture would
   be invisible on every machine, while --forge-text at 4% over the light page lands within a point
   of the band's own tone, which is the strength a faint grid wants. In dark the same 4% of the text
   colour over the page is one step lighter than the page, the same relationship the other way up.
   The plan's phrase is "4% divider"; the intent it names is a 4% line, and this is that line. */

.forge-grid-ground {
    background-image:
        repeating-linear-gradient(
            0deg,
            color-mix(in srgb, var(--forge-text) 4%, transparent) 0 1px,
            transparent 1px 32px),
        repeating-linear-gradient(
            90deg,
            color-mix(in srgb, var(--forge-text) 4%, transparent) 0 1px,
            transparent 1px 32px);
}

/* ---- The glow under the primary action --------------------------------------------------------

   A STATIC SHADOW IN THE GLOW HUE, mixed to 60% and offset downwards with a negative spread so it
   reads as light falling from the button rather than a halo around it. It is a box-shadow and only
   a box-shadow: no colour pair is painted, no transition is declared, and removing the rule leaves
   the call to action exactly as 18A drew it. */

.forge-glow-cta {
    box-shadow: 0 8px 24px -8px color-mix(in srgb, var(--forge-glow) 60%, transparent);
}

/* ---- The eyebrow ------------------------------------------------------------------------------

   CAPS, LETTER-SPACED AT THE WIDE TRACKING TOKEN, A DOT IN THE BAND'S ACCENT. The label is the muted
   text colour and the dot the primary on a plain band; on either coloured band both inherit the
   band's own text colour (currentColor for the dot), because a muted grey on the accent violet is a
   pair neither theme makes legible. The size reads the scale's smallest step with that step's own
   floor as the fallback, the convention every consuming rule in this file follows. */

.forge-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 8px;
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    font-weight: 600;
    letter-spacing: var(--forge-tracking-wide, 0.08em);
    text-transform: uppercase;
    color: var(--forge-text-muted);
}

.forge-eyebrow::before {
    content: "";
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: var(--forge-primary);
}

.forge-band-accent .forge-eyebrow,
.forge-band-proof .forge-eyebrow {
    color: inherit;
}

.forge-band-accent .forge-eyebrow::before,
.forge-band-proof .forge-eyebrow::before {
    background-color: currentColor;
}

/* ---- The gradient headline --------------------------------------------------------------------

   ONE PER PAGE (Section 5.1), --forge-primary to --forge-accent (decision Q8: the violet a reader
   meets inside the product on its AI surfaces, so the page and the product agree).

   THE PLAIN COLOUR IS WRITTEN FIRST AND OUTSIDE THE FEATURE QUERY, AND THE ORDER IS LOAD-BEARING.
   The gradient arm clips a background to the glyphs and then makes the text itself transparent; an
   engine that cannot clip would paint invisible text if it took that arm, which is exactly what the
   @supports test prevents. The fallback rule precedes the arm so that an engine which passes the
   query and later drops one declaration still has a colour to fall back on, and
   PublicDepthRecipeTests asserts that order through the parser rather than trusting this sentence. */

.forge-headline-gradient {
    color: var(--forge-text);
}

@supports (background-clip: text) {
    .forge-headline-gradient {
        background-image: linear-gradient(90deg, var(--forge-primary), var(--forge-accent));
        background-clip: text;
        color: transparent;
    }
}

/* ---- The monospace figure ---------------------------------------------------------------------

   AppTheme.MonospaceFontStack, CHARACTER FOR CHARACTER. A stylesheet cannot call into AppTheme, so
   the stack is written out here and SharedFontStackTests compares this rule against that array -
   the same guard, the same reason and the same shape as the body's text stack above. tabular-nums
   so a column of figures lines up, which is what a monospace face is for on a stat. */

.forge-figure {
    font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums;
}

/* ---- The stat strip ---------------------------------------------------------------------------

   TWO BY TWO BELOW THE BREAKPOINT, FOUR ACROSS FROM IT (Section 9.3). Each cell is a glass frame
   around a solid body; the figure is the display step in the monospace class and the label beneath
   it is the eyebrow's own caps treatment at the smallest step, so the strip and the section labels
   read as one voice.

   AND THE TEMPLATE FOLLOWS THE COUNT RATHER THAN ASSUMING FOUR (round-1 audit finding F21-R1-36). A
   fixed repeat(2)/repeat(4) is right for four figures and wrong for every other number the shipped
   flag defaults produce: with all three counted families dark the strip was ONE cell in a
   four-column row. The 120px minimum is measured against the narrowest matrix width's own container
   - .forge-band-inner is 288px at 320 - so two tracks (120 + 12 + 120 = 252) fit and three (384) do
   not, which is the two-by-two the matrix asks for; at the breakpoint's 736px measure five tracks
   fit, auto-fit collapses the empty one and four figures take four equal columns. */

.forge-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 12px;
    margin: 24px 0 0;
    padding: 0;
    list-style: none;
}

.forge-stat {
    min-width: 0;
}

.forge-stat-figure {
    display: block;
    font-size: 2rem;
    font-size: var(--forge-text-display, 2rem);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: var(--forge-tracking-tight, normal);
    color: var(--forge-text);
}

.forge-stat-label {
    display: block;
    margin-top: 6px;
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    letter-spacing: var(--forge-tracking-wide, 0.08em);
    text-transform: uppercase;
    color: var(--forge-text-muted);
}

/* NO BREAKPOINT OVERRIDE FOR THE STRIP ANY MORE: the auto-fit template above produces the matrix's
   own answer at every width, and a fixed four-column rule here is exactly what made a one-figure
   strip occupy a quarter of the band (round-1 audit finding F21-R1-36). */

/* ================================================================================================
   THE SPECIMENS (ratified Phase 21 plan Sections 3.2, 3.3, 5.2 and 9.1; slice 21B)
   ================================================================================================

   WHAT A SPECIMEN IS. A picture of one of this product's own surfaces, drawn in HTML and CSS from
   typed fictional data, so a stranger meets the product rather than a wireframe (research F1). Eight
   of them live under Components/Public/Specimens/ and every one is a <figure role="img"> with a
   visible caption; PublicSpecimenSweepTests holds the four rules that make them data rather than
   surfaces, and PublicSpecimenRenderTests renders every one in both themes.

   EVERY COLOUR HERE IS A TOKEN, AND EVERY ONE OF THEM IS A TOKEN THAT CLEARS ITS BAR. A chip in this
   block never brings a fill of its own: it is a border and a text colour on the solid body it sits
   in, so its pair is (token, --forge-raised) and the contrast suite computes it from the cascade
   like any other. The four chips are told apart by WHICH token - the control edge, the primary, the
   accent, the secondary - rather than by a mixed background whose ground nothing could compute.

   NOTHING IN THIS BLOCK MOVES. No transition, no animation, no transform: a specimen is a still
   picture of a screen, so this block owes no reduced-motion arm and 18E's arm above still covers
   every selector this file animates.

   THE THREE INLINE STYLES A SPECIMEN CARRIES ARE COMPUTED VALUES, NOT DECISIONS - a bar's length, a
   legend swatch's fill and the share panel's conic-gradient, all written by PublicSpecimenData from
   the same percentages the legend prints. They are the one place this site allows a style attribute,
   they name only --forge-* colours, and the render guard parses the gradient back out and recomputes
   its stops.
   ------------------------------------------------------------------------------------------------

   WIDTH, WHICH IS THE ONLY THING THE MATRIX ASKS OF THIS BLOCK. A specimen draws surfaces that are
   wide by nature - a board with three columns, a list with five readings in a row - and the rule
   this site has carried since Phase 17 is that the DOCUMENT never scrolls sideways and wide content
   scrolls inside its own box. So every row wraps, every grid is one column until the breakpoint,
   every flex child declares min-width: 0 so it may shrink below its content, the one genuinely
   horizontal surface (the board) is an overflow-x: auto container, and long unbroken strings - a
   domain, an address - break rather than push. */

.forge-specimen {
    margin: 0;
    min-width: 0;
}

.forge-specimen-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

/* THE CAPTION IS THE ACCESSIBLE NAME, SPELLED OUT (Section 3.2). SpecimenFigure writes one parameter
   into both the aria-label and this element, so a listener and a reader are told the same thing, and
   the render guard asserts they are equal on every specimen. */
.forge-specimen-caption {
    margin: 8px 0 0;
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    color: var(--forge-text-muted);
}

.forge-specimen-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 10px;
    min-width: 0;
}

.forge-specimen-title {
    min-width: 0;
    font-size: 0.85rem;
    font-size: var(--forge-text-sm, 0.85rem);
    font-weight: 600;
    color: var(--forge-text);
    overflow-wrap: anywhere;
}

.forge-specimen-meta {
    min-width: 0;
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    color: var(--forge-text-muted);
    overflow-wrap: anywhere;
}

.forge-specimen-line {
    margin: 0;
    font-size: 0.85rem;
    font-size: var(--forge-text-sm, 0.85rem);
    line-height: 1.5;
    color: var(--forge-text);
}

/* AN ABSENCE A READER COULD ACT ON IS WRITTEN OUT AND NEVER DRAWN AS A DASH. Phase 14's rule, with a
   product-wide sweep of its own (BareDashCellTests); here it is also the pending invitation's note
   and the compliance footer, both of which are quiet statements rather than data. */
.forge-specimen-absent {
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    color: var(--forge-text-muted);
}

/* ---- The chips --------------------------------------------------------------------------------

   ONE SHAPE, FIVE TOKENS. The base chip is the control edge and the page's text colour; each variant
   repoints both to one token, so every chip's pair is that token against --forge-raised and every
   one of those clears 4.5 for the text and 3.0 for the edge in both themes. */

.forge-specimen-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.forge-specimen-chip {
    display: inline-flex;
    align-items: center;
    padding: 1px 8px;
    border: 1px solid var(--forge-control-edge);
    border-radius: 999px;
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    font-weight: 600;
    color: var(--forge-text);
    white-space: nowrap;
}

.forge-specimen-chip-quiet {
    color: var(--forge-text-muted);
}

/* The evidence tier, in the hue the product itself uses for a resolved first-party source. */
.forge-specimen-chip-tier {
    border-color: var(--forge-primary);
    color: var(--forge-primary);
}

/* A citation and a resolved token are both the assistant's own vocabulary, so both take the violet a
   reader meets on every AI surface inside the product (decision Q8's argument, one layer down). */
.forge-specimen-chip-cite,
.forge-specimen-chip-token {
    border-color: var(--forge-accent);
    color: var(--forge-accent);
}

/* An import row that would CREATE a record and one that MATCHES an existing one are different
   outcomes, and a reader is told which by the words first and the colour second. */
.forge-specimen-chip-create {
    border-color: var(--forge-secondary);
    color: var(--forge-secondary);
}

.forge-specimen-chip-match {
    color: var(--forge-text-muted);
}

/* THE ONE AFFORDANCE IN THE WHOLE SET, AND IT IS A SPAN (Section 12, R3). A finding is a proposal
   until a person accepts it, so the picture has to show the control that accepts it; a button here
   would be a control on a marketing page that does nothing when a reader presses it, and the sweep
   is what keeps it a span. It is aria-hidden inside a role="img" figure, which is what it is: part
   of the drawing. */
.forge-specimen-action {
    display: inline-flex;
    align-items: center;
    padding: 1px 10px;
    border: 1px solid var(--forge-primary);
    border-radius: 6px;
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    font-weight: 600;
    color: var(--forge-primary);
}

/* ---- The rows: leads, import, members ---------------------------------------------------------

   ONE LIST SHAPE FOR THE THREE SPECIMENS THAT ARE LISTS. Every row wraps rather than scrolling,
   because a row of five readings at 320 is exactly the case Section 9.3 asks about, and a divider
   between rows rather than a card each, which is how the product's own list surfaces draw. */

.forge-specimen-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
    min-width: 0;
}

.forge-specimen-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    padding-top: 8px;
    border-top: 1px solid var(--forge-divider);
    min-width: 0;
}

.forge-specimen-row:first-child {
    padding-top: 0;
    border-top: 0;
}

/* The invitation nobody has accepted yet, marked by a dashed edge rather than by a colour, so the
   distinction survives a reader who cannot tell the two hues apart. */
.forge-specimen-row-pending {
    border-top-style: dashed;
}

.forge-specimen-avatar {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: 1px solid var(--forge-control-edge);
    border-radius: 50%;
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    font-weight: 600;
    color: var(--forge-text-muted);
}

/* ---- The board --------------------------------------------------------------------------------

   THE ONE SURFACE THAT SCROLLS IN ITS OWN BOX. Three stage columns do not wrap into a usable board,
   so this container carries the overflow and the page does not - which is the Phase 17 rule stated
   exactly, and why nothing else in this block declares a width. */

.forge-specimen-columns {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    padding-bottom: 4px;
}

.forge-specimen-column {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    gap: 6px;
    width: 42%;
    min-width: 132px;
}

.forge-specimen-column-head {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--forge-divider);
}

.forge-specimen-card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px 8px;
    border: 1px solid var(--forge-control-edge);
    border-radius: 8px;
}

/* ONE TOTAL PER COLUMN AND NEVER A TOTAL OF THE TOTALS (Phase 13's F13-1 lesson). The figure takes
   the monospace class in the markup; the size floor here is the smallest step on the scale, which is
   12.8px - above Section 9.1's "figures never smaller than 12px". */
.forge-specimen-total,
.forge-specimen-amount,
.forge-specimen-reading {
    font-size: 0.8rem;
    font-size: var(--forge-text-xs, 0.8rem);
    font-weight: 600;
    color: var(--forge-text);
}

.forge-specimen-amount {
    color: var(--forge-text-muted);
}

/* ---- The dashboard pair -----------------------------------------------------------------------

   ONE COLUMN UNTIL THE BREAKPOINT, TWO FROM IT (Section 9.3). The bar panel is a track and a fill
   whose width is the one computed inline style; the share panel is a conic-gradient with a hole
   punched by a pseudo-element in the body's own colour, which is how a donut is drawn without an
   inline drawing and without a url(). */

.forge-specimen-panels {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

.forge-specimen-panel {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.forge-specimen-bars {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.forge-specimen-bar {
    display: grid;
    grid-template-columns: minmax(0, 5rem) minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
}

.forge-specimen-bar-track {
    height: 8px;
    border-radius: 999px;
    background-color: var(--forge-band);
}

.forge-specimen-bar-fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background-color: var(--forge-primary);
}

.forge-specimen-donut {
    position: relative;
    align-self: center;
    width: 108px;
    height: 108px;
    border-radius: 50%;
}

.forge-specimen-donut::after {
    content: "";
    position: absolute;
    inset: 26%;
    border-radius: 50%;
    background-color: var(--forge-raised);
}

/* NO SECOND DONUT RULE. The hole above reads --forge-raised, and public.css re-points that token on
   the alternating band, so the hole follows the card's own ground with nothing to keep in sync -
   which is what the .forge-glass-strong variant that stood here used to do for a class no .razor in
   the repository ever applied (round-1 audit finding F21-R1-13). */

.forge-specimen-legend {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.forge-specimen-legend-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
}

.forge-specimen-swatch {
    width: 10px;
    height: 10px;
    border-radius: 2px;
}

/* ---- The sparklines ---------------------------------------------------------------------------

   A COMPOSED FILE RATHER THAN AN INLINE DRAWING, which is the only shape available: an inline
   drawing element in a .razor or a .cs under src/Forge.Web/ fails the build, and a public stylesheet
   may write no url(). The box is reserved here from PublicImages' own declared size (320 by 80, four
   to one), so the specimen's height does not change when the file decodes. */

.forge-specimen-spark {
    display: block;
}

.forge-specimen-spark-mark {
    display: block;
    width: 100%;
    height: auto;
    max-width: 320px;
}

/* ---- The draft --------------------------------------------------------------------------------

   THE OPENING, THE RESOLVED TOKEN AND THE REST OF THE SENTENCE, on one wrapping line: what the
   picture is about is that a draft carries a RESOLVED value where a name goes, so the chip has to sit
   inside the sentence rather than above it. */

.forge-specimen-opening,
.forge-specimen-continues {
    display: inline;
}

@media (min-width: 768px) {
    .forge-specimen-panels {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .forge-specimen-column {
        flex: 1 1 0;
        width: auto;
        min-width: 0;
    }
}

/* ================================================================================================
   THE LANDING RE-CUT (ratified Phase 21 plan Sections 4, 5.3, 5.5, 9.1 and 9.3; slice 21C)
   ================================================================================================

   ONE APPENDED BLOCK, after 21A's and 21B's, which is Section 6.0's rule for this file. Three rules
   ABOVE were deleted rather than left: the proof strip's two layout rules and its two stagger
   delays, and .forge-ai-body's two, because the bands they described are gone and a colour-bearing
   rule no render reaches is exactly what PublicContrastTests fails on. Everything else above is
   untouched.

   EVERY NEW SURFACE REUSES 21A's RECIPE RATHER THAN RESTATING IT. The overview cards and the
   built-right cards are .forge-glass around .forge-glass-body, which is the stat strip's own shape
   and therefore the same computed pairs; the section labels are .forge-eyebrow; the two calls to
   action wear .forge-glow-cta; the hero headline is the one .forge-headline-gradient this page is
   allowed. What is new here is layout, and one frame.

   NOT ONE LITERAL COLOUR, AND NOT ONE NEW TOKEN. Every colour below is a --forge-* name 21A or 18A
   already emitted.

   ONE BREAKPOINT, WHICH IS WHAT THE COLUMN COUNTS ARE ARITHMETIC ABOUT. The band measure is
   64rem with 16px sides, so the inner width is 288px at 320, 328 at 360, 568 at 600, 736 at 768 and
   992 at 1024. A repeat(auto-fit, minmax(B, 1fr)) grid fits floor((W + gap) / (B + gap)) columns,
   so the counts below are read off that formula rather than off a second media query. Two cells of
   Section 9.3's matrix are deliberately not met and the PR body records why: "What's inside" is 3
   across at 1024 rather than 4, and "Built right" is 2 rather than 4, because 4 at 1024 AND 2 at
   768 is a 992:736 window against a 4:3 requirement - 1.6px of slack, which a scrollbar spends -
   and this site may not write a second breakpoint to buy it.
   --------------------------------------------------------------------------------------------- */

/* ---- The slot frame with nothing of its own to draw ------------------------------------------

   TWO SLOTS NOW RESOLVE TO THE PRODUCT'S OWN OUTPUT RATHER THAN TO A PICTURE: the hero, which holds
   a capture or the specimen collage inside the window frame, and the AI showcase, which holds two
   captioned specimens. Both keep .forge-band-visual - so the entrance, the stagger and the accent
   band's edge rule all still reach them - and this modifier takes away the border and the clipping,
   because what is inside draws its own edges and a specimen's caption must not be cut off. */

.forge-band-visual-open {
    border-width: 0;
    border-radius: 0;
    overflow: visible;
}

/* ---- The window frame (Section 3.6) -----------------------------------------------------------

   THE FRAME IS THE SAME IN ALL THREE STATES, which is its whole job: a recording, a screenshot and
   the collage sit in one shape, so nothing on the page moves when a capture lands. The bar is three
   dots and an address strip with no address in it - every one of them the divider token, which is
   the decorative edge this design already exempts from the 3:1 arithmetic because none of them is a
   control or a boundary a reader operates. */

.forge-window {
    border: 1px solid var(--forge-divider);
    border-radius: 14px;
    overflow: hidden;
    background-color: var(--forge-raised);
}

.forge-window-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--forge-divider);
}

.forge-window-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background-color: var(--forge-divider);
}

.forge-window-address {
    flex: 1 1 auto;
    height: 10px;
    margin-left: 8px;
    border-radius: 5px;
    background-color: var(--forge-divider);
}

.forge-window-body {
    padding: 12px;
}

/* THE COLLAGE TAKES ITS NATURAL HEIGHT AND THE CAPTURE DOES NOT. .forge-band-ornament holds the
   16:10 box for an image, because an image decodes late and a box that is not reserved is a layout
   shift; the collage is markup that is already laid out, and forcing it into the same ratio would
   crop a specimen's words at 320. The second card steps down and in, which is what makes it a
   collage rather than a stack, and it is a margin on a grid item so it can never widen the row. */

.forge-hero-collage {
    display: grid;
    gap: 10px;
}

.forge-hero-collage > :last-child {
    margin-top: -26px;
    margin-left: 18px;
}

/* ---- What's inside, and Built right ----------------------------------------------------------

   ONE TRACK RULE FOR BOTH, AT A 17rem (272px) BASIS: 1 column at 320 and 360 (two would need
   560px), 2 at 600 (560 <= 568) and at 768 (three would need 848 > 736), 3 at 1024 (848 <= 992).
   The built-right grid caps its own measure at 46rem so four cards land 2 x 2 from 600 upwards
   rather than 3 and a lonely fourth. */

.forge-overview {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: 16px;
    margin-top: 20px;
}

.forge-built {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: 16px;
    margin-top: 20px;
    max-width: 46rem;
}

.forge-overview-heading,
.forge-built-heading {
    margin: 10px 0 6px;
    font-size: 1.15rem;
    font-size: var(--forge-text-h3, 1.15rem);
}

.forge-overview-points {
    margin: 0;
    padding-left: 1.1em;
    color: var(--forge-text-muted);
    line-height: var(--forge-leading-prose, 1.6);
}

.forge-built-body {
    margin: 0;
    color: var(--forge-text-muted);
    line-height: var(--forge-leading-prose, 1.6);
}

.forge-built-more {
    margin: 12px 0 0;
}

/* THE ICON TILE IS A SHAPE, NOT A FILE AND NOT A GLYPH (an inline <svg fails the build under
   src/Forge.Web/, and a url( fails this stylesheet's own sweep). A rounded tile in the primary
   tint with the primary's own square inside it, aria-hidden on every caller, so nothing announces
   it. The tint is a mix towards transparent, so it reads on the raised surface in both themes. */

.forge-built-icon {
    display: block;
    width: 32px;
    height: 32px;
    border-radius: 9px;
    background-color: color-mix(in srgb, var(--forge-primary) 18%, transparent);
    background-image: radial-gradient(
        closest-side at 50% 50%,
        var(--forge-primary) 0 38%,
        transparent 40%);
}

/* ---- How it works -----------------------------------------------------------------------------

   A VERTICAL LIST BELOW THE BREAKPOINT AND A ROW OF FOUR FROM IT (Section 9.3). The numerals are
   drawn by a counter, so the markup carries no digit; the joining line is a border on the list
   rather than an element, so there is nothing to hide on a phone. */

.forge-steps {
    counter-reset: forge-step;
    display: grid;
    gap: 16px;
    margin: 20px 0 0;
    padding: 0;
    list-style: none;
}

.forge-step {
    counter-increment: forge-step;
    display: grid;
    gap: 4px;
    padding-left: 44px;
    position: relative;
}

.forge-step::before {
    content: counter(forge-step);
    position: absolute;
    left: 0;
    top: 0;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--forge-primary);
    color: var(--forge-primary-contrast);
    font-weight: 600;
}

.forge-step-heading {
    font-weight: 600;
}

.forge-step-body {
    color: var(--forge-text-muted);
    line-height: var(--forge-leading-prose, 1.6);
}

/* ---- Running today ----------------------------------------------------------------------------

   THE TICK IS TWO BORDERS ON AN EMPTY SPAN, ROTATED. currentColor, so it takes the band's own text
   colour and needs no ratio of its own - the same argument the band's frame edge uses. */

.forge-running {
    display: grid;
    gap: 12px;
    margin: 20px 0 0;
    padding: 0;
    list-style: none;
}

.forge-running-row {
    display: flex;
    align-items: center;
    gap: 12px;
    font-weight: 600;
}

.forge-running-tick {
    flex: 0 0 auto;
    width: 9px;
    height: 16px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
}

/* ---- The AI showcase's two specimens -----------------------------------------------------------

   STACKED UNTIL 1024 AND SIDE BY SIDE THERE (Section 9.1), from the same auto-fit formula at a
   23rem (368px) basis: two need 752px, which the 736px band at 768 does not have and the 992px band
   at 1024 does.

   AND THE BASIS IS CAPPED AT THE CONTAINER (round-1 audit finding F21-R1-12, High). auto-fit floors
   the repetition at one track, but a 1fr track cannot shrink below its own minmax() minimum: 368px
   inside .forge-band-inner's 288px at 320 and 328px at 360 overflowed by 80px and 40px, and because
   .forge-band-visual-open sets overflow: visible so a caption is not cut, the overflow reached
   body { overflow-x: hidden } and the right 22% of BOTH specimen cards was clipped with no scrollbar
   to say so. That is Phase 18's own F18-A2-1, whose explanation sits 2,100 lines above this rule.
   min(23rem, 100%) resolves to 368px whenever the container is wider - so the 1024 two-up and the
   768 single column are both unchanged - and to the container's own width when it is not. */

.forge-ai-specimens {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(23rem, 100%), 1fr));
    gap: 16px;
}

/* AND A CAPTION ON A COLOURED BAND TAKES THE BAND'S OWN TEXT COLOUR, which is the rule the eyebrow
   already carries and for the identical reason: a specimen's frame is solid, but its caption sits
   OUTSIDE the frame on the band itself, and the muted grey that carries a caption on the page is
   1.05:1 on the accent violet. currentColor here is the pair PublicContrastTests already computes
   for this band. */

.forge-band-accent .forge-specimen-caption {
    color: inherit;
}

@media (min-width: 768px) {
    .forge-steps {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .forge-step {
        padding-left: 0;
        padding-top: 44px;
        border-top: 1px solid var(--forge-divider);
    }

    .forge-step::before {
        top: -16px;
    }
}

/* ---- The tier pill (Phase 21 slice 21D) --------------------------------------------------------

   WHICH PLAN A CAPABILITY ARRIVES ON, UNDER THE SECTION'S HEADING (Section 5.6). It is a label
   rather than a badge: the plan's own name is the emphasised half, the "Included from:" prefix is
   muted, and neither is a colour this file typed - both are tokens. No fixed height and no
   nowrap, so a longer tier name at 320px wraps inside the pill instead of widening the document.

   ITS GROUND IS SOLID, WHICH IS SECTION 3.4's RULE RATHER THAN A PREFERENCE. The first draft gave
   it a primary tint mixed towards transparent: a good-looking pill, and a surface with no single
   background colour, so no pair in the contrast suite could say whether the two words inside it are
   legible - and 21A's translucent-surface leg named both spans on its first run. Text sits on the
   solid raised token; the tint the draft wanted lives on the BORDER, which carries no text. */

.forge-tier-pill {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
    margin: 0 0 10px;
    padding: 4px 12px;
    border: 1px solid var(--forge-divider);
    border-radius: 999px;
    background-color: var(--forge-raised);
    font-size: var(--forge-text-sm, 0.85rem);
}

.forge-tier-pill-label {
    color: var(--forge-text-muted);
}

.forge-tier-pill-plan {
    font-weight: 600;
}

/* ---- /security (Phase 21 slice 21D) ------------------------------------------------------------

   THE SAME TRACK RULE THE OVERVIEW AND BUILT-RIGHT GRIDS USE, at the same 17rem basis and for the
   same reason: 1 column at 320 and 360, 2 at 600 and 768, 3 at 1024 (Section 9.3's row for this
   page). The cards are .forge-glass around .forge-glass-body, so the ground under their text is the
   solid raised token 21A emitted and PublicContrastTests computes the pair it already knows. */

.forge-security-claims {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: 16px;
    margin-top: 20px;
}

.forge-security-heading {
    margin: 10px 0 6px;
    font-size: 1.15rem;
    font-size: var(--forge-text-h3, 1.15rem);
}

.forge-security-body {
    margin: 0;
    color: var(--forge-text-muted);
    line-height: var(--forge-leading-prose, 1.6);
}

/* THE DISCLAIMER READS AS A NOTE AND NOT AS A CLAIM, which is the whole reason it is on the page:
   it sits below the grid at the caption size, muted, with a rule above it. */

.forge-security-disclaimer {
    max-width: 46rem;
    margin: 24px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--forge-divider);
    color: var(--forge-text-muted);
    line-height: var(--forge-leading-prose, 1.6);
    font-size: var(--forge-text-sm, 0.85rem);
}

/* -----------------------------------------------------------------------------------------------
   The hero recording (ratified Phase 21 plan Sections 3.9, 5.10 and 9.1; slice 21G).

   ONE APPENDED BLOCK AT THE END OF THE FILE, which is Section 6.0's rule for this stylesheet: 21A,
   21B, 21C and 21D appended in turn and nothing above this comment was touched.

   ONE SHARED RULE UNDER A CLASS BOTH ELEMENTS WEAR, AND EACH OF THEM ITS OWN. The shared sizing is
   .forge-hero-media, so the only rules naming .forge-hero-video and .forge-hero-still are the three
   that decide WHICH of the two a reader meets - which is what lets the guard say, over the served
   file, that the video is switched off inside the reduced-motion arm and nowhere else.

   THE VIDEO FILLS THE FRAME AND DECLARES ITS OWN BOX. The element carries width and height
   attributes from PublicMedia's recorded frame, so the browser reserves the right aspect before a
   byte decodes; the rule below lets it take the frame's width and keeps its own ratio. The ground
   underneath is the band token, so the first paint inside the window is a surface rather than a
   hole while the poster loads.

   THE REDUCED-MOTION SWAP IS THE WHOLE POINT OF THE SECOND ELEMENT (Section 12 R13). The poster img
   is hidden by default and the video is hidden inside the arm, so a reader who asked their system
   to stop things moving gets the still frame in the same box with nothing else moving. Note what
   happens when this stylesheet does not arrive at all: BOTH render, which is a silent loop and a
   still of its first frame - correct and ugly, rather than a blank window. That is the same
   "the end state is the default" posture the entrances are written under, applied to a swap.

   IT IS A SECOND (prefers-reduced-motion: reduce) ARM AND NOT AN EDIT TO 18E'S. That one switches
   MOTION off and owes the animation/transition pair every arm in this file is required to carry;
   this one hides one element and shows another and neutralises no animation, which is the shape
   PublicMotionTests admits explicitly - "a block that merely restyles something is not a block that
   switches motion off, so it contributes no coverage". Folding these two rules into the motion arm
   would make that arm's coverage claim depend on a display swap.
   --------------------------------------------------------------------------------------------- */

.forge-hero-media {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 10px;
    background-color: var(--forge-band);
}

.forge-hero-still {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .forge-hero-video {
        display: none;
    }

    .forge-hero-still {
        display: block;
    }
}
