/**
 * Conference Public Frontend Styles
 *
 * Purpose-built for conference program types.
 * Complements the base styles injected by conference.js (conf-* classes).
 * Uses Fusebox brand palette with Space Grotesk headings, Inter body text.
 */

/* =============================================================================
   CSS Variables / Design Tokens
   ============================================================================= */

:root {
    /* Theme tokens (#2718) — per-org overrides set by conference.js
       _applyBranding() via document.documentElement.style.setProperty().
       When no override is set, fall back to the Fusebox brand palette so
       existing customers look identical. */
    --color-primary: var(--theme-primary, #ec0244);
    --color-dark: #262f35;
    --color-light: #dddfd8;
    --color-maroon: var(--theme-accent, #7b0035);

    /* Form-focus glow (#2765) — 12% alpha of --theme-primary. Default tracks the
       Fusebox red focus ring; per-org JS overrides set this alongside
       --theme-primary so cfp.html / sponsor-apply.html focus states match the
       active theme. Inline styles consume it via var(--theme-primary-glow). */
    --theme-primary-glow: rgba(236, 2, 68, 0.12);

    --color-bg: var(--theme-page-bg, #fafafa);
    --color-surface: var(--theme-surface, #ffffff);
    --color-surface-alt: #f5f5f5;

    --color-text: var(--theme-text, #1a1a1a);
    --color-text-muted: var(--theme-text-muted, #666666);
    --color-text-light: #999999;

    --color-border: #e5e5e5;
    --color-border-dark: #cccccc;

    /* #7017 — the space a cued schedule row reserves at its right-hand
       end. Must clear .session-row-cue's own 20px inset plus the mark
       itself; the labelled value also clears the Details label. */
    --cue-gutter: 42px;
    --cue-gutter-labelled: 96px;

    /* Typography */
    --font-heading: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

    /* Spacing */
    --space-xs: 4px;
    --space-sm: 8px;
    --space-md: 16px;
    --space-lg: 24px;
    --space-xl: 32px;
    --space-xxl: 48px;
    --space-xxxl: 64px;

    /* Layout */
    --max-width: 1200px;
}

/* =============================================================================
   Reset & Base
   ============================================================================= */

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

body {
    font-family: var(--font-body);
    color: var(--color-text);
    background: var(--theme-bg, #262f35);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--color-primary); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }

/* =============================================================================
   Per-org dark hero variant (#2718)
   Applied when body.hero-style-dark is present (set by conference.js when
   branding.theme.hero_style === "dark"). Uses theme tokens with fallback to
   the UMich navy palette ABG ships as the first preset.
   ============================================================================= */

body.hero-style-dark .conf-hero,
body.hero-style-dark .ch-hero-bg {
    background-image: linear-gradient(
        135deg,
        var(--theme-bg, #00274c) 0%,
        var(--theme-bg-gradient-to, #1a2c45) 100%
    );
}

body.hero-style-dark .conf-hero {
    color: #fff;
    text-shadow: none;
}

/* Dark-theme readable body copy (#2949). When the org ships
   hero_style=dark, paint section headings + paragraphs in light text by
   default — without these, body copy and section h2/h3 fall back to
   #1a1a1a / #262f35 (the values in `var(--theme-text, …)` references
   throughout this file) which is unreadable on the dark page bg set by
   #2921. Orgs that explicitly set theme.text_color via branding still
   win because schedule-builder.html:49 / sponsor-apply.html:48 set
   --theme-text on :root before this rule applies. */
body.hero-style-dark {
    --theme-text: #e5e7eb;
    --theme-text-muted: #b1bac4;
    color: var(--theme-text);
}

/* =============================================================================
   Legible text on a dark page background (#6099)

   conference.js sets body.page-bg-dark from the background the page actually
   paints (getComputedStyle on body), not from a branding flag.

   INVARIANT: this block sets `color` on an enumerated selector list and NOTHING
   else. It must never set --color-text/-muted/-light or any other token, at any
   level. --color-surface is #ffffff and nothing in the repo moves it, so a token
   flip turns white-card text light-on-white — the #3089 regression, re-proved on
   the abandoned first attempt at this issue.

   Every selector below was checked to sit directly on the body background on
   EVERY page where it renders:
     .section-header        cfp, passes, sponsor-apply, speakers, tracks,
                            sponsors — always a direct child of main.page-content
     .schedule-page-header  schedule, schedule-builder — inside .schedule-container,
                            which declares no background
     .sponsor-form          sponsor-apply only; its fieldsets have a border and no
                            background
     .speaker-info/-bio     speaker.html only; .speaker-detail and .speaker-hero
                            declare no background. cfp.html's `speaker-bio` is an
                            ID on a textarea, which .speaker-bio cannot match
     .session-detail-section session.html only; a sibling of the white
                            .session-detail-hero, and neither it nor
                            .session-detail-wrapper declares a background
     .session-detail-abstract session.html only; a direct child of
                            .session-detail-section, same background as its h2
     .session-detail-back-link session.html only; .session-detail-back-row and
                            .session-detail-wrapper declare no background (#6388)
     .day-tab               schedule, schedule-builder — inside .day-tabs, a
                            direct child of .schedule-container (#6388)
     .schedule-single-day   schedule only; a direct child of
     .schedule-tz-note      .schedule-container, which declares no background —
                            the same audit as .schedule-page-header (#7263)
     .speaker-sessions h2   speaker only; .speaker-sessions declares no
                            background and is a direct child of
                            main.page-content. It declares NO colour of its own
                            and inherits --color-text from body, which is the
                            shape every sweep before #7281 missed — they all
                            enumerated rules that DECLARE a colour (#7281)
     .ch-advance-info-section .ch-section-label
     .ch-cfp-section .ch-section-label
                            index only, and SECTION-SCOPED on purpose.
                            .ch-section-label renders in seven places; five sit
                            inside a section that paints its own surface
                            (.ch-speakers-section, .ch-why-section,
                            .ch-whos-section, .ch-section-dark,
                            .ch-venue-section). Only these two sit on the page
                            background, so a bare .ch-section-label entry would
                            be the #3089 regression (#7281)
     .ch-cta-card-link      deliberately NOT here. It reads --theme-accent,
                            which for abgumich is #ffcb05 and measures 9.89:1 on
                            their page background — legible today. A fixed
                            on-dark value would repaint a brand colour for no
                            accessibility gain, so it is a product call, filed
                            separately. ARA does need it (3.45:1).
     .conf-event-rsvp-heading  schedule only; rendered by conference.js as a
                            SIBLING of .conf-event-rsvp-card, never inside it —
                            that card paints --color-surface. Its container
                            #conf-event-rsvp-panel is a bare div in
                            .schedule-container (#7268)
     .speaker-title         speaker.html only; inside .speaker-info, whose
     .social-links a        .speaker-hero / .speaker-detail ancestors declare no
                            background — the same audit as .speaker-info h1 and
                            .speaker-bio, which sit immediately above and below
                            them and are already enumerated (#7268)
     .tier-name             sponsors.html only; inside .sponsor-tier, which
                            declares no background (#6388)
     .empty-state           every render site is a bare grid/list container:
                            .speakers-grid, .tracks-grid, #schedule-grid,
                            .schedule-list, #sponsors-container,
                            .conf-sponsor-pitch__tiers, #builder-list — none
                            declares a background (#6388)
     .loading-state         schedule-builder (#builder-list), session
                            (#session-detail), speaker (.speaker-detail),
                            tracks (.tracks-grid) — the same containers already
                            audited for .error-state, and the same CSS rule
                            (#6388 Gate #2)
     .sponsor-form .form-help sponsor-apply.html only; scoped to .sponsor-form
                            because cfp.html's .form-help sits in the white
                            .cfp-form card (#6388)
     .conf-sponsor-pitch__title      sponsors.html only; direct child of
                            .conf-sponsor-pitch__head, which declares no
                            background (#6581)
     .conf-sponsor-pitch__body       sponsors.html only; same ancestor as
                            .conf-sponsor-pitch__title (#6581)
     .conf-sponsor-pitch__body-html  sponsors.html only; direct child of
                            .conf-sponsor-pitch, which declares no
                            background (#6581)
   Bare `legend`/`label` are deliberately NOT used: cfp.html's .cfp-form and
   passes.html's .passes-extras are white cards that contain both.
   Colors match the values conference_static.py already emits server-side for
   the same elements, so first paint equals the post-JS state. That SSR list
   fires whenever conference_static.py's is_dark predicate resolves dark — by
   text_color_mode or by the hero background hex — which is the signal this
   issue exists to stop trusting alone, so these rules also cover a
   dark-background org that never set text_color_mode. */

body.page-bg-dark .section-header h1,
body.page-bg-dark .schedule-page-header h1,
body.page-bg-dark .schedule-single-day,
body.page-bg-dark .conf-event-rsvp-heading,
body.page-bg-dark .speaker-sessions h2,
body.page-bg-dark .sponsor-form legend,
body.page-bg-dark .sponsor-form label,
body.page-bg-dark .speaker-info h1,
body.page-bg-dark .ssr-detail-title,
body.page-bg-dark .speaker-bio,
body.page-bg-dark .session-detail-section h2,
body.page-bg-dark .session-detail-abstract,
body.page-bg-dark .conf-sponsor-pitch__title,
body.page-bg-dark .conf-sponsor-pitch__body-html {
    color: #e5e7eb;
}

body.page-bg-dark .section-subtitle,
body.page-bg-dark .schedule-tz-note,
body.page-bg-dark .speaker-title,
body.page-bg-dark .social-links a,
body.page-bg-dark .day-tab,
body.page-bg-dark .tier-name,
body.page-bg-dark .empty-state,
body.page-bg-dark .loading-state,
body.page-bg-dark .session-detail-back-link,
body.page-bg-dark .sponsor-form .form-help,
body.page-bg-dark .conf-sponsor-pitch__body {
    color: #b1bac4;
}

/* #6388 root cause B — a brand color is a safe foreground only against a
   surface the theme controls. --color-primary IS the page background's own
   palette, so on the page background it can land on itself: ARA's #223660 on
   #0f172a measured 1.50:1. Both rules resolve to a fixed on-dark value. */
body.page-bg-dark .day-tab.active,
body.page-bg-dark .social-links a:hover,
body.page-bg-dark .ch-advance-info-section .ch-section-label,
body.page-bg-dark .ch-cfp-section .ch-section-label {
    color: #ffffff;
}

body.page-bg-dark .error-state {
    color: #fca5a5;
}

/* The ch- namespace (index.html) is scoped per SECTION, because most ch-
   sections paint their own surface via a modifier class:
     .ch-speakers-section  .ch-why-section    --color-bg          #fafafa
     .ch-whos-section                         --color-surface-alt #f5f5f5
     .ch-sponsor-pitch-section                .ch-section-dark    #262f35
                                              (+ .ch-title-onDark = #fff)
     .ch-getinvolved-section                  text is in .ch-cta-card, whose
                                              background reads --theme-bg, the
                                              page background itself
     sales-banner                             .ch-sales-banner brand gradient
   .ch-cta-card DECLARES a background equal to the page's; the other two declare
   none. Its line is not redundant — deleting it is #6889.
   .ch-cfp-section, .ch-advance-info-section and .ch-cta-card all render on the
   page background, so all three are listed (#6889). Bare .ch-section-title would hit
   4 of its 6 render sites on a light surface; .ch-section-subtitle renders
   ONLY inside .ch-speakers-section and .ch-whos-section, so it is absent here
   on purpose. */

body.page-bg-dark .ch-cfp-section .ch-section-title,
body.page-bg-dark .ch-cfp-section .ch-cfp-body,
body.page-bg-dark .ch-cfp-section .ch-cfp-body strong,
body.page-bg-dark .ch-advance-info-section .ch-section-title,
body.page-bg-dark .ch-advance-info-section .ch-advance-info-body,
body.page-bg-dark .ch-advance-info-section .ch-advance-fact-value,
body.page-bg-dark .ch-cta-card {
    color: #e5e7eb;
}

body.page-bg-dark .ch-cfp-section .ch-cfp-meta-item,
body.page-bg-dark .ch-advance-info-section .ch-advance-fact-label,
body.page-bg-dark .ch-cta-card-body {
    color: #b1bac4;
}

/* Accent-word span — used by hero h1 when theme.hero_accent_word matches a
   token in hero_title. Gradient text effect that degrades to a solid accent
   color when background-clip: text isn't supported. */
.conf-hero-accent,
.ch-hero-accent {
    color: var(--theme-accent, var(--color-primary));
    background: linear-gradient(
        to right,
        var(--theme-accent, var(--color-primary)),
        var(--theme-accent-2, var(--color-primary))
    );
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* Glass-card treatment for sponsor + speaker tiles on dark hero pages.
   Subtle backdrop blur, semi-transparent white surface, hairline border. */
body.hero-style-dark .sponsor-card,
body.hero-style-dark .ch-sponsor-card,
body.hero-style-dark .ch-speaker-card,
body.hero-style-dark .conf-speaker-card {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: #fff;
}

/* =============================================================================
   Hero Section (Landing Page)
   ============================================================================= */

.conf-hero {
    background: linear-gradient(135deg, var(--color-dark) 0%, var(--color-maroon) 100%);
    color: #fff;
    padding: var(--space-xxxl) var(--space-lg);
    text-align: center;
}

.conf-hero-inner {
    max-width: 800px;
    margin: 0 auto;
}

.conf-hero h1 {
    font-family: var(--font-heading);
    font-size: 48px;
    font-weight: 700;
    line-height: 1.15;
    margin-bottom: var(--space-md);
}

.conf-hero-dates {
    font-size: 18px;
    font-weight: 500;
    opacity: 0.9;
    margin-bottom: var(--space-xs);
}

.conf-hero-venue {
    font-size: 16px;
    opacity: 0.75;
    margin-bottom: var(--space-lg);
}

.conf-hero-tagline {
    font-size: 20px;
    line-height: 1.5;
    opacity: 0.9;
    max-width: 600px;
    margin: 0 auto var(--space-xl);
}

.conf-hero-actions {
    display: flex;
    gap: var(--space-md);
    justify-content: center;
    flex-wrap: wrap;
}

.btn-primary {
    display: inline-block;
    background: var(--color-primary);
    color: #fff;
    padding: 14px 32px;
    border-radius: 8px;
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 16px;
    border: none;
    cursor: pointer;
    transition: background 0.2s;
    text-decoration: none;
}

.btn-primary:hover { background: #d0023b; text-decoration: none; }

.btn-outline {
    display: inline-block;
    background: transparent;
    color: #fff;
    padding: 14px 32px;
    border-radius: 8px;
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 16px;
    border: 2px solid rgba(255, 255, 255, 0.5);
    cursor: pointer;
    transition: border-color 0.2s, color 0.2s;
    text-decoration: none;
}

.btn-outline:hover { border-color: #fff; color: #fff; text-decoration: none; }

.btn-outline-dark {
    display: inline-block;
    background: transparent;
    color: var(--color-dark);
    padding: 12px 28px;
    border-radius: 8px;
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 15px;
    border: 2px solid var(--color-border-dark);
    cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
    text-decoration: none;
}

.btn-outline-dark:hover { border-color: var(--color-dark); background: var(--color-surface-alt); text-decoration: none; }

/* =============================================================================
   Section Layout
   ============================================================================= */

.conf-section {
    padding: var(--space-xxxl) var(--space-lg);
}

.conf-section-inner {
    max-width: var(--max-width);
    margin: 0 auto;
}

.conf-section-alt { background: var(--color-surface-alt); }

.section-header {
    text-align: center;
    margin-bottom: var(--space-xl);
}

.section-header h2 {
    font-family: var(--font-heading);
    font-size: 32px;
    font-weight: 700;
    color: var(--color-dark);
    margin-bottom: var(--space-sm);
}

.section-subtitle {
    font-size: 16px;
    color: var(--color-text-muted);
}

/* =============================================================================
   Speaker Card Grid (landing page keynotes)
   ============================================================================= */

.speakers-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--space-lg);
}

/* Speaker detail page overrides */
.speaker-detail { max-width: var(--max-width); margin: 0 auto; padding: var(--space-xl) var(--space-lg); }

.speaker-hero {
    display: flex;
    gap: var(--space-xl);
    align-items: flex-start;
    margin-bottom: var(--space-xl);
}

.speaker-photo img {
    width: 200px;
    height: 200px;
    object-fit: cover;
    border-radius: 12px;
}

.photo-placeholder {
    width: 200px;
    height: 200px;
    background: var(--color-surface-alt);
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-light);
    font-size: 64px;
}

.speaker-info h1 { font-family: var(--font-heading); font-size: 32px; margin-bottom: var(--space-xs); }
.speaker-title { font-size: 16px; color: var(--color-text-muted); }
.speaker-company { font-size: 14px; color: var(--color-text-light); }
.speaker-bio { font-size: 16px; line-height: 1.7; color: var(--color-text); }

.social-links { display: flex; gap: var(--space-md); margin-top: var(--space-md); }
.social-links a { color: var(--color-text-muted); font-size: 20px; transition: color 0.2s; }
.social-links a:hover { color: var(--color-primary); text-decoration: none; }

.tags { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-top: var(--space-sm); }
.tags .tag {
    display: inline-block;
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    font-size: 12px;
    padding: 3px 10px;
    border-radius: 4px;
}

.speaker-sessions { max-width: var(--max-width); margin: 0 auto; padding: 0 var(--space-lg) var(--space-xl); }
.speaker-sessions h2 { font-family: var(--font-heading); font-size: 24px; margin-bottom: var(--space-md); }

/* =============================================================================
   Track Cards
   ============================================================================= */

.tracks-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--space-lg);
}

.track-card {
    background: var(--color-surface);
    border-radius: 12px;
    padding: var(--space-lg);
    border-left: 5px solid var(--color-primary);
    border-top: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
    transition: transform 0.2s, box-shadow 0.2s;
}

.track-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}

.track-card-name {
    font-family: var(--font-heading);
    font-size: 20px;
    font-weight: 600;
    margin-bottom: var(--space-sm);
}

.track-card-count {
    font-size: 14px;
    color: var(--color-text-muted);
}

.track-card-description {
    font-size: 14px;
    color: var(--color-text-muted);
    margin-top: var(--space-sm);
    line-height: 1.5;
}

/* =============================================================================
   Sponsors Section
   ============================================================================= */

.sponsors-tier {
    margin-bottom: var(--space-xl);
    text-align: center;
}

.sponsors-tier-name {
    font-family: var(--font-heading);
    font-size: 14px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--color-text-muted);
    margin-bottom: var(--space-md);
}

.sponsors-logos {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-xl);
}

.sponsor-logo {
    display: block;
    transition: opacity 0.2s;
}

/* Public sponsors page layout — used by /conference/sponsors.html (#2613 follow-up).
   The JS there generates .sponsor-tier / .tier-name / .sponsors-grid /
   .sponsor-card / .sponsor-name-only which were previously unstyled,
   collapsing the page into overlapping inline text. */
.sponsor-tier {
    margin-bottom: var(--space-xl);
    text-align: center;
}

.tier-name {
    font-family: var(--font-heading);
    font-size: 18px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-lg);
}

.sponsors-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 280px));
    gap: var(--space-lg);
    justify-content: center;
    align-items: stretch;
}

/* #6948 — SPO-1 consolidated sponsor view: one flat grid, at most 4 cards
   wide. #7034 — this rule defines NO tracks on purpose. It inherits the
   `auto-fit, minmax(220px, 280px)` track and `justify-content: center` from
   `.sponsors-grid` above, which is what keeps a card the same shape here as in
   the tiered view, and what collapses empty tracks so a short roster centres
   instead of hugging the left edge. Only the container is added, because
   `.sponsors-grid` never had one — the tiered view merely hid that, since its
   capped tracks are always narrower than the viewport. */
.sponsors-grid--consolidated {
    /* 4 tracks + 3 gaps + 2 gutters; box-sizing is border-box (line 67). */
    max-width: calc(4 * 280px + 5 * var(--space-lg));
    margin: 0 auto;
    padding: 0 var(--space-lg);
}

.sponsor-card__tier {
    font-family: var(--font-heading);
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--color-text-muted);
    margin: 0;
}

.sponsor-card {
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 12px;
    padding: var(--space-lg);
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    min-height: 140px;
    transition: box-shadow 0.2s, transform 0.2s;
}

.sponsor-card:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    transform: translateY(-2px);
}

.sponsor-name-only {
    font-family: var(--font-heading);
    font-size: 18px;
    font-weight: 600;
    color: var(--color-text);
}

.sponsor-description {
    font-size: 14px;
    color: var(--color-text-muted);
    margin: 0;
    line-height: 1.4;
}

.sponsor-logo:hover { opacity: 0.7; text-decoration: none; }

.sponsor-logo img {
    height: 48px;
    width: auto;
    object-fit: contain;
    filter: grayscale(30%);
    transition: filter 0.2s;
}

.sponsor-logo:hover img { filter: grayscale(0%); }

.sponsors-tier:first-child .sponsor-logo img { height: 64px; }

.sponsor-name-text {
    display: inline-block;
    font-size: 14px;
    font-weight: 500;
    color: var(--color-text-muted);
    padding: var(--space-sm) var(--space-md);
    background: var(--color-surface-alt);
    border-radius: 6px;
    text-decoration: none;
}

.sponsor-name-text:hover { color: var(--color-text); text-decoration: none; }

/* =============================================================================
   Schedule Page
   ============================================================================= */

.schedule-container {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: var(--space-xl) var(--space-lg);
}

/* Shared page gutter for pages whose content sits directly in
   main.page-content (which supplies no width cap or padding). Same
   geometry as .schedule-container. Declares NO background — see the
   #6099 invariant block at conference.css:110. */
.conf-page-container {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: var(--space-xl) var(--space-lg);
}

.schedule-page-header {
    text-align: center;
    margin-bottom: var(--space-xl);
}

.schedule-page-header h1 {
    font-family: var(--font-heading);
    font-size: 36px;
    font-weight: 700;
    color: var(--color-dark);
    margin-bottom: var(--space-xs);
}

/* #7263 — these two lived in `style="…"` on schedule.html. An inline `color`
   outranks the body.page-bg-dark block below, so the block could never reach
   them and the date painted #1a1a1a on a #00274c page. Style lives here now. */
.schedule-single-day {
    font-family: var(--font-heading);
    font-size: 22px;
    font-weight: 600;
    color: var(--color-text);
    text-align: center;
    margin: 0 0 16px;
}

.schedule-tz-note {
    font-size: 13px;
    color: var(--color-text-muted);
    text-align: center;
    margin: 0 0 16px;
}

/* Day tabs */
.day-tabs {
    display: flex;
    gap: var(--space-xs);
    margin-bottom: var(--space-lg);
    border-bottom: 2px solid var(--color-border);
    overflow-x: auto;
}

.day-tab {
    padding: var(--space-sm) var(--space-lg);
    background: none;
    border: none;
    font-family: var(--font-heading);
    font-size: 15px;
    font-weight: 500;
    color: var(--color-text-muted);
    cursor: pointer;
    border-bottom: 3px solid transparent;
    margin-bottom: -2px;
    white-space: nowrap;
    transition: color 0.2s, border-color 0.2s;
}

.day-tab:hover { color: var(--color-text); }
.day-tab.active { color: var(--color-primary); border-bottom-color: currentColor; font-weight: 600; }

/* Filter bar */
.filter-bar {
    display: flex;
    gap: var(--space-md);
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: var(--space-lg);
    padding: var(--space-md);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
}

.filter-group {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.filter-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.filter-select {
    padding: 8px 12px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-family: var(--font-body);
    font-size: 14px;
    background: var(--color-surface);
    color: var(--color-text);
    cursor: pointer;
}

.filter-select:focus { outline: none; border-color: var(--color-primary); }

.filter-input {
    /* #6945 — no width rule at all, so this fell back to the browser default of
       roughly 20 characters and cut off "Search by name or company...". Grows
       to fill the flex row instead of shortening the placeholder. The basis is
       neutralised below 768px, where .filter-bar flips to a column and the
       basis would size HEIGHT — see the media query below. */
    flex: 1 1 220px;
    min-width: 0;
    padding: 8px 12px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-family: var(--font-body);
    font-size: 14px;
    background: var(--color-surface);
    color: var(--color-text);
}

.filter-input:focus { outline: none; border-color: var(--color-primary); }

.track-filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}

.track-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: 20px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    border: 2px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}

/* Fallback only -- schedule.html sets this inline per track color (#6503). */
.track-chip.active { color: #fff; }

.track-chip-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* Schedule grid (desktop) -- complements conf-day-grid from conference.js */
.schedule-grid-wrapper {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
}

/* Session block enhancements for schedule.html inline grid */
.session-block {
    position: relative;
    padding: var(--space-sm) var(--space-md);
    padding-right: var(--cue-gutter);
    height: 100%;
    border-left: 4px solid var(--color-primary);
    cursor: pointer;
    background: var(--color-surface);
    transition: background 0.15s;
}

.session-block:hover { background: var(--color-surface-alt); }

/* #7017 — a schedule row opens the session modal and nothing said so.
   The cue is decoration only: pointer-events keeps the row's own click
   handler the one thing that fires, and aria-hidden (schedule.html) keeps
   it out of the accessibility tree. */
.session-row-cue {
    position: absolute;
    right: 20px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    gap: 6px;
    /* #7037 — a real button now, so it must TAKE the click, not pass it
       through. The click bubbles to the row's own handler, which is what
       opens the modal, so this fires it exactly once. */
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

/* #7037 — the keyboard user's only sign of where they are. 3px of Fusebox red
   with a 2px offset clears both the resting white row and the hover tint. */
.session-row-cue:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

/* Focus reveals the label the way hover does — a keyboard user gets the same
   affordance a mouse user gets. */
.schedule-grid--merged .session-row-cue:focus-visible .session-row-cue-label,
.conf-noroom-card--cued .session-row-cue:focus-visible .session-row-cue-label { opacity: 1; }

.session-row-cue-chevron {
    font-size: 22px;
    line-height: 1;
    color: #98a0ad;
}

/* The label earns its place only on a full-width row, whose right-hand end
   is otherwise empty. A multi-room column is narrow and reserves no gutter
   for it, so it stays hidden there and on the mobile list, where there is
   no hover to reveal it. */
.session-row-cue-label {
    display: none;
    font-family: var(--font-heading);
    font-size: 13px;
    font-weight: 600;
    color: var(--color-primary);
    opacity: 0;
    transition: opacity 0.15s;
}

.schedule-grid--merged .session-block { padding-right: var(--cue-gutter-labelled); }

/* conference.js:2945 injects its own .conf-noroom-card rule into <head> after
   this file, and a `padding` shorthand there beats an equal-specificity
   longhand here. The wrapping banner raises specificity so this one wins. */
.conf-noroom-card--cued { position: relative; }
.conf-noroom-banner .conf-noroom-card--cued { padding-right: var(--cue-gutter-labelled); }

.schedule-grid--merged .session-row-cue-label,
.conf-noroom-card--cued .session-row-cue-label { display: block; }

.schedule-grid--merged .session-block:hover .session-row-cue-label,
.conf-noroom-card--cued:hover .session-row-cue-label { opacity: 1; }

.session-block-name {
    font-family: var(--font-heading);
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 2px;
    line-height: 1.3;
}

.session-block-meta {
    font-size: 12px;
    color: var(--color-text-muted);
}

.session-block-speakers {
    font-size: 12px;
    color: var(--color-text-light);
    margin-top: 2px;
}

.session-block-badge {
    display: inline-block;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    margin-top: 4px;
}

/* #6570 — compact pill so the shared RSVP control fits inside the tile's
   minmax(60px, auto) row without growing it. */
.session-block .conf-rsvp-control { margin-top: 2px; gap: 0.3rem; }
.session-block .conf-btn { padding: 1px 8px; font-size: 10px; }
.session-block .conf-rsvp-seats, .session-block .conf-rsvp-note { font-size: 10px; }

/* Schedule list (mobile) */
.schedule-list { display: none; }

.schedule-list-item {
    position: relative;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: var(--space-md);
    /* #6943 — the border sits outside the padding box, so the default 16px put
       the time close to a full-height brand-coloured bar on a phone. */
    padding-left: calc(var(--space-md) + 8px);
    /* #7017 — after the shorthand above, which resets all four sides. */
    padding-right: var(--cue-gutter);
    margin-bottom: var(--space-sm);
    cursor: pointer;
    transition: box-shadow 0.15s;
    border-left: 4px solid var(--color-primary);
}

.schedule-list-item:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }

.schedule-list-time {
    font-family: var(--font-heading);
    font-size: 14px;
    font-weight: 700;
    /* #6943 — was var(--color-primary), the same token as the card's 4px left
       border, so a brand-coloured time sat beside a bar of its own colour.
       Weight now carries the emphasis the colour used to. */
    color: var(--color-text);
    margin-bottom: 4px;
}

.schedule-list-name {
    font-family: var(--font-heading);
    font-size: 18px;
    font-weight: 600;
    margin-bottom: 2px;
}

.schedule-list-meta {
    font-size: 14px;
    color: var(--color-text-muted);
}

/* #6570 — same shared control as the grid tile; the list card has more
   room, so no compact override needed here. */
.schedule-list-item .conf-rsvp-control { margin-top: 8px; }

/* =============================================================================
   Session Detail Modal
   ============================================================================= */

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-lg);
    opacity: 0;
    pointer-events: none;
    /* #7060 — opacity alone leaves the closed dialog in the tab order AND in
       the accessibility tree: #modal-close was tabbable on page load and the
       dialog sat there unnamed. visibility removes it from both, and unlike
       display:none it still composes with the fade. */
    visibility: hidden;
    /* Delay visibility to the END of the fade-out so the overlay is still
       painted while it fades, then flip it INSTANTLY on the way in — a
       transitioned visibility is not yet applied when showSessionModal calls
       .focus() on the next line, and focus on a hidden element is dropped. */
    transition: opacity 0.2s, visibility 0s 0.2s;
}

.modal-overlay.active {
    opacity: 1;
    pointer-events: auto;
    visibility: visible;
    transition: opacity 0.2s, visibility 0s 0s;
}

.modal-content {
    background: var(--color-surface);
    border-radius: 12px;
    max-width: 600px;
    width: 100%;
    max-height: 80vh;
    overflow-y: auto;
    padding: var(--space-xl);
    position: relative;
}

.modal-close {
    position: absolute;
    top: var(--space-md);
    right: var(--space-md);
    background: none;
    border: none;
    font-size: 24px;
    color: var(--color-text-muted);
    cursor: pointer;
    line-height: 1;
}

.modal-close:hover { color: var(--color-text); }

.modal-track-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 600;
    /* Fallback only -- schedule.html sets this inline per track color (#6503). */
    color: #fff;
    margin-bottom: var(--space-sm);
}

.modal-title {
    font-family: var(--font-heading);
    font-size: 24px;
    font-weight: 700;
    margin-bottom: var(--space-sm);
}

.modal-meta {
    font-size: 14px;
    color: var(--color-text-muted);
    margin-bottom: var(--space-md);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md);
}

.modal-meta-item {
    display: flex;
    align-items: center;
    gap: 6px;
}

.modal-meta-item i { color: var(--color-primary); font-size: 14px; }

.modal-description {
    font-size: 15px;
    line-height: 1.7;
    color: var(--color-text);
    margin-bottom: var(--space-lg);
}

.modal-description p,
.conf-track-desc p,
.sponsor-description p { margin-bottom: var(--space-md); }
.modal-description p:last-child,
.conf-track-desc p:last-child,
.sponsor-description p:last-child { margin-bottom: 0; }

.modal-speakers-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.modal-speaker {
    display: flex;
    align-items: center;
    gap: var(--space-md);
}

.modal-speaker img {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    object-fit: cover;
}

.modal-speaker-placeholder {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--color-surface-alt);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-light);
    font-size: 20px;
}

.modal-speaker-name { font-weight: 600; font-size: 14px; }
.modal-speaker-title { font-size: 13px; color: var(--color-text-muted); }

/* #7303 — unlike the speaker cards above, this IS a link and should read
   as one; colour + hover underline come from the base `a` rule. */
.modal-view-more {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: var(--space-lg);
    font-weight: 600;
    font-size: 14px;
}
.modal-view-more i { font-size: 12px; }

.modal-speaker--link { color: inherit; text-decoration: none; border-radius: 8px; }
/* a:hover (specificity 0,0,1,1) beats the bare .modal-speaker--link rule
   above (0,0,1,0) and would underline the whole card. This selector adds
   the pseudo-class to match (0,0,2,0), which wins — see the same pattern
   at .btn-primary:hover, .social-links a:hover, .ch-btn:hover, etc. */
.modal-speaker--link:hover { text-decoration: none; }
.modal-speaker--link:hover .modal-speaker-name,
.modal-speaker--link:focus-visible .modal-speaker-name { text-decoration: underline; }
.modal-speaker--link:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* =============================================================================
   Session Cards (speaker detail / sessions list)
   ============================================================================= */

.sessions-list {
    display: grid;
    gap: var(--space-md);
}

.session-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: var(--space-md);
    border-left: 4px solid var(--color-primary);
}

.session-card-name {
    font-family: var(--font-heading);
    font-size: 16px;
    font-weight: 600;
    margin-bottom: 4px;
}

.session-card-meta {
    font-size: 13px;
    color: var(--color-text-muted);
}

/* =============================================================================
   Footer
   ============================================================================= */

.conf-footer {
    background: var(--color-dark);
    color: rgba(255, 255, 255, 0.7);
    padding: var(--space-xl) var(--space-lg);
    text-align: center;
    font-size: 14px;
}

.conf-footer a { color: rgba(255, 255, 255, 0.85); text-decoration: none; }
.conf-footer a:hover { color: #fff; }

.conf-footer-inner {
    max-width: var(--max-width);
    margin: 0 auto;
}

.conf-footer-links {
    display: flex;
    justify-content: center;
    gap: var(--space-lg);
    margin-bottom: var(--space-md);
    flex-wrap: wrap;
}

/* =============================================================================
   Utility States
   ============================================================================= */

.loading-state, .empty-state, .error-state {
    text-align: center;
    padding: var(--space-xxxl) var(--space-lg);
    color: var(--color-text-muted);
    font-size: 16px;
}

.error-state { color: var(--color-primary); }

/* The server-rendered heading on session.html + speaker.html (#6487). It is
   the only heading a non-JS crawler sees; the client wipes it with the real
   title. Sized between the two headings that replace it (.session-detail-title
   36px, .speaker-info h1 32px) so hydration does not jump — the UA default is
   2em with 0.67em margins. Its on-dark color is in the page-bg-dark block. */
.ssr-detail-title {
    font-family: var(--font-heading);
    font-size: 32px;
    line-height: 1.2;
    font-weight: 700;
    color: var(--color-text);
    margin: 0 0 var(--space-md);
}

/* =============================================================================
   Skeleton screens (#2920) — placeholders sized to the final grid so the
   page doesn't grow downward when async data arrives. One shimmer keyframe,
   four card-shape utilities matched to the real grids in
   speakers.html / schedule.html / sponsors.html.
   ============================================================================= */

.skeleton {
    background: linear-gradient(
        90deg,
        var(--theme-skeleton-bg, rgba(255, 255, 255, 0.06)) 0%,
        var(--theme-skeleton-bg-hi, rgba(255, 255, 255, 0.12)) 50%,
        var(--theme-skeleton-bg, rgba(255, 255, 255, 0.06)) 100%
    );
    background-size: 200% 100%;
    animation: skeleton-shimmer 1.6s ease-in-out infinite;
    border-radius: 8px;
}

@keyframes skeleton-shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

.skeleton-speaker-card { height: 280px; }
.skeleton-schedule-row { height: 88px; margin-bottom: 12px; }
.skeleton-sponsor-card { height: 200px; }
.skeleton-tier-card { height: 220px; }

.page-content { min-height: calc(100vh - 56px - 120px); }

/* =============================================================================
   Tracks Page (tracks.html)
   ============================================================================= */

.tracks-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-lg);
    max-width: var(--max-width);
    margin: 0 auto;
    padding: 0 var(--space-lg);
}

.conf-track-card {
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, rgba(0, 0, 0, 0.08));
    border-top: 4px solid var(--conf-primary, #ec0244);
    border-radius: 10px;
    padding: var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    transition: box-shadow 0.15s, transform 0.15s;
}

.conf-track-card:hover {
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
    transform: translateY(-1px);
}

.conf-track-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-sm);
}

.conf-track-name {
    font-family: var(--font-heading);
    font-size: 20px;
    font-weight: 700;
    color: var(--color-dark);
    margin: 0;
}

.conf-track-count {
    font-size: 13px;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.conf-track-desc {
    font-size: 14px;
    line-height: 1.55;
    color: var(--color-text);
    margin: 0;
}

.conf-track-chair {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-top: auto;
    padding-top: var(--space-sm);
    border-top: 1px solid var(--color-border, rgba(0, 0, 0, 0.06));
    color: inherit;
    text-decoration: none;
}

a.conf-track-chair:hover { background: transparent; }
a.conf-track-chair:hover .conf-track-chair-name { color: var(--conf-primary, #ec0244); }

.conf-track-chair-photo {
    width: 36px;
    height: 36px;
    object-fit: cover;
    border-radius: 50%;
    flex-shrink: 0;
}

.conf-track-chair-placeholder {
    background: var(--color-surface-alt, #f4f4f4);
    color: var(--color-text-light, #888);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 14px;
}

.conf-track-chair-meta {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;
}

.conf-track-chair-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
}

.conf-track-chair-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* =============================================================================
   Responsive
   ============================================================================= */

@media (max-width: 768px) {
    .conf-hero h1 { font-size: 32px; }
    .conf-hero-tagline { font-size: 16px; }

    .speakers-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
    .tracks-grid { grid-template-columns: 1fr; }

    .speaker-hero { flex-direction: column; align-items: center; text-align: center; }
    .speaker-photo img, .photo-placeholder { width: 140px; height: 140px; }
    .speaker-info h1 { font-size: 24px; }

    /* Switch schedule to list view on mobile. #6352 — .schedule-grid-wrapper
       (conference.css:765) already declares the same border + 8px
       border-radius that renderGrid's own inline wrapper puts on
       #schedule-grid (schedule.html:541), so reusing it here would double
       the border and put the loading skeletons and the empty state in a
       box they don't have today. Dedicated marker class instead. */
    .schedule-grid-view,
    #schedule-grid .conf-day-grid { display: none !important; }
    .schedule-list { display: block; }

    .filter-bar { flex-direction: column; align-items: stretch; }
    /* #6945 — the axis flips here, so a 220px flex-basis becomes 220px of
       HEIGHT. Measured at 390px wide before this line: a 220px-tall search box,
       on the phone view this PR exists to fix. */
    .filter-input { flex-basis: auto; }
    .filter-group { flex-wrap: wrap; }

    .section-header h2 { font-size: 24px; }
    .schedule-page-header h1 { font-size: 28px; }
}

@media (max-width: 480px) {
    .conf-hero { padding: var(--space-xl) var(--space-md); }
    .conf-hero h1 { font-size: 26px; }
    .conf-hero-actions { flex-direction: column; align-items: center; }
    .btn-primary, .btn-outline { width: 100%; text-align: center; }
    .speakers-grid { grid-template-columns: 1fr 1fr; gap: var(--space-md); }
}


/* =============================================================================
   Conference Homepage Template (ch-* classes)
   Landing page: hero, credibility, notify, speakers, why, who, sponsor, venue
   ============================================================================= */

/* Toggle utility */
.conf-section--hidden { display: none !important; }

/* =============================================================================
   Phase-gated visibility (#2721)
   Body class <body class="phase-<value>"> is applied by conference.js.
   - .conf-section--announcement-only renders only in announcement.
   - .conf-section--sales-only renders only when sales are open or live.

   #2807: removed `.conf-section--placeholder` fade-to-grayscale treatment.
   In announcement phase the past-speakers/past-sponsors/past-artists
   sections ARE the social proof — they must render full color. When
   there is no content to surface (zero past entries), the populating JS
   hides the section outright via `.conf-section--hidden` rather than
   rendering a faded placeholder treatment.
   ============================================================================= */

.conf-section--announcement-only { display: none; }
body.phase-announcement .conf-section--announcement-only { display: block; }

.conf-section--sales-only { display: block; }
body.phase-announcement .conf-section--sales-only,
body.phase-live .conf-section--sales-only { display: none; }

body.phase-announcement .conf-section--hide-in-announcement { display: none !important; }

/* Design principle: in announcement phase, pass-tier cards must be
   HIDDEN. "If you can see a tier, you should be able to buy it" — so
   we never show tiers behind a paywall. Tiers appear when phase flips
   to sales_open. */
body.phase-announcement .pass-tier-card { display: none !important; }

/* -----------------------------------------------------------------------------
   phase=sales_open (#2889) — tickets on sale
   The lineup has been revealed AND tickets are now actively on sale. All
   `lineup_announced` content stays visible; the difference is in the
   action surfaces (hero CTAs + pass-tier buy buttons) and the appearance
   of sales-only sections (e.g. an index-page "Tickets are live" banner).

   What's shown:
   - Pass-tier checkout buttons (.pass-buy-btn): default state, no
     suppression rule needed. The Stripe Checkout path is wired to the
     existing single-tier checkout shim (#2546).
   - Hero "Sales open" indicator pill (.ch-hero-sales-open-pill) — a
     small high-contrast badge surfaced under the hero badge to signal
     that registration is live.
   - Hero "Buy Passes / View Schedule" CTA row (.ch-cta-sales-open) —
     replaces the prelaunch CTA row. Default-hidden; phase-sales_open
     reveals it.
   - Sales-only sections (.conf-section--sales-only) — sections that
     only make sense once tickets are on sale (e.g. an index-page
     "Tickets are live, save your seat" banner). Default-visible via
     the rule above (line ~959); phase-announcement / live hide it,
     leaving sales_open as the active reveal phase.
   - Speakers / Schedule / Sponsors render normally.

   What's suppressed:
   - "Sales closed" pill (sales-closed-note) — wrong copy before
     the event itself.
   - Hero prelaunch CTAs (.ch-cta-prelaunch) — sign-up-for-notify is the
     wrong primary action once sales are open. The dedicated #section-notify
     section stays in the DOM but no longer carries the hero CTA load.
   - Announcement-only sections (.conf-section--announcement-only) —
     inherit the default-hidden rule; only phase-announcement reveals them.

   Out of scope: the admin transition handler that mass-flips
   `ticket_sales_open=True` on event rows when an admin advances phase to
   sales_open — tracked in sibling issue #2890.
   ----------------------------------------------------------------------------- */

/* Sales-only sections reveal in phase-sales_open. The default rule (line
   ~959) sets `display: block` and the three other phases hide it; the
   selector below makes the intent explicit for code-search / grep and
   guards against a future refactor of the default-visible rule. */
body.phase-sales_open .conf-section--sales-only { display: block; }

/* Suppress lingering post-sale pill in sales_open. The pass-buy-btn
   default state (visible) is the right CTA here. */
body.phase-sales_open .pass-tier-sales-closed-note { display: none !important; }

/* Hide the hero prelaunch CTA row in phase-sales_open — sign-up-for-notify
   isn't the right primary CTA once tickets are on sale. */
body.phase-sales_open .ch-cta-prelaunch { display: none !important; }

/* Reveal the sales-open hero CTA row. The .ch-cta-sales-open block is
   hidden by default (rule below in the hero block); flip it on for
   phase-sales_open so the "Buy Passes / View Schedule" buttons show. */
.ch-cta-sales-open { display: none; }
body.phase-sales_open .ch-cta-sales-open { display: flex !important; gap: 16px; flex-wrap: wrap; justify-content: center; }

/* "Sales open" hero indicator pill — small high-contrast badge surfaced
   under the hero badge in sales_open phase only. Default-hidden so the
   markup can ship in every render without polluting other phases. */
.ch-hero-sales-open-pill { display: none; }
body.phase-sales_open .ch-hero-sales-open-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    margin-top: 8px;
    margin-bottom: 16px;
    background: var(--conf-primary, #ec0244);
    color: #fff;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.2px;
    text-transform: uppercase;
}
.ch-hero-sales-open-pill::before {
    content: "";
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #fff;
    animation: schedule-live-pulse 1.6s ease-in-out infinite;
}

/* "Tickets are live" sales-only banner (index page). A compact card-style
   strip that surfaces in phase-sales_open as the primary post-lineup CTA. */
.ch-sales-banner {
    margin: 0 auto;
    max-width: 1140px;
    padding: 24px 32px;
    background: linear-gradient(135deg, var(--conf-primary, #ec0244) 0%, var(--conf-accent, #7b0035) 100%);
    color: #fff;
    border-radius: 12px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.12);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}
.ch-sales-banner__text {
    flex: 1 1 60%;
    min-width: 240px;
}
.ch-sales-banner__title {
    font-size: 22px;
    font-weight: 700;
    line-height: 1.25;
    margin: 0 0 4px;
}
.ch-sales-banner__body {
    font-size: 14px;
    opacity: 0.92;
    margin: 0;
}
.ch-sales-banner__btn {
    background: #fff;
    color: var(--conf-primary, #ec0244);
    padding: 10px 22px;
    border-radius: 8px;
    font-weight: 700;
    text-decoration: none;
    font-size: 14px;
    letter-spacing: 0.3px;
    transition: transform 0.15s, box-shadow 0.15s;
}
.ch-sales-banner__btn:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(0,0,0,0.18); }

/* -----------------------------------------------------------------------------
   phase=live (#2802) — event day-of
   The conference is happening right now. Schedule is the centerpiece:
   surface a live status strip (countdown to next session / "Happening now"
   / "Just ended") and highlight the currently-running session in the grid
   and list views.

   What's suppressed:
   - Pass-tier checkout buttons (.pass-buy-btn): tickets sales closed.
   - "Sales-only" sections (already handled in the rule above with
     .conf-section--sales-only): registration sections collapsed.
   - "Get involved" announcement-only sections: inherit hidden default
     since only phase-announcement reveals them.
   - Hero "Get on the List / Apply to Speak" prelaunch CTAs: the event
     is mid-flight; these CTAs don't belong on the day-of page.

   What's shown:
   - Hero "Register Now / View Agenda" .ch-cta-live block — but JS in
     index.html overrides label/href during phase=live to point at the
     schedule page (no longer a register CTA — see issue #2802 follow-up
     to refine the live-phase hero CTA copy).
   - Schedule live-status strip + .session-live-now highlight on the
     currently-running session card.
   - Speakers, sponsors, schedule sections all render normally.

   Out of scope: phase=archived (filed as follow-up to #2802).
   ----------------------------------------------------------------------------- */

/* Suppress the checkout button on every pass-tier card. JS still
   renders the button so the DOM stays stable; CSS just hides it. */
body.phase-live .pass-buy-btn { display: none !important; }

/* Sales-closed pill — hidden by default, revealed in phase-live. */
.pass-tier-sales-closed-note { display: none; }
body.phase-live .pass-tier-sales-closed-note {
    display: block;
    width: 100%;
    padding: 12px 20px;
    background: var(--conf-dark, #262f35);
    color: #fff;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 600;
    text-align: center;
    letter-spacing: 0.2px;
}

/* Hide the hero prelaunch CTA row in phase-live. The mailing-list /
   "Apply to Speak" prompts don't belong on the day-of page. */
body.phase-live .ch-cta-prelaunch { display: none !important; }

/* Reveal the hero live-action CTA row. The .ch-cta-live block is hidden
   by default (rule at line ~1190); flip it on for phase-live so the
   "Register Now / View Agenda" buttons show. JS in index.html may
   re-label the buttons for the day-of context. */
body.phase-live .ch-cta-live { display: flex !important; gap: 16px; flex-wrap: wrap; justify-content: center; }

/* -----------------------------------------------------------------------------
   Schedule live status strip (#2802)
   Rendered into schedule.html above the grid; only visible in phase-live.
   Three states (JS-populated): "Happening now: <session>", "Up next: <session>
   in <T>", "Just ended: <session>".
   ----------------------------------------------------------------------------- */
.conf-live-only { display: none; }
body.phase-live .conf-live-only { display: block; }

.schedule-live-status {
    margin: 0 0 24px;
    padding: 18px 24px;
    background: linear-gradient(135deg, var(--conf-primary, #ec0244) 0%, var(--conf-accent, #7b0035) 100%);
    color: #fff;
    border-radius: 12px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.12);
}
.schedule-live-status__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    opacity: 0.85;
    margin-bottom: 6px;
}
.schedule-live-status__title {
    font-size: 22px;
    font-weight: 700;
    line-height: 1.25;
    margin-bottom: 4px;
}
.schedule-live-status__meta {
    font-size: 14px;
    opacity: 0.9;
}
.schedule-live-status__pulse {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #fff;
    margin-right: 8px;
    vertical-align: middle;
    animation: schedule-live-pulse 1.6s ease-in-out infinite;
}
@keyframes schedule-live-pulse {
    0%, 100% { opacity: 0.4; transform: scale(0.9); }
    50% { opacity: 1; transform: scale(1.1); }
}

/* "Happening now" highlight on the live session card in the grid + list. */
body.phase-live .session-block.session-live-now,
body.phase-live .schedule-list-item.session-live-now {
    outline: 2px solid var(--conf-primary, #ec0244);
    outline-offset: -2px;
    box-shadow: 0 0 0 4px rgba(236, 2, 68, 0.18);
}
.session-live-now-badge {
    display: none;
    background: var(--conf-primary, #ec0244);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 4px;
    margin-left: 8px;
    vertical-align: middle;
}
body.phase-live .session-live-now .session-live-now-badge { display: inline-block; }

/* ---- Shared section scaffolding ---- */
.ch-section {
    padding: 80px 24px;
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.6s ease, transform 0.6s ease;
}
.ch-section.ch-revealed,
.ch-credibility.ch-revealed,
.ch-notify.ch-revealed { opacity: 1; transform: none; }

.ch-section-inner {
    max-width: 1140px;
    margin: 0 auto;
}

.ch-section-alt  { background: var(--color-surface-alt); }
.ch-section-dark { background: var(--color-dark); }
.ch-section-ruled {
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
}

.ch-section-header {
    text-align: center;
    margin-bottom: 56px;
}

.ch-section-label {
    display: inline-block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 2.5px;
    text-transform: uppercase;
    color: var(--color-primary);
    margin-bottom: 12px;
}

.ch-label-onDark { color: var(--color-light); opacity: 0.7; }

.ch-section-title {
    font-family: var(--font-heading);
    font-size: 40px;
    font-weight: 700;
    color: var(--color-dark);
    line-height: 1.15;
    margin: 0 0 16px;
}

.ch-title-onDark { color: #fff; }

.ch-section-subtitle {
    font-size: 17px;
    color: var(--color-text-muted);
    max-width: 580px;
    margin: 0 auto;
    line-height: 1.6;
}

.ch-section-footer { text-align: center; margin-top: 40px; }

.ch-link-more {
    font-size: 15px;
    font-weight: 600;
    color: var(--color-primary);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: gap 0.2s;
}
.ch-link-more:hover { gap: 10px; text-decoration: none; }

/* ---- Buttons ---- */
.ch-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 14px 32px;
    border-radius: 8px;
    font-family: var(--font-heading);
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    border: 2px solid transparent;
    transition: background 0.18s, border-color 0.18s, color 0.18s, transform 0.15s;
    white-space: nowrap;
}
.ch-btn:hover { text-decoration: none; transform: translateY(-1px); }

.ch-btn-primary {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
}
/* The fill stays the brand color, which has no contrast guarantee against this
   always-dark section, so the edge carries 1.4.11 instead (#6143). */
.ch-section-dark .ch-btn-primary { border-color: rgba(255,255,255,0.45); }
.ch-btn-primary:hover { background: #d0023b; border-color: #d0023b; color: #fff; }

.ch-btn-ghost {
    background: transparent;
    color: #fff;
    border-color: rgba(255,255,255,0.45);
}
.ch-btn-ghost:hover { border-color: #fff; color: #fff; background: rgba(255,255,255,0.08); }

.ch-btn-lg { padding: 16px 40px; font-size: 16px; }


/* ---- Hero ---- */
.ch-hero {
    position: relative;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    overflow: hidden;
    color: #fff;
    padding: 120px 24px 80px;
}

.ch-hero-bg {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    background-image: linear-gradient(135deg, var(--color-dark) 0%, var(--color-maroon) 100%);
    transform: scale(1.03);
    transition: transform 8s ease-out;
}
.ch-hero-bg.loaded { transform: scale(1); }

.ch-hero-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to bottom,
        rgba(38,47,53,0.72) 0%,
        rgba(38,47,53,0.58) 50%,
        rgba(38,47,53,0.82) 100%
    );
}

.ch-hero-inner {
    position: relative;
    z-index: 1;
    max-width: 860px;
    animation: ch-fade-up 0.9s ease both;
}

.ch-hero-eyebrow {
    display: inline-block;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: rgba(255,255,255,0.75);
    margin-bottom: 24px;
    padding: 6px 16px;
    border: 1px solid rgba(255,255,255,0.22);
    border-radius: 20px;
    backdrop-filter: blur(4px);
}

.ch-hero-title {
    font-family: var(--font-heading);
    font-size: clamp(42px, 6vw, 80px);
    font-weight: 800;
    line-height: 1.07;
    letter-spacing: -1px;
    margin: 0 0 28px;
    color: #fff;
}

.ch-hero-tagline {
    /* Second voice in the hero, not a fourth size: above the 18px subhead,
       below the 42px title floor. Weight 600 matches the eyebrow. See #6934. */
    font-size: clamp(20px, 2.6vw, 26px);
    font-weight: 600;
    line-height: 1.6;
    color: rgba(255,255,255,0.82);
    max-width: 640px;
    margin: 0 auto 44px;
}

.ch-hero-actions {
    display: flex;
    gap: 16px;
    justify-content: center;
    flex-wrap: wrap;
}
.ch-cta-live { display: none; }

.ch-hero-scroll {
    position: absolute;
    bottom: 32px;
    left: 50%;
    transform: translateX(-50%);
    background: none;
    border: 1px solid rgba(255,255,255,0.3);
    border-radius: 50%;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255,255,255,0.7);
    cursor: pointer;
    transition: opacity 0.3s, border-color 0.2s;
    animation: ch-bounce 2.4s ease infinite 2s;
    z-index: 1;
}
.ch-hero-scroll:hover { border-color: rgba(255,255,255,0.7); color: #fff; }


/* ---- Credibility bar ---- */
.ch-credibility {
    background: var(--color-dark);
    padding: 28px 24px;
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.5s ease 0.1s, transform 0.5s ease 0.1s;
}

.ch-credibility-inner {
    max-width: 1140px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    flex-wrap: wrap;
}

.ch-cred-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 8px 36px;
    text-align: center;
}

.ch-cred-number {
    font-family: var(--font-heading);
    font-size: 26px;
    font-weight: 700;
    color: #fff;
    line-height: 1;
    margin-bottom: 4px;
}

.ch-cred-label {
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: rgba(255,255,255,0.5);
}

.ch-cred-divider {
    width: 1px;
    height: 40px;
    background: rgba(255,255,255,0.15);
    flex-shrink: 0;
}


/* ---- Email capture ---- */
.ch-notify {
    background: var(--color-dark);
    border-top: 1px solid rgba(255,255,255,0.08);
    padding: 72px 24px;
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.6s ease, transform 0.6s ease;
}

.ch-notify-inner {
    max-width: 760px;
    margin: 0 auto;
    display: flex;
    gap: 48px;
    align-items: center;
}

.ch-notify-text { flex: 1; }

.ch-notify-heading {
    font-family: var(--font-heading);
    font-size: 32px;
    font-weight: 700;
    color: #fff;
    margin: 0 0 10px;
}

.ch-notify-sub {
    font-size: 15px;
    color: rgba(255,255,255,0.65);
    line-height: 1.6;
    margin: 0;
}

.ch-notify-form { flex: 1; }

.ch-notify-input-row {
    display: flex;
    gap: 10px;
}

.ch-notify-input {
    flex: 1;
    padding: 13px 16px;
    border-radius: 8px;
    border: 1.5px solid rgba(255,255,255,0.2);
    background: rgba(255,255,255,0.07);
    color: #fff;
    font-size: 15px;
    font-family: var(--font-body);
    outline: none;
    transition: border-color 0.18s;
    min-width: 0;
}
.ch-notify-input::placeholder { color: rgba(255,255,255,0.55); }
.ch-notify-input:focus { border-color: var(--color-primary); }

.ch-notify-legal {
    margin: 10px 0 0;
    font-size: 12px;
    color: rgba(255,255,255,0.7);
}

.ch-notify-success {
    display: none;
    align-items: center;
    gap: 10px;
    color: #6ee7b7;
    font-size: 15px;
    font-weight: 500;
    padding: 14px 0;
}
.ch-notify-success i { font-size: 20px; }


/* ---- Speakers grid ---- */
.ch-speakers-section { background: var(--color-bg); }

.ch-speakers-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
}

.ch-spk-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 28px 20px 24px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;
    position: relative;
}
.ch-spk-card:hover {
    border-color: var(--color-border-dark);
    box-shadow: 0 8px 28px rgba(0,0,0,0.08);
    transform: translateY(-2px);
}

.ch-spk-card--featured {
    grid-column: span 3;
    flex-direction: row;
    text-align: left;
    gap: 32px;
    padding: 36px;
    border-left: 4px solid var(--color-primary);
    align-items: flex-start;
}

/* The 0.55 dim is deliberate: it is what makes a TBA placeholder read as
   secondary to a real speaker card. `pointer-events: none` is invisible and
   the dashed border alone is not enough. It composites the card's own text
   toward the #fafafa section, so the two text colors below are near-black to
   clear AA THROUGH it — #000000 lands at 4.87:1, and anything above #080808
   fails. Change this opacity and those two colors together (#6388). */
.ch-spk-card--tba {
    border-style: dashed;
    border-color: var(--color-border);
    opacity: 0.55;
    pointer-events: none;
}
.ch-spk-card--tba:hover { transform: none; box-shadow: none; }

.ch-spk-photo-wrap { margin-bottom: 16px; flex-shrink: 0; }
.ch-spk-card--featured .ch-spk-photo-wrap { margin-bottom: 0; }

.ch-spk-photo {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--color-surface-alt);
    display: block;
}

.ch-spk-photo--lg { width: 128px; height: 128px; }

.ch-spk-initial {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-heading);
    font-size: 32px;
    font-weight: 700;
    color: var(--color-dark);
    background: var(--color-light);
}

.ch-spk-badge {
    display: inline-block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--color-primary);
    background: rgba(236,2,68,0.09);
    padding: 3px 10px;
    border-radius: 4px;
    margin-bottom: 8px;
}

.ch-spk-name {
    font-family: var(--font-heading);
    font-size: 17px;
    font-weight: 700;
    color: var(--color-dark);
    margin: 0 0 5px;
    line-height: 1.2;
}
.ch-spk-name--lg { font-size: 26px; margin-bottom: 8px; }

.ch-spk-role {
    font-size: 13px;
    color: var(--color-text-muted);
    margin: 0 0 2px;
}

.ch-spk-company {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-dark);
    margin: 0;
}

.ch-spk-bio {
    font-size: 14px;
    line-height: 1.65;
    color: var(--color-text-muted);
    margin: 14px 0 0;
}

.ch-spk-card--featured .ch-spk-body { flex: 1; }

.ch-spk-tba-circle {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    background: var(--color-surface-alt);
}

.ch-spk-tba-label {
    font-size: 14px;
    font-weight: 600;
    /* #6388: #666666 rendered at 2.31:1 through the card's 0.55 opacity. */
    color: #000000;
    margin: 0 0 4px;
}

.ch-spk-tba-sub {
    font-size: 12px;
    /* #6388: #999999 rendered at 1.70:1 through the same dim. */
    color: #000000;
    margin: 0;
}


/* ---- Why Attend ---- */
.ch-why-section { background: var(--color-bg); }

.ch-why-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 28px;
}

.ch-why-card {
    padding: 32px 28px;
    border-left: 3px solid var(--color-primary);
    background: var(--color-surface);
    border-radius: 0 10px 10px 0;
    border-top: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
}

.ch-why-icon {
    width: 44px;
    height: 44px;
    background: rgba(236,2,68,0.07);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-primary);
    font-size: 18px;
    margin-bottom: 20px;
}

.ch-why-heading {
    font-family: var(--font-heading);
    font-size: 18px;
    font-weight: 700;
    color: var(--color-dark);
    margin: 0 0 10px;
}

.ch-why-body {
    font-size: 14px;
    line-height: 1.7;
    color: var(--color-text-muted);
    margin: 0;
}


/* ---- Who's in the Room ---- */
.ch-whos-section { background: var(--color-surface-alt); }

/* Logo scroll strip */
.ch-logo-strip {
    width: 100%;
    overflow: hidden;
    margin-bottom: 48px;
    mask-image: linear-gradient(to right, transparent 0%, black 12%, black 88%, transparent 100%);
    -webkit-mask-image: linear-gradient(to right, transparent 0%, black 12%, black 88%, transparent 100%);
}

.ch-logo-track {
    display: flex;
    gap: 0;
    animation: ch-scroll-logos 28s linear infinite;
    width: max-content;
}
.ch-logo-track:hover { animation-play-state: paused; }

@keyframes ch-scroll-logos {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

.ch-logo-item {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 40px;
    height: 60px;
    flex-shrink: 0;
}

.ch-logo-item img {
    height: 32px;
    width: auto;
    object-fit: contain;
    filter: grayscale(100%);
    opacity: 0.5;
    transition: opacity 0.2s, filter 0.2s;
}
.ch-logo-item img:hover { filter: grayscale(0%); opacity: 0.9; }

.ch-logo-wordmark {
    font-family: var(--font-heading);
    font-size: 14px;
    font-weight: 600;
    color: var(--color-text-muted);
    white-space: nowrap;
    letter-spacing: 0.3px;
}

/* Attendee profile tiles */
.ch-profile-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin-bottom: 48px;
}

.ch-profile-tile {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.ch-profile-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-dark);
    line-height: 1.3;
}

.ch-profile-company {
    font-size: 12px;
    color: var(--color-text-muted);
}

/* Testimonial quotes */
.ch-quotes-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
}

.ch-quote {
    background: var(--color-surface);
    border-radius: 10px;
    padding: 28px 24px;
    border: 1px solid var(--color-border);
    margin: 0;
    position: relative;
}
.ch-quote::before {
    content: '\201C';
    position: absolute;
    top: 16px;
    left: 20px;
    font-size: 48px;
    font-family: Georgia, serif;
    color: var(--color-primary);
    line-height: 1;
    opacity: 0.35;
}

.ch-quote-text {
    font-size: 14px;
    line-height: 1.7;
    color: var(--color-text);
    margin: 0 0 16px;
    padding-top: 16px;
}

.ch-quote-cite {
    font-size: 12px;
    font-style: normal;
    font-weight: 600;
    color: var(--color-text-muted);
}


/* ---- Sponsor pitch ---- */
.ch-sponsor-pitch-section { padding: 80px 24px; }

.ch-sponsor-split {
    display: grid;
    grid-template-columns: 1.1fr 0.9fr;
    gap: 64px;
    align-items: start;
}

.ch-sponsor-body {
    font-size: 16px;
    line-height: 1.7;
    color: rgba(255,255,255,0.72);
    margin: 0 0 32px;
}

.ch-tier-list {
    border-top: 1px solid rgba(255,255,255,0.12);
    margin-bottom: 36px;
}

.ch-tier-row {
    display: flex;
    align-items: baseline;
    gap: 16px;
    padding: 14px 0;
    border-bottom: 1px solid rgba(255,255,255,0.08);
}

.ch-tier-name {
    font-family: var(--font-heading);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    /* fixed light: this section is always dark (#6122) */
    color: rgba(255,255,255,0.92);
    flex-shrink: 0;
    width: 80px;
}

.ch-tier-benefit {
    font-size: 14px;
    color: rgba(255,255,255,0.65);
}

.ch-sponsor-incoming {
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 12px;
    padding: 36px 32px;
    text-align: center;
}

.ch-sponsor-incoming-headline {
    font-family: var(--font-heading);
    font-size: 20px;
    font-weight: 700;
    color: #fff;
    margin: 0 0 8px;
}

.ch-sponsor-incoming-sub {
    font-size: 14px;
    color: rgba(255,255,255,0.55);
    margin: 0 0 24px;
}

.ch-sponsor-inquire {
    font-size: 14px;
    font-weight: 600;
    color: #fff;
    text-decoration: underline;
    text-underline-offset: 3px;
}
.ch-sponsor-inquire:hover { opacity: 0.8; }

/* Confirmed sponsors (shown when data loads) */
.ch-confirmed-logos { display: flex; flex-direction: column; gap: 24px; }

.ch-sponsor-tier-group {}
.ch-sponsor-tier-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: rgba(255,255,255,0.4);
    margin-bottom: 12px;
}

.ch-sponsor-logo-row {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: center;
}

/* #6474 — light plate, not a knockout filter; renders every logo at
   its own colors regardless of alpha. */
.ch-sponsor-logo {
    height: 50px; /* 36px logo + 2x6px padding + 2x1px border (box-sizing:border-box, line 61) */
    width: auto;
    background: #ffffff;
    border: 1px solid rgba(0,0,0,0.08);
    border-radius: 6px;
    padding: 6px 10px;
}
.ch-sponsor-name { font-size: 13px; font-weight: 600; color: rgba(255,255,255,0.7); }


/* ---- Venue ---- */
.ch-venue-section { background: var(--color-bg); }

.ch-venue-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 64px;
    align-items: center;
}

.ch-venue-name {
    font-family: var(--font-heading);
    font-size: 36px;
    font-weight: 700;
    color: var(--color-dark);
    margin: 12px 0 4px;
    line-height: 1.2;
}

.ch-venue-institution {
    font-size: 15px;
    color: var(--color-primary);
    font-weight: 600;
    margin: 0 0 16px;
    letter-spacing: 0.3px;
}

.ch-venue-address {
    font-size: 14px;
    color: var(--color-text-muted);
    margin: 0 0 20px;
}

.ch-venue-desc {
    font-size: 15px;
    line-height: 1.75;
    color: var(--color-text);
    margin: 0 0 28px;
}

.ch-venue-links {
    display: flex;
    gap: 24px;
    flex-wrap: wrap;
}

.ch-venue-link {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 14px;
    font-weight: 600;
    color: var(--color-dark);
    text-decoration: none;
    transition: color 0.18s;
}
.ch-venue-link:hover { color: var(--color-primary); text-decoration: none; }
.ch-venue-link i { font-size: 13px; color: var(--color-primary); }

.ch-venue-visual {
    border-radius: 14px;
    overflow: hidden;
    aspect-ratio: 4/3;
    /* #4409: white card + subtle border so a white-background venue logo
       blends into the card instead of sitting on gray with letterbox bands,
       and the card still reads against the #fafafa section background. */
    background: var(--color-surface);
    border: 1px solid var(--color-border);
}

.ch-venue-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    color: var(--color-text-light);
    background: linear-gradient(135deg, var(--color-dark) 0%, #3a4a55 100%);
}
.ch-venue-placeholder i { font-size: 48px; color: rgba(255,255,255,0.25); }
/* #6388: rgba(255,255,255,0.5) composited to 3.65:1 against the light end of
   this element's own #262f35 -> #3a4a55 gradient. Opaque light grey instead. */
.ch-venue-placeholder span { font-size: 14px; font-weight: 500; color: #cbd5e1; text-align: center; line-height: 1.5; }

/* #4406: `contain` (not `cover`) so wide venue logos fit in full inside the
   4:3 box rather than being scaled up and cropped. Works for photos and logos.
   #4409: padding centers the logo with even breathing room (a padded logo
   card) instead of hugging the edges; box-sizing keeps it inside the box. */
.ch-venue-photo {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
    padding: 32px;
    box-sizing: border-box;
}


/* ---- CFP / Apply to Speak ---- */
.ch-cfp-inner {
    max-width: 680px;
    margin: 0 auto;
    text-align: center;
}

.ch-cfp-body {
    font-size: 17px;
    line-height: 1.75;
    color: var(--color-text);
    margin: 0 0 32px;
}
.ch-cfp-body strong { color: var(--color-dark); }

.ch-cfp-meta {
    display: flex;
    gap: 28px;
    justify-content: center;
    flex-wrap: wrap;
    margin-bottom: 36px;
}

.ch-cfp-meta-item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    color: var(--color-text-muted);
    font-weight: 500;
}
.ch-cfp-meta-item i { color: var(--color-primary); }


/* ---- Footer ---- */
.ch-footer {
    background: var(--color-dark);
    padding: 40px 24px;
    border-top: 1px solid rgba(255,255,255,0.08);
}

.ch-footer-inner {
    max-width: 1140px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 40px;
    flex-wrap: wrap;
}

.ch-footer-brand {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1;
}

/* Org social links (#5743). Own row under brand/nav/powered: flex-basis 100%
   forces the wrap in .ch-footer-inner's existing flex-wrap layout, so the
   three-part row above is untouched.

   :empty keeps it invisible for an org with no socials — the container is
   always emitted, and applySocialLinks writes nothing when every value is
   blank. Without this an org with no socials would get 24px of dead space,
   border included. The emitted container must therefore stay byte-empty; a
   single space would defeat :empty. Pinned in
   tests/js/conference_social_links_5743.js. */
.ch-footer-social {
    flex-basis: 100%;
    display: flex;
    justify-content: center;
    gap: 20px;
    padding-top: 24px;
    border-top: 1px solid rgba(255,255,255,0.08);
}

.ch-footer-social:empty {
    display: none;
}

.ch-footer-social a {
    color: rgba(255,255,255,0.6);
    font-size: 18px;
    line-height: 1;
    transition: color 0.15s ease;
}

.ch-footer-social a:hover,
.ch-footer-social a:focus-visible {
    color: #fff;
}

.ch-footer-name {
    font-family: var(--font-heading);
    font-size: 16px;
    font-weight: 700;
    color: #fff;
}

.ch-footer-date {
    font-size: 12px;
    color: rgba(255,255,255,0.45);
}

.ch-footer-nav {
    display: flex;
    gap: 28px;
    flex-wrap: wrap;
}

.ch-footer-nav a {
    font-size: 13px;
    font-weight: 500;
    color: rgba(255,255,255,0.6);
    text-decoration: none;
    transition: color 0.18s;
}
.ch-footer-nav a:hover { color: #fff; text-decoration: none; }

.ch-footer-powered {
    font-size: 12px;
    color: rgba(255,255,255,0.3);
    margin: 0;
}

.ch-footer-powered a { color: rgba(255,255,255,0.5); text-decoration: none; }
.ch-footer-powered a:hover { color: #fff; text-decoration: none; }


/* ---- Animations ---- */
@keyframes ch-fade-up {
    from { opacity: 0; transform: translateY(28px); }
    to   { opacity: 1; transform: none; }
}

@keyframes ch-bounce {
    0%, 100% { transform: translateX(-50%) translateY(0); }
    50%       { transform: translateX(-50%) translateY(6px); }
}


/* ---- Responsive ---- */
@media (max-width: 1024px) {
    .ch-speakers-grid { grid-template-columns: repeat(2, 1fr); }
    .ch-spk-card--featured { grid-column: span 2; }
    .ch-profile-grid { grid-template-columns: repeat(3, 1fr); }
    .ch-why-grid { grid-template-columns: repeat(3, 1fr); }
    .ch-sponsor-split { gap: 40px; }
    .ch-venue-split { gap: 40px; }
}

@media (max-width: 768px) {
    .ch-section { padding: 56px 20px; }
    .ch-section-title { font-size: 30px; }
    .ch-section-header { margin-bottom: 36px; }

    .ch-speakers-grid { grid-template-columns: repeat(2, 1fr); gap: 16px; }
    .ch-spk-card--featured { grid-column: span 2; flex-direction: column; text-align: center; }
    .ch-spk-card--featured .ch-spk-photo-wrap { margin-bottom: 16px; }

    .ch-why-grid { grid-template-columns: 1fr; gap: 16px; }
    .ch-profile-grid { grid-template-columns: repeat(2, 1fr); }
    .ch-quotes-row { grid-template-columns: 1fr; }
    .ch-sponsor-split { grid-template-columns: 1fr; gap: 40px; }
    .ch-venue-split { grid-template-columns: 1fr; gap: 32px; }
    .ch-notify-inner { flex-direction: column; gap: 28px; }
    .ch-credibility-inner { gap: 0; }
    .ch-cred-item { padding: 8px 20px; }
    .ch-cred-divider { height: 28px; }
    .ch-footer-inner { flex-direction: column; align-items: flex-start; gap: 20px; }
}

@media (max-width: 480px) {
    .ch-hero { padding: 100px 20px 60px; }
    .ch-hero-title { font-size: 36px; letter-spacing: -0.5px; }
    .ch-hero-actions { flex-direction: column; }
    .ch-btn { width: 100%; justify-content: center; }
    .ch-speakers-grid { grid-template-columns: 1fr; }
    .ch-spk-card--featured { grid-column: span 1; }
    .ch-profile-grid { grid-template-columns: 1fr 1fr; }
    .ch-notify-input-row { flex-direction: column; }
    .ch-credibility-inner { flex-direction: column; gap: 4px; }
    .ch-cred-divider { width: 40px; height: 1px; }
}


/* =============================================================================
   Session Detail Page (session.html)
   Public session page — hero, speakers, abstract, calendar button.
   ============================================================================= */

.session-detail-wrapper {
    max-width: 860px;
    margin: 0 auto;
    padding: var(--space-xl) var(--space-lg) var(--space-xxxl);
}

.session-detail-back-row { margin-bottom: var(--space-lg); }

.session-detail-back-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--color-text-muted);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
    transition: color 0.15s;
}
.session-detail-back-link:hover { color: var(--color-primary); text-decoration: none; }
.session-detail-back-link i { font-size: 12px; }

/* ---- Hero ---- */
.session-detail-hero {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: var(--space-xl) var(--space-lg);
    margin-bottom: var(--space-xl);
}

.session-detail-badges {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
}

.session-detail-badge {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
    text-transform: capitalize;
    letter-spacing: 0.02em;
}
.session-detail-badge--format {
    background: var(--color-light);
    color: var(--color-dark);
}
.session-detail-badge--level {
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
}

.session-detail-title {
    font-family: var(--font-heading);
    font-size: 36px;
    line-height: 1.2;
    font-weight: 700;
    color: var(--color-dark);
    margin-bottom: var(--space-md);
}

.session-detail-time,
.session-detail-venue {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 16px;
    color: var(--color-text);
    margin-bottom: var(--space-xs);
}
.session-detail-time i,
.session-detail-venue i {
    color: var(--color-text-muted);
    font-size: 14px;
    width: 16px;
    text-align: center;
}
.session-detail-venue { color: var(--color-text-muted); }

.session-detail-actions {
    display: flex;
    gap: var(--space-md);
    flex-wrap: wrap;
    margin-top: var(--space-lg);
}

.session-detail-cta-ics {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 15px;
    padding: 12px 24px;
}

/* Add-to-Calendar picker (#7301). The wrapper anchors the panel; the
   [hidden] rule is REQUIRED — a class selector on .session-detail-cal-menu
   would otherwise beat the UA [hidden]{display:none} rule and ship the
   panel permanently open, the same trap that kept the dead Join button on
   screen (see the issue's root-cause section). Mirrors .conf-nav-more /
   .conf-nav-more-menu in conference.js. */
.session-detail-cal { position: relative; }
.session-detail-cal-caret { font-size: 11px; margin-left: 2px; }
.session-detail-cal-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 20;
    min-width: 190px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: 0 10px 28px rgba(0,0,0,0.16);
}
.session-detail-cal-menu[hidden] { display: none; }
.session-detail-cal-item {
    display: block;
    width: 100%;
    padding: 8px 12px;
    border: none;
    border-radius: 6px;
    background: none;
    font: inherit;
    font-size: 14px;
    text-align: left;
    color: var(--color-text);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}
.session-detail-cal-item:hover,
.session-detail-cal-item:focus-visible {
    background: var(--color-surface-alt);
    outline: none;
}

/* ---- Sections ---- */
.session-detail-section {
    margin-bottom: var(--space-xl);
}

.session-detail-section h2 {
    font-family: var(--font-heading);
    font-size: 22px;
    font-weight: 700;
    color: var(--color-dark);
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
}

/* ---- Abstract ---- */
.session-detail-abstract {
    font-size: 16px;
    line-height: 1.7;
    color: var(--color-text);
}
.session-detail-abstract p { margin-bottom: var(--space-md); }
.session-detail-abstract p:last-child { margin-bottom: 0; }

/* ---- Speakers ---- */
.session-detail-speakers-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.session-detail-speaker-card {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: var(--space-md);
}

.session-detail-speaker-card--link { color: inherit; text-decoration: none; transition: border-color 0.15s; }
/* a:hover (specificity 0,0,1,1) beats the bare .session-detail-speaker-card--link
   rule above (0,0,1,0) and would underline the whole card. This selector adds
   the pseudo-class to match (0,0,2,0), which wins — same pattern as
   .modal-speaker--link:hover above. */
.session-detail-speaker-card--link:hover { text-decoration: none; border-color: var(--color-primary); }
.session-detail-speaker-card--link:hover .session-detail-speaker-name,
.session-detail-speaker-card--link:focus-visible .session-detail-speaker-name { text-decoration: underline; }
.session-detail-speaker-card--link:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

.session-detail-speaker-photo {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--color-light);
    flex-shrink: 0;
}
.session-detail-speaker-photo--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-heading);
    font-size: 28px;
    font-weight: 700;
    color: var(--color-dark);
}

.session-detail-speaker-info {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    flex: 1;
}
.session-detail-speaker-name {
    font-family: var(--font-heading);
    font-size: 18px;
    font-weight: 700;
    color: var(--color-dark);
    margin: 0;
}
.session-detail-speaker-subtitle {
    font-size: 14px;
    color: var(--color-text-muted);
    margin: 0;
    line-height: 1.4;
}
.session-detail-speaker-role {
    display: inline-block;
    align-self: flex-start;
    margin-top: 4px;
    padding: 2px 10px;
    border-radius: 10px;
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* ---- Mobile ---- */
@media (max-width: 600px) {
    .session-detail-wrapper {
        padding: var(--space-lg) var(--space-md) var(--space-xxl);
    }
    .session-detail-hero {
        padding: var(--space-lg) var(--space-md);
    }
    .session-detail-title { font-size: 26px; }
    .session-detail-time,
    .session-detail-venue { font-size: 14px; }
    .session-detail-actions { flex-direction: column; align-items: stretch; }
    .session-detail-cal { width: 100%; }
    .session-detail-cta-ics { width: 100%; justify-content: center; }
    .session-detail-cal-menu { left: 0; right: 0; min-width: 0; }
    .session-detail-section h2 { font-size: 18px; }
    .session-detail-abstract { font-size: 15px; }
    .session-detail-speaker-card { padding: var(--space-sm) var(--space-md); }
    .session-detail-speaker-photo { width: 64px; height: 64px; }
    .session-detail-speaker-photo--placeholder { font-size: 22px; }
    .session-detail-speaker-name { font-size: 16px; }
}

/* =============================================================================
   Announcement Phase Components (#2721)
   Hero subhead, inline hero mailing-list form, two-card CTA row,
   advance information section, footer mailing-list.
   ============================================================================= */

/* Hero subhead */
.ch-hero-subhead {
    margin-top: 18px;
    font-size: 18px;
    line-height: 1.55;
    color: rgba(255, 255, 255, 0.85);
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
}

/* Inline hero mailing-list form (announcement phase) */
.ch-hero-notify {
    margin-top: 28px;
    max-width: 520px;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
    position: relative;
}
.ch-hero-notify-row {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    justify-content: center;
}
.ch-hero-notify-input {
    flex: 1 1 240px;
    min-width: 0;
    padding: 14px 18px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
    font-size: 15px;
    font-family: inherit;
}
.ch-hero-notify-input::placeholder { color: rgba(255, 255, 255, 0.55); }
.ch-hero-notify-input:focus {
    outline: none;
    border-color: var(--theme-accent, var(--color-primary, #ec0244));
    background: rgba(255, 255, 255, 0.12);
}
.ch-hero-notify-legal {
    margin-top: 10px;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.55);
}
.ch-hero-notify-success {
    margin-top: 12px;
    color: #b8e3c1;
    font-size: 14px;
    display: flex;
    gap: 8px;
    align-items: center;
    justify-content: center;
}

/* Two-card CTA row */
.ch-getinvolved-section { padding: 56px 24px 32px; }
.ch-cta-row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 24px;
    max-width: 980px;
    margin: 0 auto;
}
.ch-cta-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 32px 28px;
    border: 1px solid var(--color-border, rgba(38, 47, 53, 0.12));
    border-radius: 14px;
    /* Fallback MUST match body's (:66): --theme-bg can be unset, and then each
       rule takes its own. #fff here put the on-dark text on white (#6889). */
    background: var(--theme-bg, #262f35);
    color: var(--theme-text, #262f35);
    text-decoration: none;
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.ch-cta-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.08);
    border-color: var(--theme-accent, var(--color-primary, #ec0244));
}
.ch-cta-card-icon {
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: linear-gradient(
        135deg,
        var(--theme-accent, var(--color-primary, #ec0244)),
        var(--theme-accent-2, var(--color-maroon, #7b0035))
    );
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
}
.ch-cta-card-title {
    margin: 0;
    font-size: 22px;
    font-weight: 600;
    font-family: var(--conf-font-display, inherit);
}
.ch-cta-card-body {
    margin: 0;
    color: var(--theme-text-muted, #5a6770);
    font-size: 15px;
    line-height: 1.55;
}
.ch-cta-card-link {
    margin-top: auto;
    padding-top: 8px;
    font-weight: 600;
    color: var(--theme-accent, var(--color-primary, #ec0244));
}
.ch-cta-card-link i { margin-left: 6px; transition: transform 0.18s ease; }
.ch-cta-card:hover .ch-cta-card-link i { transform: translateX(3px); }
@media (max-width: 700px) {
    .ch-cta-row { grid-template-columns: 1fr; gap: 16px; }
    .ch-cta-card { padding: 24px 20px; }
}

/* Advance Information section */
.ch-advance-info-section { padding: 64px 24px; }
.ch-advance-info-grid {
    display: grid;
    grid-template-columns: minmax(220px, 320px) 1fr;
    gap: 48px;
    max-width: 1100px;
    margin: 0 auto;
}
.ch-advance-info-facts {
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.ch-advance-fact {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--color-border, rgba(38, 47, 53, 0.12));
}
.ch-advance-fact:last-child { border-bottom: none; }
.ch-advance-fact-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    color: var(--theme-text-muted, #5a6770);
    font-weight: 600;
}
.ch-advance-fact-value {
    font-size: 18px;
    color: var(--theme-text, #262f35);
    font-weight: 500;
}
.ch-advance-info-body {
    color: var(--theme-text, #262f35);
    font-size: 16px;
    line-height: 1.65;
}
.ch-advance-info-body p { margin: 0 0 14px; }
.ch-advance-info-body p:last-child { margin-bottom: 0; }
.ch-advance-info-body ul { padding-left: 1.25em; margin: 0 0 14px; }
.ch-advance-info-body li { margin-bottom: 6px; }
@media (max-width: 760px) {
    .ch-advance-info-grid { grid-template-columns: 1fr; gap: 32px; }
}

/* Footer mailing-list — visual parity with .ch-notify but variant class */
.ch-notify--footer {
    padding: 56px 24px;
}

/* =============================================================================
   Announcement UX Pass #1 (#2728)
   - Hide the duplicate "Advance Information" section in announcement phase
     (the hero now carries title + tagline + dates + venue).
   - Hide the "Apply to Speak" / "Become a Sponsor" nav items in announcement
     (their CTAs live inside the section pages now).
   - When a hero background image is set, swap the gradient overlay to a
     darker treatment so the title + tagline + date badge stay legible.
   - Section-page CTA strip styles (announcement phase only).
   - Sponsors-page announcement-phase pitch block above the existing grid.
   ============================================================================= */

/* Hide the duplicate Advance Information section in announcement phase.
   The hero already shows title + tagline + date badge + venue, so the bottom
   section is redundant (and was showing stale "Oct 23-24, Austin" data). */
body.phase-announcement .ch-advance-info-section,
body.phase-announcement section[data-section="advance-info"],
body.phase-announcement #section-advance-info {
    display: none !important;
}

/* Announcement-phase nav: hide "Apply to Speak". conference.js renderNav()
   emits data-nav-page attributes (#2728) so the CSS can target by destination. */
body.phase-announcement .conf-nav-link[data-nav-page="cfp.html"] {
    display: none;
}

/* Register nav link: hidden by default, revealed only when ticket sales are
   open. renderNav() always emits the link; the body.phase-sales_open class
   (set by conference.js on branding load AND by the per-page pre-paint
   script from sessionStorage cache) is what makes it visible. */
.conf-nav-link[data-nav-page="passes.html"] {
    display: none;
}
body.phase-sales_open .conf-nav-link[data-nav-page="passes.html"] {
    display: revert;
}

/* Hero with background image — when hero_image_url is set, conference.js adds
   body.has-hero-image. The stock .ch-hero-overlay gradient is too light for
   most photos; this swaps to a dark navy → near-black gradient so the title
   and tagline always read. Opacity tuned for real photographs (#2741) — keep
   it transparent enough that the hero image is still visibly the hero, dark
   enough that the title + tagline always read. */
body.has-hero-image .ch-hero-overlay {
    background: linear-gradient(
        180deg,
        rgba(0, 39, 76, 0.55) 0%,
        rgba(0, 39, 76, 0.65) 55%,
        rgba(38, 47, 53, 0.78) 100%
    );
}

/* When a hero image is loaded, paint it cover/center and remove the default
   linear-gradient that #2731 used as a placeholder so the photo isn't
   double-painted. */
body.has-hero-image .ch-hero-bg {
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    opacity: 1;
}

/* Section-page CTA strip (#2728) — used at the bottom of schedule.html,
   speakers.html and at the bottom of the sponsors pitch block. */
.conf-section-cta {
    margin: 56px auto 24px;
    padding: 28px 28px;
    max-width: 760px;
    background: var(--color-surface-alt, #f5f6f3);
    border: 1px solid var(--color-border, rgba(38, 47, 53, 0.1));
    border-radius: 12px;
    text-align: center;
}
.conf-section-cta__title {
    margin: 0 0 6px;
    font-family: var(--font-heading);
    font-size: 20px;
    font-weight: 700;
    color: var(--theme-text, #262f35);
}
.conf-section-cta__body {
    margin: 0 0 16px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--theme-text-muted, #5a6770);
}
.conf-section-cta__btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 12px 24px;
    background: var(--color-primary, #ec0244);
    color: #fff;
    font-weight: 600;
    font-size: 15px;
    text-decoration: none;
    border-radius: 8px;
    transition: background 0.15s ease, transform 0.15s ease;
}
.conf-section-cta__btn:hover {
    background: var(--color-maroon, #7b0035);
    transform: translateY(-1px);
}

/* Sponsors-page pitch block (#2728) — announcement-phase only.
   Hidden by default; conference.js + sponsors.html template makes it visible
   when phase=announcement. */
.conf-sponsor-pitch {
    max-width: 1100px;
    margin: 0 auto 48px;
    padding: 56px 24px 32px;
}
.conf-sponsor-pitch__head {
    text-align: center;
    max-width: 720px;
    margin: 0 auto 36px;
}
.conf-sponsor-pitch__title {
    font-family: var(--font-heading);
    font-size: clamp(28px, 4vw, 40px);
    font-weight: 800;
    color: var(--theme-text, #262f35);
    margin: 0 0 12px;
    letter-spacing: -0.5px;
}
.conf-sponsor-pitch__body {
    font-size: 17px;
    line-height: 1.6;
    color: var(--theme-text-muted, #5a6770);
    margin: 0;
}
.conf-sponsor-pitch__tiers {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    margin: 0 0 28px;
}
@media (max-width: 900px) {
    .conf-sponsor-pitch__tiers { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
    .conf-sponsor-pitch__tiers { grid-template-columns: 1fr; }
}
.conf-sponsor-tier-card {
    background: #fff;
    border: 1px solid var(--color-border, rgba(38, 47, 53, 0.12));
    border-radius: 10px;
    padding: 20px 18px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    box-shadow: 0 1px 3px rgba(38, 47, 53, 0.04);
}
.conf-sponsor-tier-card__name {
    font-family: var(--font-heading);
    font-size: 16px;
    font-weight: 700;
    color: var(--color-primary, #ec0244);
    text-transform: uppercase;
    letter-spacing: 0.8px;
    margin: 0;
}
.conf-sponsor-tier-card__price {
    font-size: 13px;
    font-weight: 600;
    color: var(--theme-text, #262f35);
    margin: 0;
}
.conf-sponsor-tier-card__benefit {
    font-size: 13px;
    line-height: 1.5;
    color: var(--theme-text-muted, #5a6770);
    margin: 0;
}
.conf-sponsor-pitch__body-html {
    max-width: 720px;
    margin: 8px auto 0;
    font-size: 15px;
    line-height: 1.65;
    color: var(--theme-text, #262f35);
}
.conf-sponsor-pitch__body-html p { margin: 0 0 12px; }
.conf-sponsor-pitch__body-html p:last-child { margin: 0; }

/* =============================================================================
   Event RSVP panel (#5292) — event-level RSVP, distinct from the #6570
   session-level control above.
   ============================================================================= */
.conf-event-rsvp-heading {
    font-family: var(--font-heading);
    font-size: 20px;
    font-weight: 700;
    color: var(--theme-text, #262f35);
    margin: 0 0 12px;
}
.conf-event-rsvp-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #e2e5e8);
    border-radius: 8px;
    padding: 12px 16px;
    margin-bottom: 8px;
}
.conf-event-rsvp-name { font-size: 15px; font-weight: 600; margin: 0; color: var(--theme-text, #262f35); }
.conf-event-rsvp-time, .conf-event-rsvp-venue, .conf-event-rsvp-seats {
    display: block;
    font-size: 13px;
    color: var(--theme-text-muted, #5a6770);
}
.conf-event-rsvp-action { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.conf-event-rsvp-status { font-size: 13px; font-weight: 600; }
.conf-event-rsvp-confirmed { color: #1a7a3d; }
.conf-event-rsvp-waitlisted { color: var(--color-primary, #ec0244); }

