/* ==========================================================================
   Forge 2026 — page-specific styles
   Layered on /styles.css (which provides design tokens + base patterns).

   Modeled on the Nathan EH-2026-06 workshop page rhythm — same shared
   shell (header, footer, .section, .section-tint, .container), same design
   tokens (Playfair Display, Source Sans 3, IBM Plex Mono, indigo brand).
   Tighter section padding than the marketing-page default because the
   page packs 10 sections of content.
   ========================================================================== */

/* Section + hero spacing override — same pattern as workshop.css. The
   default marketing-page rhythm produces oversized gaps when sections
   stack 10-deep. */
.forge-page .section,
body.forge-page .section {
    padding: var(--space-lg) 0;
}
.forge-page .hero,
body.forge-page .hero {
    padding: var(--space-xl) 0 var(--space-lg);
}

@media (min-width: 768px) {
    .forge-page .section,
    body.forge-page .section {
        padding: var(--space-xl) 0;
    }
    .forge-page .hero,
    body.forge-page .hero {
        padding: var(--space-2xl) 0 var(--space-xl);
    }
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.forge-hero {
    text-align: center;
}

.forge-eyebrow {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-brand-indigo);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    margin-bottom: var(--space-md);
}

.forge-hero h1 {
    font-size: clamp(3rem, 8vw, 6rem);
    letter-spacing: -0.02em;
    margin-bottom: var(--space-md);
}

.forge-date-band {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 3vw, 2rem);
    color: var(--color-foreground);
    margin-bottom: var(--space-xs);
}

.forge-venue-line {
    font-family: var(--font-mono);
    font-size: 0.95rem;
    color: var(--color-muted-foreground);
    margin-bottom: var(--space-lg);
    letter-spacing: 0.02em;
}

.forge-hero .hero-subhead {
    font-style: italic;
    margin-bottom: var(--space-xl);
}

.forge-hero-cta {
    margin-top: var(--space-md);
}

/* --------------------------------------------------------------------------
   Section content patterns
   -------------------------------------------------------------------------- */
.forge-prose {
    max-width: var(--max-width-text);
    margin: 0 auto;
}

.forge-prose p + p {
    margin-top: 0.75em;
}

.forge-section-intro {
    max-width: var(--max-width-text);
    margin: 0 auto var(--space-xl);
    text-align: center;
    color: var(--color-muted-foreground);
    font-size: 1.05rem;
}

/* Program-header model sentence (story nx-eaa31acb418a, cap doc §3.4 / §3.1 #6).
   Frames the workshop model — Content Committee defines the topic, a sponsor
   teaches it alongside Provarro, a member who lived it speaks, the room works
   it — so a reader scanning the agenda sees the model before the grid. Reads
   with more weight than the muted .forge-section-intro counts line above it:
   foreground display type, centered, constrained to the text measure. */
.forge-program-model {
    max-width: var(--max-width-text);
    margin: calc(-1 * var(--space-md)) auto var(--space-xl);
    text-align: center;
    color: var(--color-foreground);
    font-family: var(--font-display);
    font-size: 1.15rem;
    line-height: 1.5;
}

.forge-prose-note {
    color: var(--color-muted-foreground);
    margin-bottom: var(--space-md);
}

.forge-prose-note.muted {
    color: var(--color-muted-foreground);
}

.forge-subhead {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    max-width: var(--max-width-text);
    margin: var(--space-xl) auto var(--space-md);
    color: var(--color-foreground);
}

.forge-subhead:first-of-type {
    margin-top: var(--space-md);
}

.forge-tier-heading {
    color: var(--color-brand-indigo);
    text-align: center;
    margin-bottom: var(--space-lg);
}

/* --------------------------------------------------------------------------
   Tables — used for The Format week overview, attendee/business profile,
   venue details
   -------------------------------------------------------------------------- */
.forge-table-wrap {
    overflow-x: auto;
    margin: var(--space-md) 0 var(--space-xl);
    max-width: var(--max-width-text);
    margin-left: auto;
    margin-right: auto;
}

.forge-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    font-size: 0.95rem;
}

.forge-table th,
.forge-table td {
    padding: var(--space-sm) var(--space-md);
    text-align: left;
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
}

.forge-table thead th {
    background: rgba(74, 78, 140, 0.06);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-brand-indigo);
}

.forge-table tbody tr:last-child td {
    border-bottom: none;
}

.forge-table tbody tr:hover {
    background: rgba(74, 78, 140, 0.02);
}

/* --------------------------------------------------------------------------
   Program section — workshops + breakouts as card grid
   -------------------------------------------------------------------------- */
.forge-program-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
    margin: var(--space-md) 0 var(--space-xl);
}

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

/* Breakouts grid stays pinned to 3 columns and is deliberately NOT escalated to
   4 at ≥1024px. It carries all NINE breakouts — member-led and sponsor-led in
   one unified track (Brock UAT verdict 2026-08-20, story nx-90747863f855): 3-up
   splits 3+3+3 and reads as one balanced slate, where 4-up leaves a single
   orphan card on a third row. Revisit the column count if the session count
   changes — a 4-up escalation only reads right at a multiple of four.
   RETIRED with that same verdict: .forge-program-grid-members, the separate
   member-led track's grid modifier. Do not reintroduce a member/sponsor track
   split on this page. */

.forge-program-card {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    min-height: 160px;
}

.forge-program-card-placeholder {
    background: transparent;
    border-style: dashed;
}

.forge-program-marker {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--color-brand-indigo);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.forge-program-title {
    font-family: var(--font-display);
    font-size: 1.05rem;
    color: var(--color-foreground);
    margin: 0;
    line-height: 1.4;
}

.forge-program-title.forge-placeholder {
    color: var(--color-muted-foreground);
    font-style: italic;
}

/* --------------------------------------------------------------------------
   Sponsor attribution in Program cards — SUBORDINATE "presented by {Vendor}"
   line rendered BELOW the topic title (story nx-eaa31acb418a — topic-forward
   reshape, cap doc §3.4). The card leads with the topic; the vendor is a
   muted attribution line beneath it, NOT the headline. Only rendered on slots
   that have a confirmed topic; not-yet-titled committed slots omit it entirely
   (vendors live in the §3.5 Sponsors section in that state).
   History: replaced the v1 wordmark color-blocks (removed per story
   nx-8c76f9964a63 — interim "no logo treatments" posture) which rendered the
   vendor as the card LEAD between marker and title; nx-eaa31acb418a demoted it
   to subordinate. When logo SVGs + scaling rules arrive, the logo attaches to
   this subordinate "presented by" slot (below the topic), not the lead.
   -------------------------------------------------------------------------- */
.forge-program-sponsor {
    font-family: var(--font-display);
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--color-muted-foreground);
    margin: 0;
    line-height: 1.3;
}

/* --------------------------------------------------------------------------
   Speaker attribution in Program cards — OPTIONAL line rendered as the LAST
   element of the card (story nx-90747863f855 AC4a, cap doc §3.4). Extends the
   announced-state template, which was topic + "presented by {Vendor}" only.

   Order on a vendor card:  topic → "presented by {Vendor}" → speaker
   Order on a member card:  topic → speaker            (no vendor line)

   OPTIONAL IS LOAD-BEARING: when the speaker is unknown the element is OMITTED
   ENTIRELY — never rendered empty, never a "TBD" string (Cynomi is the live
   proof case). Reads slightly quieter than the vendor line so the card is a
   clean topic → attribution → person cascade rather than three equal lines.
   -------------------------------------------------------------------------- */
.forge-program-speaker {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--color-brand-indigo);
    margin: 0;
    line-height: 1.3;
    margin-top: auto;
}

/* --------------------------------------------------------------------------
   Program — Evenings (Welcome Reception, Awards Dinner)
   -------------------------------------------------------------------------- */
.forge-evenings {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
    margin-top: var(--space-md);
    max-width: var(--max-width-text);
    margin-left: auto;
    margin-right: auto;
}

@media (min-width: 640px) {
    .forge-evenings {
        grid-template-columns: 1fr 1fr;
    }
}

.forge-evening {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    text-align: center;
}

.forge-evening h4 {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: var(--space-xs);
}

.forge-evening .muted {
    color: var(--color-muted-foreground);
    font-size: 0.95rem;
}

/* --------------------------------------------------------------------------
   Sponsors section — tier-grouped logo wall
   -------------------------------------------------------------------------- */
.forge-sponsor-row {
    /* FLEX, not grid, and the same geometry for BOTH tiers.

       Brock UAT round-3 ruling (story nx-90747863f855, AC10 item 4, verbatim):
       "Do NOT put Sherweb on a line lower than the other two. All three on the
       same line. They can wrap if viewport size forces it, but right now they
       are intentionally a line lower." The invariant is per-CARD, not per-three,
       so nothing here hard-codes a column count: flex-basis 0 + flex-grow 1 at
       desktop puts EVERY card in the row on one line at equal width whether the
       row holds 3, 4 or 6, and wrap only ever happens when min-width forces it.

       The prior treatment (centering an odd last card at half width) satisfied
       every DOM assertion and still failed the ruling -- a centered card is
       still a card on a lower line.

       Equal widths across tiers is the deliberate resolution of the tradeoff
       Margot put to me: at four-up inside a 64rem container, Premier cards are
       necessarily narrower than a 2-up Standard row would be, so protecting
       Premier width by keeping a card on its own line is exactly what the ruling
       forbids. Both rows therefore share one grid rhythm and the TIER SIGNAL is
       carried by .forge-sponsor-card-premier (2px indigo border + heavier
       padding) and the filled .forge-tier-badge-premier, never by card width.
       Consequence: the premier row's old larger gap override is gone -- an
       unequal gap would make Premier cards a few px NARROWER than Standard at
       the same column count, re-inverting the very weighting it was meant to
       express.

       Row width was also lifted off --max-width-text (48rem) to the full
       container: four-up inside 48rem leaves ~110px of content per Premier card,
       which is not enough for the "Premier Sponsor" badge. */
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-lg);
    margin-bottom: var(--space-2xl);
    margin-left: auto;
    margin-right: auto;
}

/* --sponsor-card-basis is the SINGLE SOURCE for tier card width in every band.
   Declared on the row container and consumed by the card rule, so tier-row
   width lives in one place rather than in two rule sets kept in sync by hand.

   That hand-sync is exactly what broke: bugs nx-57fbf969c27b + nx-255d40ada8bc
   (2026-08-29). The (now-retired) emcee row carried its own duplicate copy of
   the base and 640 rules, so the geometry lived in two places and a defect in
   one shape was a defect in both. The emcee credit is card-less as of story
   nx-8265bf66c47b, so only the tier rows consume this now. Add a band here, not
   in two places. */
.forge-sponsor-row {
    --sponsor-card-basis: 100%;
}

/* --sponsor-card-floor is the DESKTOP CARD FLOOR: the narrowest a sponsor card
   may render before the row wraps instead of squeezing. It replaced
   `min-width: 8rem` (bug nx-e86678f725cd), which was documented as a legibility
   guard but permitted a 62px content box -- a count cap wearing a floor's
   costume, and 48px below the ~110px this file already called insufficient.

   WHAT SETS THE VALUE: a sponsor name is never abbreviated and never broken
   mid-word, so the binding constraint is the longest UNBREAKABLE WORD on the
   wall. Today that is "Communications" (Loop Communications) at 158.53px in
   Playfair Display 20px/600, measured -- not computed. 13rem = 208px clears it
   with ~47px of headroom, which is deliberate: the headroom is for the NEXT
   sponsor, roughly a name up to 18 characters, not for today's.

   WHY 13rem AND NOT SOMETHING TIGHTER: any floor from 167px to 216px yields the
   same four-column desktop wall, so 13rem buys maximum headroom for free. Going
   below 167px would seat five cards per line, which fits the name only by
   letting it run to within 3.9px of the card border -- legible, but a sponsor
   name grazing its own card edge is not what this wall is for, and it would
   leave no room at all for a name longer than today's.

   This value is NOT self-maintaining and is not meant to look like it is. The
   pin in tests/forge-page-smoke.mjs measures the longest published name at test
   time and fails by name if it outgrows this token, so raising it is a
   CI-prompted one-line edit rather than something a future editor has to
   remember to re-measure. See §3.5. */
.forge-sponsor-row {
    --sponsor-card-floor: 13rem;
}

.forge-sponsor-row > .forge-sponsor-card {
    /* Mobile: one card per line.

       flex-grow is 0, and that is THE fix for nx-255d40ada8bc. A grow of 1 on a
       WRAPPING row means any card left alone on a line stretches to the whole
       container: with 3 Premier cards at a 2-up basis, Sherweb wrapped to line 2
       by herself and rendered 836px against her peers' 402px (2.08x) everywhere
       between 640px and 1023px. The defect is a function of PARITY, not of tier
       -- Standard escaped only because it happens to hold an even 4, and is
       specced to 7.

       So the rule is: a card never grows past its basis. Grow is not restored
       anywhere: the >=1024px band used to re-enable it, and that re-enabled
       exactly this defect one band up -- a 7th card wrapped alone and grew to
       the full 960 (bug nx-e86678f725cd). That band is now a grid, where equal
       tracks give equal widths ACROSS wrapped lines without growing anything.
       If a future band lets a row wrap, it must NOT re-enable grow. */
    flex: 0 1 var(--sponsor-card-basis);
    min-width: 0;
}

@media (min-width: 640px) {
    /* Tablet: two per line -- the viewport genuinely forces a wrap here, which
       the ruling explicitly permits ("they can wrap if viewport size forces
       it"). Wrapping is allowed; UNEQUAL WIDTH is the defect. An odd last card
       now renders at the same 2-up basis as its peers, on its own line. */
    .forge-sponsor-row {
        --sponsor-card-basis: calc(50% - (var(--space-lg) / 2));
    }
}

@media (min-width: 1024px) {
    /* Desktop: as many cards per line as fit ABOVE THE CARD FLOOR, all equal
       width, count-agnostic -- and a line that wraps stays equal instead of
       full-bleeding its orphan.

       WHY GRID HERE, when this file records a move OFF grid: that move was off a
       FIXED COLUMN COUNT, which is a different thing. `auto-fit` picks the count
       from the container, so nothing here hard-codes one -- the count-agnostic
       property the flex treatment was chosen for is preserved, and two
       properties flex could not express are gained:
         1. every track is `1fr`, so cards are equal ACROSS wrapped lines, not
            just within one line. Flex `basis: 0 + grow: 1` only equalises within
            a line: a wrapped orphan grew to the full 960 (bug nx-e86678f725cd,
            measured [133x6, 960] at 7-up).
         2. a lone card on a wrapped line occupies ONE track, so it cannot
            full-bleed. That is the nx-57fbf969c27b failure mode, which lived
            here too -- in this band, where grow was still 1.

       WHY THE FLOOR IS A DECLARED VALUE AND NOT `min-content` -- do not
       "improve" this into deriving itself; both derived forms were measured and
       both fail:
         * `min-width: min-content` on the card clamps EACH CARD to ITS OWN
           longest word, and cards differ, so the row goes UNEQUAL -- measured
           11.36px spread at 4-up, 72.66px at 5-up. That breaks the equal-width
           invariant nx-255d40ada8bc shipped.
         * `repeat(auto-fit, minmax(min-content, 1fr))` is INVALID CSS -- an
           auto-repeat needs a definite minimum. Chromium drops the declaration.
       CSS has no "widest sibling's min-content" to compute a UNIFORM floor from,
       and the floor must be uniform or the row is unequal. So the floor is
       declared, and the thing that keeps a declared floor honest lives in
       tests/forge-page-smoke.mjs: a pin derives the longest published sponsor
       name's min-content at test time and fails BY NAME if it outgrows this
       token. A longer name than today's is caught in CI before it reaches the
       public wall -- it cannot re-create this defect silently. See §3.5. */
    .forge-sponsor-row {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(min(var(--sponsor-card-floor), 100%), 1fr));
    }

    /* Premier cards sit at 3-up against Standard's 4-up, so they are naturally
       WIDER -- the tier weighting now reads from width as well as from the
       border and badge. Round 4 had both rows at 4-up (equal widths, tier
       carried by border + badge alone); the AC12 round-5 correction returning
       Premier to 3 restored the width signal for free. The padding step-down
       below is retained for the Standard-density case, not for Premier. */
    .forge-sponsor-row-premier > .forge-sponsor-card-premier {
        padding: var(--space-lg);
    }
}

.forge-sponsor-card {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-md);
}

.forge-sponsor-card-premier {
    padding: var(--space-xl);
    border-width: 2px;
    border-color: var(--color-brand-indigo);
}

.forge-sponsor-meta {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
}

.forge-sponsor-name {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--color-foreground);
}

.forge-tier-badge {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 0.2em 0.7em;
    border-radius: 999px;
    background: rgba(74, 78, 140, 0.1);
    color: var(--color-brand-indigo);
}

.forge-tier-badge-premier {
    background: var(--color-brand-indigo);
    color: #ffffff;
}

/* .forge-tier-badge-host DELETED 2026-08-28 (story nx-bee2effbdd05) and NOT
   replaced. The emcee card carries no tier badge at all: a pill in the same
   language as PREMIER SPONSOR / STANDARD SPONSOR is exactly what a sponsor
   reads as a rung on the ladder, and the "Featuring our emcee" heading already
   states the role. Do not reintroduce a badge on this card in any colour --
   the absence is pinned in tests/forge-page-smoke.mjs.

   --------------------------------------------------------------------------
   EMCEE CREDIT block -- OFF the tier ladder, below it
   --------------------------------------------------------------------------
   Host / Emcee is an event-program ROLE CLASS, not a rung, so it is not a
   .forge-sponsor-row and takes none of the tier treatments: no
   .forge-tier-heading (that class is the ladder's own vocabulary and is
   reserved for Premier and Standard), no .forge-sponsor-card-premier border,
   no tier badge. The heading is the plain foreground colour, NOT the tier
   indigo, so the two heading classes are visually distinguishable at a glance;
   the border-top rule separates the credit from the ladder above it, which is
   what encodes "off the ladder" rather than "a fourth rung". */
/* Option B -- CARD-LESS host credit + warm accent (story nx-8265bf66c47b,
   design pass nx-d06c76a2b085, 2026-09-02). The block is its own object, NOT a
   tier card minus its badge. The border-top still does the "off the ladder /
   new zone" job -- and now, with the card box gone, it is no longer drowned out
   by shared card chrome. Centred column: mono credit label, a short warm accent
   rule, the host name. The featuring is carried by warmth + composition, never
   by a box or by type size. */
.forge-emcee-credit {
    border-top: 1px solid var(--color-border);
    padding-top: var(--space-xl);
    margin-top: var(--space-xl);
    margin-bottom: var(--space-2xl);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-sm);
}

/* Mono credit label -- the section-label vocabulary (var(--font-mono),
   uppercase, tracked), NOT a .forge-subhead / .forge-tier-heading H3. A credit
   label reads as a credit; three same-styled H3s in a stack read as a ladder,
   which is the exact failure this line of work removed. */
.forge-emcee-credit-label {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-muted-foreground);
    margin: 0;
}

/* The "featured" signal: a short warm coral->amber bar, borrowed from the
   section dividers' own accent (var(--color-accent) -> var(--color-accent-mid)).
   Deliberately NOT tier indigo -- indigo is the ladder's colour and would
   re-borrow rung vocabulary. Narrow by design (this is a credit, not a hero
   band); the width is pinned small in tests/forge-page-smoke.mjs. */
.forge-emcee-credit-accent {
    width: 44px;
    height: 2px;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--color-accent), var(--color-accent-mid));
}

/* Host name at TIER-CARD-NAME SCALE (1.25rem / 600, matches .forge-sponsor-name)
   with NO card chrome -- provably subordinate to Premier: same name size, no
   box, no border. The accent does the featuring, not the type size. This scale
   is the successor to the retired emcee-card width cap; a name larger than the
   largest tier-card name is the new full-bleed, and is pinned by computed style
   in tests/forge-page-smoke.mjs. */
.forge-emcee-credit-name {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--color-foreground);
}

/* OPTIONAL, same rule as .forge-program-speaker: a sponsor whose own marketing
   one-liner has not been sourced yet renders the card WITHOUT this element —
   never empty, never "TBD" (Brock UAT verdict 2026-08-20, story
   nx-90747863f855: "Put their cards in without the taglines"). Monjur and MSP
   Process are the live proof cases. Provarro does not author sponsor taglines
   (§3.5, no-ad-lib directive). */
.forge-sponsor-tagline {
    font-size: 0.95rem;
    color: var(--color-muted-foreground);
    line-height: 1.5;
    max-width: 28rem;
    margin: 0;
}

/* --------------------------------------------------------------------------
   Venue — hotel block placeholder
   -------------------------------------------------------------------------- */
.forge-hotel-block {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-brand-indigo);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    margin: var(--space-xl) auto 0;
    max-width: var(--max-width-text);
}

.forge-hotel-block h4 {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    margin-bottom: var(--space-xs);
    color: var(--color-brand-indigo);
}

.forge-hotel-block p {
    margin: 0;
    color: var(--color-foreground);
}

/* Live booking CTA inside the Venue hotel block (story nx-3a8d001b3cf6).
   Sits below the address line; href injected from constants.js
   HOTEL_BOOKING_URL by render.js::wireVenueHotelLink. */
.forge-hotel-block-btn {
    display: inline-block;
    margin-top: var(--space-md);
}

/* "No code needed" clarifying clause beneath the hotel CTAs — Venue block +
   reg-success state (story nx-294ba574da7d). Preventive against members
   conflating their Forge registration code with a nonexistent hotel discount
   code. Verbatim copy authored by Colette (nx-b66c0cf36465). Muted clarifying-
   note treatment; spacing overrides the flush .forge-hotel-block p { margin:0 }. */
.forge-hotel-no-code {
    margin-top: var(--space-sm) !important;
    margin-bottom: 0;
    font-size: 0.9rem;
    color: var(--color-muted-foreground, var(--color-foreground));
}

/* --------------------------------------------------------------------------
   CEO message
   -------------------------------------------------------------------------- */
.forge-ceo-message {
    max-width: var(--max-width-text);
    margin: 0 auto;
}

.forge-ceo-attribution {
    margin-top: var(--space-lg);
    padding-top: var(--space-md);
    border-top: 1px solid var(--color-border);
}

.forge-ceo-name {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.1rem;
    margin: 0;
}

.forge-ceo-attribution .muted {
    color: var(--color-muted-foreground);
    font-size: 0.95rem;
    margin: 0;
}

/* --------------------------------------------------------------------------
   Register — reg form (story nx-30ac57f10912).

   Form styles are decoupled from workshop.css (Nathan's pattern) so the Forge
   page owns its own form-style surface. When AnnMarie's content reframe lands
   on the survey block (§3.11 #3 + Maren cadence nx-98d1c57d3a4d), no CSS
   change is required — the labels change, the structure stays.

   .forge-form              — top-level wrapper (mirrors .workshop-form spec)
   .forge-radio-group       — attendee_type radio (and the survey workshop-
                              interest radio block)
   .forge-radio             — individual radio label wrapper (boxed style)
   .forge-checkbox          — individual checkbox label wrapper
   .forge-tcs               — consent / acknowledgment fieldset
   .forge-tcs-box           — scrollable consent text container
   .forge-conditional       — member-only blocks (visibility driven by JS
                              [hidden] attribute; CSS class is a hook for
                              future overrides without restamping the JS)
   .forge-survey-block      — Forge member survey block (ratified 6-question
                              content per story nx-ca8f11525a6a)
   .forge-survey-question   — individual question wrapper inside survey block
   .forge-turnstile         — Turnstile widget mount
   .forge-form-error        — inline error message (role=alert)
   .forge-submit            — primary submit button
   .forge-cohort-closed     — registrations-closed state container
   .forge-success           — inline confirmation state container
   .forge-form-intro        — top-of-form intro copy
   -------------------------------------------------------------------------- */

.forge-form {
    max-width: var(--max-width-text);
    margin: var(--space-md) auto 0;
}

.forge-form-intro {
    color: var(--color-muted-foreground);
    margin-bottom: var(--space-lg);
}

.form-group-full {
    grid-column: 1 / -1;
}

/* Conditional blocks driven by attendee_type. JS toggles [hidden]; the class
   exists so future-Wren can add transitions/animations without changing JS. */
.forge-conditional[hidden] {
    display: none !important;
}

/* --- +1 (Social Pass) block — cap doc §3.13, story nx-9ea5b8f86e74 ---
   Wraps the checkbox + the conditionally-revealed name/dietary fields.
   The checkbox uses .forge-checkbox boxed styling; when checked, the
   .forge-plus-one-fields reveal renders below with form-row spacing so
   the two new inputs sit cleanly inside the fieldset. */
.forge-plus-one-fields {
    margin-top: var(--space-sm);
}

/* Prominent pre-registration price callout (story nx-a0b9fb5a6b75, AC1 / cap
   doc §3.13). Replaces the prior muted .forge-field-helper so the $350 Social
   Pass price is unmistakable BEFORE submit — [pin-allow:comment-currency], that
   is the PUBLISHED Social Pass price, rendered in visible copy a few hundred
   bytes away, not a commercial term (story nx-b8e2835a19b9). Brock go-live
   finding (note 19452):
   price was previously read clearly only at confirmation. Mirrors the
   .forge-hotel-block indigo-left-accent card treatment for strong-but-calm
   prominence; the price leads in display voice. Display-only — no gating. */
.forge-plus-one-price {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-brand-indigo);
    border-radius: var(--radius-md);
    padding: var(--space-md);
    margin-top: var(--space-sm);
}

.forge-plus-one-price-lead {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--color-brand-indigo);
    margin: 0 0 var(--space-xs);
}

.forge-plus-one-price-detail {
    margin: 0;
    color: var(--color-foreground);
    font-size: 0.95rem;
}

/* +1 confirmation paragraph (cap doc §3.13 + AC5). Subtle visual lift
   from the surrounding success copy so the additional logistics are
   recognizable as the +1 follow-up note. */
.forge-plus-one-confirmation {
    padding: var(--space-md);
    background: var(--color-card-hover, rgba(0, 0, 0, 0.03));
    border-left: 3px solid var(--color-primary);
    border-radius: var(--radius-sm, 6px);
}

/* Fieldset reset for radio + checkbox + tcs groups */
.forge-form fieldset.form-group {
    border: 0;
    padding: 0;
    margin: 0 0 var(--space-md);
}

.forge-form fieldset.form-group legend {
    display: block;
    font-weight: 600;
    margin-bottom: var(--space-sm);
    color: var(--color-foreground);
    padding: 0;
}

/* --- Radios + checkboxes (boxed label style, accessibility-friendly) --- */
.forge-form .forge-radio,
.forge-form .forge-checkbox {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-xs);
    cursor: pointer;
    background: var(--color-card);
    transition: border-color 0.15s, background 0.15s;
    /* Override .form-group label (styles.css) — sentence-length labels render
       in body voice, not the small-caps mono used for short field labels per
       Forge Landing Page cap doc §3.12 #7-8 (story nx-9ba3f5463195). */
    font-family: var(--font-body);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    color: var(--color-foreground);
}

.forge-form .forge-radio:hover,
.forge-form .forge-checkbox:hover {
    border-color: var(--color-primary);
    background: var(--color-card-hover, var(--color-card));
}

.forge-form .forge-radio input[type="radio"],
.forge-form .forge-checkbox input[type="checkbox"] {
    flex-shrink: 0;
    margin-top: 0.2rem;
    width: 1.1rem;
    height: 1.1rem;
    accent-color: var(--color-primary);
    cursor: pointer;
}

.forge-form .forge-radio span,
.forge-form .forge-checkbox span {
    flex: 1;
    line-height: 1.4;
}

.forge-form .forge-radio .muted,
.forge-form .forge-checkbox .muted {
    color: var(--color-muted-foreground);
    font-weight: 400;
}

/* --- Consent / TCS scrollable boxes --- */
.forge-tcs-box {
    max-height: 14em;
    overflow-y: auto;
    padding: var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-card);
    margin-bottom: var(--space-sm);
    line-height: 1.55;
}

.forge-tcs-box p {
    margin-bottom: var(--space-sm);
}

.forge-tcs-box p:last-child {
    margin-bottom: 0;
}

/* --- Survey block --- */
.forge-survey-block {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
}

.forge-survey-intro {
    margin-bottom: var(--space-md);
    font-size: 0.95rem;
}

.forge-survey-intro p {
    margin: 0 0 var(--space-sm) 0;
}

.forge-survey-intro p:last-child {
    margin-bottom: 0;
}

.forge-survey-question {
    margin-bottom: var(--space-lg);
}

.forge-survey-question:last-child {
    margin-bottom: 0;
}

/* All sentence-length labels inside the survey block (question headers,
   optional follow-up prompts, Other text reveal label) render in body
   voice per §3.12 #8 — overrides .form-group label uppercase-mono default
   from styles.css. Story nx-ca8f11525a6a. */
.forge-survey-block label:not(.forge-radio):not(.forge-checkbox) {
    font-family: var(--font-body);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    color: var(--color-foreground);
}

.forge-survey-question > label,
.forge-survey-question-label {
    /* Survey question labels are full sentences — render in body voice per
       Forge Landing Page cap doc §3.12 #8 (sentence-length labels in
       sentence case, not the small-caps mono uppercase from .form-group label
       in styles.css). Story nx-ca8f11525a6a. */
    display: block;
    font-weight: 500;
    margin-bottom: var(--space-sm);
}

.forge-survey-question-hint {
    margin: calc(-1 * var(--space-xs)) 0 var(--space-sm) 0;
    font-size: 0.875rem;
    color: var(--color-muted-foreground);
}

.forge-survey-question textarea,
.forge-survey-question select,
.forge-survey-question input[type="text"] {
    width: 100%;
}

/* "Optional: What makes that format valuable for you?" follow-up label
   under Q2 radios sits inside the same question wrapper — bump top margin
   so it doesn't collide with the last radio option. */
.forge-survey-question .forge-radio + label,
.forge-survey-question .forge-checkbox + label {
    margin-top: var(--space-sm);
}

/* Q1 "Other" free-text reveal wrapper — sits inside the question stack. */
#survey-q1-other-text-wrap {
    margin-top: var(--space-sm);
}

#survey-q1-other-text-wrap label {
    display: block;
    margin-bottom: var(--space-xs);
    font-size: 0.875rem;
}

/* Disabled checkbox styling (Q1 max-3 cap reached) — keep visible but
   muted so the cap is discoverable. */
.forge-form .forge-checkbox input[type="checkbox"]:disabled ~ span {
    opacity: 0.55;
}

.forge-form .forge-checkbox:has(input[type="checkbox"]:disabled) {
    cursor: not-allowed;
    opacity: 0.7;
}

/* --- Turnstile mount --- */
.forge-turnstile {
    margin: var(--space-md) 0;
    min-height: 0;
}

.forge-turnstile:not(:empty) {
    min-height: 65px;
}

/* --- Inline error message --- */
.forge-form-error {
    background: rgba(220, 53, 69, 0.08);
    border: 1px solid rgba(220, 53, 69, 0.3);
    color: var(--color-foreground);
    padding: var(--space-md);
    border-radius: var(--radius-md);
    margin: var(--space-md) 0;
    line-height: 1.5;
}

/* --- Field-level error (used by reg-code rejections per story nx-b0a5f1c21bd9
       AC3 — surfaced inline below the offending field, field stays populated). --- */
.forge-field-error {
    color: rgb(180, 35, 50);
    font-size: 0.95rem;
    margin-top: var(--space-xs);
    line-height: 1.4;
}

/* --- Field helper text (used by reg-code helper copy per story nx-b0a5f1c21bd9
       AC1) — small italicized line between field and the next form-group. --- */
.forge-field-helper {
    font-size: 0.9rem;
    margin-top: var(--space-xs);
    margin-bottom: 0;
    line-height: 1.4;
}

/* --- Reg-code block (story nx-b0a5f1c21bd9 AC1/AC2): the reg-code input
       owns the sponsor-dropdown sibling beneath it so revealing the
       dropdown doesn't shift the rest of the form. --- */
.forge-reg-code-block {
    margin-bottom: var(--space-md);
}

.forge-sponsor-dropdown {
    margin-top: var(--space-md);
}

/* --- Submit button --- */
.forge-submit {
    width: 100%;
    margin-top: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    font-size: 1.05rem;
}

.forge-submit:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* --- Cohort-closed state --- */
.forge-cohort-closed {
    max-width: var(--max-width-text);
    margin: var(--space-md) auto;
    padding: var(--space-xl);
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    text-align: center;
}

.forge-cohort-closed h3 {
    margin-bottom: var(--space-sm);
}

/* --- Success state --- */
.forge-success {
    max-width: var(--max-width-text);
    margin: var(--space-md) auto;
    padding: var(--space-xl);
    background: var(--color-card);
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-lg);
}

.forge-success h3 {
    color: var(--color-primary);
    margin-bottom: var(--space-md);
}

.forge-success p {
    margin-bottom: var(--space-md);
    line-height: 1.6;
}

.forge-success p:last-child {
    margin-bottom: 0;
}

/* Hotel room-block booking CTA inside the registration success state
   (story nx-c5a84941da35). Mirrors the venue .forge-hotel-block indigo
   left-accent so the "book your room" prompt reads as the same program
   element; transparent background lets it stand out within the
   --color-card success panel via the accent border rather than a nested
   card. */
.forge-hotel-cta {
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-brand-indigo);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    margin-bottom: var(--space-md);
}

.forge-hotel-cta h4 {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    margin-bottom: var(--space-xs);
    color: var(--color-brand-indigo);
}

.forge-hotel-cta p {
    margin-bottom: var(--space-md);
    line-height: 1.6;
}

.forge-hotel-cta-btn {
    display: inline-block;
}

/* --- Mobile polish for the form --- */
@media (max-width: 639px) {
    .forge-form {
        margin-top: var(--space-sm);
    }
    .forge-form fieldset.form-group {
        margin-bottom: var(--space-sm);
    }
    .forge-tcs-box {
        max-height: 12em;
        padding: var(--space-sm);
    }
    .forge-survey-block {
        padding: var(--space-md);
    }
}

/* Smooth-scroll for the hero Register CTA (cap doc AC #7 — smooth-scroll
   preferred but instant jump acceptable). Honors prefers-reduced-motion via
   the global media query in /styles.css. */
html {
    scroll-behavior: smooth;
}

/* --------------------------------------------------------------------------
   Section nav — reveal-on-scroll, Forge-page-local
   (story nx-4e1317090504, cap doc §3.1)

   Slim bar that pins to the viewport top once the hero scrolls out of view
   (secnav.js toggles .is-visible). position: fixed (NOT sticky) — the bar
   lives before the hero in source order, so a sticky bar would scroll away
   with the hero; fixed pins it to the viewport regardless of scroll. Hidden
   default state (translateY offscreen + opacity 0 + pointer-events none) means
   no flash on first paint and graceful no-JS degradation.

   --forge-secnav-height is re-measured into the :root by secnav.js after layout
   (and on resize) so .section/.hero scroll-margin-top exactly matches the real
   rendered bar height across breakpoints + font-load (AC5). 48px is the
   pre-JS fallback.
   -------------------------------------------------------------------------- */
:root {
    --forge-secnav-height: 48px;
}

.forge-secnav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
    background: var(--color-card);
    border-bottom: 2px solid var(--color-brand-indigo);
    box-shadow: 0 1px 6px rgba(26, 26, 26, 0.06);
    transform: translateY(-100%);
    opacity: 0;
    pointer-events: none;
    transition: transform var(--transition-base), opacity var(--transition-base);
}

.forge-secnav.is-visible {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
}

.forge-secnav-inner {
    display: flex;
    align-items: stretch;
    gap: var(--space-sm);
    /* Slimmer horizontal padding than the default .container so the bar reads
       as a utility strip, not a content section. */
    padding-top: 0;
    padding-bottom: 0;
}

/* Scrollable content-links strip — fills the available width left of the
   pinned Register link. Overflows horizontally on mobile; sits comfortably on
   one row on desktop (no scroll). */
.forge-secnav-links {
    display: flex;
    align-items: stretch;
    gap: 0;
    list-style: none;
    margin: 0;
    padding: 0;
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;            /* Firefox — hide the scrollbar, keep scroll */
    -ms-overflow-style: none;
}
.forge-secnav-links::-webkit-scrollbar {
    display: none;                    /* WebKit — hide the scrollbar */
}
.forge-secnav-links li {
    flex: 0 0 auto;
}

.forge-secnav-link {
    display: flex;
    align-items: center;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    text-decoration: none;
    color: var(--color-muted-foreground);
    padding: 0.75rem var(--space-sm);
    border-bottom: 2px solid transparent;
    transition: color var(--transition-fast), border-color var(--transition-fast);
}

.forge-secnav-link:hover,
.forge-secnav-link:focus-visible {
    color: var(--color-brand-indigo);
}

/* Scroll-spy current-section highlight (AC3). */
.forge-secnav-link.is-current {
    color: var(--color-brand-indigo);
    border-bottom-color: var(--color-brand-indigo);
}

/* Register — accent-filled, pinned right, one tap from anywhere (AC4).
   Uses the page primary-CTA accent gradient, compacted to the slim bar. */
.forge-secnav-register {
    flex: 0 0 auto;
    align-self: center;
    color: #FFFFFF;
    background: linear-gradient(135deg, var(--color-accent) 0%, var(--color-accent-mid) 50%, var(--color-accent-hover) 100%);
    border-bottom: 2px solid transparent;
    border-radius: var(--radius-sm);
    padding: 0.4rem var(--space-md);
    margin: 0.35rem 0;
    box-shadow: 0 1px 4px rgba(232, 90, 79, 0.25);
}
.forge-secnav-register:hover,
.forge-secnav-register:focus-visible {
    color: #FFFFFF;
}
/* When Register itself is the current section, keep the accent fill but add a
   subtle inset ring so scroll-spy still reads "you're here" (AC3 + AC4). */
.forge-secnav-register.is-current {
    color: #FFFFFF;
    border-bottom-color: transparent;
    box-shadow: 0 1px 4px rgba(232, 90, 79, 0.25), inset 0 0 0 2px rgba(255, 255, 255, 0.55);
}

/* scroll-margin-top so anchor jumps don't land headings clipped under the
   fixed bar (AC5). Applied to both .section and .hero per cap doc §3.1. */
.forge-page .section,
.forge-page .hero {
    scroll-margin-top: calc(var(--forge-secnav-height) + var(--space-xs));
}

/* Mobile (≤767px): the eight labels won't fit one 390px row. The content
   strip scrolls horizontally (secnav.js auto-centers the active chip so the
   current section is always visible — AC6a); Register stays pinned + visible
   (AC6b/c). Tighten paddings so more chips are reachable per swipe. */
@media (max-width: 767px) {
    .forge-secnav-inner {
        gap: var(--space-xs);
    }
    .forge-secnav-link {
        padding: 0.75rem 0.625rem;
        font-size: 0.75rem;
    }
    .forge-secnav-register {
        padding: 0.4rem 0.75rem;
    }
}

/* Aesthetic restraint (AC7): honor reduced-motion — no slide/fade animation,
   just an instant show/hide. Mirrors the global reduced-motion posture in
   /styles.css that also disables scroll-behavior: smooth. */
@media (prefers-reduced-motion: reduce) {
    .forge-secnav {
        transition: none;
    }
}

/* --------------------------------------------------------------------------
   Mobile polish
   -------------------------------------------------------------------------- */
@media (max-width: 639px) {
    .forge-table th,
    .forge-table td {
        padding: var(--space-xs) var(--space-sm);
        font-size: 0.85rem;
    }
}

/* --------------------------------------------------------------------------
   Invitation request (story nx-b0a5f1c21bd9 AC5)
   -------------------------------------------------------------------------- */
.forge-invitation-section {
    max-width: var(--max-width-text);
    margin: var(--space-xl) auto 0;
}

.forge-invitation-cta {
    padding: var(--space-xl);
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    text-align: center;
}

.forge-invitation-cta h3 {
    margin-bottom: var(--space-sm);
}

.forge-invitation-cta p {
    margin-bottom: var(--space-md);
}

.forge-invitation-form {
    margin-top: var(--space-md);
}

.forge-invitation-toggle {
    min-width: 220px;
}

/* --------------------------------------------------------------------------
   S2 invitation-only two-path gate (story nx-a783fed6498a)
   -------------------------------------------------------------------------- */

/* Code-gate row — input + Continue button inline; stacks on narrow screens. */
.forge-code-gate-row {
    display: flex;
    gap: var(--space-sm);
    align-items: stretch;
}

.forge-code-gate-row input {
    flex: 1 1 auto;
    min-width: 0;
}

.forge-code-continue {
    flex: 0 0 auto;
    white-space: nowrap;
}

.forge-code-continue:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* [hidden] guard — .btn sets display:inline-block (author rule) which outranks
   the [hidden] UA rule, so the Continue button would stay visible after the
   code validates. Restore display:none explicitly. */
.forge-code-continue[hidden] {
    display: none;
}

@media (max-width: 480px) {
    .forge-code-gate-row {
        flex-direction: column;
    }
}

/* "Code accepted" indicator — shown after a valid code reveals the fields. */
.forge-code-accepted {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    margin-top: var(--space-sm);
    font-size: 0.95rem;
    color: var(--color-foreground);
}

/* [hidden] guard — an author display:flex outranks the [hidden] UA rule, so
   restore display:none explicitly (same trap the .forge-conditional pattern
   documents). Without this the indicator paints in the initial gate state. */
.forge-code-accepted[hidden] {
    display: none;
}

.forge-code-accepted-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background: var(--color-brand-indigo);
    color: #fff;
    font-size: 0.8rem;
    line-height: 1;
    flex: 0 0 auto;
}

/* Text-style buttons (no-code prompt, change-code, back-to-code). Render as a
   link without the <a href> semantics — they drive JS state transitions. */
.forge-link-btn {
    appearance: none;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: var(--color-brand-indigo);
    text-decoration: underline;
    cursor: pointer;
}

.forge-link-btn:hover {
    opacity: 0.8;
}

.forge-no-code-prompt {
    margin-top: var(--space-md);
    margin-bottom: 0;
    font-size: 0.95rem;
    color: var(--color-muted-foreground);
}

/* Registration fields wrapper — revealed by JS [hidden] toggle after a valid
   code. The .forge-reg-fields class is a CSS hook paralleling .forge-conditional
   so an author display value can't override [hidden]'s display:none. */
.forge-reg-fields[hidden] {
    display: none;
}

/* Completing-framing sub-header (story nx-ebbe0775fe59) — shown only on the
   pre-filled redemption arrival. Sentence-case acknowledgment of the pre-filled
   state (Forge Landing Page §3.12 rule 8). Honors [hidden] via the wrapper hook
   pattern so applyRegistrationFraming()'s toggle can't be overridden by display. */
.forge-completing-subhead {
    margin-bottom: var(--space-lg);
    color: var(--color-muted-foreground);
    font-size: 1.05rem;
}
.forge-completing-subhead[hidden] {
    display: none;
}

/* Locked attribution-identity field (story nx-ebbe0775fe59) — the email
   pre-filled from an approved-request payload is read-only (it's the code's
   attribution identity). Muted, non-editable affordance so the lock reads as
   intentional rather than broken. */
.forge-reg-fields input.forge-locked {
    background: var(--color-muted, #f1f1f4);
    color: var(--color-muted-foreground);
    cursor: not-allowed;
}

/* Request-invitation intro (replaces the old always-visible CTA). */
.forge-invitation-intro {
    margin-bottom: var(--space-md);
}

.forge-invitation-intro h3 {
    margin-bottom: var(--space-sm);
}

.forge-invitation-intro p {
    margin-bottom: var(--space-sm);
    color: var(--color-muted-foreground);
}
