/* ---- Reset ---- */

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

/* ---- Base ---- */

html {
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--color-text);
    background: var(--color-bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Better default line breaking for content prose - balance the last few
       lines of paragraphs and wrap on word boundaries even in tight layouts. */
    text-rendering: optimizeLegibility;
    /* Account for the sticky .site-header when navigating to in-page anchors
       (#top, #footer, etc.). Without this the header overlays the target. */
    scroll-padding-top: 80px;
}

body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--color-bg);
    color: var(--color-text);
}

/* Links carry the primary navy site-wide. The base rule stays minimal
   (color + hover deepen) so per-class hovers (underline for state-link,
   bg fill for header-link, etc.) don't conflict with the global rule.
   For prose passages that want the polished animated-underline-on-hover,
   add .link--anim on the anchor - see definition below. */
a {
    color: var(--color-primary);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

a:hover {
    color: var(--color-primary-dark);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
}

/* Opt-in: animated baseline-to-full underline. Reserved for prose links
   (where the polish reads as considered rather than busy). Apply with
   <a class="link--anim"> on body-copy passages, not on chrome links. */
.link--anim {
    background-image: linear-gradient(currentColor, currentColor);
    background-position: 0 100%;
    background-repeat: no-repeat;
    background-size: 0 1px;
    text-decoration: none;
    transition: background-size var(--duration-medium) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}
.link--anim:hover {
    text-decoration: none;
    background-size: 100% 1px;
}

/* Headings default to the sans face for in-content h2/h3/etc. The editorial
   .display class (below) opts a heading INTO the Fraunces serif treatment -
   reserved for hero / page-title / section moments where the typographic
   weight should be felt, not just read. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-heading);
    line-height: var(--leading-tight);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--color-text);
}

h1 { font-size: var(--text-3xl); margin-bottom: var(--space-md); }
h2 { font-size: var(--text-2xl); margin-bottom: var(--space-sm); }
h3 { font-size: var(--text-xl);  margin-bottom: var(--space-sm); }

/* ── Editorial display type ──────────────────────────────────────────
   Opt-in serif treatment via .display (paired with size modifiers).
   Uses Fraunces with optical sizing - the variable-font opsz axis
   automatically renders heavier on larger sizes for proper editorial
   weight. Italic variants kept off the wire; if needed later, add to
   the App.razor Google Fonts link. */
.display {
    font-family: var(--font-display);
    font-weight: 500;
    line-height: var(--leading-tight);
    letter-spacing: -0.02em;
    color: var(--color-text);
    font-feature-settings: 'ss01';     /* Fraunces stylistic set 1: refined Q + g */
    font-optical-sizing: auto;
}
.display--1 { font-size: var(--text-display-1); font-weight: 600; line-height: 1.05; letter-spacing: -0.025em; }
.display--2 { font-size: var(--text-display-2); font-weight: 600; line-height: 1.1; }
.display--3 { font-size: var(--text-display-3); font-weight: 500; line-height: 1.15; }

/* Hero page-title pattern: any h1 inside .site-main with .display gets the
   editorial treatment without needing a size class - falls back to display-1. */
.site-main h1.display { font-size: var(--text-display-1); font-weight: 600; line-height: 1.05; letter-spacing: -0.025em; }

/* ── Editorial promotion of bespoke hero classes ─────────────────────
   These hero-headline classes ship across many pages (Home, RegionDetail,
   PlaceHome, Newsroom, Coverage, ItemDetail, EventDetail, etc.) using
   the legacy --route-title-* sans treatment. Promoting them to Fraunces
   here means every page gets the editorial lift without per-page edits.
   The hero subhead classes stay in the sans face - serif everywhere is
   newspaper-y; the contrast between serif headline and sans body is what
   gives editorial pages their authority. */
.dossier__headline,
.route-title,
.page-title--hero,
.home-hero__title,
.hero-title,
.brief-shell__title,
.dossier-shell__title,
.gsearch__h1 {
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.05;
    font-optical-sizing: auto;
    font-feature-settings: 'ss01';
}

p { margin-bottom: var(--space-md); }

ul, ol { padding-left: var(--space-lg); margin-bottom: var(--space-md); }

/* Selection: branded primary tint instead of OS default blue/white. Subtle
   detail, but registers as "considered" to anyone selecting text. */
::selection {
    background: var(--color-primary-light);
    color: var(--color-primary-dark);
}

/* Focus rings on interactive elements use the design system focus token.
   Skips elements that opt out via :focus:not(:focus-visible) - keyboard-only
   focus, no ring on mouse click. */
:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-sm);
}

/* ---- Container ---- */

.container {
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--container-padding);
    width: 100%;
}

/* ---- Header - light, clean, thin border ---- */

/* Header is sticky-on-scroll with a hairline border that strengthens after
   1px of scroll via the position:sticky + a subtle shadow. The
   backdrop-filter glass effect renders on Safari/Chrome/Firefox; the solid
   background fallback keeps non-supporting browsers usable. background-color
   uses a partial-alpha tint so content below shows through faintly when
   the glass is active. */
.site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    background: color-mix(in srgb, var(--color-bg-card) 88%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--color-border);
    padding: 14px 0;
    transition: box-shadow var(--duration-medium) var(--ease-out),
                border-color var(--duration-medium) var(--ease-out);
}
/* Fallback for older Safari that ignores backdrop-filter - opaque card bg
   keeps the header readable rather than dropping to transparent. */
@supports not (backdrop-filter: blur(12px)) {
    .site-header { background: var(--color-bg-card); }
}

.site-header .container {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    /* Allow the search row to wrap below logo+nav+auth on narrow viewports.
       Without this the search input held ~291px of a 500px viewport,
       forcing the Sign In/Up cluster off-screen and creating page-wide
       horizontal scroll. Mobile rule below sends .header-center to its
       own row. */
    flex-wrap: wrap;
}

.header-center {
    flex: 1;
    display: flex;
    justify-content: center;
    /* Allow this flex item to shrink past its content's intrinsic size,
       which is what was blocking the wrap on mid-width viewports. */
    min-width: 0;
}

.header-center .search-form {
    max-width: 28rem;
    width: 100%;
}

/* Mobile: push the search input to its own row beneath the logo / place
   pill / auth cluster. Order:99 sends .header-center to the end; the
   flex-basis:100% forces it to fill the line, which (with flex-wrap on
   the container) wraps it. Removes the horizontal overflow on viewports
   below ~720px. */
@media (max-width: 720px) {
    .site-header .container { row-gap: var(--space-sm); }
    .header-center {
        order: 99;
        flex-basis: 100%;
    }
    .header-center .search-form { max-width: none; }
}

.site-logo {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* Brand link is clickable -> primary palette. Mark + wordmark both
       inherit currentColor from here, so the whole logo lives on the
       primary slate. Hover deepens to primary-dark. */
    color: var(--color-primary);
    font-size: 18px;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    letter-spacing: 0;
}

.site-logo__mark {
    display: inline-flex;
    align-items: center;
}
.site-logo__mark svg { display: block; }

.site-logo__wordmark {
    /* Stylized wordmark: JetBrains Mono (loaded via Google Fonts subset in
       App.razor). Reads "structured / index / data" without screaming
       monospace because we land at weight 600 and only show 12 letters.
       Tight tracking pulls the monospace columns closer to a wordmark feel. */
    font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    font-weight: 600;
    letter-spacing: 0;
}

.site-logo:hover {
    text-decoration: none;
    color: var(--color-primary-dark);
}

/* Mobile collapse: drop the wordmark, keep the mark. The header-nav
   media query below hides the place pill at the same breakpoint, leaving
   a tight three-element row (mark + search + auth). */
@media (max-width: 720px) {
    .site-logo__wordmark { display: none; }
}

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

.header-link {
    font-size: 14px;
    font-weight: 500;
    /* Clickable header text -> primary palette. Hover swaps to a soft
       primary-light fill (not underline) - chrome row treatment. */
    color: var(--color-primary);
    text-decoration: none;
    padding: 7px 12px;
    border-radius: var(--radius-md);
    transition: color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}

.header-link:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
    background: var(--color-primary-light);
}

/* Primary CTA in the header (Sign Up). Solid navy fill with a subtle
   inset highlight so it reads as a "real" button against the chrome. */
.header-link-primary {
    background: var(--color-primary);
    color: #ffffff !important;       /* override the anchor :focus token */
    font-weight: 600;
    box-shadow: var(--shadow-xs), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.header-link-primary:hover {
    background: var(--color-primary-dark);
    color: #ffffff !important;
    box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.header-nav {
    display: flex;
    align-items: center;
    gap: 4px;
    /* margin-left:auto pushes the pill (and the auth tail right after it)
       to the right edge on every page. Without this, on Home (where the
       SearchBar isn't rendered) the pill collapsed left next to the logo
       because only .header-right carried the auto-margin. */
    margin-left: auto;
}

.header-nav .header-link {
    padding: 6px 10px;
}

/* ---- My-place header pill ------------------------------------------ */
/* Looks like a pill, feels like a link. The icon + caret frame the label
   so the "click to change" affordance is obvious even without a border.
   Background uses a token-driven tinted surface so the pill flips with
   dark mode instead of staying a hardcoded rgba black. */
.header-link-place {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 12px;
    border-radius: var(--radius-full);
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border-light);
    transition: background var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}
.header-link-place:hover { text-decoration: none; }
.header-link-place:hover {
    background: var(--color-primary-light);
    border-color: var(--color-border);
}
/* SVG pin inherits currentColor (slate-700) from the link, replacing the
   platform-red 📍 emoji that fought the rest of the chrome. */
.header-place-icon { font-size: 13px; display: inline-flex; align-items: center; }
.header-place-icon svg { display: block; }
.header-place-label {
    font-weight: 600;
    max-width: 22ch;          /* fits "Choose your place" + most city,ST combos */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.header-place-caret { font-size: 10px; opacity: 0.6; }

@media (max-width: 720px) {
    /* Place pill stays visible at mobile - it's the primary nav affordance.
       Earlier this block hid .header-nav (which once held Newsroom Desk +
       Weekly Brief + For Newsrooms) to declutter the mobile header; those
       were moved into footer / in-page modules, leaving only the pill. With
       a single item, hiding the wrapper would suppress the very thing the
       comment promised to keep visible. Tighten the label instead so the
       pill stays narrow next to the search and auth links. */
    .header-place-label { max-width: 14ch; }
    /* Tighter pill padding so it fits beside the header search at narrow
       widths without collapsing the search input. */
    .header-link-place { padding: 4px 8px; gap: 3px; }
    /* Header link padding tightens too - SignIn / SignOut / Sign Up button. */
    .header-link { padding: 4px 8px; }
}

@media (max-width: 480px) {
    /* Phone viewports: keep the label visible (the pin icon alone is too
       cryptic - "Choose..." or a city,ST is the actual nav cue). Tighten
       max-width hard so it doesn't crowd the auth tail. The dropdown caret
       drops since it's redundant once the rest is compact. */
    .header-place-label { max-width: 10ch; }
    .header-place-caret { display: none; }
    .header-link-place { padding: 4px 6px; }
}

/* ---- /my-place page ------------------------------------------------- */
.my-place { max-width: 820px; margin: 0 auto; }
.my-place__section { margin-top: 2rem; }
.my-place__section--primary { margin-top: 1.5rem; }

.my-place__card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 1.1rem 1.35rem;
    background: var(--color-bg-card);
    box-shadow: var(--shadow-xs);
    transition: border-color var(--duration-medium) var(--ease-out),
                box-shadow var(--duration-medium) var(--ease-out);
}
.my-place__card:hover {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-sm);
}
.my-place__card--primary {
    border-color: var(--color-primary);
    background: var(--color-primary-light);
    box-shadow: var(--shadow-sm);
}
.my-place__card-name { font-size: 1.15rem; font-weight: 600; margin-bottom: 0.35rem; }
.my-place__card-meta { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; font-size: 0.9rem; }
.my-place__card-cta { margin-top: 0.75rem; }

.my-place__address-form { display: flex; gap: 0.5rem; margin-top: 0.5rem; }
.my-place__address-form .search-input { flex: 1; }

.my-place__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.my-place__grid-card {
    display: block;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.85rem 1rem;
    background: var(--color-bg-card);
    text-decoration: none;
    box-shadow: var(--shadow-xs);
    transition: border-color var(--duration-medium) var(--ease-out),
                box-shadow var(--duration-medium) var(--ease-out),
                transform var(--duration-medium) var(--ease-out);
}
.my-place__grid-card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}
.my-place__grid-name { font-weight: 600; margin-bottom: 0.25rem; }
.my-place__grid-meta { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; font-size: 0.8rem; }

/* Confirmation strip on /your-government when the cookie was set but the
   header hasn't updated yet (SSR render-order quirk). */
.yg__pinned-note {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    margin: 1rem 0;
    background: #ecfdf5;       /* soft green - "we saved your preference" */
    border: 1px solid #a7f3d0;
    border-radius: 6px;
    font-size: 0.9rem;
}

/* ---- Secondary Nav - light with underline active ---- */

.nav-bar {
    background: var(--color-bg-card);
    padding: 0 32px;
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--color-border);
}

.nav-bar a {
    color: var(--color-text-secondary);
    text-decoration: none;
    padding: 12px 20px;
    font-size: 14px;
    font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.15s, border-color 0.15s;
}

.nav-bar a.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.nav-bar a:hover {
    color: var(--color-text);
    text-decoration: none;
}

/* ---- Main ---- */

.site-main {
    flex: 1;
    padding: var(--space-xl) 0;
}

/* ---- Footer - 5-column SaaS layout --------------------------------- */
/* Top: brand block + 5 link columns. Bottom: copyright strip with a thin
   hairline above. The brand block carries the mark + wordmark + a one-line
   tagline; the columns are link lists grouped by audience/intent. On
   tablet (<=960px) columns collapse to 3-up with the brand spanning full
   width above; on phone (<=540px) columns collapse to 2-up. */

/* Footer reads as a warm "below-the-fold" surface. The off-white-warm tint
   (--color-bg-warm) is a paper-cream in light mode, cool deep slate in dark.
   Stronger top border anchors it visually as a distinct page section. */
.site-footer {
    background: var(--color-bg-warm);
    border-top: 1px solid var(--color-border);
    padding: var(--space-2xl) 0 var(--space-lg);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    margin-top: var(--space-2xl);
}

.site-footer__columns {
    display: grid;
    grid-template-columns: 1.6fr repeat(5, 1fr);
    gap: 2.5rem 1.5rem;
    margin-bottom: var(--space-xl);
}

@media (max-width: 960px) {
    .site-footer__columns {
        grid-template-columns: repeat(3, 1fr);
        gap: 2rem 1.25rem;
    }
    .site-footer__brand { grid-column: 1 / -1; }
}

@media (max-width: 540px) {
    .site-footer__columns {
        grid-template-columns: repeat(2, 1fr);
    }
}

.site-footer__brand {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.site-footer__brand-row {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* Footer brand link is clickable -> primary palette, matching the
       header logo. Mark + wordmark both inherit currentColor. */
    color: var(--color-primary);
    text-decoration: none;
    width: max-content;
}
.site-footer__brand-row:hover { color: var(--color-primary-dark); text-decoration: none; }
.site-footer__brand-mark {
    display: inline-flex;
    align-items: center;
}
.site-footer__brand-mark svg { display: block; }
.site-footer__brand-name {
    /* Same JetBrains Mono treatment as the header wordmark. */
    font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: 0;
}
.site-footer__brand-tag {
    margin: 0;
    font-size: 0.82rem;
    color: var(--color-text-secondary);
    line-height: 1.5;
    max-width: 28ch;
}

.site-footer__col {
    /* nav element resets */
}
.site-footer__col-title {
    margin: 0 0 0.7rem 0;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-secondary);
}
.site-footer__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.site-footer__list a {
    /* Clickable -> primary palette per the chrome rule. Hover deepens. */
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.85rem;
    transition: color 120ms ease;
}
.site-footer__list a:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
}

.site-footer__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: 0.8rem;
}
.site-footer__copy { margin: 0; }

/* ---- Theme toggle chip ------------------------------------------- */
/* Lives in the footer bottom bar; cycled by wwwroot/js/theme.js.
   Visually a low-contrast pill that doesn't compete with primary nav.
   Border + bg follow tokens so it reads correctly in both themes. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.4rem 0.85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    background: var(--color-bg-card);
    color: var(--color-text-secondary);
    font-size: 0.78rem;
    font-family: inherit;
    font-weight: 500;
    cursor: pointer;
    line-height: 1;
    box-shadow: var(--shadow-xs);
    transition: border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}
.theme-toggle:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
    box-shadow: var(--shadow-sm);
}
.theme-toggle:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}
.theme-toggle__label {
    /* Hide the text label on very narrow screens - icon stays visible
       as the affordance, the title/aria-label still announces the state. */
    display: inline;
}
@media (max-width: 480px) {
    .theme-toggle__label { display: none; }
}

/* ---- Dark-mode overrides for obfuscated classes ------------------ */
/* These class names are in CssObfuscationService.ObfuscatedClasses, so
   their HTML attributes get rewritten to .x{hash}-foo on non-streaming
   responses. Living in site.css means the obfuscation middleware
   doubles the rules (original + prefixed), so the selectors match in
   both streaming and non-streaming HTML. Equivalent v2.css rules would
   only fire on streaming pages where HTML obfuscation is bypassed.
   Mirror to BOTH the prefers-color-scheme media query and the explicit
   data-theme="dark" attribute - same as the tokens.css pattern. */
:root[data-theme="dark"] .nav-bar,
:root[data-theme="dark"] .empty-state,
:root[data-theme="dark"] .stat-card,
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .data-table,
:root[data-theme="dark"] .data-list {
    background: var(--color-bg-card);
    color: var(--color-text);
    border-color: var(--color-border);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .nav-bar,
    :root:not([data-theme="light"]) .empty-state,
    :root:not([data-theme="light"]) .stat-card,
    :root:not([data-theme="light"]) .card,
    :root:not([data-theme="light"]) .data-table,
    :root:not([data-theme="light"]) .data-list {
        background: var(--color-bg-card);
        color: var(--color-text);
        border-color: var(--color-border);
    }
}

/* ---- Stub / placeholder pages ------------------------------------ */
/* Used by /api, /about, /privacy, /terms, /stats, /for-{audience}*.
   Narrow centered column for readable copy plus a soft "coming soon"
   callout. Real pages keep their own page-specific styles; this is just
   the shared shape so brand-new stubs don't look like 404s. */
.page-stub {
    max-width: 820px;
    margin: 0 auto;
}
.page-stub__body {
    margin-top: var(--space-xl);
    line-height: var(--route-lede-line);
}
.page-stub__body h2 {
    margin: 2rem 0 0.65rem;
    font-size: var(--route-section-title-size);
    line-height: 1.18;
    font-weight: var(--route-title-weight);
    color: var(--color-text);
}
.page-stub__body p { margin: 0 0 0.85rem 0; }
.page-stub__body ul {
    margin: 0 0 1rem 1.25rem;
    padding: 0;
}
.page-stub__body li { margin-bottom: 0.4rem; }
.page-stub__coming-soon {
    margin: 1rem 0 1.5rem 0;
    padding: 1rem 1.25rem;
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    line-height: 1.55;
}

/* ---- About and legal pages --------------------------------------- */
/* Wider editorial shell for the finished About pages. Text remains
   measured; grids and proof strips use the wider canvas. */
.about-page {
    max-width: 1080px;
    margin: 0 auto;
}

.about-hero {
    padding: 1.25rem 0 2rem;
    border-bottom: 1px solid var(--color-border);
}

.about-hero__headline {
    max-width: 980px;
    margin: 0.25rem 0 1rem;
    font-family: var(--font-heading);
    font-size: var(--route-title-size);
    line-height: var(--route-title-line);
    font-weight: var(--route-title-weight);
    letter-spacing: 0;
    color: var(--color-text);
}

.about-hero__lede {
    max-width: 72ch;
    margin: 0;
    font-size: var(--route-lede-size);
    line-height: var(--route-lede-line);
    color: var(--color-text-secondary);
}

.about-signal-strip {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
    margin: 1.75rem 0 3rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
    background: var(--color-bg-card);
}

.about-signal-strip div {
    padding: 1.15rem 1.25rem;
    border-right: 1px solid var(--color-border);
}

.about-signal-strip div:last-child {
    border-right: 0;
}

.about-signal-strip strong {
    display: block;
    font-size: var(--route-metric-size);
    line-height: 1.05;
    color: var(--color-text);
}

.about-signal-strip span {
    display: block;
    margin-top: 0.35rem;
    color: var(--color-text-secondary);
    font-size: 0.9rem;
    line-height: 1.4;
}

.about-section {
    margin-top: 3.5rem;
}

.about-section--split {
    display: grid;
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
    gap: 2.5rem;
    align-items: start;
}

.about-section h2,
.about-founder h2,
.about-cta h2 {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--route-section-title-size);
    line-height: 1.18;
    font-weight: var(--route-title-weight);
    letter-spacing: 0;
    color: var(--color-text);
}

.about-section__copy,
.about-founder,
.about-cta {
    font-size: 1rem;
    line-height: 1.7;
    color: var(--color-text);
}

.about-section__copy p,
.about-founder p,
.about-cta p {
    max-width: 72ch;
    margin: 0 0 1rem;
}

.about-proof-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.85rem;
    margin: 3rem 0 0;
}

.about-proof-card {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 1rem;
    background: var(--color-bg-card);
}

.about-proof-card h3 {
    margin: 0 0 0.45rem;
    font-size: 1rem;
    color: var(--color-text);
}

.about-proof-card p {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 0.9rem;
    line-height: 1.55;
}

.about-founder {
    margin-top: 3.5rem;
    padding: 2rem;
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-primary);
    border-radius: 8px;
    background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
}

.about-founder h2 {
    max-width: 860px;
    margin-bottom: 1rem;
}

.about-cta {
    margin-top: 3.5rem;
    padding: 2rem;
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-primary);
    border-radius: 8px;
    background: var(--color-bg-card);
    color: var(--color-text);
}

.about-cta h2 {
    color: var(--color-text);
}

.about-cta p {
    color: var(--color-text-secondary);
}

.about-cta__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 1.25rem;
}

.about-cta__actions .btn {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: #ffffff;
}

.about-cta__actions .btn:hover {
    border-color: var(--color-primary-dark);
    background: var(--color-primary-dark);
    color: #ffffff;
    text-decoration: none;
}

.legal-page {
    max-width: 820px;
    margin: 0 auto;
}

.legal-hero {
    padding-top: 1rem;
    padding-bottom: 1.5rem;
    border-bottom: 1px solid var(--color-border);
}

.legal-hero h1 {
    margin: 0.25rem 0 0.75rem;
    font-family: var(--font-heading);
    font-size: clamp(2rem, 5vw, 3.2rem);
    line-height: 1.05;
    letter-spacing: 0;
}

.legal-hero p,
.legal-section p,
.legal-section li {
    line-height: 1.65;
}

.legal-hero p {
    max-width: 70ch;
    margin: 0 0 0.75rem;
    color: var(--color-text-secondary);
}

.legal-page__updated {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.legal-section {
    padding-top: 1.6rem;
}

.legal-section h2 {
    margin: 0 0 0.65rem;
    font-size: 1.18rem;
    color: var(--color-text);
}

.legal-section p {
    margin: 0 0 0.9rem;
}

.legal-section ul {
    margin: 0 0 0.9rem 1.25rem;
    padding: 0;
}

.legal-section li {
    margin-bottom: 0.45rem;
}

@media (max-width: 860px) {
    .about-section--split,
    .about-signal-strip,
    .about-proof-grid {
        grid-template-columns: 1fr;
    }

    .about-signal-strip div {
        border-right: 0;
        border-bottom: 1px solid var(--color-border);
    }

    .about-signal-strip div:last-child {
        border-bottom: 0;
    }
}

/* ---- /advanced power-user hub --------------------------------------- */
/* Composite page: embedded components (FeaturedTopics, TrendingRipples)
   stacked above a 2x2 grid of link cards for the page-backed features.
   The grid auto-flows on narrow viewports (single column ~520px and below). */
.advanced { max-width: 1100px; margin: 0 auto; }
.advanced__section { margin-top: 2.5rem; }
.advanced__lede {
    margin: -0.25rem 0 1rem;
    line-height: 1.55;
    max-width: 60ch;
}

.advanced__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}
.advanced__card {
    display: block;
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-bg-card);
    text-decoration: none;
    transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
.advanced__card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    text-decoration: none;
    transform: translateY(-1px);
}
.advanced__card-title {
    color: var(--color-primary);
    font-weight: 600;
    font-size: 1.02rem;
    margin-bottom: 0.35rem;
}
.advanced__card-desc {
    color: var(--color-text-secondary);
    font-size: 0.88rem;
    line-height: 1.5;
}

/* ---- Stats Row ---- */

.stats-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    margin-bottom: 24px;
}

@media (max-width: 768px) {
    .stats-row {
        grid-template-columns: repeat(2, 1fr);
    }
}

.stat-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 20px;
}

.stat-card .label {
    font-size: 12px;
    color: var(--color-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.stat-card .value {
    font-size: 28px;
    font-weight: 700;
    margin-top: 4px;
}

.stat-card .value.green { color: var(--color-accent); }
.stat-card .value.red { color: var(--color-danger); }
.stat-card .value.blue { color: var(--color-primary); }
.stat-card .value.orange { color: var(--color-warning); }

/* ---- Cards - white with subtle border ---- */

.card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-md);
    transition: border-color 0.15s, box-shadow 0.15s;
}

.card:hover {
    border-color: #d1d5db;
    box-shadow: var(--shadow-md);
}

.card-header {
    padding: 16px 20px;
    border-bottom: 1px solid var(--color-border);
    font-weight: 600;
    font-size: 15px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.card-body {
    padding: 20px;
}

.card .card-title {
    font-size: var(--text-lg);
    font-weight: 600;
    margin-bottom: var(--space-xs);
    padding: 0;
}

.card .card-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-sm);
}

.card .card-meta span + span::before {
    content: " \00b7 ";
}

a.card {
    display: block;
    color: inherit;
    text-decoration: none;
    padding: var(--space-lg);
}

a.card:hover {
    text-decoration: none;
}

/* ---- Badges ---- */

.badge {
    display: inline-block;
    font-size: var(--text-xs);
    font-weight: 600;
    padding: 2px 10px;
    border-radius: 9999px;
    letter-spacing: 0.025em;
}

.badge-primary { background: var(--color-primary-light); color: var(--color-primary); }
.badge-success { background: var(--color-accent-light); color: var(--color-accent); }
.badge-warning { background: var(--color-warning-light); color: var(--color-warning); }
.badge-danger { background: var(--color-danger-light); color: var(--color-danger); }
.badge-muted { background: var(--color-bg-secondary); color: var(--color-text-secondary); }

.badge-green { background: var(--color-accent-light); color: var(--color-accent); }
.badge-blue { background: var(--color-primary-light); color: var(--color-primary); }

/* ---- Data Table ---- */

.data-table {
    width: 100%;
    font-size: 14px;
    border-collapse: collapse;
}

.data-table th {
    text-align: left;
    padding: 10px 12px;
    color: var(--color-text-secondary);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-bottom: 1px solid var(--color-border);
}

.data-table td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--color-border-light);
}

.data-table .status-active { color: var(--color-accent); font-weight: 600; }
.data-table .status-inactive { color: var(--color-danger); font-weight: 600; }

/* ---- Search ---- */

.search-form {
    display: flex;
    gap: var(--space-sm);
    max-width: 24rem;
    width: 100%;
    /* align-items defaults to stretch - that makes input + button grow to match
       the Turnstile widget's height (~145px) on the GlobalSearch page. Pin items
       to the top so each keeps its intrinsic height. */
    align-items: flex-start;
}

/* Standard screen-reader-only utility. Labels/headings that are redundant with
   surrounding context visually but still useful to assistive tech. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.search-input {
    flex: 1;
    padding: 0.55rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-family: inherit;
    /* Light mode: pure-white input so it reads as a clean writing surface
       against the slightly-gray panel chrome around it. Dark mode override
       (in v2.css) flips this to slate-200 - same "light writing surface
       on darker panel" effect inverted. */
    background: #ffffff;
    color: var(--color-text);
    box-shadow: var(--shadow-inset);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}

.search-input:focus,
.search-input:focus-visible {
    outline: none;
    background: var(--color-bg-card);
    border-color: var(--color-primary);
    box-shadow: var(--focus-ring);
}

.search-button {
    padding: 0.55rem 1rem;
    background: var(--color-primary);
    color: #ffffff;
    border: none;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    box-shadow: var(--shadow-xs), inset 0 1px 0 rgba(255, 255, 255, 0.15);
    transition: background var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.search-button:hover {
    background: var(--color-primary-dark);
    box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

/* ---- Home Search Section ---- */

.home-search-section {
    text-align: center;
    padding: var(--space-xl) 0 var(--space-lg);
}

.home-subtitle {
    font-size: var(--text-lg);
    color: var(--color-text-secondary);
    max-width: 50rem;
    margin-inline: auto;
    margin-bottom: var(--space-lg);
}

.home-search-form {
    max-width: 36rem;
    margin-inline: auto;
}

/* ---- Inline Stats ---- */

.inline-stats {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) 0 var(--space-xl);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.inline-stat {
    color: var(--color-text-secondary);
    text-decoration: none;
    transition: color 120ms ease;
}
a.inline-stat:hover,
a.inline-stat:hover strong {
    color: var(--color-primary-dark);
    text-decoration: none;
}
.inline-stat strong {
    /* Default: non-link stat (a span) - number is just visual emphasis,
       not a click affordance, so it stays on the text color. */
    color: var(--color-text);
    font-weight: 600;
}
a.inline-stat strong {
    /* Link variant: primary palette per the chrome rule (clickable = primary). */
    color: var(--color-primary);
}

.inline-stat-sep::after {
    content: "\00b7";
    color: var(--color-border);
}

/* ---- Country / State Directory ---- */

.country-section {
    margin-bottom: var(--space-2xl);
}

.country-heading {
    font-size: var(--text-xl);
    font-weight: 600;
    color: var(--color-text);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-md);
}

.country-heading a {
    /* Country name is a clickable link to the country home -> primary palette. */
    color: var(--color-primary);
    text-decoration: none;
}

.country-heading a:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
}

.country-place-count {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

.browse-link {
    font-size: var(--text-sm);
    margin-bottom: var(--space-sm);
}

.state-list + .browse-link {
    margin-top: var(--space-sm);
}

.state-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-lg);
}

.state-link {
    /* Browse-by-place state links share the same font / weight / size as
       topic links and category tile names so every clickable label across
       the Home page reads as one type system. Weight 400 + base size feels
       lighter and more readable than the 500/0.88rem variant we tried. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    color: var(--color-primary);
    text-decoration: none;
    padding: var(--space-xs) 0;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
}

.state-link:hover {
    text-decoration: underline;
}

.state-count {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

/* ---- State Places (alpha grouped) ---- */

.state-place-count {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

/*  A-Z quick-jump row at top of StatePlaces. Sticky so it stays usable as
    the reader scrolls a long alphabetical list (CA has 579 cities across
    20+ letter groups). Letters with no matching section are shown dimmed
    rather than hidden, so the A-Z row reads in consistent order and absent
    letters are obvious at a glance. */
.alpha-jump {
    position: sticky;
    /* Sit BELOW the sticky .site-header (z-index 50, ~70px tall) so the
       letter bar isn't covered when scrolled. */
    top: 70px;
    z-index: 5;
    display: flex; flex-wrap: wrap; gap: 4px;
    padding: var(--space-xs) var(--space-sm);
    margin-bottom: var(--space-md);
    /* color-mix carries the token bg with partial alpha so the blur shows
       content scrolling behind. Flips with theme via --color-bg-card. */
    background: color-mix(in srgb, var(--color-bg-card) 92%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: 0.85rem;
}
@supports not (backdrop-filter: blur(6px)) {
    .alpha-jump { background: var(--color-bg-card); }
}
.alpha-jump__link {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 28px; height: 28px;
    padding: 0 6px;
    color: var(--color-primary);
    text-decoration: none;
    font-weight: 600;
    border-radius: 4px;
    transition: background 0.1s;
}
.alpha-jump__link:hover { background: var(--color-primary-light); }
.alpha-jump__link--empty {
    color: var(--color-text-muted);
    opacity: 0.35;
    font-weight: 400;
    cursor: default;
    pointer-events: none;
}

.alpha-group {
    margin-bottom: var(--space-lg);
}

.alpha-heading {
    /* The id="letter-X" anchor lives on this <h2>, not on .alpha-group, so
       scroll-margin-top has to be HERE for the browser to honor it. The
       sticky .alpha-jump bar (~50px) plus the page header (~60px) cover
       roughly 110px from the viewport top, so we offset by 120px to leave
       breathing room - the heading lands just below the chrome instead of
       being cut off above it. */
    scroll-margin-top: 120px;
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text-muted);
    padding-bottom: var(--space-xs);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-sm);
}

.alpha-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-xl);
}

/* A-Z grouping for long alpha lists (TagList). The letter heading is muted
   chrome - it organises the list but isn't itself clickable, so it stays
   off the primary palette. */
.tag-group {
    margin-top: 1.25rem;
}
.tag-group:first-of-type {
    margin-top: 0.75rem;
}
.tag-group__heading {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text-secondary);
    margin: 0 0 0.4rem;
    padding-bottom: 0.2rem;
    border-bottom: 1px solid var(--color-border);
    letter-spacing: 0.04em;
}


.alpha-link {
    font-size: var(--text-base);
    color: var(--color-primary);
    text-decoration: none;
    padding: var(--space-xs) 0;
}

.alpha-link:hover {
    /* Color-shift on hover instead of underline - matches the chrome rule
       (no underlines, only primary -> primary-dark transitions). */
    color: var(--color-primary-dark);
    text-decoration: none;
}

/* ---- Category-filter pill bar (StatePlaces, future PlaceHome / Region pages)
   --- single-row chooser of place types (Municipal / County / Township / etc.).
   Active pill is solid primary; inactive is the gradient card style with
   primary text. Hover deepens. */
.cat-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
    margin-bottom: 1rem;
}
.cat-filter__label {
    font-size: 0.85rem;
    color: var(--color-text-secondary);
    font-weight: 500;
    margin-right: 0.25rem;
}
.cat-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.75rem;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--gradient-panel-soft);
    color: var(--color-primary);
    font-size: 0.85rem;
    font-weight: 500;
    text-decoration: none;
    transition: background 120ms, border-color 120ms, color 120ms;
}
.cat-pill:hover {
    border-color: var(--color-primary);
    text-decoration: none;
}
.cat-pill--active {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
}
.cat-pill--active:hover {
    background: var(--color-primary-dark);
    border-color: var(--color-primary-dark);
    color: #fff;
}
.cat-pill__count {
    opacity: 0.7;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

/* ---- Place Portal Overview ---- */

.place-header {
    margin-bottom: var(--space-md);
}

.place-header h1 {
    margin-bottom: var(--space-xs);
}

/* Meta strip below the place hero - type badge + indexing status + residents
   + state + Set-as-my-place CTA on the right. Replaces the inline-styled
   version that hardcoded #555 / #eef2ff / #fee2e2 colors off-palette. */
.place-meta-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin-top: 0.5rem;
    color: var(--color-text-secondary);
    font-size: 0.95rem;
}
/* Title row: place name h1 + Set-as-my-place CTA aligned baseline. The
   CTA used to sit at the far right of the meta strip via margin-left:auto;
   moved here 2026-05-10 so it reads as a sibling to the place name (close
   to where the user's eye lands first). Wraps to a new line on narrow
   viewports where h1 + button can't both fit. */
.place-header__title-row {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Pill-shaped type badge ("City", "County", "School District", etc.).
   Brand-primary palette by default; --unindexed modifier flips to the
   warning-amber palette to flag "Not yet indexed" places without dropping
   to a hardcoded red. Sits inline in .place-meta-strip and inside the
   covering-county / nearby-place card meta line. */
.place-type-badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 500;
    background: var(--color-primary-light);
    color: var(--color-primary);
}
.place-type-badge--unindexed {
    background: var(--color-warning-light);
    color: var(--color-warning);
}

/* ---- BodyList: featured card + grouped card grid ---------------------
   The page is a "city government glossary" - featured Primary Legislative
   Body card up top, then type-grouped card grid (Committees / Boards /
   Commissions / Advisory / Administrative / Inactive). Each card surfaces
   the body's Description so the page reads as a referenceable list of
   what each body does, not a bare name list. */

/* Featured card: distinct primary-tinted treatment. The Council is the
   thing most readers come here looking for; pulling it out of the grid
   makes that intent obvious. */
.bodies-featured {
    display: block;
    margin: 1.25rem 0 1.5rem;
    padding: 1.5rem 1.75rem;
    background: linear-gradient(135deg, var(--color-primary-light) 0%, #f1f5f9 100%);
    border: 1px solid var(--color-primary);
    border-radius: 12px;
    text-decoration: none;
    color: var(--color-text);
    transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.bodies-featured:hover {
    border-color: var(--color-primary-dark);
    box-shadow: 0 2px 12px rgba(36, 108, 173, 0.12);
    transform: translateY(-1px);
    text-decoration: none;
}
.bodies-featured__kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--color-primary);
}
.bodies-featured__icon {
    font-size: 1.1rem;
}
.bodies-featured__name {
    margin: 0.4rem 0 0;
    font-size: 1.65rem;
    font-weight: 600;
    color: var(--color-primary);
    line-height: 1.2;
}
.bodies-featured__desc {
    margin: 0.75rem 0 0;
    color: var(--color-text);
    font-size: 1rem;
    line-height: 1.55;
    max-width: 50rem;
}
.bodies-featured__cta {
    display: inline-block;
    margin-top: 0.85rem;
    color: var(--color-primary);
    font-weight: 600;
    font-size: 0.9rem;
}

/* Stats row inside the featured card: members + last meeting + next
   meeting. Inline-stat shape (number bold + label) on a hairline row
   that wraps to a new line on narrow viewports. */
.bodies-featured__stats {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.25rem;
    align-items: center;
    margin-top: 1rem;
    padding-top: 0.85rem;
    border-top: 1px solid rgba(36, 108, 173, 0.18);
    color: var(--color-text-secondary);
    font-size: 0.9rem;
}
.bodies-featured__stat strong {
    color: var(--color-text);
    font-weight: 600;
    margin: 0 0.15rem;
}

/* Search-as-you-type input. Single control on the toolbar - the type
   sections below replace the old chip rail / sort dropdown. */
.bodies-toolbar {
    margin: 0 0 1.25rem;
}
.bodies-toolbar__search {
    width: 100%;
    max-width: 32rem;
    padding: 0.6rem 0.85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    font-size: 0.95rem;
    font-family: inherit;
}
.bodies-toolbar__search:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(36, 108, 173, 0.15);
}

/* Grouped sections: heading with type icon + count, card grid below. */
.bodies-group {
    margin-top: 2rem;
}
.bodies-group:first-of-type {
    margin-top: 0.5rem;
}
.bodies-group__heading {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--v2-ink-muted);
    padding-bottom: 0.4rem;
    margin: 0 0 0.85rem 0;
    border-bottom: 1px solid var(--color-border);
}
.bodies-group__icon {
    font-size: 0.95rem;
    margin-right: 0.1rem;
}
.bodies-group__count {
    margin-left: auto;
    font-size: 0.7rem;
    color: var(--color-text-muted);
    font-weight: 500;
    letter-spacing: 0.04em;
    font-variant-numeric: tabular-nums;
    text-transform: none;
}
.bodies-group--inactive {
    opacity: 0.7;
    margin-top: 3rem;
}

/* Card grid: auto-fit so cards adapt to viewport. minmax(280px, 1fr)
   gives ~3-up on a wide main column, 2-up on tablet, 1-up on mobile. */
.bodies-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 0.75rem;
}
.bodies-card {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--gradient-panel-soft);
    text-decoration: none;
    color: var(--color-text);
    transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.bodies-card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}
.bodies-card__name {
    color: var(--color-primary);
    font-weight: 500;
    font-size: 1rem;
    line-height: 1.3;
}
.bodies-card__desc {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 0.85rem;
    line-height: 1.45;
    /* Clamp to 3 lines so cards stay roughly equal height in the grid. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
/* Vendor-sourced description HTML defenses. Body descriptions in
   Legistar/Granicus admin panels can carry: <p>, <a>, <strong>, <em>
   (fine), <ul>/<ol> (extra height, clamp handles), inline styles
   (font-family/size/color often weird), <img>, <table>, <iframe>
   (break card layout). The rules below normalize all of it so card
   chrome stays predictable. */

/* Card description renders as plain text via CardSummary in BodyList -
   no nested HTML to defend against here. The 3-line clamp on
   .bodies-card__desc (above) handles overflow naturally. */

/* Featured card has more space - keep block layout (paragraphs, lists)
   but still cap inline styles + hide media. */
.bodies-featured__desc * {
    max-width: 100%;
    font-size: inherit !important;
    color: inherit !important;
    font-family: inherit !important;
    background: transparent !important;
    word-break: break-word;
    overflow-wrap: anywhere;
}
.bodies-featured__desc p,
.bodies-featured__desc div,
.bodies-featured__desc ul,
.bodies-featured__desc ol { margin: 0 0 0.5rem; padding: 0 0 0 1.25rem; }
.bodies-featured__desc ul,
.bodies-featured__desc ol { padding-left: 1.25rem; }
.bodies-featured__desc p:last-child,
.bodies-featured__desc div:last-child,
.bodies-featured__desc ul:last-child,
.bodies-featured__desc ol:last-child { margin-bottom: 0; }
.bodies-featured__desc img,
.bodies-featured__desc table,
.bodies-featured__desc iframe,
.bodies-featured__desc video,
.bodies-featured__desc embed,
.bodies-featured__desc object,
.bodies-featured__desc form,
.bodies-featured__desc input,
.bodies-featured__desc button { display: none !important; }
.bodies-featured__desc a {
    color: inherit;
    text-decoration: underline;
    pointer-events: none;
}
.bodies-card--inactive .bodies-card__name {
    color: var(--color-text-muted);
}

/* Meeting volume badge on each body card. Shows "12 meetings in 90d"
   when the body has logged any past meetings in the trailing window.
   Subordinate to the name + description; mostly there as a relative
   activity signal across cards in the same group. */
.bodies-card__meetings {
    margin-top: auto;
    padding-top: 0.4rem;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.bodies-card__meetings strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

/* People list: featured leadership cluster + per-person card chrome.
   Reuses .bodies-card-grid + .bodies-card for the main grid; the
   selectors below add the leadership cluster ("Mayor / Vice Mayor /
   President / Chair / Speaker" cards on top) and the secondary
   role/body/votes line each person card carries below the name. */
.people-featured {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.75rem;
    margin: 0 0 1.5rem;
}
.people-featured__card {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--color-primary);
    border-radius: 8px;
    background: linear-gradient(180deg, #f0f6fc 0%, #e6efff 100%);
    text-decoration: none;
    color: var(--color-text);
    transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.people-featured__card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}
.people-featured__role {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-primary);
}
.people-featured__name {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--color-text);
    line-height: 1.3;
}
.people-featured__body {
    font-size: 0.82rem;
    color: var(--color-text-secondary);
}
.people-featured__votes {
    margin-top: 0.25rem;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.people-featured__votes strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

/* Role label sits between the name and the body/votes meta strip.
   Slightly muted - it's descriptive, not the click signal. */
.people-card__role {
    font-size: 0.85rem;
    color: var(--color-text-secondary);
    line-height: 1.3;
}
.people-card__meta {
    margin-top: auto;
    padding-top: 0.4rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.6rem;
    align-items: center;
    font-size: 0.78rem;
    color: var(--color-text-muted);
}
.people-card__votes {
    font-variant-numeric: tabular-nums;
}
.people-card__votes strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

/* Calendar wrapper - lives in .place-cal-slot which is positioned via
   grid-template-areas: top of the sidebar column on desktop, top of the
   page stack on mobile. The slot's column width (320px on desktop)
   already constrains the calendar grid - no max-width override needed. */

.place-stats {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.place-stats strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

.place-search {
    margin-bottom: var(--space-xl);
}

.place-search-form {
    max-width: 32rem;
}

.place-grid {
    display: grid;
    /* Four named slots so the right pane can read top-down as
       topics -> cal -> bodies/people/advanced on desktop, while mobile
       still puts cal above events. Splitting "sidebar" into a topics
       slot + a rest slot lets the calendar slot wedge between them on
       desktop without falling to the bottom. */
    grid-template-columns: 1fr;
    grid-template-areas:
        "topics"
        "cal"
        "main"
        "sidebar";
    gap: var(--space-xl);
}

.place-cal-slot { grid-area: cal; }
.place-main { grid-area: main; }
.place-topics-slot { grid-area: topics; }
.place-sidebar { grid-area: sidebar; }

@media (min-width: 768px) {
    .place-grid {
        grid-template-columns: 1fr 320px;
        grid-template-areas:
            "main topics"
            "main cal"
            "main sidebar";
    }
}

.place-section {
    margin-bottom: var(--space-xl);
}

.place-section-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    /* Hairline divider sits on the wrapper (not the title) when the section
       has a side link - matches the divider on the standalone heading. */
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: 0.75rem;
}

.place-section-header .place-section-title {
    /* Title's own divider is suppressed inside the inline header - the
       wrapper above carries it. */
    padding-bottom: 0;
    border-bottom: none;
    margin-bottom: 0;
}

.section-all-link {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-primary);
    text-decoration: none;
    text-decoration: none;
    white-space: nowrap;
}

.section-all-link:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
}

.place-section-title {
    /* Matches .dossier__section-heading (used on Home + Top 10 Topics) so
       every section label across the site reads as one heading rhythm.
       Includes the same hairline divider as that class for a consistent
       section-edge cue. */
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--v2-ink-muted);
    padding-bottom: 0.4rem;
    margin: 0 0 0.75rem 0;
    border-bottom: 1px solid var(--color-border);
}

/* Sub-heading used inside a section-with-multiple-groups (e.g. "Census
   Bureau Regions" / "BEA Regions" inside "Browse by Region"). Quieter
   than the section title - same color but no uppercase / no border. */
.place-section-subhead {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text);
    margin: 1.25rem 0 0.5rem;
}
.place-section > .place-section-subhead:first-of-type {
    /* Tighter top margin when the subhead immediately follows the section
       header divider. */
    margin-top: 0.5rem;
}

.meeting-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border-light);
    /* Default row color is text-color; the visual click signal (primary
       blue) lives on .meeting-title for body/people/legislation rows or
       on .meeting-row__when for event rows. The whole anchor stays
       clickable - the color treatment just signals which span is the
       primary affordance. */
    color: var(--color-text);
    text-decoration: none;
    transition: background 0.1s;
}

.meeting-row:hover {
    text-decoration: none;
    background: var(--color-bg-secondary);
    margin-inline: calc(-1 * var(--space-sm));
    padding-inline: var(--space-sm);
    border-radius: var(--radius-md);
}
/* Inside a row, .meeting-title / .meeting-row__when carry the primary blue
   click signal. Hover deepens them to primary-dark. */
.meeting-row:hover .meeting-title,
.meeting-row:hover .meeting-row__when {
    color: var(--color-primary-dark);
}

.meeting-row-today {
    background: var(--color-primary-light);
    margin-inline: calc(-1 * var(--space-sm));
    padding-inline: var(--space-sm);
    border-radius: var(--radius-md);
    border-bottom-color: transparent;
}

.meeting-title {
    /* Default: primary-blue clickable signal for body/people/legislation
       rows where the title is the only label. In event rows the body
       name is descriptive (date is the click anchor) - the
       .meeting-row--event override below demotes title to text color.
       Font + weight + size match .home-aside__hot-label so every clickable
       record across the page reads as one type system. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    color: var(--color-primary);
}

/* Event row: date/time leads (.meeting-row__when), body name is descriptive.
   Legislation row: file number leads (.meeting-row__id), title is descriptive.
   Same visual treatment - one primary-blue lead element + neutral title.
   Font + weight + size match .meeting-title and .home-aside__hot-label. */
.meeting-row__when,
.meeting-row__id {
    font-family: var(--font-sans);
    color: var(--color-primary);
    font-weight: 400;
    font-size: 1rem;
    white-space: nowrap;
    flex: 0 0 auto;
}
.meeting-row__what {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.meeting-row--event .meeting-title,
.meeting-row--legislation .meeting-title {
    /* Title is descriptive when a primary lead element (when / id) is
       present; the lead element carries the click signal. */
    color: var(--color-text);
    font-weight: 400;
}

.meeting-date {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
}

.meeting-meta {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.section-more {
    margin-top: var(--space-sm);
    font-size: var(--text-sm);
}

.section-empty {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    padding: var(--space-sm) 0;
}

/* ---- Mini Calendar ---- */

.cal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--space-sm) 0;
    margin-bottom: var(--space-sm);
}

.cal-month-label {
    font-weight: 600;
    font-size: var(--text-sm);
}

.cal-nav {
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text-secondary);
    text-decoration: none;
    font-size: 16px;
    line-height: 1;
}

.cal-nav:hover {
    background: var(--color-bg-secondary);
    text-decoration: none;
}

.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    text-align: center;
}

.cal-dow {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    padding: 4px 0;
}

.cal-cell {
    font-size: var(--text-xs);
    padding: 6px 2px;
    border-radius: var(--radius-sm);
}

.cal-empty {
    visibility: hidden;
}

.cal-today {
    background: var(--color-primary);
    color: #ffffff;
    font-weight: 700;
}

.cal-has-event {
    font-weight: 700;
    color: var(--color-primary);
    text-decoration: none;
    cursor: pointer;
}

.cal-has-event:hover {
    background: var(--color-primary-light);
    text-decoration: none;
}

.cal-has-event.cal-today {
    background: var(--color-primary);
    color: #ffffff;
}

/* ---- Sidebar Lists ---- */

.sidebar-list {
    display: flex;
    flex-direction: column;
}

.sidebar-link {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) 0;
    font-size: var(--text-sm);
    color: var(--color-primary);
    text-decoration: none;
    border-bottom: 1px solid var(--color-border-light);
}

.sidebar-link:hover {
    text-decoration: underline;
}

/* ---- Region Pages ---- */

.region-intro {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

.region-systems {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xl);
}

.region-system-heading {
    font-size: var(--text-xl);
    font-weight: 600;
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-xs);
}

.region-system-desc {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-md);
}

.region-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-md);
}

.region-card {
    /* Matches the home-aside / category-card / hot-topics card chrome:
       same warm-to-cool gradient + standard border so every clickable card
       on the geo pages reads as the same surface family. */
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-md) var(--space-lg);
    background: var(--gradient-panel-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    text-decoration: none;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}

.region-card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}

.region-card-name {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--color-primary);
}

.region-card-meta {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.region-detail-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

/* Main + aside split, mirrors Home/StatePlaces. Collapses below 840px. */
.region-detail-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: var(--space-xl);
    align-items: start;
}
.region-detail-aside { min-width: 0; }
@media (max-width: 840px) {
    .region-detail-layout { grid-template-columns: 1fr; }
}

.region-state-list {
    margin-top: var(--space-md);
}

.region-browse-link {
    margin-top: var(--space-md);
    font-size: var(--text-sm);
}

/* ---- Tab Nav (inline) ---- */

.tab-nav {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-lg);
}

.tab-nav a {
    color: var(--color-text-secondary);
    text-decoration: none;
    padding: 10px 20px;
    font-size: 14px;
    font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.15s, border-color 0.15s;
}

.tab-nav a.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.tab-nav a:hover {
    color: var(--color-text);
    text-decoration: none;
}

/* ---- Pagination ---- */

.pagination {
    display: flex;
    gap: var(--space-md);
    margin-top: var(--space-xl);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border);
}

.pagination a {
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    background: var(--color-bg-card);
    transition: background 0.15s;
}

.pagination a:hover {
    background: var(--color-bg-secondary);
    text-decoration: none;
}

/* ---- Breadcrumb ---- */

.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    list-style: none;
    padding: 0;
    margin-bottom: var(--space-lg);
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.breadcrumb li + li::before {
    content: "/";
    margin-right: var(--space-xs);
    color: var(--color-text-muted);
}

/* ---- Section ---- */

.section {
    margin-bottom: var(--space-2xl);
}

.section-title {
    font-size: var(--text-xl);
    font-weight: 600;
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
}

/* ---- Agenda ---- */

.agenda-section {
    margin-bottom: var(--space-lg);
}

.agenda-section-title {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text);
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-sm);
}

.agenda-item {
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border-light);
}

.agenda-item:last-child {
    border-bottom: none;
}

.agenda-item-title {
    font-weight: 500;
}

.agenda-item-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-top: var(--space-xs);
}

/* ---- Vote Tally ---- */

.vote-tally {
    display: flex;
    gap: var(--space-lg);
    margin-bottom: var(--space-md);
}

.vote-tally-bucket {
    text-align: center;
}

.vote-tally-count {
    font-size: var(--text-2xl);
    font-weight: 700;
}

.vote-tally-label {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.vote-list {
    list-style: none;
    padding: 0;
}

.vote-list li {
    padding: var(--space-xs) 0;
    font-size: var(--text-sm);
    display: flex;
    justify-content: space-between;
    border-bottom: 1px solid var(--color-border-light);
}

/* ---- Empty / Error States ---- */

.empty-state {
    text-align: center;
    padding: var(--space-2xl);
    color: var(--color-text-secondary);
}

.empty-state-title {
    font-size: var(--text-xl);
    font-weight: 600;
    margin-bottom: var(--space-sm);
}

.error-alert {
    background: var(--color-danger-light);
    border: 1px solid #fecaca;
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    color: var(--color-danger);
    margin-bottom: var(--space-md);
}

/* One-shot flash banner. Rendered by FlashBanner.razor at the top of every
   page, immediately above @Body. Compact (py 12px) so it doesn't shove
   page content visibly down on success cases; the icon column anchors a
   distinct shape per level so the banner reads at a glance. */
.flash-banner {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    padding: 12px var(--space-lg);
    margin-bottom: var(--space-md);
    font-size: var(--text-sm);
    font-weight: 500;
}

.flash-banner__icon {
    flex: 0 0 1.25rem;
    width: 1.25rem;
    height: 1.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 0.875rem;
    font-weight: 700;
    line-height: 1;
}

.flash-banner__text { flex: 1 1 auto; }

.flash-banner--success {
    background: var(--color-accent-light);
    border-color: #a7f3d0;
    color: #065f46;
}
.flash-banner--success .flash-banner__icon {
    background: var(--color-accent);
    color: #fff;
}

.flash-banner--error {
    background: var(--color-danger-light);
    border-color: #fecaca;
    color: var(--color-danger);
}
.flash-banner--error .flash-banner__icon {
    background: var(--color-danger);
    color: #fff;
}

.flash-banner--warning {
    background: var(--color-warning-light);
    border-color: #fde68a;
    color: #92400e;
}
.flash-banner--warning .flash-banner__icon {
    background: var(--color-warning);
    color: #fff;
}

.flash-banner--info {
    background: var(--color-primary-light);
    border-color: #bfdbfe;
    color: var(--color-primary-dark);
}
.flash-banner--info .flash-banner__icon {
    background: var(--color-primary);
    color: #fff;
}

.not-found {
    text-align: center;
    padding: var(--space-2xl);
}

.not-found h1 {
    font-size: 4rem;
    font-weight: 800;
    color: var(--color-text-muted);
}

/* ---- Detail Page ---- */

.detail-header {
    margin-bottom: var(--space-xl);
}

.detail-title {
    font-size: var(--text-3xl);
    margin-bottom: var(--space-sm);
}

.detail-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    align-items: center;
}

.detail-meta span + span::before {
    content: "\00b7\00a0";
    margin-right: 0.25rem;
    color: var(--color-text-muted);
}

/* ---- Event header: title → meta → location → artifacts → status ---- */

.event-header {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.event-location {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    line-height: 1.4;
}

/* Default sizing for any inline <svg class="icon-sm">. Without this, SVGs
   without explicit width/height fall back to the browser default (300x150)
   and render as enormous icons inside small kicker rows. Contextual rules
   below (.event-location .icon-sm, .meeting-artifact .icon-sm, etc.) keep
   their overrides via specificity. */
.icon-sm {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* /topics flat-list-by-category. One section per category with a heading
   that links to /categories/{slug}, then a wrapping pill list of topics
   each linking to /topics/{slug}. Same hierarchy as the data: category
   then topic. */
.topics-index {
    display: grid;
    gap: var(--space-xl);
    margin-top: var(--space-lg);
}
.topics-index__group { }
.topics-index__cat {
    margin: 0 0 var(--space-sm) 0;
    font-size: 1.05rem;
    letter-spacing: 0.02em;
    color: var(--color-text);
}
.topics-index__cat a {
    color: inherit;
    text-decoration: none;
    border-bottom: 2px solid var(--color-border);
    padding-bottom: 2px;
}
.topics-index__cat a:hover { border-bottom-color: var(--color-primary); }
.topics-index__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}
.topics-index__item { margin: 0; }
.topics-index__link {
    display: inline-block;
    padding: 4px 10px;
    background: var(--color-bg-card, #f8fafc);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    color: var(--color-text);
    text-decoration: none;
    font-size: 0.9rem;
}
.topics-index__link:hover {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

.event-location .icon-sm {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    margin-top: 2px;
    color: var(--color-text-muted);
}

.event-location a {
    color: var(--color-primary);
    word-break: break-all;
}

.event-artifacts,
.meeting-artifacts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.2rem;
}
/* AI-narrative buttons live in a POST form so clicking triggers generation
   on the destination page directly. The form wrapper would otherwise stack
   each button on its own row inside .event-artifacts; reset its display so
   it participates as a normal flex child carrying the button. */
.event-artifact-form {
    display: contents;
}
/* Card variant: tighter spacing inside list cards (EventCard) so the pill
   row doesn't dominate visually next to the title. */
.meeting-artifacts--card {
    margin-top: 0.4rem;
    gap: 0.35rem;
}
.meeting-artifacts--card .meeting-artifact {
    padding: 0.15rem 0.5rem;
    font-size: 0.75rem;
}
/* Row variant: aligned to the right of the wrapping container so the pill
   row sits with the date column rather than below the title. */
.meeting-artifacts--row {
    margin: 0.15rem 0 0.6rem 0;
    padding: 0 0.75rem 0 0.75rem;
}
@media (min-width: 768px) {
    /* Desktop: artifacts (Agenda / Minutes / Video pills) sit inline on
       the same line as the date+title row, aligned to the right edge.
       The mobile fallback margin-top doesn't apply once we're flex-row. */
    .meeting-row-with-artifacts > .meeting-artifacts--row {
        margin: 0;
        padding: 0;
        flex-shrink: 0;
    }
}
.meeting-artifacts--row .meeting-artifact {
    padding: 0.15rem 0.5rem;
    font-size: 0.75rem;
}
/* Container that wraps a meeting-row anchor + a sibling artifacts row.
   Needed because nested <a> is invalid HTML; the outer container just
   stacks them. */
.meeting-row-with-artifacts {
    display: flex;
    /* Mobile-first: stack the row link above its artifact pills. Desktop
       (>=768px) flips to row layout so the pills align to the right
       on the same line as date+title - avoids the doubled vertical
       footprint per meeting row when there's space. */
    flex-direction: column;
}
@media (min-width: 768px) {
    .meeting-row-with-artifacts {
        flex-direction: row;
        align-items: center;
        gap: 0.75rem;
    }
    .meeting-row-with-artifacts > .meeting-row {
        flex: 1 1 auto;
        min-width: 0;
    }
}

/* Section row count pill (e.g. "Sponsors (3 records)"). Previously .section-count, but
   MapStaticAssets was auto-scoping that class with a hash prefix so the CSS never applied
   to the un-prefixed HTML. Renaming to .sec-count dodges the collision. */
.sec-count {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 400;
    color: var(--color-text-muted);
    margin-left: 0.35rem;
}
.sec-count::before { content: "("; }
.sec-count::after { content: ")"; }

/* Right-floating action link next to a section title. Class name is .sec-action (NOT
   .section-action) because Blazor's static-assets pipeline auto-scopes classes matching
   .section-* in CSS but not in the rendered HTML - an asymmetric rewrite that makes targeted
   classes silently stop matching. Same trap the earlier .section-count rename dodged. */
.section-title:has(.sec-action),
h2:has(> .sec-action) {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.sec-action {
    margin-left: auto;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 500;
    white-space: nowrap;
}

/* Compare screen: two-column picker with FROM on the left, TO on the right. Radio rows
   stack vertically; on narrow viewports the two columns collapse to a single column. */
.compare-picker__form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
    align-items: start;
}
.compare-picker__col {
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 0.5rem;
    padding: 0.75rem 1rem;
    background: #fafafa;
}
.compare-picker__row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0;
    cursor: pointer;
    font-size: var(--text-sm, 0.875rem);
    border-bottom: 1px solid var(--color-border-subtle, #f3f4f6);
}
.compare-picker__row:last-child { border-bottom: none; }
.compare-picker__row:hover { background: var(--color-bg-card); }
.compare-picker__actions {
    grid-column: 1 / -1;
    text-align: center;
    margin-top: 0.25rem;
}
@media (max-width: 700px) {
    .compare-picker__form { grid-template-columns: 1fr; }
}

/* ---- EventItemDetail: two-column header with outcome pinned right ---- */

.item-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.item-header__info {
    flex: 1 1 60%;
    min-width: 20rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.item-outcome {
    flex: 0 0 auto;
    min-width: 9rem;
    padding: 1rem 1.5rem;
    border-radius: 10px;
    text-align: center;
    border: 1px solid;
}

.item-outcome--passed {
    background: #ecfdf5;
    border-color: #6ee7b7;
    color: #065f46;
}

.item-outcome--failed {
    background: #fef2f2;
    border-color: #fca5a5;
    color: #991b1b;
}

.item-outcome--neutral {
    background: var(--color-surface-alt, #f4f4f5);
    border-color: var(--color-border, #e4e4e7);
    color: var(--color-text-secondary);
}

.item-outcome__label {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.item-outcome__sub {
    font-size: var(--text-xs);
    font-weight: 500;
    margin-top: 0.35rem;
    opacity: 0.85;
}

.vote-voice-note {
    padding: 0.75rem 1rem;
    background: var(--color-surface-alt, #f4f4f5);
    border-left: 3px solid var(--color-border, #e4e4e7);
    border-radius: 4px;
    margin: 0.5rem 0 1rem;
    color: var(--color-text-secondary);
}

.detail-list {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.4rem 1rem;
    margin: 0;
}
.detail-list dt {
    font-weight: 600;
    color: var(--color-text-secondary);
    white-space: nowrap;
}
.detail-list dd {
    margin: 0;
}

.details-link {
    font-size: var(--text-sm);
    color: var(--color-primary);
    white-space: nowrap;
    text-decoration: none;
}

.details-link:hover {
    text-decoration: underline;
}

/* Activity timeline table on ItemDetail. Slightly denser than .data-table - this is
   history-in-one-place, not a browse surface, so we accept more rows per fold. */
.timeline-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm, 0.875rem);
}
.timeline-table th {
    text-align: left;
    font-weight: 600;
    color: var(--color-text-secondary);
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--color-border, #e5e7eb);
}
.timeline-table td {
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--color-border-subtle, #f3f4f6);
    vertical-align: top;
}
.timeline-table__date {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.timeline-table__action {
    display: inline-block;
    margin-left: 0.5rem;
    color: var(--color-text, inherit);
}
.timeline-table__tally {
    margin-left: 0.4rem;
    font-variant-numeric: tabular-nums;
}
.timeline-table__details {
    text-align: right;
    white-space: nowrap;
}
.timeline-table__ver {
    white-space: nowrap;
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}
.timeline-table__video {
    text-align: center;
    white-space: nowrap;
    font-size: 1rem;
}
.timeline-table__video a {
    text-decoration: none;
    color: var(--color-primary);
}
/* Matter-only rows (no meeting link). We used to dim the date for these but readers asked
   for the dates to remain primary text since they're still authoritative action dates - just
   without a clickable meeting. Keep the row background subtle so meeting-linked rows still
   visually pop as the primary read path. */
.timeline-table__row--matter-only td { background: #fafafa; }
/* Plain-text Action column - no pill, just small tracked-out caps for scannability. */
.timeline-table__action-type {
    font-size: var(--text-xs, 0.75rem);
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--color-text);
    text-transform: uppercase;
}

/* Per-appearance outcome chip - smaller sibling of .item-outcome. Inline with the row. */
.outcome-chip {
    display: inline-block;
    font-size: var(--text-xs, 0.75rem);
    font-weight: 600;
    padding: 0.15rem 0.45rem;
    border-radius: 0.25rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.outcome-chip--passed {
    background: #dcfce7;
    color: #166534;
}
.outcome-chip--failed {
    background: #fee2e2;
    color: #991b1b;
}

/* Attachment type grouping - keeps staff reports visible even when 40 exhibits are attached. */
.attachment-group + .attachment-group {
    margin-top: 1rem;
}
.attachment-group__title {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    color: var(--color-text-secondary);
    margin: 0 0 0.35rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Ordinance full-text block. Preserves monospace layout like the original <pre>, but uses
   a div (not <pre>) so section spans can render with their own typography. `..Header` lines
   in Legistar source become ordinance-text__section - uppercase bold, mini rule above, so
   the ..Number / ..Title / ..Sponsor / ..Analysis / ..Body sections visibly chunk the text. */
.ordinance-text {
    white-space: pre-wrap;
    word-break: break-word;
    background: #fafafa;
    padding: 1rem;
    border-radius: 6px;
    max-height: 520px;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85rem;
    line-height: 1.5;
}
.ordinance-text__section {
    display: block;
    margin-top: 0.9rem;
    padding-top: 0.4rem;
    border-top: 1px solid var(--color-border-subtle, #e5e7eb);
    font-family: var(--font-sans, system-ui);
    font-weight: 700;
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
}
/* First section has no top rule - it sits flush with the pane. */
.ordinance-text > .ordinance-text__section:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

/* Extracted attachment text - similar styling to ordinance-text but for any attachment file. */
.attach-text { border-top: 1px solid var(--color-border-subtle, #e5e7eb); padding-top: 0.5rem; }
.attach-text summary { cursor: pointer; font-size: var(--text-sm, 0.875rem); color: var(--color-primary); margin-bottom: 0.5rem; }
.attach-text__body {
    white-space: pre-wrap;
    word-break: break-word;
    background: #fafafa;
    padding: 1rem;
    border-radius: 6px;
    max-height: 600px;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85rem;
    line-height: 1.55;
}

/* Sponsor chips with per-version dots. Each chip shows sponsor name + an inline row of dots,
   one per matter-version this item ever had. Dot is filled + numbered when the sponsor was
   on that version, hollow + faded otherwise. Dropped sponsors (not on the latest version)
   get a muted chip color so the eye jumps to active sponsors first. */
.sponsor-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.sponsor-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.65rem;
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 999px;
    background: var(--color-bg-card);
    color: var(--color-text, #1f2937);
    text-decoration: none;
    font-size: var(--text-sm, 0.875rem);
    transition: border-color 120ms ease, box-shadow 120ms ease;
}
.sponsor-chip:hover {
    border-color: var(--color-primary);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
    text-decoration: none;
}
.sponsor-chip--dropped {
    background: #f9fafb;
    color: #6b7280;
    border-color: #e5e7eb;
}
.sponsor-chip__name { font-weight: 500; }
.sponsor-chip__badge {
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-secondary);
    padding: 0.05rem 0.35rem;
    border-radius: 3px;
    background: rgba(0,0,0,0.06);
}
.sponsor-chip__versions {
    display: inline-flex;
    gap: 2px;
    margin-left: 0.1rem;
}
.version-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.65rem;
    font-weight: 600;
    line-height: 1;
}
.version-dot--on {
    background: #2563eb;
    color: #fff;
}
.version-dot--off {
    background: transparent;
    color: #d1d5db;
    border: 1px solid #e5e7eb;
}
.sponsor-chips__hint {
    margin-top: 0.5rem;
    font-size: var(--text-xs, 0.75rem);
}

/* Attachment pills - clickable cards with file-type icon + human label + meta (pages/bytes).
   Grid keeps long document titles from collapsing to single-column on mobile; at desktop
   widths 2-3 pills sit side by side for scan-ability. */
.attachment-pills {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 0.5rem;
}
.attach-pill {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 0.5rem;
    text-decoration: none;
    color: var(--color-text, #1f2937);
    background: var(--color-bg-card);
    transition: border-color 120ms ease, box-shadow 120ms ease;
    min-width: 0;
}
.attach-pill:hover {
    border-color: var(--color-primary);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
    text-decoration: none;
}
.attach-pill__icon {
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    border-radius: 0.35rem;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
}
/* Per-kind chip backgrounds removed 2026-05-16: the file-type icon now carries
   its own native brand color (FileKindIcons - red PDF badge, blue Word, etc.)
   and renders identically everywhere. A saturated chip behind a self-colored
   badge is muddy, so the icon box stays transparent and the badge is the
   color signal. (The .attach-pill--{kind} class is still emitted - it keeps
   the .attach-pill__type label tint - just no longer paints the icon box.) */
.attach-pill__label {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    flex: 1 1 auto;
}
.attach-pill__name {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 500;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.attach-pill__meta {
    font-size: var(--text-xs, 0.75rem);
    color: var(--color-text-secondary);
}

/* Primary action pills: crisp inline SVG icons, higher contrast than badges */
.meeting-artifact {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.8rem;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-primary);
    background: var(--color-primary-light);
    border: 1px solid var(--color-bg-tertiary, #e5e7eb);
    border-radius: 6px;
    text-decoration: none;
    transition: background 0.1s ease, border-color 0.1s ease;
}

.meeting-artifact:hover {
    background: var(--color-bg-tertiary, #e5e7eb);
    border-color: var(--color-primary);
    text-decoration: none;
}

/* Inline FileKind suffix on agenda/minutes pills when the file type is NOT the
   default PDF (e.g. "Agenda DOCX" or "Minutes HTML"). Plain colored uppercase
   monospace - matches the .attach-pill__type style used inside ItemDetail's
   attachment grid. Hidden by default for the common-case PDF; renders only
   when AnomalousFileKind() returns non-null (see MeetingArtifacts.razor). */
.meeting-artifact__filekind {
    margin-left: 0.35rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    opacity: 0.75;
}

/* AI / Ripple / Crystal Ball variants - all unified under the slate
   palette as of 2026-05-10. Distinguish via icon + label, not hue. The
   pre-2026-05-10 multi-color treatment (purple AI / teal Ripple / amber
   Crystal Ball) read as a rainbow on dense pages. Now they all default
   to the .meeting-artifact base style; the variant classes survive only
   so existing markup compiles and so we have hooks if a tiny tonal
   distinction (e.g. left-border accent) is ever wanted. */
.meeting-artifact--ai,
.meeting-artifact--ripple {
    /* base style inherited; no overrides */
}

/* ── The LGD Ripple page (R2-R3) ─────────────────────────────────────── */
.ripple-header { border-left: 4px solid #0d9488; padding-left: var(--space-md); }
.ripple-kicker {
    display: inline-flex; align-items: center; gap: 0.4rem;
    font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase;
    font-weight: 700; color: #0d9488;
    margin-bottom: var(--space-xs);
}
.ripple-place { font-weight: 600; color: var(--color-text-secondary); }
.ripple-date  { color: var(--color-text-secondary); font-variant-numeric: tabular-nums; }

.ripple-summary {
    margin: var(--space-lg) 0;
    padding: 0.9rem 1.1rem;
    background: #f8fafc;
    border-left: 3px solid #0d9488;
    border-radius: 4px;
}
.ripple-summary__headline { margin: 0; font-size: 1rem; line-height: 1.5; color: var(--color-text); }
.ripple-summary__empty { color: var(--color-text-secondary); }
.ripple-summary__headline strong { color: #0d9488; font-weight: 700; }
.ripple-summary__headline a { color: #0d9488; text-decoration: underline; }

/* A match = score badge on the left, card on the right. */
.ripple-match {
    display: grid;
    grid-template-columns: 70px minmax(0, 1fr);
    gap: var(--space-md);
    align-items: start;
    margin-bottom: var(--space-md);
}
.ripple-match__score {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 0.6rem 0.4rem;
    background: linear-gradient(180deg, #0d9488 0%, #0f766e 100%);
    color: #f0fdfa;
    border-radius: 8px;
    min-height: 74px;
}
.ripple-match__score-num   { font-size: 1.4rem; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.ripple-match__score-label { font-size: 0.65rem; letter-spacing: 0.1em; text-transform: uppercase; margin-top: 0.25rem; opacity: 0.85; }
.ripple-match__body { min-width: 0; }
.ripple-match__signals {
    margin-top: 0.25rem; padding-left: 0.4rem;
    font-size: 0.8rem; color: var(--color-text-muted);
    display: flex; flex-wrap: wrap; gap: 0.25rem 0.5rem;
}

/* Sub-800px: stack score above card. */
@media (max-width: 800px) {
    .ripple-match { grid-template-columns: 1fr; }
    .ripple-match__score { flex-direction: row; gap: 0.5rem; min-height: 0; padding: 0.4rem 0.75rem; }
}

/* ── R3: timeline + map ─────────────────────────────────────────────── */
.ripple-timeline {
    margin: var(--space-lg) 0;
}
.ripple-timeline__title {
    font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--color-text-muted); font-weight: 600; margin-bottom: 0.5rem;
}
.ripple-timeline__chart {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(8px, 1fr);
    align-items: end;
    gap: 2px;
    height: 120px;
    padding: 0.5rem;
    background: #f8fafc;
    border-radius: 6px;
    border: 1px solid #e5e7eb;
}
.ripple-timeline__bar {
    background: #0d9488;
    border-radius: 2px 2px 0 0;
    min-height: 2px;
    transition: background 0.12s;
    position: relative;
}
.ripple-timeline__bar--empty  { background: #e2e8f0; min-height: 1px; }
.ripple-timeline__bar--seed   { background: #dc2626; min-height: 6px; }
.ripple-timeline__bar:hover   { background: #0f766e; }
.ripple-timeline__axis {
    display: flex; justify-content: space-between;
    font-size: 0.7rem; color: #94a3b8; margin-top: 0.4rem;
    font-variant-numeric: tabular-nums;
}
.ripple-timeline__legend {
    display: flex; gap: 1rem; font-size: 0.75rem; color: var(--color-text-muted); margin-top: 0.35rem;
}
.ripple-timeline__legend-dot {
    display: inline-block; width: 8px; height: 8px; border-radius: 2px;
    vertical-align: middle; margin-right: 0.25rem;
}

.ripple-map {
    margin: var(--space-lg) 0;
    border-radius: 8px; overflow: hidden;
    border: 1px solid #e5e7eb;
    height: 360px;
}
.ripple-map__container {
    width: 100%; height: 100%;
}
.ripple-map__fallback {
    padding: 2rem; text-align: center; color: var(--color-text-muted); font-size: 0.9rem;
}

/* ── R4: per-state spread chart on topic ripple ─────────────────────── */
.ripple-states {
    margin: var(--space-lg) 0;
    padding: 0.75rem 1rem;
    background: #f8fafc;
    border-radius: 8px;
    border: 1px solid #e5e7eb;
}
.ripple-states__title {
    font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--color-text-muted); font-weight: 600; margin-bottom: 0.6rem;
}
.ripple-states__list { list-style: none; padding: 0; margin: 0; }
.ripple-states__row {
    display: grid;
    grid-template-columns: 44px 1fr 40px;
    gap: 0.6rem;
    align-items: center;
    padding: 0.2rem 0;
}
.ripple-states__state {
    font-weight: 700; color: var(--color-text);
    text-decoration: none; font-variant-numeric: tabular-nums;
}
.ripple-states__state:hover { color: #0d9488; text-decoration: underline; }
.ripple-states__bar-wrap {
    background: #e5e7eb; border-radius: 3px; height: 12px; overflow: hidden;
}
.ripple-states__bar {
    height: 100%;
    background: linear-gradient(90deg, #14b8a6 0%, #0d9488 100%);
    border-radius: 3px;
}
.ripple-states__count {
    font-variant-numeric: tabular-nums; color: var(--color-text-secondary);
    font-size: 0.85rem; text-align: right;
}

/* ── Unified embedded-component panel header (TrendingRipples + FeaturedTopics)
     Both panels render in the same kicker / heading / explanation rhythm and
     share neutral card chrome. Earlier each panel had its own rainbow-y
     gradient (teal vs amber), which fought the 3-color palette rule. Now
     both read as quiet white cards with a slate kicker label and a
     standard h2 + lede. The .trending-ripples__list / .featured-topics__grid
     bodies still differ - those are the actual content surfaces. */
.trending-ripples,
.featured-topics {
    margin: var(--space-xl) 0;
    padding: 1.5rem;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}
.trending-ripples__header { margin-bottom: 1rem; }
.trending-ripples__kicker,
.featured-topics__kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.7rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--color-secondary);
    /* Reset the old amber-pill treatment that .featured-topics__kicker
       carried; both kickers are now plain labels. */
    background: transparent;
    padding: 0;
    border-radius: 0;
}
.trending-ripples__title,
.featured-topics__title {
    margin: 0.4rem 0 0.35rem;
    font-size: 1.5rem;
    color: var(--color-text);
    line-height: 1.25;
}
.trending-ripples__sub,
.featured-topics__sub {
    /* No max-width: the panel itself is already constrained by the page
       container. Earlier 46rem clamp produced awkward wrap points
       (e.g. "where it's" then "spreading" on the next line). Let the sub
       fill the container width and wrap naturally. */
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 0.95rem;
    line-height: 1.55;
}
.trending-ripples__list { list-style: none; padding: 0; margin: 0; }
.trending-ripples__row {
    margin-bottom: 0.5rem;
}
.trending-ripples__link {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 0.75rem;
    align-items: center;
    padding: 0.7rem 0.9rem;
    background: var(--color-bg-card);
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.trending-ripples__link:hover {
    border-color: var(--color-primary);
    box-shadow: 0 2px 8px rgba(36, 108, 173, 0.12);
    text-decoration: none;
}
.trending-ripples__label {
    min-width: 0;
}
.trending-ripples__name {
    /* The row's primary clickable signal -> primary palette per the chrome rule. */
    display: block; font-size: 1.05rem; font-weight: 600; color: var(--color-primary);
}
.trending-ripples__category {
    display: block; font-size: 0.75rem; color: var(--color-text-muted); margin-top: 0.1rem;
}
.trending-ripples__stats {
    display: flex; flex-wrap: wrap; gap: 0.35rem 0.75rem;
    font-size: 0.8rem; color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
    justify-content: flex-end;
}
/* Inline stat emphasis is data, not a separate link - keep it on the
   text-color tone rather than a brand accent. */
.trending-ripples__stat strong { color: var(--color-text); }
.trending-ripples__cta {
    /* End-of-row "See map ->" - same link surface as the row, primary blue. */
    font-size: 0.85rem; color: var(--color-primary); font-weight: 600; white-space: nowrap;
}

@media (max-width: 680px) {
    .trending-ripples__link { grid-template-columns: 1fr; gap: 0.3rem; }
    .trending-ripples__stats { justify-content: flex-start; }
    .trending-ripples__cta { text-align: right; }
}

/* ── R6: subscription UI ────────────────────────────────────────── */

/* "Following" state of the ripple button - filled teal vs. the outline
   Follow state. Reuses meeting-artifact shell for layout parity. */
.meeting-artifact--ripple-on {
    background: #0d9488;
    border-color: #0d9488;
    color: #f0fdfa;
    cursor: default;
}
.meeting-artifact--ripple-on:hover {
    background: #0f766e; border-color: #0f766e; color: #f0fdfa;
}
/* When inside a <form>, the button inherits button styling from the browser;
   <button> has more user-agent defaults than <a> (text-align: center, its own
   color/font, vertical-align differences, default margins). Reset to match the
   sibling <a class="meeting-artifact"> rendering byte-for-byte so the AI/Source
   action row reads as one consistent control set. */
form button.meeting-artifact {
    /* CRITICAL: do NOT use `font: inherit` (or `color: inherit`) here. This
       selector has specificity 0,2,2 - higher than `.meeting-artifact` (0,1,0)
       and `.meeting-artifact--ai` (0,1,0). A shorthand `font: inherit` would
       win the font-size / font-weight cascade against `.meeting-artifact`
       (which sets 14px / 500) and the button would render at body 16px / 400.
       Same trap with `color: inherit` and the AI variant's purple.
       Only override the UA defaults `<button>` actually applies on top of
       what `.meeting-artifact` sets - notably the system font-family. */
    font-family: inherit;
    line-height: inherit;
    text-align: left;
    box-sizing: border-box;
    margin: 0;
    cursor: pointer;
    appearance: none;            /* strip native button chrome (Safari) */
    -webkit-appearance: none;
}
form button.meeting-artifact--ripple-on { cursor: pointer; }

/* /my/ripples page list */
.my-ripples__list { list-style: none; padding: 0; margin: 1.5rem 0 0; }
.my-ripples__row {
    display: flex; align-items: center; gap: 1rem;
    padding: 0.85rem 1rem;
    border: 1px solid #e2e8f0; border-radius: 8px;
    background: var(--color-bg-card);
    margin-bottom: 0.5rem;
}
.my-ripples__row:hover { border-color: #5eead4; }
.my-ripples__main { min-width: 0; flex: 1; }
.my-ripples__kind-chip {
    display: inline-block;
    padding: 0.1rem 0.5rem; border-radius: 999px;
    font-size: 0.65rem; font-weight: 700; letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-right: 0.5rem;
}
.my-ripples__kind-chip--topic { background: #f0fdfa; color: #0d9488; }
.my-ripples__kind-chip--item  { background: #eff6ff; color: #2563eb; }
.my-ripples__label { display: inline; }
.my-ripples__label a {
    font-weight: 600; color: var(--color-text); text-decoration: none;
}
.my-ripples__label a:hover { color: #0d9488; text-decoration: underline; }
.my-ripples__context {
    margin-left: 0.4rem; color: var(--color-text-muted); font-size: 0.85rem;
}
.my-ripples__meta {
    margin-top: 0.2rem; color: var(--color-text-muted); font-size: 0.8rem;
    display: flex; flex-wrap: wrap; gap: 0.2rem 0.4rem;
}
.my-ripples__unsub {
    padding: 0.4rem 0.85rem;
    background: var(--color-bg-card); color: var(--color-text-muted);
    border: 1px solid #e2e8f0; border-radius: 6px;
    cursor: pointer; font-size: 0.85rem;
    transition: all 0.12s;
}
.my-ripples__unsub:hover {
    background: #fef2f2; color: #b91c1c; border-color: #fecaca;
}

/* ── The LGD Crystal Ball ── unified under base meeting-artifact style. */
.meeting-artifact--cb { /* base style inherited */ }

.cb-header { border-left: 4px solid #d97706; padding-left: var(--space-md); }
.cb-kicker {
    display: inline-flex; align-items: center; gap: 0.4rem;
    font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase;
    font-weight: 700; color: #d97706;
    margin-bottom: var(--space-xs);
}
.cb-category { font-weight: 600; color: var(--color-text-secondary); }

.cb-summary {
    margin: var(--space-lg) 0;
    padding: 0.9rem 1.1rem;
    background: #fffbeb;
    border-left: 3px solid #d97706;
    border-radius: 4px;
}
.cb-summary__line { margin: 0; font-size: 1rem; line-height: 1.5; color: var(--color-text); }
.cb-summary__line strong { color: #b45309; }
.cb-summary__disclaimer { margin: 0.35rem 0 0; font-size: 0.85rem; }
.cb-summary__empty { color: var(--color-text-secondary); }
.cb-summary__line a { color: #b45309; text-decoration: underline; }

.cb-adopters {
    margin: var(--space-md) 0;
    padding: 0.75rem 1rem;
    background: #f8fafc; border-radius: 8px; border: 1px solid #e5e7eb;
}
.cb-adopters__title {
    font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--color-text-muted); font-weight: 600; margin-bottom: 0.5rem;
}
.cb-adopters__chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.cb-adopter-chip {
    display: inline-flex; align-items: baseline; gap: 0.25rem;
    padding: 0.3rem 0.65rem;
    background: #fee2e2; border: 1px solid #fecaca;
    color: #b91c1c; border-radius: 999px;
    font-size: 0.85rem; text-decoration: none;
    transition: background 0.12s;
}
.cb-adopter-chip:hover { background: #fecaca; text-decoration: none; color: #991b1b; }
.cb-adopter-chip__name { font-weight: 500; }
.cb-adopter-chip__state { font-size: 0.7rem; opacity: 0.75; }
.cb-adopter-chip__count { font-weight: 600; font-variant-numeric: tabular-nums; margin-left: 0.15rem; }
.cb-adopter-chip--more { background: #f1f5f9; border-color: #e2e8f0; color: var(--color-text-muted); cursor: default; }

.cb-map { position: relative; }
.cb-map__legend {
    position: absolute; bottom: 8px; left: 8px;
    background: rgba(255,255,255,0.95);
    padding: 0.3rem 0.6rem; border-radius: 6px;
    font-size: 0.75rem; color: var(--color-text-secondary);
    display: flex; flex-direction: column; gap: 0.2rem;
    box-shadow: 0 1px 3px rgba(0,0,0,0.15);
    z-index: 1000;
}
.cb-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; vertical-align: middle; margin-right: 0.35rem; }
.cb-dot--adopter    { background: #dc2626; }
.cb-dot--prediction { background: #f59e0b; border: 1px solid #d97706; }

/* Prediction cards: rank badge + content + factor breakdown */
.cb-prediction {
    display: grid;
    grid-template-columns: 54px minmax(0, 1fr);
    gap: var(--space-md);
    align-items: start;
    margin-bottom: var(--space-md);
    padding: 1rem 1.1rem;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    background: var(--color-bg-card);
    transition: border-color 0.12s;
}
.cb-prediction:hover { border-color: #fcd34d; }
.cb-prediction__rank {
    display: flex; align-items: center; justify-content: center;
    padding: 0.6rem 0;
    background: linear-gradient(180deg, #f59e0b 0%, #d97706 100%);
    color: #fffbeb;
    border-radius: 8px;
    font-size: 1.5rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
    min-height: 80px;
}
.cb-prediction__body { min-width: 0; }
.cb-prediction__head {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
    margin-bottom: 0.6rem;
}
.cb-prediction__name {
    font-size: 1.1rem; font-weight: 600; color: var(--color-text);
    text-decoration: none;
}
.cb-prediction__name:hover { color: #b45309; text-decoration: underline; }
.cb-prediction__state {
    font-size: 0.85rem; color: var(--color-text-muted); font-weight: 500;
}
.cb-prediction__pop {
    font-size: 0.8rem; color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    padding: 0.1rem 0.45rem; background: #f1f5f9; border-radius: 4px;
}
.cb-prediction__score {
    margin-left: auto;
    display: flex; flex-direction: column; align-items: flex-end;
}
.cb-prediction__score-num {
    font-size: 1.2rem; font-weight: 700; color: #b45309;
    line-height: 1; font-variant-numeric: tabular-nums;
}
.cb-prediction__score-label {
    font-size: 0.65rem; color: #94a3b8;
    letter-spacing: 0.08em; text-transform: uppercase;
}
.cb-prediction__reasoning {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.5rem;
    margin: 0.5rem 0;
}
.cb-factor { display: grid; grid-template-columns: auto 1fr auto; gap: 0.35rem; align-items: center; font-size: 0.78rem; color: var(--color-text-secondary); }
.cb-factor__label { min-width: 6rem; }
.cb-factor__bar { height: 6px; background: #fef3c7; border-radius: 3px; overflow: hidden; }
.cb-factor__fill { display: block; height: 100%; background: linear-gradient(90deg, #fbbf24 0%, #d97706 100%); border-radius: 3px; }
.cb-factor__value { font-variant-numeric: tabular-nums; font-weight: 500; color: var(--color-text); min-width: 2.2rem; text-align: right; }

.cb-prediction__evidence { font-size: 0.82rem; margin-top: 0.35rem; }

/* ── Featured Topics - curated hot-button issues. Container + kicker/title/sub
     styles now live in the unified .trending-ripples + .featured-topics block
     above (search this file for "Unified embedded-component panel header"). */
.featured-topics__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 0.75rem;
    margin-top: 1rem;
}
.featured-topic {
    background: var(--color-bg-card);
    border: 1px solid #f1f5f9;
    border-radius: 10px;
    padding: 0.9rem 1rem;
    display: flex; flex-direction: column;
}
.featured-topic__header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.35rem; }
.featured-topic__emoji { font-size: 1.4rem; }
.featured-topic__name { margin: 0; font-size: 1.05rem; color: var(--color-text); }
.featured-topic__desc {
    margin: 0 0 0.7rem; color: var(--color-text-secondary); font-size: 0.85rem;
    flex: 1; line-height: 1.4;
}
.featured-topic__actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }
/* Both action chips are clickable -> primary palette per the chrome rule.
   Earlier they used teal (ripple) + amber (crystal ball) for visual
   differentiation, but the rule wins: identical color, the labels
   ("See the Ripple" / "Crystal Ball") carry the meaning. */
.featured-topic__action {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.35rem 0.7rem;
    font-size: 0.8rem; font-weight: 500;
    border-radius: 6px;
    text-decoration: none;
    border: 1px solid var(--color-primary);
    background: var(--color-primary-light);
    color: var(--color-primary);
    transition: background 0.12s, color 0.12s;
}
.featured-topic__action:hover {
    background: var(--color-primary);
    color: #fff;
    text-decoration: none;
}
/* --ripple and --cb modifiers are now structural-only (kept on the markup
   in case future styling wants to differentiate them); no color overrides. */

@media (max-width: 680px) {
    .cb-prediction { grid-template-columns: 1fr; }
    .cb-prediction__rank { min-height: 0; padding: 0.3rem 0.7rem; font-size: 1rem; display: inline-flex; width: auto; }
    .cb-prediction__score { margin-left: 0; flex-direction: row; gap: 0.3rem; align-items: baseline; }
}

/* Narrative page (brief / analysis) */
.narrative-kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #6b21a8;
    margin-bottom: 0.25rem;
    white-space: nowrap;
}
.narrative-kicker .icon-sm { width: 16px; height: 16px; flex-shrink: 0; }
.narrative-section p {
    line-height: 1.6;
    margin: 0 0 0.9rem 0;
    max-width: 44rem;
}
.narrative-footer {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    border-top: 1px solid var(--color-border, #e4e4e7);
    margin-top: 1.5rem;
    padding-top: 0.75rem;
    max-width: 44rem;
}

.meeting-artifact .icon-sm {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* ---- Section header with view toggle on the right ---- */

.section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.view-toggle {
    display: inline-flex;
    font-size: var(--text-sm);
    border: 1px solid var(--color-border, #e4e4e7);
    border-radius: 6px;
    overflow: hidden;
}

.view-toggle a {
    padding: 0.3rem 0.75rem;
    color: var(--color-text-secondary);
    text-decoration: none;
    border-right: 1px solid var(--color-border, #e4e4e7);
}

.view-toggle a:last-child {
    border-right: none;
}

.view-toggle a.active {
    background: var(--color-primary);
    color: white;
}

.view-toggle a:not(.active):hover {
    background: var(--color-surface-alt, #f4f4f5);
}

/* ---- Agenda table (Legistar-parity render) ---- */

.agenda-table td {
    vertical-align: top;
    font-size: var(--text-sm);
}

.agenda-row-procedural td {
    color: var(--color-text-muted);
    background: var(--color-surface-alt, #fafafa);
}

/* In-page event search overlay (EventDetail.razor when ?q= present) */
.event-search-overlay {
    margin: 1rem 0 1.5rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--color-primary);
    border-radius: 4px;
    background: var(--color-surface-alt, #f5f7fa);
}
.event-search-overlay-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    font-size: var(--text-sm);
}
.event-search-overlay-count strong { font-weight: 600; }
.event-search-overlay-clear {
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--text-sm);
}
.event-search-overlay-clear:hover { text-decoration: underline; }
.event-search-banner {
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--color-border, #e0e3e8);
}
.event-search-banner-title {
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    margin-bottom: 0.5rem;
}
.event-search-snippet {
    font-size: var(--text-sm);
    line-height: 1.4;
    margin-bottom: 0.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.event-search-snippet .hit-source {
    font-weight: 600;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    margin-right: 0.5em;
}

/* Header row for a single hit: the source-document chip on the left,
   optional "(N matches)" count on the right when multiple chunks of
   that document matched. Stays on one line; chip wraps independently. */
.hit-source-line {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.hit-count {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    background: var(--color-surface-alt, #eef2f6);
    padding: 0.1rem 0.4rem;
    border-radius: 0.25rem;
    font-weight: 500;
}

/* Compact attach-pill used inside search-overlay snippets and per-row hit
   expansions. Same shape as the standard attach-pill but smaller text and
   tighter padding so it fits next to a snippet without dominating it. */
.attach-pill--inline {
    display: inline-flex;
    padding: 0.2rem 0.5rem 0.2rem 0.3rem;
    gap: 0.35rem;
    font-size: var(--text-xs);
    align-self: flex-start;
}
.attach-pill--inline .attach-pill__icon {
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    /* Transparent: the inline icon is now a self-colored FileKindIcons badge
       (was a muted grey chip). Keeps it consistent with the list pills. */
    background: transparent;
    font-size: 12px;
    border-radius: 0.25rem;
}
.attach-pill--inline .attach-pill__name {
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 32rem;
}
.attach-pill--text {
    color: var(--color-text-muted);
    background: var(--color-surface-alt, #f5f7fa);
    border-style: dashed;
    cursor: default;
}
.attach-pill--text:hover { box-shadow: none; border-color: var(--color-border, #e5e7eb); }

/* In-page-search decoration on the existing attachment-pill grid.
   Default state: each .attach-card uses `display: contents` so the
   wrapped <a class="attach-pill"> stays the grid item - non-matching
   pills behave exactly as before. When the wrapper carries --hit,
   it switches to a block that spans the full grid row, with the pill
   visually accented and the matching snippets stacked underneath. */
.attach-card { display: contents; }
.attach-card--hit {
    display: block;
    grid-column: 1 / -1;
    border: 1px solid var(--color-border, #e5e7eb);
    border-left: 3px solid var(--color-primary);
    border-radius: 6px;
    padding: 0.5rem 0.75rem;
    background: rgba(255, 243, 163, 0.12);
}
.attach-card--hit .attach-pill { display: inline-flex; background: var(--color-bg-card); }
.attach-pill--hit { border-color: var(--color-primary); }
.attach-card__hits {
    margin-top: 0.5rem;
    padding-left: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: var(--text-xs);
    line-height: 1.4;
}
.attach-card__hit-snippet { color: var(--color-text); }
.attach-card__hit-snippet mark { background: #fff3a3; padding: 0 1px; }
.attach-card__hit-more { color: var(--color-text-muted); font-style: italic; }

/* Compact top-of-page alert. Replaces the bigger event-search-overlay
   banner on Item / EventItem detail pages where the per-pill snippets
   carry the load instead. Stays one line: count on the left, jump
   link on the right. */
.search-alert {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0.75rem;
    margin: 0.75rem 0 1rem;
    background: var(--color-surface-alt, #f5f7fa);
    border: 1px solid var(--color-primary);
    border-radius: 6px;
    font-size: var(--text-sm);
}
.search-alert__count strong { font-weight: 600; }
.search-alert__actions { display: flex; gap: 1rem; align-items: center; }
.search-alert__jump { font-weight: 500; }
.search-alert__clear { color: var(--color-text-muted); text-decoration: none; }
.search-alert__clear:hover { text-decoration: underline; }

/* Inline list of Pass-2 item-text hits shown in the alert when chunks
   matched against c.ItemId without an AttachmentId behind them. Compact
   so it doesn't dominate the alert. */
.search-alert__itemtext {
    margin: 0.5rem 0 0;
    padding: 0.5rem 0 0;
    border-top: 1px dashed var(--color-border, #e5e7eb);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}
.search-alert__itemtext-title {
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.25rem;
}
.search-alert__itemtext-snippet {
    line-height: 1.4;
    margin-bottom: 0.25rem;
}

/* TopicDetail faceted-browse layout. Sidebar of year/state/place facets
   on the left, results on the right. Plain GET sidebar - each row is a
   link that toggles one CSV value, no JS. Mirrors /search's left-rail
   feel without pulling SearchContentStream's full machinery in. */
.topic-research { margin-top: 1.25rem; }
.topic-research__layout {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: 1.5rem;
}
@media (max-width: 768px) {
    .topic-research__layout { grid-template-columns: 1fr; }
}
.topic-research__sidebar {
    font-size: var(--text-sm);
    color: var(--color-text);
}
.topic-research__group { margin-bottom: 1rem; }
.topic-research__group-title {
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-bottom: 0.4rem;
}
.topic-research__list { list-style: none; padding: 0; margin: 0; }
.topic-research__row {
    display: flex;
    justify-content: space-between;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
    text-decoration: none;
    color: var(--color-primary);
}
.topic-research__row:hover { background: var(--color-primary-light); color: var(--color-primary-dark); }
.topic-research__row--on {
    background: var(--color-primary);
    color: #fff;
    font-weight: 500;
}
.topic-research__row--on .muted { color: rgba(255,255,255,0.85); }
.topic-research__clear { margin-bottom: 0.75rem; font-size: var(--text-xs); }
.topic-research__main { min-width: 0; }
.event-search-snippet-more {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    font-style: italic;
}
.event-search-overlay mark,
.agenda-table mark { background: #fff3a3; padding: 0 1px; }

/* "Show all 142 items" restore link below the agenda section header */
.agenda-search-restore {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0.75rem;
    margin: 0.25rem 0 0.5rem;
    background: var(--color-surface-alt, #f5f7fa);
    border-radius: 4px;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}
.agenda-search-restore a { font-weight: 500; }

/* Per-row search hit decoration on agenda items that matched */
.agenda-table tr.agenda-row-hit td {
    background: rgba(255, 243, 163, 0.18);
}
.agenda-table tr.agenda-row-hit-expand td {
    padding-top: 0.25rem;
    padding-bottom: 0.5rem;
    background: rgba(255, 243, 163, 0.18);
    border-bottom: 1px solid var(--color-border, #e0e3e8);
}
.agenda-row-hit-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.agenda-row-hit-snippet {
    font-size: var(--text-xs);
    line-height: 1.4;
    margin-bottom: 0.3rem;
}
.agenda-row-hit-snippet .hit-source {
    font-weight: 600;
    color: var(--color-text-muted);
    margin-right: 0.5em;
}
.agenda-row-hit-snippet .hit-text { color: var(--color-text); }
.agenda-row-hit-more {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    font-style: italic;
}

.action-details {
    margin-top: 0.25rem;
    font-size: var(--text-xs);
}

.action-details > summary {
    cursor: pointer;
    color: var(--color-text-muted);
    user-select: none;
    list-style: none;
    display: inline-block;
    padding: 0.1rem 0.25rem;
    border-radius: 3px;
}

.action-details > summary::before {
    content: "\25B8";
    margin-right: 0.25rem;
    display: inline-block;
    transition: transform 0.15s ease;
}

.action-details[open] > summary::before {
    transform: rotate(90deg);
}

.action-details > summary:hover {
    color: var(--color-text-primary);
    background: var(--color-surface-alt, #f4f4f5);
}

.action-details-body {
    margin: 0.35rem 0 0.5rem 0.9rem;
    padding: 0.4rem 0.6rem;
    border-left: 2px solid var(--color-border, #e4e4e7);
    display: grid;
    gap: 0.15rem;
}

/* ---- Grid ---- */

.grid-2 {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-lg);
}

@media (min-width: 768px) {
    .grid-2 {
        grid-template-columns: 1fr 1fr;
    }
}

/* ---- Month Selector ---- */

.month-selector {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
    font-size: var(--text-sm);
}

.month-selector a {
    padding: var(--space-xs) var(--space-sm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    transition: background 0.15s;
}

.month-selector a:hover {
    background: var(--color-bg-secondary);
    text-decoration: none;
}

.month-selector .current {
    font-weight: 600;
    color: var(--color-text);
}

/* ---- Blazor error boundary ---- */

.blazor-error-boundary {
    background: var(--color-danger);
    padding: var(--space-md) var(--space-md) var(--space-md) var(--space-2xl);
    color: #ffffff;
    border-radius: var(--radius-md);
}

.blazor-error-boundary::after {
    content: "An error has occurred.";
}

/* ── PersonDetail redesign ──────────────────────────────────────────────────
   Hero strip, signature sections, alignment pills, tenure timeline, filtered
   votes table. All additive to the existing layout system (no rewrites to
   shared tokens).
*/

/* Hero */
.person-hero {
    padding: 1.25rem 0 1.5rem;
    border-bottom: 1px solid var(--v2-rule, #e2e8f0);
    margin-bottom: 1.5rem;
}
.person-hero__title-row { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.person-hero__name { font-size: clamp(1.5rem, 3vw, 2.25rem); font-weight: 700; margin: 0; }
.person-hero__status {
    display: inline-block; padding: 0.15rem 0.55rem; font-size: 0.7rem;
    font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
    border-radius: 999px;
}
.person-hero__status--active   { background: #dcfce7; color: #166534; }
.person-hero__status--inactive { background: #e5e7eb; color: var(--color-text-secondary); }

.person-hero__lead {
    margin: 0.65rem 0 0.9rem; font-size: 1.05rem; line-height: 1.5;
    color: var(--color-text-secondary); max-width: 62ch;
}
.person-hero__lead--derived { color: var(--color-text-muted); font-style: italic; }
.person-hero__lead-tag {
    display: inline-block; margin-left: 0.35rem; padding: 0 0.4rem;
    font-size: 0.65rem; font-weight: 700; letter-spacing: 0.05em;
    background: #f1f5f9; color: var(--color-text-secondary); border-radius: 4px; vertical-align: middle;
}

.person-hero__counters {
    display: flex; flex-wrap: wrap; gap: 0.4rem 1.25rem;
    font-size: 0.85rem; color: var(--color-text-secondary);
}
.person-hero__counter strong { color: var(--color-text); font-weight: 700; margin-right: 0.2rem; }
.person-hero__counter em { font-style: normal; color: #94a3b8; font-variant-numeric: tabular-nums; }

/* Stand-for section */
.stand-for__block { margin-top: 1.25rem; }
.stand-for__block:first-child { margin-top: 0; }
.stand-for__subtitle {
    font-size: 0.95rem; font-weight: 600; margin: 0 0 0.6rem;
    display: flex; align-items: baseline; gap: 0.55rem; flex-wrap: wrap;
}

/* Signature issue tags */
.sigtag-chips { list-style: none; padding: 0; margin: 0;
    display: flex; flex-wrap: wrap; gap: 0.4rem; }
.sigtag-chip {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.3rem 0.7rem; background: #f8fafc; border: 1px solid #e2e8f0;
    border-radius: 999px; font-size: 0.85rem;
}
.sigtag-chip__label { color: var(--color-text); }
.sigtag-chip__count {
    background: #0f172a; color: #ffffff; padding: 0.05rem 0.45rem;
    border-radius: 999px; font-size: 0.7rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.code-refs { margin-top: 0.7rem; font-size: 0.85rem; color: var(--color-text-secondary);
    display: flex; flex-wrap: wrap; gap: 0.4rem 0.8rem; align-items: baseline; }
.code-refs__label { color: #94a3b8; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; }
.code-refs__ref { font-family: ui-monospace, Consolas, monospace; color: var(--color-text); }
.code-refs__ref .sec-count { margin-left: 0.2rem; }

/* Signature votes */
.sig-votes { list-style: none; padding: 0; margin: 0;
    display: flex; flex-direction: column; gap: 0.5rem; }
.sig-vote {
    display: grid; grid-template-columns: 130px minmax(140px, 1fr) 2fr auto;
    gap: 0.75rem; align-items: baseline;
    padding: 0.6rem 0.75rem; border-left: 3px solid #94a3b8; background: #f8fafc;
    border-radius: 0 6px 6px 0;
}
.sig-vote--lone-dissent   { border-left-color: #dc2626; background: #fef2f2; }
.sig-vote--tiebreaker     { border-left-color: #7c3aed; background: #f5f3ff; }
.sig-vote--sponsored-win  { border-left-color: #0d9488; background: #f0fdfa; }
.sig-vote__kind {
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em;
    color: inherit; white-space: nowrap;
}
.sig-vote--lone-dissent  .sig-vote__kind { color: #b91c1c; }
.sig-vote--tiebreaker    .sig-vote__kind { color: #6d28d9; }
.sig-vote--sponsored-win .sig-vote__kind { color: #0f766e; }
.sig-vote--dissent       .sig-vote__kind { color: var(--color-text-secondary); }
.sig-vote__rationale { font-size: 0.82rem; color: var(--color-text-secondary); }
.sig-vote__title a { color: var(--color-text); font-weight: 500; }
.sig-vote__date { font-size: 0.78rem; color: #94a3b8; white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
    .sig-vote { grid-template-columns: 1fr; gap: 0.25rem; }
}

/* Alignment pills */
.alignment-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.alignment-pair__col { display: flex; flex-direction: column; gap: 0.35rem; }
.alignment-pair__label {
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
    color: var(--color-text-muted); margin-bottom: 0.2rem;
}
.alignment-row {
    display: grid; grid-template-columns: 1fr auto auto;
    gap: 0.5rem; align-items: baseline;
    padding: 0.5rem 0.75rem; background: #f8fafc; border: 1px solid #e2e8f0;
    border-radius: 6px; text-decoration: none; color: inherit;
}
.alignment-row:hover { background: #f1f5f9; }
.alignment-row--close { border-left: 3px solid #16a34a; }
.alignment-row--sharp { border-left: 3px solid #dc2626; }
.alignment-row__name { font-weight: 500; color: var(--color-text); }
.alignment-row__pct { font-weight: 700; color: var(--color-text); font-variant-numeric: tabular-nums; }
.alignment-row__shared { font-size: 0.75rem; color: #94a3b8; font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
    .alignment-pair { grid-template-columns: 1fr; }
}

/* Tenure timeline */
.tenure-timeline { display: flex; flex-direction: column; gap: 0.35rem; margin: 0.5rem 0; }
.tenure-timeline__header {
    display: flex; justify-content: space-between;
    font-size: 0.7rem; color: #94a3b8; font-variant-numeric: tabular-nums;
    margin-left: calc(200px + 0.75rem); margin-right: 100px;
}
.tenure-timeline__row {
    display: grid; grid-template-columns: 200px 1fr 100px;
    gap: 0.75rem; align-items: center; min-height: 28px;
}
.tenure-timeline__body { font-size: 0.85rem; color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tenure-timeline__body a { color: inherit; }
.tenure-timeline__role { display: block; font-size: 0.7rem; color: #94a3b8; }
.tenure-timeline__track {
    position: relative; height: 12px; background: #f1f5f9;
    border-radius: 6px; overflow: hidden;
}
.tenure-timeline__bar {
    position: absolute; top: 0; bottom: 0;
    background: #334155; border-radius: 6px; min-width: 3px;
}
.tenure-timeline__bar--ongoing {
    background: linear-gradient(90deg, #334155 0%, #334155 85%, #16a34a 100%);
}
.tenure-timeline__dates { font-size: 0.75rem; color: var(--color-text-muted); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tenure-timeline__more summary {
    font-size: 0.82rem; color: #0369a1; cursor: pointer;
    padding: 0.35rem 0; margin-top: 0.3rem;
    list-style: none; user-select: none;
}
.tenure-timeline__more summary::before { content: "+ "; }
.tenure-timeline__more[open] summary::before { content: "- "; }
@media (max-width: 640px) {
    .tenure-timeline__row { grid-template-columns: 1fr; gap: 0.1rem; }
    .tenure-timeline__header { display: none; }
    .tenure-timeline__dates { text-align: left; }
}

/* Person meeting context */
.person-meetings__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    margin-bottom: 0.9rem;
}
.person-meetings__lede {
    margin: 0.35rem 0 0;
    max-width: 68ch;
    color: var(--color-text-secondary);
    font-size: 0.92rem;
    line-height: 1.5;
}
.person-meetings__all {
    flex: 0 0 auto;
    color: var(--color-primary);
    font-size: 0.86rem;
    font-weight: 600;
    text-decoration: none;
    margin-top: 0.15rem;
}
.person-meetings__all:hover { color: var(--color-primary-dark); text-decoration: none; }
.person-meetings__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.55rem;
}
.person-meetings__card {
    display: block;
    min-height: 4.2rem;
    padding: 0.7rem 0.8rem;
    border: 1px solid #e2e8f0;
    border-left: 3px solid var(--color-primary);
    border-radius: 6px;
    background: var(--color-bg-card);
    text-decoration: none;
}
.person-meetings__card:hover {
    border-color: #cbd5e1;
    border-left-color: var(--color-primary-dark);
    background: #f8fafc;
}
.person-meetings__name {
    display: block;
    color: var(--color-primary);
    font-weight: 600;
    line-height: 1.25;
}
.person-meetings__role {
    display: block;
    margin-top: 0.25rem;
    color: var(--color-text-muted);
    font-size: 0.78rem;
    line-height: 1.3;
}
@media (max-width: 640px) {
    .person-meetings__header { display: block; }
    .person-meetings__all { display: inline-block; margin-top: 0.65rem; }
}

/* Vote filter + table */
.votes-filter {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
    padding: 0.75rem; background: #f8fafc; border: 1px solid #e2e8f0;
    border-radius: 8px; margin-bottom: 1rem;
}
.votes-filter__q {
    flex: 1 1 200px; padding: 0.4rem 0.6rem; border: 1px solid #cbd5e1;
    border-radius: 6px; font-size: 0.9rem;
}
.votes-filter__select, .votes-filter__date {
    padding: 0.4rem 0.6rem; border: 1px solid #cbd5e1;
    border-radius: 6px; font-size: 0.9rem; background: var(--color-bg-card);
    /* Same overflow guard as .people-filter__select: native <select>
       width follows the widest option, and PersonDetail's body picker
       can carry long body names that would otherwise blow the mobile
       viewport. */
    max-width: 100%;
}
.votes-filter__check {
    display: inline-flex; align-items: center; gap: 0.35rem;
    font-size: 0.85rem; color: var(--color-text-secondary); white-space: nowrap;
}
.votes-filter__btn {
    padding: 0.4rem 0.9rem; background: var(--color-primary); color: #ffffff;
    border: none; border-radius: 6px; font-size: 0.85rem; font-weight: 600;
    cursor: pointer;
}
.votes-filter__btn:hover { background: var(--color-primary-dark); }
.votes-filter__reset {
    font-size: 0.8rem; color: var(--color-text-muted); text-decoration: underline;
    margin-left: 0.5rem;
}

.votes-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
/* Mobile responsive fallback: turn the table into a horizontally
   scrollable strip below 540px. Without this, the 5-column votes /
   attendance tables on PersonDetail overflowed the viewport by ~40px
   on mobile. `display: block` breaks auto-column-balancing but the
   table's short cell content (date / vote / item title / body /
   outcome) renders fine in content-width columns. */
@media (max-width: 540px) {
    .votes-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        max-width: 100%;
        white-space: nowrap;
    }
    .votes-table .meeting-title,
    .votes-table .resultcard__snippet { white-space: normal; }
}
.votes-table th {
    text-align: left; padding: 0.4rem 0.6rem; border-bottom: 2px solid #e2e8f0;
    font-weight: 600; color: var(--color-text-muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em;
}
.votes-table td { padding: 0.55rem 0.6rem; border-bottom: 1px solid #f1f5f9; vertical-align: top; }
.votes-table__date { white-space: nowrap; color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.votes-table__body { color: var(--color-text-muted); }
.votes-table__bucket {
    display: inline-block; padding: 0.1rem 0.5rem; font-size: 0.7rem; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase; border-radius: 4px;
}
.votes-table__bucket--for     { background: #dcfce7; color: #166534; }
.votes-table__bucket--against { background: #fee2e2; color: #b91c1c; }
.votes-table__bucket--other   { background: #e5e7eb; color: var(--color-text-secondary); }

/* Outcome pill (reused across pages) */
.outcome-pill {
    display: inline-block; padding: 0.1rem 0.5rem; font-size: 0.7rem; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase; border-radius: 4px;
}
.outcome-pill--passed { background: #dcfce7; color: #166534; }
.outcome-pill--failed { background: #fee2e2; color: #b91c1c; }

/* ── LLM topic tags ─────────────────────────────────────────────────────────
   Tag strip at top of ItemDetail, right-margin Hot Topics on Home, and
   PersonDetail signature tags reuse the existing .sigtag-chip styles.
*/

/* Item tag strip (above the title) */
.item-tag-strip {
    display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.65rem;
}
.item-tag-strip__chip {
    display: inline-block; padding: 0.2rem 0.6rem;
    font-size: 0.75rem; font-weight: 600; color: var(--color-text);
    background: #f1f5f9; border: 1px solid #cbd5e1;
    border-radius: 999px; text-decoration: none; letter-spacing: 0.01em;
}
.item-tag-strip__chip:hover { background: #e2e8f0; border-color: #94a3b8; }
/* Rank 1 = top pick, slightly more prominent */
.item-tag-strip__chip--rank1 { background: var(--color-primary); color: #ffffff; border-color: var(--color-primary); }
.item-tag-strip__chip--rank1:hover { background: var(--color-primary-dark); border-color: var(--color-primary-dark); }

/* Hot topics aside module */
.home-aside__hot-topics {
    /* Match the home-aside__card visual: same subtle warm-to-cool gradient,
       same border + radius + padding rhythm, so Top 10 Topics and Advanced
       Features read as paired panels in the aside rather than two
       different chrome systems. */
    background: var(--gradient-panel-soft);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 0.9rem 1rem;
    margin-bottom: 0.75rem;
}
.home-aside__hot-title {
    /* Section title - matches .dossier__section-heading (used by "Browse by
       place" on Home) so every section label across the page reads as the
       same heading rhythm. Flex layout retained so the "last N days" window
       label can ride to the right edge. */
    display: flex; align-items: baseline; justify-content: space-between;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--v2-ink-muted);
    margin: 0 0 0.5rem 0;
}
.home-aside__hot-window {
    font-size: 0.7rem; font-weight: 500; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.04em;
}
.home-aside__hot-list { list-style: none; padding: 0; margin: 0; }
.home-aside__hot-row {
    display: flex; justify-content: space-between; align-items: baseline;
    padding: 0.3rem 0; border-bottom: 1px solid #f1f5f9;
}
.home-aside__hot-row:last-child { border-bottom: none; }
.home-aside__hot-label {
    /* Topic name is the clickable signal -> primary palette per the chrome rule.
       Same font / weight / size as .state-link and .category-card__name. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    color: var(--color-primary);
    text-decoration: none;
}
.home-aside__hot-label:hover { color: var(--color-primary-dark); text-decoration: none; }
.home-aside__hot-count {
    font-size: 0.75rem; font-weight: 600; color: var(--color-text-secondary); font-variant-numeric: tabular-nums;
    background: var(--color-bg-secondary); padding: 0.05rem 0.4rem; border-radius: 999px;
}
/* "All topics" footer link, surfaces below the top-10 list. Same primary
   color as the topic links themselves, set apart by margin-top + a small
   font weight bump so it reads as the panel's CTA, not another row. */
.home-aside__hot-all {
    display: inline-block;
    margin-top: 0.6rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--color-border);
    width: 100%;
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 600;
}
.home-aside__hot-all:hover { color: var(--color-primary-dark); text-decoration: none; }

/* Auth pages (signup, signin, profile). Single-column, narrow, focused. */
.auth-shell {
    max-width: 420px; margin: 2rem auto; padding: 1.5rem 1.75rem;
    background: var(--color-bg-card); border: 1px solid #e2e8f0; border-radius: 10px;
}
.auth-shell__title { font-size: 1.5rem; font-weight: 700; margin: 0 0 0.5rem; }
.auth-shell__sub   { color: var(--color-text-secondary); margin: 0 0 1.25rem; font-size: 0.9rem; line-height: 1.5; }
.auth-shell__error {
    background: #fee2e2; color: #b91c1c; padding: 0.6rem 0.85rem;
    border-radius: 6px; margin-bottom: 1rem; font-size: 0.88rem;
}
.auth-shell__ok {
    background: #dcfce7; color: #166534; padding: 0.6rem 0.85rem;
    border-radius: 6px; margin-bottom: 1rem; font-size: 0.88rem;
}
.auth-shell__alt { margin: 1rem 0 0; font-size: 0.85rem; color: var(--color-text-muted); text-align: center; }
.auth-form { display: flex; flex-direction: column; gap: 0.9rem; }
.auth-form label {
    display: flex; flex-direction: column; gap: 0.25rem;
    font-size: 0.85rem; font-weight: 600; color: var(--color-text-secondary);
}
.auth-form input, .auth-form select {
    padding: 0.55rem 0.7rem; border: 1px solid #cbd5e1;
    border-radius: 6px; font-size: 0.95rem; background: var(--color-bg-card);
    font-weight: 400; color: var(--color-text);
}
.auth-form input:disabled { background: #f8fafc; color: var(--color-text-muted); }
.auth-form__hint { font-size: 0.72rem; font-weight: 400; color: var(--color-text-muted); }
.auth-form__strength--weak   { color: #b91c1c; font-weight: 600; }
.auth-form__strength--ok     { color: #b45309; font-weight: 600; }
.auth-form__strength--strong { color: #15803d; font-weight: 600; }
.auth-form__btn {
    margin-top: 0.5rem; padding: 0.6rem 1rem;
    background: var(--color-primary); color: #ffffff; border: none;
    border-radius: 6px; font-size: 0.95rem; font-weight: 600; cursor: pointer;
}
.auth-form__btn:hover { background: var(--color-primary-dark); }
.auth-form__checkbox {
    flex-direction: row; flex-wrap: wrap; align-items: flex-start;
    gap: 0.5rem; font-size: 0.9rem;
}
.auth-form__checkbox input[type="checkbox"] { margin-top: 0.2rem; }
.auth-form__checkbox .auth-form__hint { flex-basis: 100%; margin-left: 1.75rem; }

/* Dev mode footer - renders for users with devmode=1 claim. */
.devmode-footer {
    margin: 2.5rem 0 0; padding: 1rem 1.25rem;
    background: #0f172a; color: #e2e8f0;
    border-radius: 10px; font-size: 0.85rem;
}
.devmode-footer summary {
    display: flex; align-items: center; gap: 0.6rem;
    cursor: pointer; user-select: none;
    font-weight: 600; list-style: none;
}
.devmode-footer summary::-webkit-details-marker { display: none; }
.devmode-footer__badge {
    background: #eab308; color: var(--color-text);
    padding: 0.1rem 0.5rem; border-radius: 4px;
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em;
}
.devmode-footer__count {
    background: #334155; padding: 0.1rem 0.5rem; border-radius: 999px;
    font-variant-numeric: tabular-nums; font-size: 0.75rem;
}
.devmode-footer__total { color: #94a3b8; font-weight: 400; font-size: 0.8rem; }
.devmode-footer__empty { color: #94a3b8; font-style: italic; margin: 0.75rem 0 0; }
.devmode-footer__docs { color: #94a3b8; margin: 0.75rem 0 0; font-size: 0.8rem; }
.devmode-footer__docs a { color: #38bdf8; }

.devmode-table { width: 100%; border-collapse: collapse; margin-top: 0.75rem; }
.devmode-table th, .devmode-table td {
    padding: 0.4rem 0.6rem; border-bottom: 1px solid #1e293b;
    text-align: left; vertical-align: middle;
}
.devmode-table th {
    color: #94a3b8; font-size: 0.7rem;
    text-transform: uppercase; letter-spacing: 0.04em;
    font-weight: 600;
}
.devmode-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.devmode-method {
    background: #1e293b; color: #38bdf8;
    padding: 0.1rem 0.4rem; border-radius: 4px;
    font-family: ui-monospace, Consolas, monospace; font-size: 0.75rem; font-weight: 700;
}
.devmode-path {
    color: #e2e8f0; font-family: ui-monospace, Consolas, monospace;
    font-size: 0.8rem; word-break: break-all;
}
.devmode-status {
    display: inline-block; padding: 0.1rem 0.45rem; border-radius: 4px;
    font-size: 0.72rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.devmode-status--ok  { background: #166534; color: #bbf7d0; }
.devmode-status--4xx { background: #854d0e; color: #fde68a; }
.devmode-status--5xx { background: #b91c1c; color: #fecaca; }
.devmode-status--err { background: #b91c1c; color: #fecaca; }
.devmode-tag {
    display: inline-block; padding: 0.05rem 0.4rem; border-radius: 4px;
    background: #1e293b; color: #94a3b8; font-size: 0.7rem; margin-right: 0.25rem;
}
.devmode-tag--err { background: #7f1d1d; color: #fecaca; }
.devmode-copy {
    background: #1e293b; color: #e2e8f0; border: 1px solid #334155;
    padding: 0.2rem 0.55rem; border-radius: 4px;
    font-size: 0.72rem; cursor: pointer; white-space: nowrap;
}
.devmode-copy:hover { background: #334155; }

/* Profile link inherits the primary-blue .header-link color; this rule
   keeps the heavier weight to mark "this is your account" without breaking
   the unified-blue chrome rule. */
.header-link-profile { font-weight: 600; }

/* Inline tag chips - compact, for list cards. Distinct from the prominent
   .item-tag-strip used at the top of ItemDetail. */
.tag-chips-inline { display: inline-flex; flex-wrap: wrap; gap: 0.25rem; align-items: center; }
.tag-chips-inline__chip {
    display: inline-block; padding: 0.05rem 0.4rem;
    font-size: 0.7rem; font-weight: 500; color: var(--color-text-secondary);
    background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 999px;
    text-decoration: none;
}
.tag-chips-inline__chip:hover { background: #e2e8f0; border-color: #94a3b8; }
.tag-chips-inline__more { font-size: 0.7rem; color: #94a3b8; }

/* Unified result card (Search + Feed + list pages). */
.resultcard {
    padding: 0.85rem 1rem; background: var(--color-bg-card);
    border: 1px solid #e2e8f0; border-radius: 8px;
    margin-bottom: 0.6rem;
    transition: border-color 0.12s ease;
}
.resultcard:hover { border-color: #cbd5e1; }
.resultcard__tags { margin-bottom: 0.4rem; }
.resultcard__title {
    font-size: 1rem; font-weight: 600; line-height: 1.35;
    margin-bottom: 0.35rem;
}
.resultcard__title a {
    color: var(--color-primary);
    text-decoration: underline;
    text-decoration-style: dotted;
    text-decoration-color: var(--color-primary);
    text-underline-offset: 3px;
}
.resultcard__title a:hover {
    color: var(--color-primary-dark);
    text-decoration-style: solid;
    text-decoration-color: var(--color-primary-dark);
}
.resultcard__itemkey {
    margin-left: 0.45rem; font-size: 0.75rem; font-weight: 500;
    color: var(--color-text-muted); font-family: ui-monospace, Consolas, monospace;
}
.resultcard__meta {
    display: flex; flex-wrap: wrap; gap: 0.3rem 0.75rem;
    font-size: 0.78rem; color: var(--color-text-muted);
    align-items: baseline;
}
.resultcard__type {
    background: #f1f5f9; color: var(--color-text-secondary);
    padding: 0.05rem 0.45rem; border-radius: 4px;
    font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
}
.resultcard__place { font-weight: 500; color: var(--color-text-secondary); }
.resultcard__body { color: var(--color-text-secondary); }
.resultcard__date { font-variant-numeric: tabular-nums; white-space: nowrap; }
.resultcard__outcome {
    padding: 0.05rem 0.5rem; border-radius: 4px;
    font-size: 0.7rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
}
.resultcard__outcome--passed   { background: #dcfce7; color: #166534; }
.resultcard__outcome--failed   { background: #fee2e2; color: #b91c1c; }
.resultcard__outcome--tabled   { background: #fef3c7; color: #854d0e; }
.resultcard__outcome--inactive { background: #f1f5f9; color: var(--color-text-muted); }
.resultcard__outcome--neutral  { background: #e5e7eb; color: var(--color-text-secondary); }

/* Consistent vertical rhythm for any list of ResultCards (PeopleList, BodyList,
   ItemList, EventList, Search, Feed, Ripple). Replaces the legacy <table>
   and <div class="card"> patterns across list pages. */
.resultcard-list { display: flex; flex-direction: column; gap: 0.5rem; }

/* Compare page - user-facing error state when the API rejects the request
   (topic too short, timeout, etc). Replaces the misleading "retrieving..."
   placeholder that used to hang when the API returned null. */
.compare__error {
    padding: 0.9rem 1rem; margin: 1rem 0;
    background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px;
    color: #991b1b;
}
.compare__error strong { display: block; margin-bottom: 0.3rem; font-size: 0.95rem; }
.compare__error p { margin: 0; font-size: 0.88rem; color: #b91c1c; }

/* Crystal Ball methodology footnote. Placed at the bottom of the page so the
   predictions are the headline; the "how we scored it" note is available for
   readers who want it but doesn't get in the way of the ranked list above. */
.cb-methodology {
    margin-top: 2.5rem; padding-top: 1.25rem;
    border-top: 1px solid #e2e8f0;
    font-size: 0.85rem; line-height: 1.5;
}
.cb-methodology__title {
    font-size: 0.82rem; font-weight: 600;
    color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.06em;
    margin: 0 0 0.5rem 0;
}
.cb-methodology p { margin: 0; max-width: 720px; }

/* Attendance section on PersonDetail. Inherits the .votes-table grid; only
   needs the filter bar spacing + the attendance-value pill. */
.attendance-filter {
    display: flex; align-items: center; gap: 1rem;
    margin: 0.5rem 0 1rem 0;
    padding: 0.6rem 0.85rem;
    background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px;
}
.attendance-pill {
    display: inline-block; padding: 0.12rem 0.6rem;
    background: #f1f5f9; color: var(--color-text-secondary);
    border-radius: 999px; font-size: 0.78rem; font-weight: 600;
    text-transform: capitalize;
}

/* Search-result hit highlighting inside ResultCard snippets, titles, and
   AI gloss. Subtle amber underline + background so the mark reads as
   emphasis, not as a toxic yellow block across half the paragraph.
   Applied to title + gloss as of 2026-05-10 so the visible card actually
   shows the match - the snippet `<details>` is collapsed by default and
   was hiding every highlight. */
.resultcard__snippet mark,
.resultcard__title mark,
.resultcard__gloss mark {
    background: #fef3c7; color: inherit;
    padding: 0 0.12rem; border-radius: 2px;
    box-shadow: inset 0 -2px 0 #fbbf24;
}

/* Crystal Ball - confidence tier pill, state filter chips, field-team queue
   highlight. All additive: the base .cb-prediction layout is untouched. */
.cb-queue-hint {
    margin: 0.25rem 0 0.9rem;
    font-size: 0.88rem; color: var(--color-text-secondary);
}
.cb-state-chips {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
    margin: 0.5rem 0 1.25rem;
    padding: 0.6rem 0.85rem;
    background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px;
}
.cb-state-chips__label {
    font-size: 0.78rem; color: var(--color-text-muted); margin-right: 0.25rem;
}
.cb-state-chip {
    padding: 0.22rem 0.7rem;
    background: var(--color-bg-card); color: var(--color-text-secondary);
    border: 1px solid #cbd5e1; border-radius: 999px;
    font-size: 0.78rem; text-decoration: none;
    transition: background-color 0.12s ease;
}
.cb-state-chip:hover { background: #f1f5f9; }
.cb-state-chip--active {
    background: #0f172a; color: #ffffff; border-color: #0f172a;
}
.cb-tier {
    display: inline-block; padding: 0.12rem 0.55rem;
    font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.04em; border-radius: 4px; margin-left: 0.3rem;
}
.cb-tier--high   { background: #dcfce7; color: #166534; }
.cb-tier--medium { background: #fef3c7; color: #854d0e; }
.cb-tier--low    { background: #f1f5f9; color: var(--color-text-muted); }
/* Field-team queue: amber left border + stronger rank badge on the top-3 so
   they read as "act on these first" without restructuring the list. */
.cb-prediction--queue {
    border-left: 3px solid #f59e0b;
    background: linear-gradient(to right, #fffbeb 0%, transparent 60%);
}
.cb-prediction__rank--queue {
    background: #f59e0b; color: #78350f; font-weight: 700;
}

/* Ripple - date-window chip row, outcome breakdown chips, bellwether callout. */
.ripple-window-chips {
    display: flex; flex-wrap: wrap; gap: 0.35rem;
    margin: 0.6rem 0 0.25rem;
}
.ripple-window-chip {
    padding: 0.2rem 0.75rem;
    background: var(--color-bg-card); color: var(--color-text-secondary);
    border: 1px solid #cbd5e1; border-radius: 999px;
    font-size: 0.78rem; text-decoration: none;
    font-variant-numeric: tabular-nums;
    transition: background-color 0.12s ease;
}
.ripple-window-chip:hover { background: #f1f5f9; }
.ripple-window-chip--active {
    background: #0d9488; color: #ffffff; border-color: #0d9488;
}
.ripple-outcomes {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
    margin: 0.9rem 0;
}
.ripple-outcomes__label {
    font-size: 0.78rem; color: var(--color-text-muted); margin-right: 0.25rem;
}
.ripple-outcomes__chip {
    padding: 0.15rem 0.65rem;
    border-radius: 999px;
    font-size: 0.78rem; font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.ripple-outcomes__chip--passed { background: #dcfce7; color: #166534; }
.ripple-outcomes__chip--failed { background: #fee2e2; color: #b91c1c; }
.ripple-outcomes__chip--tabled { background: #fef3c7; color: #854d0e; }
.ripple-outcomes__chip--other  { background: #f1f5f9; color: var(--color-text-muted); }
.ripple-bellwether {
    margin: 1rem 0 1.25rem;
    padding: 0.85rem 1rem;
    background: linear-gradient(to right, #ecfeff 0%, #f0fdfa 100%);
    border-left: 3px solid #0d9488;
    border-radius: 6px;
}
.ripple-bellwether__kicker {
    font-size: 0.74rem; font-weight: 700; color: #0f766e;
    text-transform: uppercase; letter-spacing: 0.06em;
    margin-bottom: 0.3rem;
}
.ripple-bellwether__body {
    font-size: 0.92rem; color: var(--color-text); line-height: 1.5;
}
.ripple-bellwether__city {
    white-space: nowrap;
}

/* PeopleList filter bar - "currently serving only" checkbox + body dropdown
   + sort. Same visual pattern as the votes-filter bar on PersonDetail so the
   filter-form language stays consistent across person surfaces. */
.people-filter {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem;
    margin: 0.5rem 0 1.25rem;
    padding: 0.65rem 0.85rem;
    background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px;
    font-size: 0.88rem;
}
.people-filter__check { display: inline-flex; align-items: center; gap: 0.35rem; color: var(--color-text-secondary); }
.people-filter__select, .people-filter__btn {
    padding: 0.25rem 0.55rem; font-size: 0.85rem;
    border: 1px solid #cbd5e1; border-radius: 5px;
    background: var(--color-bg-card); color: var(--color-text);
    /* Native <select> width = widest <option>. Long body names
       ("MILWAUKEE FIRE AND POLICE COMMISSION SUBCOMMITTEE: …") were
       blowing the select past 900px on a 500px mobile viewport, creating
       page-wide horizontal scroll. Cap at parent width so the wrapped
       filter row stays inside the viewport. */
    max-width: 100%;
}
.people-filter__btn {
    background: var(--color-primary); color: #ffffff; border-color: var(--color-primary);
    padding-inline: 0.9rem; cursor: pointer;
}
.people-filter__btn:hover { background: var(--color-primary-dark); border-color: var(--color-primary-dark); }
.people-filter__reset {
    color: var(--color-text-muted); font-size: 0.82rem; text-decoration: underline;
    text-decoration-style: dotted; text-underline-offset: 3px;
}
.cb-prediction__follow {
    margin-top: 0.5rem;
    display: flex; gap: 0.5rem;
}

/* Category landing page hero. Minimal - the page itself is mostly a list. */
.category-hero { margin-bottom: 1.25rem; }
.category-hero__kicker {
    font-size: 0.74rem; font-weight: 700; color: var(--color-text-muted);
    text-transform: uppercase; letter-spacing: 0.06em;
    margin-bottom: 0.35rem;
}
.category-hero__name { font-size: 1.9rem; margin: 0 0 0.35rem; }
.category-hero__stats { margin: 0; color: var(--color-text-secondary); font-size: 0.95rem; }

/* Profile page - tabs + Following section + Alerts placeholder. The profile
   is one of the few pages with real interactive state per user, so it gets
   its own dedicated shell + tab strip. Stays SSR-pure: tabs are just links,
   unfollow is a POST form. */
.profile-shell { max-width: 820px; margin: 0 auto; padding: 0 0 2rem; }
.profile-shell__title { font-size: 1.9rem; margin: 0 0 1rem; }
.profile-tabs {
    display: flex; gap: 0.25rem;
    margin: 0 0 1.5rem; padding: 0;
    border-bottom: 1px solid #e2e8f0;
}
.profile-tab {
    padding: 0.55rem 1rem;
    color: var(--color-text-secondary); text-decoration: none;
    font-size: 0.92rem; font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    display: inline-flex; align-items: center; gap: 0.4rem;
}
.profile-tab:hover { color: var(--color-text); }
.profile-tab--active {
    color: var(--color-text); font-weight: 600;
    border-bottom-color: #0f172a;
}
.profile-tab__badge {
    display: inline-block; padding: 0.05rem 0.45rem;
    background: #e0f2fe; color: #075985;
    border-radius: 999px;
    font-size: 0.72rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.profile-section { margin-bottom: 2rem; }
.profile-section__title { font-size: 1.25rem; margin: 0 0 0.3rem; }
.profile-section__lede { font-size: 0.92rem; margin: 0 0 1.25rem; }
.profile-section__foot { margin-top: 1.5rem; font-size: 0.88rem; }
.profile-empty {
    padding: 1.5rem 1.25rem;
    background: #f8fafc; border: 1px dashed #cbd5e1; border-radius: 8px;
    text-align: center;
}
.profile-empty p { margin: 0.25rem 0; }

.follow-group {
    margin-bottom: 1.75rem;
    padding: 1rem 1.15rem;
    background: var(--color-bg-card);
    border: 1px solid #e2e8f0; border-radius: 8px;
}
.follow-group__title {
    display: flex; align-items: baseline; gap: 0.55rem;
    margin: 0 0 0.2rem; font-size: 0.95rem;
}
.follow-group__kicker { font-weight: 600; color: var(--color-text); }
.follow-group__count {
    display: inline-block; padding: 0.05rem 0.5rem;
    background: #f1f5f9; color: var(--color-text-secondary);
    border-radius: 999px; font-size: 0.74rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.follow-group__hint { font-size: 0.82rem; margin: 0 0 0.75rem; }
.follow-list { list-style: none; padding: 0; margin: 0; }
.follow-item {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 0.5rem 0.75rem;
    align-items: baseline;
    padding: 0.55rem 0;
    border-top: 1px solid #f1f5f9;
}
.follow-item:first-child { border-top: none; }
.follow-item__name {
    font-weight: 600; color: var(--color-text);
    text-decoration: underline; text-decoration-style: dotted;
    text-decoration-color: #94a3b8; text-underline-offset: 3px;
}
.follow-item__name:hover { text-decoration-style: solid; text-decoration-color: #0f172a; }
.follow-item__scope { font-weight: 500; color: var(--color-text-secondary); }
.follow-item__meta { font-size: 0.78rem; color: var(--color-text-muted); }
.follow-item__form { margin: 0; display: inline; }
.follow-item__unfollow {
    padding: 0.2rem 0.7rem; font-size: 0.78rem;
    background: var(--color-bg-card); color: var(--color-text-secondary);
    border: 1px solid #cbd5e1; border-radius: 5px;
    cursor: pointer;
}
.follow-item__unfollow:hover { background: #fee2e2; color: #991b1b; border-color: #fecaca; }

.profile-alerts {
    display: flex; flex-direction: column; gap: 0.65rem;
}
.profile-alerts__row {
    display: grid; grid-template-columns: 1fr auto; gap: 1rem;
    align-items: center;
    padding: 0.9rem 1.15rem;
    background: var(--color-bg-card); border: 1px solid #e2e8f0; border-radius: 8px;
}
.profile-alerts__label strong { display: block; margin-bottom: 0.2rem; }
.profile-alerts__label p { margin: 0; font-size: 0.85rem; }
.profile-alerts__status {
    padding: 0.2rem 0.65rem; font-size: 0.76rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
    border-radius: 4px;
}
.profile-alerts__status--off { background: #fef3c7; color: #854d0e; }
.profile-alerts__status--on  { background: #dcfce7; color: #166534; }

/* PlaceHome "For officeholders" tools card (Serve digest entry point). */
.place-tools { margin: 2rem 0 1rem; }
.place-tools__card {
    display: block;
    padding: 1rem 1.15rem;
    background: linear-gradient(to right, #fff7ed 0%, #fffbeb 100%);
    border: 1px solid #fed7aa; border-left: 3px solid #f97316;
    border-radius: 8px;
    text-decoration: none; color: inherit;
}
.place-tools__card:hover { border-color: #fb923c; text-decoration: none; }
.place-tools__kicker {
    font-size: 0.74rem; font-weight: 700; color: #9a3412;
    text-transform: uppercase; letter-spacing: 0.06em;
    margin-bottom: 0.3rem;
}
.place-tools__title {
    font-size: 1.05rem; font-weight: 600; color: var(--color-text);
    margin-bottom: 0.3rem;
}
.place-tools__body { font-size: 0.9rem; color: var(--color-text-secondary); line-height: 1.5; max-width: 720px; }
.resultcard__ripple, .activity-feed__ripple {
    display: inline-flex; align-items: center; gap: 0.25rem;
    padding: 0.12rem 0.5rem;
    background: #f0fdfa; color: #0d9488;
    border: 1px solid #5eead4;
    border-radius: 999px;
    font-size: 0.72rem; font-weight: 500;
    white-space: nowrap;
    text-decoration: none;
}
.activity-feed__ripple:hover {
    background: #ccfbf1; color: #0f766e; text-decoration: none;
}
.resultcard__snippet {
    margin: 0.45rem 0 0; font-size: 0.88rem; color: var(--color-text-secondary); line-height: 1.5;
}

/* AI-generated one-liner explaining why a result matched. Slightly stronger
   weight than the raw snippet, soft accent tint, sparkle glyph as a subtle
   visual cue this is model-generated prose (not verbatim from the source). */
.resultcard__gloss {
    margin: 0.5rem 0 0;
    padding: 0.45rem 0.65rem;
    background: #f5f3ff; border-left: 3px solid #8b5cf6;
    color: var(--color-text); font-size: 0.9rem; line-height: 1.5;
    border-radius: 0 4px 4px 0;
}
.resultcard__gloss-sparkle {
    margin-right: 0.35rem; opacity: 0.75;
}
/* "Show source passage" collapse. Subtle so it doesn't compete with the gloss. */
.resultcard__passage { margin: 0.4rem 0 0; }
.resultcard__passage summary {
    cursor: pointer; font-size: 0.78rem; color: var(--color-text-muted);
    padding: 0.1rem 0; user-select: none;
}
.resultcard__passage summary:hover { color: var(--color-text-secondary); }
.resultcard__passage .resultcard__snippet { margin-top: 0.25rem; }

/* Streaming-render skeleton for ScopedSearchView during cold Haiku+FTS
   runs. Shows while OnParametersSetAsync awaits; swaps to results when
   the async work completes. Pattern matches /serve's "Generating digest…"
   block so the reader recognizes the shape. */
.scoped-search-loading {
    margin: 1rem 0;
    padding: 1.25rem;
    background: #f5f3ff; border: 1px solid #ddd6fe;
    border-radius: 8px; max-width: 720px;
}
.scoped-search-loading__spinner {
    width: 28px; height: 28px; border-radius: 50%;
    border: 3px solid #e9d5ff; border-top-color: #7c3aed;
    animation: serve-spin 0.9s linear infinite;
}
.scoped-search-loading__text {
    margin: 0.75rem 0 0 0; font-size: 0.95rem;
}
.scoped-search-loading__hint {
    margin: 0.5rem 0 0 0; font-size: 0.82rem; line-height: 1.5;
}

/* Scope chip on /search when a state filter is active. One-click "clear"
   removes the filter by linking to /search?q=<same-query> without the
   states parameter. */
.search-scope-chip {
    display: inline-flex; align-items: center; gap: 0.5rem;
    margin: 0.25rem 0 1rem;
    padding: 0.35rem 0.85rem; border-radius: 999px;
    background: #eff6ff; color: var(--color-primary);
    border: 1px solid #bfdbfe;
    font-size: 0.88rem;
}
.search-scope-chip__clear {
    color: var(--color-primary); text-decoration: none;
    font-weight: 500; cursor: pointer;
    border-left: 1px solid #bfdbfe; padding-left: 0.6rem;
}
.search-scope-chip__clear:hover { color: var(--color-primary-dark); }

/* Freshness filter chip on search results. Rendered whenever a query ran,
   so users understand what window covers the results. Mirrors the
   search-expanded-terms chip row pattern - flat, pill-shaped, inline. */
.search-freshness {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
    margin: 0.25rem 0 0.85rem;
    font-size: 0.88rem; color: var(--color-text-secondary);
}
.search-freshness__label { font-weight: 600; color: var(--color-text-secondary); }
.search-freshness__opt {
    padding: 0.25rem 0.7rem; border-radius: 999px;
    background: #f1f5f9; color: var(--color-text-secondary);
    border: 1px solid #e2e8f0;
    text-decoration: none;
}
.search-freshness__opt:hover { background: #e2e8f0; color: var(--color-text); }
.search-freshness__opt--active {
    background: #eff6ff; color: var(--color-primary); border-color: #bfdbfe;
    font-weight: 600;
}
.search-freshness__opt--active:hover { background: #dbeafe; color: var(--color-primary-dark); }

/* Serve page "generating digest" placeholder. Simple CSS-only spinner keeps
   the no-JS contract intact; page meta-refresh handles the polling. */
.serve-generating {
    margin-top: 1.5rem; padding: 1.25rem;
    background: #f5f3ff; border: 1px solid #ddd6fe;
    border-radius: 8px; max-width: 720px;
}
.serve-generating__spinner {
    width: 28px; height: 28px; border-radius: 50%;
    border: 3px solid #e9d5ff; border-top-color: #7c3aed;
    animation: serve-spin 0.9s linear infinite;
}
@keyframes serve-spin { to { transform: rotate(360deg); } }

/* Home-page category grid: 3 columns x 6 rows = 18 tiles, alphabetical. */
.category-grid {
    /* Fixed 3 cols x 6 rows on desktop / tablet (the canonical 3x6 of 18
       categories); collapse to 2 cols x 9 rows on phones, then 1 col on
       the very smallest viewports. Auto-fit was producing 4 cols at the
       user's desktop width which felt off-grid. */
    display: grid;
    gap: 0.5rem;
    grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 540px) {
    .category-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 360px) {
    .category-grid { grid-template-columns: 1fr; }
}
.category-card {
    /* Tightened padding/gap so the 18-tile grid fits cleanly in narrow
       columns. Background gradient + border match the Hot Topics + Advanced
       Features panels, so the home-page chrome reads as one unified
       surface family rather than three different card systems. */
    display: flex; flex-direction: row; align-items: center; gap: 0.5rem;
    padding: 0.5rem 0.6rem;
    background: var(--gradient-panel-soft);
    border: 1px solid var(--color-border);
    border-radius: 8px; text-decoration: none; color: var(--color-text);
    min-height: 0;
    transition: border-color 0.12s ease, transform 0.12s ease;
}
.category-card:hover { border-color: var(--color-primary); transform: translateY(-1px); }
.category-card__icon { font-size: 1.15rem; line-height: 1; flex: 0 0 auto; }
.category-card__text {
    display: flex; flex-direction: column; gap: 0.1rem;
    flex: 1 1 auto; min-width: 0;
}
/* Card name is the primary clickable signal -> primary palette.
   Long names wrap naturally to a second line rather than truncating with
   ellipsis - tile rows in the grid auto-size to the tallest card so a
   wrapped "Real Estate & Development" doesn't break alignment. */
.category-card__name {
    /* Same font / weight / size as .state-link and .home-aside__hot-label so
       the three Home-page link surfaces (states, topics, categories) read
       as one type system. Tile readability without weight comes from the
       icon + tile chrome around it. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    line-height: 1.2;
    color: var(--color-primary);
    /* No nowrap / ellipsis - allow wrapping. */
    word-break: break-word;
}
.category-card__meta {
    /* Bumped 0.7rem -> 0.8rem for legibility under the 1rem name link.
       Still clearly subordinate (slate, ~80% of the name's size) but no
       longer squinting-small. */
    display: flex; gap: 0.3rem; align-items: baseline;
    font-size: 0.8rem; color: var(--color-text-muted); font-variant-numeric: tabular-nums;
}
.category-card__items { font-weight: 600; color: var(--color-text-secondary); }
.category-card__sep { color: #cbd5e1; }
.category-card--empty { opacity: 0.55; pointer-events: none; }

/* Inline hot-topics strip (PlaceHome, EventDetail): flatten the aside panel into
   a horizontal block that doesn't compete with the main title. Same content as
   the aside variant, different container shape. */
.place-hot-topics-strip { margin: 0.5rem 0 1rem; }
.place-hot-topics-strip .home-aside__hot-topics { background: #f8fafc; border-color: #cbd5e1; }
.place-hot-topics-strip .home-aside__hot-list {
    display: flex; flex-wrap: wrap; gap: 0.35rem 0.75rem;
}
.place-hot-topics-strip .home-aside__hot-row {
    border-bottom: none; padding: 0.15rem 0;
    display: inline-flex; gap: 0.4rem;
}

/* AI summary banner on /search. Subtle, indigo-tinted call-out above results. */
.ai-summary-banner {
    background: linear-gradient(135deg, #eef2ff 0%, #f5f3ff 100%);
    border: 1px solid #c7d2fe;
    border-radius: var(--radius-lg);
    padding: var(--space-md) var(--space-lg);
    margin-bottom: var(--space-lg);
    max-width: 64rem;
}
.ai-summary-banner__header {
    display: flex; align-items: center; gap: var(--space-sm);
    font-size: 0.85rem; color: #4338ca; font-weight: 600;
    margin-bottom: var(--space-xs);
    text-transform: uppercase; letter-spacing: 0.03em;
}
.ai-summary-banner__sparkle { font-size: 1rem; }
.ai-summary-banner__model {
    margin-left: auto; font-size: 0.7rem; font-weight: 500;
    color: var(--color-text-muted); text-transform: none; letter-spacing: 0;
}
.ai-summary-banner__text {
    color: var(--color-text);
    font-size: 0.95rem; line-height: 1.5;
}
/* Loading variant - auto-AI summary streams in 5-10s after content lands.
   The shimmer + "Synthesizing across N documents…" text is what the user
   sees during that gap, so the area reads as "something coming" rather
   than "empty space". Subtle; not a flashy spinner - this is informational
   chrome, not a status modal. */
.ai-summary-banner--loading {
    border-style: dashed;
    background: linear-gradient(135deg, #f5f7ff 0%, #fafafe 100%);
}
.ai-summary-banner__text--shimmer {
    color: var(--color-text-muted);
    font-style: italic;
    background: linear-gradient(90deg,
        rgba(99, 102, 241, 0.0) 0%,
        rgba(99, 102, 241, 0.10) 50%,
        rgba(99, 102, 241, 0.0) 100%);
    background-size: 200% 100%;
    animation: ai-shimmer 1.6s ease-in-out infinite;
}
@keyframes ai-shimmer {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
}
/* Turnstile human-verification gate on /search. Rendered in place of
   results when an anonymous user hits /search without a valid _tv or
   lgd_human_verified cookie. Cloudflare's invisible challenge auto-solves
   for real browsers in <1s; the page then reloads with the token query
   param and the middleware sets the cookies + redirects to the clean URL.
   For the small minority where the challenge surfaces UI, the centered
   layout keeps it clean. */
.turnstile-gate {
    max-width: 30rem;
    margin: 4rem auto;
    text-align: center;
    color: var(--color-text);
}
.turnstile-gate h1 {
    font-size: 1.4rem;
    margin-bottom: 0.5rem;
}
.turnstile-gate p {
    color: var(--color-text-muted);
    margin-bottom: 1.5rem;
}
.turnstile-gate .cf-turnstile {
    display: flex;
    justify-content: center;
    margin: 1rem 0;
}
.turnstile-gate__noscript {
    color: #b91c1c;
    font-size: 0.88rem;
}

/* Two-column /search layout: facet sidebar (left) + results (right). The
   sidebar only renders when the API returned at least one facet dimension
   with hits; otherwise the layout collapses to a single full-width column
   via the --no-sidebar modifier. Mobile: sidebar drops below results so
   the cards stay above the fold. */
.gsearch__layout {
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    gap: var(--space-lg);
    margin-top: var(--space-md);
}
.gsearch__layout--no-sidebar { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 768px) {
    .gsearch__layout { grid-template-columns: minmax(0, 1fr); }
    /* Filters first, then results. The sidebar IS the slicing UI - hiding
       it below the result list on mobile means users have to scroll past
       50 results to discover they can narrow. order:0 keeps the natural
       DOM order (sidebar before results); margin-bottom separates the
       two. Sticky positioning is opt-in via the min-width:769px rule
       above, so we don't need to unstick it here. */
    .gsearch__sidebar {
        order: 0;
        margin-bottom: var(--space-md);
    }
}
.gsearch__sidebar {
    font-size: 0.88rem;
    align-self: start; /* don't stretch full height of results column */
}
/* Sticky filters scoped to desktop only. The original `position: sticky`
   sat in the base rule and appeared AFTER the mobile @media block in the
   cascade - so it overrode the mobile `position: static` override at
   every width and froze the sidebar to the top on phones. Wrapping it in
   min-width keeps the sticky desktop-only without source-order games. */
@media (min-width: 769px) {
    .gsearch__sidebar {
        position: sticky;
        top: var(--space-md);
    }
}
.gsearch__sidebar-header {
    display: flex; align-items: baseline; justify-content: space-between;
    margin-bottom: var(--space-sm);
}
.gsearch__sidebar-title {
    font-weight: 600; font-size: 0.78rem; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--color-text-muted);
}
.gsearch__sidebar-clear {
    font-size: 0.78rem; color: var(--color-primary); text-decoration: none;
}
.gsearch__sidebar-clear:hover { text-decoration: underline; }
.gsearch__facet-group {
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid #e5e7eb;
}
.gsearch__facet-group:last-child { border-bottom: none; }
.gsearch__facet-label {
    font-weight: 600; font-size: 0.72rem; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--color-text-muted);
    margin-bottom: 0.4rem;
}
.gsearch__facet-row {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.3rem 0.4rem; margin: 0 -0.4rem;
    color: var(--color-text); text-decoration: none;
    border-radius: 4px;
    line-height: 1.3;
}
.gsearch__facet-row:hover {
    background: #f3f4f6;
    color: var(--color-text);
}
.gsearch__facet-row--selected {
    background: #eff6ff;
    color: var(--color-primary);
    font-weight: 500;
}
.gsearch__facet-row--selected:hover { background: #dbeafe; }
.gsearch__facet-check {
    flex: 0 0 auto;
    font-size: 0.95rem;
    width: 1rem; text-align: center;
}
.gsearch__facet-name {
    flex: 1 1 auto;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gsearch__facet-count {
    flex: 0 0 auto;
    color: var(--color-text-muted);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}
.gsearch__facet-row--selected .gsearch__facet-count { color: var(--color-primary); }

/* Place events browse: same faceted grammar as /search, but tuned for a
   deterministic meeting calendar rather than text search results. */
.event-browse__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--space-lg);
    padding-top: 1.25rem;
}
.event-browse__signal {
    min-width: 10rem;
    text-align: right;
    color: var(--color-text-muted);
}
.event-browse__signal strong {
    display: block;
    color: var(--color-text);
    font-size: 1.65rem;
    line-height: 1;
    font-weight: 650;
}
.event-browse__signal span {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.82rem;
}
.event-browse__month {
    margin-top: var(--space-md);
}
.event-browse__presets {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin: var(--space-md) 0 0;
}
.event-browse__preset {
    color: var(--color-primary);
    text-decoration: none;
    border: 1px solid #d1d5db;
    border-radius: 999px;
    padding: 0.32rem 0.7rem;
    font-size: 0.88rem;
    background: var(--color-bg-card);
}
.event-browse__preset:hover {
    background: #f8fafc;
    text-decoration: none;
}
.event-browse__preset--active {
    color: #fff;
    background: var(--color-primary);
    border-color: var(--color-primary);
}
.event-browse__results {
    min-width: 0;
}
.event-browse__window {
    color: var(--color-text-muted);
    font-size: 0.9rem;
    font-weight: 600;
    padding-bottom: 0.45rem;
}
.event-browse__toolbar {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--space-md);
    margin-bottom: var(--space-sm);
}
.event-date-jump {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.event-window-search {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
}
.event-window-search input[type="search"] {
    width: min(18rem, 42vw);
    min-height: 2.35rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    padding: 0.35rem 0.55rem;
}
.event-browse__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0.25rem 0 0.75rem;
}
.event-browse__chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    border: 1px solid #d1d5db;
    border-radius: 999px;
    padding: 0.2rem 0.55rem;
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.82rem;
    background: var(--color-bg-card);
}
.event-browse__chip:hover {
    background: #f8fafc;
    text-decoration: none;
}
.event-browse__cards {
    display: grid;
    gap: var(--space-sm);
}
@media (max-width: 768px) {
    .event-browse__header,
    .event-browse__toolbar {
        align-items: stretch;
        flex-direction: column;
    }
    .event-browse__signal {
        text-align: left;
        min-width: 0;
    }
    .event-window-search input[type="search"] {
        width: 100%;
    }
}

/* Refinement chips. Same LLM call that generates the summary returns 4-5
   short drill-down phrases - rendered here as clickable pill chips below
   the summary prose. Click jumps to /search?q=<phrase> while preserving
   the current scope. Indigo accent matches the banner family. */
.ai-summary-banner__refinements {
    display: flex; flex-wrap: wrap; gap: 0.4rem;
    align-items: center;
    margin-top: 0.75rem;
}
.ai-summary-banner__refinements-label {
    font-size: 0.72rem; font-weight: 600;
    color: #4338ca; text-transform: uppercase; letter-spacing: 0.05em;
    margin-right: 0.25rem;
}
.ai-summary-banner__chip {
    display: inline-flex; align-items: center;
    background: white;
    border: 1px solid #c7d2fe;
    color: #4338ca; font-weight: 500; font-size: 0.82rem;
    padding: 0.3rem 0.75rem; border-radius: 999px;
    text-decoration: none;
    transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.ai-summary-banner__chip:hover {
    background: #eef2ff;
    border-color: #818cf8;
    transform: translateY(-1px);
}

/* Expanded-terms chip strip. Shown above /search results to make the query
   rewrite visible: when the user searches "solar panels" and sees results
   containing "photovoltaic", the chip row explains why. Muted styling so it
   doesn't compete with the actual result list. */
.search-expanded-terms {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
    font-size: 0.85rem;
    max-width: 64rem;
}
.search-expanded-terms__label {
    color: var(--color-text-muted);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    font-size: 0.72rem;
    margin-right: var(--space-xs);
}
.search-expanded-terms__chip {
    display: inline-block;
    padding: 2px 10px;
    background: var(--v2-accent-soft, #e8f0f7);
    color: var(--v2-accent, #246cad);
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 500;
    white-space: nowrap;
}



/* --- obfuscated selectors (streaming-bypass safety) --- */
/* ---- Reset ---- */

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

/* ---- Base ---- */

html {
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--color-text);
    background: var(--color-bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Better default line breaking for content prose - balance the last few
       lines of paragraphs and wrap on word boundaries even in tight layouts. */
    text-rendering: optimizeLegibility;
    /* Account for the sticky .x0bb1db-site-header when navigating to in-page anchors
       (#top, #footer, etc.). Without this the header overlays the target. */
    scroll-padding-top: 80px;
}

body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--color-bg);
    color: var(--color-text);
}

/* Links carry the primary navy site-wide. The base rule stays minimal
   (color + hover deepen) so per-class hovers (underline for state-link,
   bg fill for header-link, etc.) don't conflict with the global rule.
   For prose passages that want the polished animated-underline-on-hover,
   add .link--anim on the anchor - see definition below. */
a {
    color: var(--color-primary);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

a:hover {
    color: var(--color-primary-dark);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
}

/* Opt-in: animated baseline-to-full underline. Reserved for prose links
   (where the polish reads as considered rather than busy). Apply with
   <a class="link--anim"> on body-copy passages, not on chrome links. */
.link--anim {
    background-image: linear-gradient(currentColor, currentColor);
    background-position: 0 100%;
    background-repeat: no-repeat;
    background-size: 0 1px;
    text-decoration: none;
    transition: background-size var(--duration-medium) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}
.link--anim:hover {
    text-decoration: none;
    background-size: 100% 1px;
}

/* Headings default to the sans face for in-content h2/h3/etc. The editorial
   .display class (below) opts a heading INTO the Fraunces serif treatment -
   reserved for hero / page-title / section moments where the typographic
   weight should be felt, not just read. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-heading);
    line-height: var(--leading-tight);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--color-text);
}

h1 { font-size: var(--text-3xl); margin-bottom: var(--space-md); }
h2 { font-size: var(--text-2xl); margin-bottom: var(--space-sm); }
h3 { font-size: var(--text-xl);  margin-bottom: var(--space-sm); }

/* ── Editorial display type ──────────────────────────────────────────
   Opt-in serif treatment via .display (paired with size modifiers).
   Uses Fraunces with optical sizing - the variable-font opsz axis
   automatically renders heavier on larger sizes for proper editorial
   weight. Italic variants kept off the wire; if needed later, add to
   the App.razor Google Fonts link. */
.display {
    font-family: var(--font-display);
    font-weight: 500;
    line-height: var(--leading-tight);
    letter-spacing: -0.02em;
    color: var(--color-text);
    font-feature-settings: 'ss01';     /* Fraunces stylistic set 1: refined Q + g */
    font-optical-sizing: auto;
}
.display--1 { font-size: var(--text-display-1); font-weight: 600; line-height: 1.05; letter-spacing: -0.025em; }
.display--2 { font-size: var(--text-display-2); font-weight: 600; line-height: 1.1; }
.display--3 { font-size: var(--text-display-3); font-weight: 500; line-height: 1.15; }

/* Hero page-title pattern: any h1 inside .x0bb1db-site-main with .display gets the
   editorial treatment without needing a size class - falls back to display-1. */
.x0bb1db-site-main h1.display { font-size: var(--text-display-1); font-weight: 600; line-height: 1.05; letter-spacing: -0.025em; }

/* ── Editorial promotion of bespoke hero classes ─────────────────────
   These hero-headline classes ship across many pages (Home, RegionDetail,
   PlaceHome, Newsroom, Coverage, ItemDetail, EventDetail, etc.) using
   the legacy --route-title-* sans treatment. Promoting them to Fraunces
   here means every page gets the editorial lift without per-page edits.
   The hero subhead classes stay in the sans face - serif everywhere is
   newspaper-y; the contrast between serif headline and sans body is what
   gives editorial pages their authority. */
.dossier__headline,
.route-title,
.page-title--hero,
.home-hero__title,
.hero-title,
.brief-shell__title,
.dossier-shell__title,
.gsearch__h1 {
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.05;
    font-optical-sizing: auto;
    font-feature-settings: 'ss01';
}

p { margin-bottom: var(--space-md); }

ul, ol { padding-left: var(--space-lg); margin-bottom: var(--space-md); }

/* Selection: branded primary tint instead of OS default blue/white. Subtle
   detail, but registers as "considered" to anyone selecting text. */
::selection {
    background: var(--color-primary-light);
    color: var(--color-primary-dark);
}

/* Focus rings on interactive elements use the design system focus token.
   Skips elements that opt out via :focus:not(:focus-visible) - keyboard-only
   focus, no ring on mouse click. */
:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-sm);
}

/* ---- Container ---- */

.x0bb1db-container {
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--container-padding);
    width: 100%;
}

/* ---- Header - light, clean, thin border ---- */

/* Header is sticky-on-scroll with a hairline border that strengthens after
   1px of scroll via the position:sticky + a subtle shadow. The
   backdrop-filter glass effect renders on Safari/Chrome/Firefox; the solid
   background fallback keeps non-supporting browsers usable. background-color
   uses a partial-alpha tint so content below shows through faintly when
   the glass is active. */
.x0bb1db-site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    background: color-mix(in srgb, var(--color-bg-card) 88%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--color-border);
    padding: 14px 0;
    transition: box-shadow var(--duration-medium) var(--ease-out),
                border-color var(--duration-medium) var(--ease-out);
}
/* Fallback for older Safari that ignores backdrop-filter - opaque card bg
   keeps the header readable rather than dropping to transparent. */
@supports not (backdrop-filter: blur(12px)) {
    .x0bb1db-site-header { background: var(--color-bg-card); }
}

.x0bb1db-site-header .x0bb1db-container {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    /* Allow the search row to wrap below logo+nav+auth on narrow viewports.
       Without this the search input held ~291px of a 500px viewport,
       forcing the Sign In/Up cluster off-screen and creating page-wide
       horizontal scroll. Mobile rule below sends .header-center to its
       own row. */
    flex-wrap: wrap;
}

.header-center {
    flex: 1;
    display: flex;
    justify-content: center;
    /* Allow this flex item to shrink past its content's intrinsic size,
       which is what was blocking the wrap on mid-width viewports. */
    min-width: 0;
}

.header-center .x0bb1db-search-form {
    max-width: 28rem;
    width: 100%;
}

/* Mobile: push the search input to its own row beneath the logo / place
   pill / auth cluster. Order:99 sends .header-center to the end; the
   flex-basis:100% forces it to fill the line, which (with flex-wrap on
   the container) wraps it. Removes the horizontal overflow on viewports
   below ~720px. */
@media (max-width: 720px) {
    .x0bb1db-site-header .x0bb1db-container { row-gap: var(--space-sm); }
    .header-center {
        order: 99;
        flex-basis: 100%;
    }
    .header-center .x0bb1db-search-form { max-width: none; }
}

.x0bb1db-site-logo {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* Brand link is clickable -> primary palette. Mark + wordmark both
       inherit currentColor from here, so the whole logo lives on the
       primary slate. Hover deepens to primary-dark. */
    color: var(--color-primary);
    font-size: 18px;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    letter-spacing: 0;
}

.x0bb1db-site-logo__mark {
    display: inline-flex;
    align-items: center;
}
.x0bb1db-site-logo__mark svg { display: block; }

.x0bb1db-site-logo__wordmark {
    /* Stylized wordmark: JetBrains Mono (loaded via Google Fonts subset in
       App.razor). Reads "structured / index / data" without screaming
       monospace because we land at weight 600 and only show 12 letters.
       Tight tracking pulls the monospace columns closer to a wordmark feel. */
    font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    font-weight: 600;
    letter-spacing: 0;
}

.x0bb1db-site-logo:hover {
    text-decoration: none;
    color: var(--color-primary-dark);
}

/* Mobile collapse: drop the wordmark, keep the mark. The header-nav
   media query below hides the place pill at the same breakpoint, leaving
   a tight three-element row (mark + search + auth). */
@media (max-width: 720px) {
    .x0bb1db-site-logo__wordmark { display: none; }
}

.x0bb1db-header-right {
    display: flex;
    align-items: center;
    gap: var(--space-md);
}

.header-link {
    font-size: 14px;
    font-weight: 500;
    /* Clickable header text -> primary palette. Hover swaps to a soft
       primary-light fill (not underline) - chrome row treatment. */
    color: var(--color-primary);
    text-decoration: none;
    padding: 7px 12px;
    border-radius: var(--radius-md);
    transition: color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}

.header-link:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
    background: var(--color-primary-light);
}

/* Primary CTA in the header (Sign Up). Solid navy fill with a subtle
   inset highlight so it reads as a "real" button against the chrome. */
.header-link-primary {
    background: var(--color-primary);
    color: #ffffff !important;       /* override the anchor :focus token */
    font-weight: 600;
    box-shadow: var(--shadow-xs), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.header-link-primary:hover {
    background: var(--color-primary-dark);
    color: #ffffff !important;
    box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.header-nav {
    display: flex;
    align-items: center;
    gap: 4px;
    /* margin-left:auto pushes the pill (and the auth tail right after it)
       to the right edge on every page. Without this, on Home (where the
       SearchBar isn't rendered) the pill collapsed left next to the logo
       because only .x0bb1db-header-right carried the auto-margin. */
    margin-left: auto;
}

.header-nav .header-link {
    padding: 6px 10px;
}

/* ---- My-place header pill ------------------------------------------ */
/* Looks like a pill, feels like a link. The icon + caret frame the label
   so the "click to change" affordance is obvious even without a border.
   Background uses a token-driven tinted surface so the pill flips with
   dark mode instead of staying a hardcoded rgba black. */
.header-link-place {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 12px;
    border-radius: var(--radius-full);
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border-light);
    transition: background var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}
.header-link-place:hover { text-decoration: none; }
.header-link-place:hover {
    background: var(--color-primary-light);
    border-color: var(--color-border);
}
/* SVG pin inherits currentColor (slate-700) from the link, replacing the
   platform-red 📍 emoji that fought the rest of the chrome. */
.header-place-icon { font-size: 13px; display: inline-flex; align-items: center; }
.header-place-icon svg { display: block; }
.header-place-label {
    font-weight: 600;
    max-width: 22ch;          /* fits "Choose your place" + most city,ST combos */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.header-place-caret { font-size: 10px; opacity: 0.6; }

@media (max-width: 720px) {
    /* Place pill stays visible at mobile - it's the primary nav affordance.
       Earlier this block hid .header-nav (which once held Newsroom Desk +
       Weekly Brief + For Newsrooms) to declutter the mobile header; those
       were moved into footer / in-page modules, leaving only the pill. With
       a single item, hiding the wrapper would suppress the very thing the
       comment promised to keep visible. Tighten the label instead so the
       pill stays narrow next to the search and auth links. */
    .header-place-label { max-width: 14ch; }
    /* Tighter pill padding so it fits beside the header search at narrow
       widths without collapsing the search input. */
    .header-link-place { padding: 4px 8px; gap: 3px; }
    /* Header link padding tightens too - SignIn / SignOut / Sign Up button. */
    .header-link { padding: 4px 8px; }
}

@media (max-width: 480px) {
    /* Phone viewports: keep the label visible (the pin icon alone is too
       cryptic - "Choose..." or a city,ST is the actual nav cue). Tighten
       max-width hard so it doesn't crowd the auth tail. The dropdown caret
       drops since it's redundant once the rest is compact. */
    .header-place-label { max-width: 10ch; }
    .header-place-caret { display: none; }
    .header-link-place { padding: 4px 6px; }
}

/* ---- /my-place page ------------------------------------------------- */
.my-place { max-width: 820px; margin: 0 auto; }
.my-place__section { margin-top: 2rem; }
.my-place__section--primary { margin-top: 1.5rem; }

.my-place__card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 1.1rem 1.35rem;
    background: var(--color-bg-card);
    box-shadow: var(--shadow-xs);
    transition: border-color var(--duration-medium) var(--ease-out),
                box-shadow var(--duration-medium) var(--ease-out);
}
.my-place__card:hover {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-sm);
}
.my-place__card--primary {
    border-color: var(--color-primary);
    background: var(--color-primary-light);
    box-shadow: var(--shadow-sm);
}
.my-place__card-name { font-size: 1.15rem; font-weight: 600; margin-bottom: 0.35rem; }
.my-place__card-meta { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; font-size: 0.9rem; }
.my-place__card-cta { margin-top: 0.75rem; }

.my-place__address-form { display: flex; gap: 0.5rem; margin-top: 0.5rem; }
.my-place__address-form .x0bb1db-search-input { flex: 1; }

.my-place__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.my-place__grid-card {
    display: block;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.85rem 1rem;
    background: var(--color-bg-card);
    text-decoration: none;
    box-shadow: var(--shadow-xs);
    transition: border-color var(--duration-medium) var(--ease-out),
                box-shadow var(--duration-medium) var(--ease-out),
                transform var(--duration-medium) var(--ease-out);
}
.my-place__grid-card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}
.my-place__grid-name { font-weight: 600; margin-bottom: 0.25rem; }
.my-place__grid-meta { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; font-size: 0.8rem; }

/* Confirmation strip on /your-government when the cookie was set but the
   header hasn't updated yet (SSR render-order quirk). */
.yg__pinned-note {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    margin: 1rem 0;
    background: #ecfdf5;       /* soft green - "we saved your preference" */
    border: 1px solid #a7f3d0;
    border-radius: 6px;
    font-size: 0.9rem;
}

/* ---- Secondary Nav - light with underline active ---- */

.x0bb1db-nav-bar {
    background: var(--color-bg-card);
    padding: 0 32px;
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--color-border);
}

.x0bb1db-nav-bar a {
    color: var(--color-text-secondary);
    text-decoration: none;
    padding: 12px 20px;
    font-size: 14px;
    font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.15s, border-color 0.15s;
}

.x0bb1db-nav-bar a.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.x0bb1db-nav-bar a:hover {
    color: var(--color-text);
    text-decoration: none;
}

/* ---- Main ---- */

.x0bb1db-site-main {
    flex: 1;
    padding: var(--space-xl) 0;
}

/* ---- Footer - 5-column SaaS layout --------------------------------- */
/* Top: brand block + 5 link columns. Bottom: copyright strip with a thin
   hairline above. The brand block carries the mark + wordmark + a one-line
   tagline; the columns are link lists grouped by audience/intent. On
   tablet (<=960px) columns collapse to 3-up with the brand spanning full
   width above; on phone (<=540px) columns collapse to 2-up. */

/* Footer reads as a warm "below-the-fold" surface. The off-white-warm tint
   (--color-bg-warm) is a paper-cream in light mode, cool deep slate in dark.
   Stronger top border anchors it visually as a distinct page section. */
.x0bb1db-site-footer {
    background: var(--color-bg-warm);
    border-top: 1px solid var(--color-border);
    padding: var(--space-2xl) 0 var(--space-lg);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    margin-top: var(--space-2xl);
}

.x0bb1db-site-footer__columns {
    display: grid;
    grid-template-columns: 1.6fr repeat(5, 1fr);
    gap: 2.5rem 1.5rem;
    margin-bottom: var(--space-xl);
}

@media (max-width: 960px) {
    .x0bb1db-site-footer__columns {
        grid-template-columns: repeat(3, 1fr);
        gap: 2rem 1.25rem;
    }
    .x0bb1db-site-footer__brand { grid-column: 1 / -1; }
}

@media (max-width: 540px) {
    .x0bb1db-site-footer__columns {
        grid-template-columns: repeat(2, 1fr);
    }
}

.x0bb1db-site-footer__brand {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.x0bb1db-site-footer__brand-row {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* Footer brand link is clickable -> primary palette, matching the
       header logo. Mark + wordmark both inherit currentColor. */
    color: var(--color-primary);
    text-decoration: none;
    width: max-content;
}
.x0bb1db-site-footer__brand-row:hover { color: var(--color-primary-dark); text-decoration: none; }
.x0bb1db-site-footer__brand-mark {
    display: inline-flex;
    align-items: center;
}
.x0bb1db-site-footer__brand-mark svg { display: block; }
.x0bb1db-site-footer__brand-name {
    /* Same JetBrains Mono treatment as the header wordmark. */
    font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: 0;
}
.x0bb1db-site-footer__brand-tag {
    margin: 0;
    font-size: 0.82rem;
    color: var(--color-text-secondary);
    line-height: 1.5;
    max-width: 28ch;
}

.x0bb1db-site-footer__col {
    /* nav element resets */
}
.x0bb1db-site-footer__col-title {
    margin: 0 0 0.7rem 0;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-secondary);
}
.x0bb1db-site-footer__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.x0bb1db-site-footer__list a {
    /* Clickable -> primary palette per the chrome rule. Hover deepens. */
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.85rem;
    transition: color 120ms ease;
}
.x0bb1db-site-footer__list a:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
}

.x0bb1db-site-footer__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: 0.8rem;
}
.x0bb1db-site-footer__copy { margin: 0; }

/* ---- Theme toggle chip ------------------------------------------- */
/* Lives in the footer bottom bar; cycled by wwwroot/js/theme.js.
   Visually a low-contrast pill that doesn't compete with primary nav.
   Border + bg follow tokens so it reads correctly in both themes. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.4rem 0.85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    background: var(--color-bg-card);
    color: var(--color-text-secondary);
    font-size: 0.78rem;
    font-family: inherit;
    font-weight: 500;
    cursor: pointer;
    line-height: 1;
    box-shadow: var(--shadow-xs);
    transition: border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}
.theme-toggle:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
    box-shadow: var(--shadow-sm);
}
.theme-toggle:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}
.theme-toggle__label {
    /* Hide the text label on very narrow screens - icon stays visible
       as the affordance, the title/aria-label still announces the state. */
    display: inline;
}
@media (max-width: 480px) {
    .theme-toggle__label { display: none; }
}

/* ---- Dark-mode overrides for obfuscated classes ------------------ */
/* These class names are in CssObfuscationService.ObfuscatedClasses, so
   their HTML attributes get rewritten to .x{hash}-foo on non-streaming
   responses. Living in site.css means the obfuscation middleware
   doubles the rules (original + prefixed), so the selectors match in
   both streaming and non-streaming HTML. Equivalent v2.css rules would
   only fire on streaming pages where HTML obfuscation is bypassed.
   Mirror to BOTH the prefers-color-scheme media query and the explicit
   data-theme="dark" attribute - same as the tokens.css pattern. */
:root[data-theme="dark"] .x0bb1db-nav-bar,
:root[data-theme="dark"] .x0bb1db-empty-state,
:root[data-theme="dark"] .x0bb1db-stat-card,
:root[data-theme="dark"] .x0bb1db-card,
:root[data-theme="dark"] .x0bb1db-data-table,
:root[data-theme="dark"] .x0bb1db-data-list {
    background: var(--color-bg-card);
    color: var(--color-text);
    border-color: var(--color-border);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .x0bb1db-nav-bar,
    :root:not([data-theme="light"]) .x0bb1db-empty-state,
    :root:not([data-theme="light"]) .x0bb1db-stat-card,
    :root:not([data-theme="light"]) .x0bb1db-card,
    :root:not([data-theme="light"]) .x0bb1db-data-table,
    :root:not([data-theme="light"]) .x0bb1db-data-list {
        background: var(--color-bg-card);
        color: var(--color-text);
        border-color: var(--color-border);
    }
}

/* ---- Stub / placeholder pages ------------------------------------ */
/* Used by /api, /about, /privacy, /terms, /stats, /for-{audience}*.
   Narrow centered column for readable copy plus a soft "coming soon"
   callout. Real pages keep their own page-specific styles; this is just
   the shared shape so brand-new stubs don't look like 404s. */
.page-stub {
    max-width: 820px;
    margin: 0 auto;
}
.page-stub__body {
    margin-top: var(--space-xl);
    line-height: var(--route-lede-line);
}
.page-stub__body h2 {
    margin: 2rem 0 0.65rem;
    font-size: var(--route-section-title-size);
    line-height: 1.18;
    font-weight: var(--route-title-weight);
    color: var(--color-text);
}
.page-stub__body p { margin: 0 0 0.85rem 0; }
.page-stub__body ul {
    margin: 0 0 1rem 1.25rem;
    padding: 0;
}
.page-stub__body li { margin-bottom: 0.4rem; }
.page-stub__coming-soon {
    margin: 1rem 0 1.5rem 0;
    padding: 1rem 1.25rem;
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    line-height: 1.55;
}

/* ---- About and legal pages --------------------------------------- */
/* Wider editorial shell for the finished About pages. Text remains
   measured; grids and proof strips use the wider canvas. */
.about-page {
    max-width: 1080px;
    margin: 0 auto;
}

.about-hero {
    padding: 1.25rem 0 2rem;
    border-bottom: 1px solid var(--color-border);
}

.about-hero__headline {
    max-width: 980px;
    margin: 0.25rem 0 1rem;
    font-family: var(--font-heading);
    font-size: var(--route-title-size);
    line-height: var(--route-title-line);
    font-weight: var(--route-title-weight);
    letter-spacing: 0;
    color: var(--color-text);
}

.about-hero__lede {
    max-width: 72ch;
    margin: 0;
    font-size: var(--route-lede-size);
    line-height: var(--route-lede-line);
    color: var(--color-text-secondary);
}

.about-signal-strip {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
    margin: 1.75rem 0 3rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
    background: var(--color-bg-card);
}

.about-signal-strip div {
    padding: 1.15rem 1.25rem;
    border-right: 1px solid var(--color-border);
}

.about-signal-strip div:last-child {
    border-right: 0;
}

.about-signal-strip strong {
    display: block;
    font-size: var(--route-metric-size);
    line-height: 1.05;
    color: var(--color-text);
}

.about-signal-strip span {
    display: block;
    margin-top: 0.35rem;
    color: var(--color-text-secondary);
    font-size: 0.9rem;
    line-height: 1.4;
}

.about-section {
    margin-top: 3.5rem;
}

.about-section--split {
    display: grid;
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
    gap: 2.5rem;
    align-items: start;
}

.about-section h2,
.about-founder h2,
.about-cta h2 {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--route-section-title-size);
    line-height: 1.18;
    font-weight: var(--route-title-weight);
    letter-spacing: 0;
    color: var(--color-text);
}

.about-section__copy,
.about-founder,
.about-cta {
    font-size: 1rem;
    line-height: 1.7;
    color: var(--color-text);
}

.about-section__copy p,
.about-founder p,
.about-cta p {
    max-width: 72ch;
    margin: 0 0 1rem;
}

.about-proof-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.85rem;
    margin: 3rem 0 0;
}

.about-proof-card {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 1rem;
    background: var(--color-bg-card);
}

.about-proof-card h3 {
    margin: 0 0 0.45rem;
    font-size: 1rem;
    color: var(--color-text);
}

.about-proof-card p {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 0.9rem;
    line-height: 1.55;
}

.about-founder {
    margin-top: 3.5rem;
    padding: 2rem;
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-primary);
    border-radius: 8px;
    background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
}

.about-founder h2 {
    max-width: 860px;
    margin-bottom: 1rem;
}

.about-cta {
    margin-top: 3.5rem;
    padding: 2rem;
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-primary);
    border-radius: 8px;
    background: var(--color-bg-card);
    color: var(--color-text);
}

.about-cta h2 {
    color: var(--color-text);
}

.about-cta p {
    color: var(--color-text-secondary);
}

.about-cta__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 1.25rem;
}

.about-cta__actions .btn {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: #ffffff;
}

.about-cta__actions .btn:hover {
    border-color: var(--color-primary-dark);
    background: var(--color-primary-dark);
    color: #ffffff;
    text-decoration: none;
}

.legal-page {
    max-width: 820px;
    margin: 0 auto;
}

.legal-hero {
    padding-top: 1rem;
    padding-bottom: 1.5rem;
    border-bottom: 1px solid var(--color-border);
}

.legal-hero h1 {
    margin: 0.25rem 0 0.75rem;
    font-family: var(--font-heading);
    font-size: clamp(2rem, 5vw, 3.2rem);
    line-height: 1.05;
    letter-spacing: 0;
}

.legal-hero p,
.legal-section p,
.legal-section li {
    line-height: 1.65;
}

.legal-hero p {
    max-width: 70ch;
    margin: 0 0 0.75rem;
    color: var(--color-text-secondary);
}

.legal-page__updated {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.legal-section {
    padding-top: 1.6rem;
}

.legal-section h2 {
    margin: 0 0 0.65rem;
    font-size: 1.18rem;
    color: var(--color-text);
}

.legal-section p {
    margin: 0 0 0.9rem;
}

.legal-section ul {
    margin: 0 0 0.9rem 1.25rem;
    padding: 0;
}

.legal-section li {
    margin-bottom: 0.45rem;
}

@media (max-width: 860px) {
    .about-section--split,
    .about-signal-strip,
    .about-proof-grid {
        grid-template-columns: 1fr;
    }

    .about-signal-strip div {
        border-right: 0;
        border-bottom: 1px solid var(--color-border);
    }

    .about-signal-strip div:last-child {
        border-bottom: 0;
    }
}

/* ---- /advanced power-user hub --------------------------------------- */
/* Composite page: embedded components (FeaturedTopics, TrendingRipples)
   stacked above a 2x2 grid of link cards for the page-backed features.
   The grid auto-flows on narrow viewports (single column ~520px and below). */
.advanced { max-width: 1100px; margin: 0 auto; }
.advanced__section { margin-top: 2.5rem; }
.advanced__lede {
    margin: -0.25rem 0 1rem;
    line-height: 1.55;
    max-width: 60ch;
}

.advanced__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}
.advanced__card {
    display: block;
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-bg-card);
    text-decoration: none;
    transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
.advanced__card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    text-decoration: none;
    transform: translateY(-1px);
}
.advanced__card-title {
    color: var(--color-primary);
    font-weight: 600;
    font-size: 1.02rem;
    margin-bottom: 0.35rem;
}
.advanced__card-desc {
    color: var(--color-text-secondary);
    font-size: 0.88rem;
    line-height: 1.5;
}

/* ---- Stats Row ---- */

.stats-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    margin-bottom: 24px;
}

@media (max-width: 768px) {
    .stats-row {
        grid-template-columns: repeat(2, 1fr);
    }
}

.x0bb1db-stat-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 20px;
}

.x0bb1db-stat-card .label {
    font-size: 12px;
    color: var(--color-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.x0bb1db-stat-card .value {
    font-size: 28px;
    font-weight: 700;
    margin-top: 4px;
}

.x0bb1db-stat-card .value.green { color: var(--color-accent); }
.x0bb1db-stat-card .value.red { color: var(--color-danger); }
.x0bb1db-stat-card .value.blue { color: var(--color-primary); }
.x0bb1db-stat-card .value.orange { color: var(--color-warning); }

/* ---- Cards - white with subtle border ---- */

.x0bb1db-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-md);
    transition: border-color 0.15s, box-shadow 0.15s;
}

.x0bb1db-card:hover {
    border-color: #d1d5db;
    box-shadow: var(--shadow-md);
}

.x0bb1db-card-header {
    padding: 16px 20px;
    border-bottom: 1px solid var(--color-border);
    font-weight: 600;
    font-size: 15px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.x0bb1db-card-body {
    padding: 20px;
}

.x0bb1db-card .x0bb1db-card-title {
    font-size: var(--text-lg);
    font-weight: 600;
    margin-bottom: var(--space-xs);
    padding: 0;
}

.x0bb1db-card .x0bb1db-card-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-sm);
}

.x0bb1db-card .x0bb1db-card-meta span + span::before {
    content: " \00b7 ";
}

a.x0bb1db-card {
    display: block;
    color: inherit;
    text-decoration: none;
    padding: var(--space-lg);
}

a.x0bb1db-card:hover {
    text-decoration: none;
}

/* ---- Badges ---- */

.x0bb1db-badge {
    display: inline-block;
    font-size: var(--text-xs);
    font-weight: 600;
    padding: 2px 10px;
    border-radius: 9999px;
    letter-spacing: 0.025em;
}

.x0bb1db-badge-primary { background: var(--color-primary-light); color: var(--color-primary); }
.x0bb1db-badge-success { background: var(--color-accent-light); color: var(--color-accent); }
.x0bb1db-badge-warning { background: var(--color-warning-light); color: var(--color-warning); }
.x0bb1db-badge-danger { background: var(--color-danger-light); color: var(--color-danger); }
.x0bb1db-badge-muted { background: var(--color-bg-secondary); color: var(--color-text-secondary); }

.x0bb1db-badge-green { background: var(--color-accent-light); color: var(--color-accent); }
.x0bb1db-badge-blue { background: var(--color-primary-light); color: var(--color-primary); }

/* ---- Data Table ---- */

.x0bb1db-data-table {
    width: 100%;
    font-size: 14px;
    border-collapse: collapse;
}

.x0bb1db-data-table th {
    text-align: left;
    padding: 10px 12px;
    color: var(--color-text-secondary);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-bottom: 1px solid var(--color-border);
}

.x0bb1db-data-table td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--color-border-light);
}

.x0bb1db-data-table .status-active { color: var(--color-accent); font-weight: 600; }
.x0bb1db-data-table .status-inactive { color: var(--color-danger); font-weight: 600; }

/* ---- Search ---- */

.x0bb1db-search-form {
    display: flex;
    gap: var(--space-sm);
    max-width: 24rem;
    width: 100%;
    /* align-items defaults to stretch - that makes input + button grow to match
       the Turnstile widget's height (~145px) on the GlobalSearch page. Pin items
       to the top so each keeps its intrinsic height. */
    align-items: flex-start;
}

/* Standard screen-reader-only utility. Labels/headings that are redundant with
   surrounding context visually but still useful to assistive tech. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.x0bb1db-search-input {
    flex: 1;
    padding: 0.55rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-family: inherit;
    /* Light mode: pure-white input so it reads as a clean writing surface
       against the slightly-gray panel chrome around it. Dark mode override
       (in v2.css) flips this to slate-200 - same "light writing surface
       on darker panel" effect inverted. */
    background: #ffffff;
    color: var(--color-text);
    box-shadow: var(--shadow-inset);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}

.x0bb1db-search-input:focus,
.x0bb1db-search-input:focus-visible {
    outline: none;
    background: var(--color-bg-card);
    border-color: var(--color-primary);
    box-shadow: var(--focus-ring);
}

.x0bb1db-search-button {
    padding: 0.55rem 1rem;
    background: var(--color-primary);
    color: #ffffff;
    border: none;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    box-shadow: var(--shadow-xs), inset 0 1px 0 rgba(255, 255, 255, 0.15);
    transition: background var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.x0bb1db-search-button:hover {
    background: var(--color-primary-dark);
    box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

/* ---- Home Search Section ---- */

.home-search-section {
    text-align: center;
    padding: var(--space-xl) 0 var(--space-lg);
}

.home-subtitle {
    font-size: var(--text-lg);
    color: var(--color-text-secondary);
    max-width: 50rem;
    margin-inline: auto;
    margin-bottom: var(--space-lg);
}

.home-search-form {
    max-width: 36rem;
    margin-inline: auto;
}

/* ---- Inline Stats ---- */

.inline-stats {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) 0 var(--space-xl);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.inline-stat {
    color: var(--color-text-secondary);
    text-decoration: none;
    transition: color 120ms ease;
}
a.inline-stat:hover,
a.inline-stat:hover strong {
    color: var(--color-primary-dark);
    text-decoration: none;
}
.inline-stat strong {
    /* Default: non-link stat (a span) - number is just visual emphasis,
       not a click affordance, so it stays on the text color. */
    color: var(--color-text);
    font-weight: 600;
}
a.inline-stat strong {
    /* Link variant: primary palette per the chrome rule (clickable = primary). */
    color: var(--color-primary);
}

.inline-stat-sep::after {
    content: "\00b7";
    color: var(--color-border);
}

/* ---- Country / State Directory ---- */

.country-section {
    margin-bottom: var(--space-2xl);
}

.country-heading {
    font-size: var(--text-xl);
    font-weight: 600;
    color: var(--color-text);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-md);
}

.country-heading a {
    /* Country name is a clickable link to the country home -> primary palette. */
    color: var(--color-primary);
    text-decoration: none;
}

.country-heading a:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
}

.country-place-count {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

.browse-link {
    font-size: var(--text-sm);
    margin-bottom: var(--space-sm);
}

.state-list + .browse-link {
    margin-top: var(--space-sm);
}

.state-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-lg);
}

.state-link {
    /* Browse-by-place state links share the same font / weight / size as
       topic links and category tile names so every clickable label across
       the Home page reads as one type system. Weight 400 + base size feels
       lighter and more readable than the 500/0.88rem variant we tried. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    color: var(--color-primary);
    text-decoration: none;
    padding: var(--space-xs) 0;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
}

.state-link:hover {
    text-decoration: underline;
}

.state-count {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

/* ---- State Places (alpha grouped) ---- */

.state-place-count {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

/*  A-Z quick-jump row at top of StatePlaces. Sticky so it stays usable as
    the reader scrolls a long alphabetical list (CA has 579 cities across
    20+ letter groups). Letters with no matching section are shown dimmed
    rather than hidden, so the A-Z row reads in consistent order and absent
    letters are obvious at a glance. */
.alpha-jump {
    position: sticky;
    /* Sit BELOW the sticky .x0bb1db-site-header (z-index 50, ~70px tall) so the
       letter bar isn't covered when scrolled. */
    top: 70px;
    z-index: 5;
    display: flex; flex-wrap: wrap; gap: 4px;
    padding: var(--space-xs) var(--space-sm);
    margin-bottom: var(--space-md);
    /* color-mix carries the token bg with partial alpha so the blur shows
       content scrolling behind. Flips with theme via --color-bg-card. */
    background: color-mix(in srgb, var(--color-bg-card) 92%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: 0.85rem;
}
@supports not (backdrop-filter: blur(6px)) {
    .alpha-jump { background: var(--color-bg-card); }
}
.alpha-jump__link {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 28px; height: 28px;
    padding: 0 6px;
    color: var(--color-primary);
    text-decoration: none;
    font-weight: 600;
    border-radius: 4px;
    transition: background 0.1s;
}
.alpha-jump__link:hover { background: var(--color-primary-light); }
.alpha-jump__link--empty {
    color: var(--color-text-muted);
    opacity: 0.35;
    font-weight: 400;
    cursor: default;
    pointer-events: none;
}

.alpha-group {
    margin-bottom: var(--space-lg);
}

.alpha-heading {
    /* The id="letter-X" anchor lives on this <h2>, not on .alpha-group, so
       scroll-margin-top has to be HERE for the browser to honor it. The
       sticky .alpha-jump bar (~50px) plus the page header (~60px) cover
       roughly 110px from the viewport top, so we offset by 120px to leave
       breathing room - the heading lands just below the chrome instead of
       being cut off above it. */
    scroll-margin-top: 120px;
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text-muted);
    padding-bottom: var(--space-xs);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-sm);
}

.alpha-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-xl);
}

/* A-Z grouping for long alpha lists (TagList). The letter heading is muted
   chrome - it organises the list but isn't itself clickable, so it stays
   off the primary palette. */
.tag-group {
    margin-top: 1.25rem;
}
.tag-group:first-of-type {
    margin-top: 0.75rem;
}
.tag-group__heading {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text-secondary);
    margin: 0 0 0.4rem;
    padding-bottom: 0.2rem;
    border-bottom: 1px solid var(--color-border);
    letter-spacing: 0.04em;
}


.alpha-link {
    font-size: var(--text-base);
    color: var(--color-primary);
    text-decoration: none;
    padding: var(--space-xs) 0;
}

.alpha-link:hover {
    /* Color-shift on hover instead of underline - matches the chrome rule
       (no underlines, only primary -> primary-dark transitions). */
    color: var(--color-primary-dark);
    text-decoration: none;
}

/* ---- Category-filter pill bar (StatePlaces, future PlaceHome / Region pages)
   --- single-row chooser of place types (Municipal / County / Township / etc.).
   Active pill is solid primary; inactive is the gradient card style with
   primary text. Hover deepens. */
.cat-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
    margin-bottom: 1rem;
}
.cat-filter__label {
    font-size: 0.85rem;
    color: var(--color-text-secondary);
    font-weight: 500;
    margin-right: 0.25rem;
}
.cat-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.75rem;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--gradient-panel-soft);
    color: var(--color-primary);
    font-size: 0.85rem;
    font-weight: 500;
    text-decoration: none;
    transition: background 120ms, border-color 120ms, color 120ms;
}
.cat-pill:hover {
    border-color: var(--color-primary);
    text-decoration: none;
}
.cat-pill--active {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
}
.cat-pill--active:hover {
    background: var(--color-primary-dark);
    border-color: var(--color-primary-dark);
    color: #fff;
}
.cat-pill__count {
    opacity: 0.7;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

/* ---- Place Portal Overview ---- */

.place-header {
    margin-bottom: var(--space-md);
}

.place-header h1 {
    margin-bottom: var(--space-xs);
}

/* Meta strip below the place hero - type badge + indexing status + residents
   + state + Set-as-my-place CTA on the right. Replaces the inline-styled
   version that hardcoded #555 / #eef2ff / #fee2e2 colors off-palette. */
.place-meta-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin-top: 0.5rem;
    color: var(--color-text-secondary);
    font-size: 0.95rem;
}
/* Title row: place name h1 + Set-as-my-place CTA aligned baseline. The
   CTA used to sit at the far right of the meta strip via margin-left:auto;
   moved here 2026-05-10 so it reads as a sibling to the place name (close
   to where the user's eye lands first). Wraps to a new line on narrow
   viewports where h1 + button can't both fit. */
.place-header__title-row {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Pill-shaped type badge ("City", "County", "School District", etc.).
   Brand-primary palette by default; --unindexed modifier flips to the
   warning-amber palette to flag "Not yet indexed" places without dropping
   to a hardcoded red. Sits inline in .place-meta-strip and inside the
   covering-county / nearby-place card meta line. */
.place-type-badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 500;
    background: var(--color-primary-light);
    color: var(--color-primary);
}
.place-type-badge--unindexed {
    background: var(--color-warning-light);
    color: var(--color-warning);
}

/* ---- BodyList: featured card + grouped card grid ---------------------
   The page is a "city government glossary" - featured Primary Legislative
   Body card up top, then type-grouped card grid (Committees / Boards /
   Commissions / Advisory / Administrative / Inactive). Each card surfaces
   the body's Description so the page reads as a referenceable list of
   what each body does, not a bare name list. */

/* Featured card: distinct primary-tinted treatment. The Council is the
   thing most readers come here looking for; pulling it out of the grid
   makes that intent obvious. */
.bodies-featured {
    display: block;
    margin: 1.25rem 0 1.5rem;
    padding: 1.5rem 1.75rem;
    background: linear-gradient(135deg, var(--color-primary-light) 0%, #f1f5f9 100%);
    border: 1px solid var(--color-primary);
    border-radius: 12px;
    text-decoration: none;
    color: var(--color-text);
    transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.bodies-featured:hover {
    border-color: var(--color-primary-dark);
    box-shadow: 0 2px 12px rgba(36, 108, 173, 0.12);
    transform: translateY(-1px);
    text-decoration: none;
}
.bodies-featured__kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--color-primary);
}
.bodies-featured__icon {
    font-size: 1.1rem;
}
.bodies-featured__name {
    margin: 0.4rem 0 0;
    font-size: 1.65rem;
    font-weight: 600;
    color: var(--color-primary);
    line-height: 1.2;
}
.bodies-featured__desc {
    margin: 0.75rem 0 0;
    color: var(--color-text);
    font-size: 1rem;
    line-height: 1.55;
    max-width: 50rem;
}
.bodies-featured__cta {
    display: inline-block;
    margin-top: 0.85rem;
    color: var(--color-primary);
    font-weight: 600;
    font-size: 0.9rem;
}

/* Stats row inside the featured card: members + last meeting + next
   meeting. Inline-stat shape (number bold + label) on a hairline row
   that wraps to a new line on narrow viewports. */
.bodies-featured__stats {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.25rem;
    align-items: center;
    margin-top: 1rem;
    padding-top: 0.85rem;
    border-top: 1px solid rgba(36, 108, 173, 0.18);
    color: var(--color-text-secondary);
    font-size: 0.9rem;
}
.bodies-featured__stat strong {
    color: var(--color-text);
    font-weight: 600;
    margin: 0 0.15rem;
}

/* Search-as-you-type input. Single control on the toolbar - the type
   sections below replace the old chip rail / sort dropdown. */
.bodies-toolbar {
    margin: 0 0 1.25rem;
}
.bodies-toolbar__search {
    width: 100%;
    max-width: 32rem;
    padding: 0.6rem 0.85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    font-size: 0.95rem;
    font-family: inherit;
}
.bodies-toolbar__search:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(36, 108, 173, 0.15);
}

/* Grouped sections: heading with type icon + count, card grid below. */
.bodies-group {
    margin-top: 2rem;
}
.bodies-group:first-of-type {
    margin-top: 0.5rem;
}
.bodies-group__heading {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--v2-ink-muted);
    padding-bottom: 0.4rem;
    margin: 0 0 0.85rem 0;
    border-bottom: 1px solid var(--color-border);
}
.bodies-group__icon {
    font-size: 0.95rem;
    margin-right: 0.1rem;
}
.bodies-group__count {
    margin-left: auto;
    font-size: 0.7rem;
    color: var(--color-text-muted);
    font-weight: 500;
    letter-spacing: 0.04em;
    font-variant-numeric: tabular-nums;
    text-transform: none;
}
.bodies-group--inactive {
    opacity: 0.7;
    margin-top: 3rem;
}

/* Card grid: auto-fit so cards adapt to viewport. minmax(280px, 1fr)
   gives ~3-up on a wide main column, 2-up on tablet, 1-up on mobile. */
.bodies-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 0.75rem;
}
.bodies-card {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--gradient-panel-soft);
    text-decoration: none;
    color: var(--color-text);
    transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.bodies-card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}
.bodies-card__name {
    color: var(--color-primary);
    font-weight: 500;
    font-size: 1rem;
    line-height: 1.3;
}
.bodies-card__desc {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 0.85rem;
    line-height: 1.45;
    /* Clamp to 3 lines so cards stay roughly equal height in the grid. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
/* Vendor-sourced description HTML defenses. Body descriptions in
   Legistar/Granicus admin panels can carry: <p>, <a>, <strong>, <em>
   (fine), <ul>/<ol> (extra height, clamp handles), inline styles
   (font-family/size/color often weird), <img>, <table>, <iframe>
   (break card layout). The rules below normalize all of it so card
   chrome stays predictable. */

/* Card description renders as plain text via CardSummary in BodyList -
   no nested HTML to defend against here. The 3-line clamp on
   .bodies-card__desc (above) handles overflow naturally. */

/* Featured card has more space - keep block layout (paragraphs, lists)
   but still cap inline styles + hide media. */
.bodies-featured__desc * {
    max-width: 100%;
    font-size: inherit !important;
    color: inherit !important;
    font-family: inherit !important;
    background: transparent !important;
    word-break: break-word;
    overflow-wrap: anywhere;
}
.bodies-featured__desc p,
.bodies-featured__desc div,
.bodies-featured__desc ul,
.bodies-featured__desc ol { margin: 0 0 0.5rem; padding: 0 0 0 1.25rem; }
.bodies-featured__desc ul,
.bodies-featured__desc ol { padding-left: 1.25rem; }
.bodies-featured__desc p:last-child,
.bodies-featured__desc div:last-child,
.bodies-featured__desc ul:last-child,
.bodies-featured__desc ol:last-child { margin-bottom: 0; }
.bodies-featured__desc img,
.bodies-featured__desc table,
.bodies-featured__desc iframe,
.bodies-featured__desc video,
.bodies-featured__desc embed,
.bodies-featured__desc object,
.bodies-featured__desc form,
.bodies-featured__desc input,
.bodies-featured__desc button { display: none !important; }
.bodies-featured__desc a {
    color: inherit;
    text-decoration: underline;
    pointer-events: none;
}
.bodies-card--inactive .bodies-card__name {
    color: var(--color-text-muted);
}

/* Meeting volume badge on each body card. Shows "12 meetings in 90d"
   when the body has logged any past meetings in the trailing window.
   Subordinate to the name + description; mostly there as a relative
   activity signal across cards in the same group. */
.bodies-card__meetings {
    margin-top: auto;
    padding-top: 0.4rem;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.bodies-card__meetings strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

/* People list: featured leadership cluster + per-person card chrome.
   Reuses .bodies-card-grid + .bodies-card for the main grid; the
   selectors below add the leadership cluster ("Mayor / Vice Mayor /
   President / Chair / Speaker" cards on top) and the secondary
   role/body/votes line each person card carries below the name. */
.people-featured {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.75rem;
    margin: 0 0 1.5rem;
}
.people-featured__card {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--color-primary);
    border-radius: 8px;
    background: linear-gradient(180deg, #f0f6fc 0%, #e6efff 100%);
    text-decoration: none;
    color: var(--color-text);
    transition: border-color 120ms, transform 120ms, box-shadow 120ms;
}
.people-featured__card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}
.people-featured__role {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-primary);
}
.people-featured__name {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--color-text);
    line-height: 1.3;
}
.people-featured__body {
    font-size: 0.82rem;
    color: var(--color-text-secondary);
}
.people-featured__votes {
    margin-top: 0.25rem;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.people-featured__votes strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

/* Role label sits between the name and the body/votes meta strip.
   Slightly muted - it's descriptive, not the click signal. */
.people-card__role {
    font-size: 0.85rem;
    color: var(--color-text-secondary);
    line-height: 1.3;
}
.people-card__meta {
    margin-top: auto;
    padding-top: 0.4rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.6rem;
    align-items: center;
    font-size: 0.78rem;
    color: var(--color-text-muted);
}
.people-card__votes {
    font-variant-numeric: tabular-nums;
}
.people-card__votes strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

/* Calendar wrapper - lives in .place-cal-slot which is positioned via
   grid-template-areas: top of the sidebar column on desktop, top of the
   page stack on mobile. The slot's column width (320px on desktop)
   already constrains the calendar grid - no max-width override needed. */

.place-stats {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.place-stats strong {
    color: var(--color-text-secondary);
    font-weight: 600;
}

.place-search {
    margin-bottom: var(--space-xl);
}

.place-search-form {
    max-width: 32rem;
}

.place-grid {
    display: grid;
    /* Four named slots so the right pane can read top-down as
       topics -> cal -> bodies/people/advanced on desktop, while mobile
       still puts cal above events. Splitting "sidebar" into a topics
       slot + a rest slot lets the calendar slot wedge between them on
       desktop without falling to the bottom. */
    grid-template-columns: 1fr;
    grid-template-areas:
        "topics"
        "cal"
        "main"
        "sidebar";
    gap: var(--space-xl);
}

.place-cal-slot { grid-area: cal; }
.place-main { grid-area: main; }
.place-topics-slot { grid-area: topics; }
.place-sidebar { grid-area: sidebar; }

@media (min-width: 768px) {
    .place-grid {
        grid-template-columns: 1fr 320px;
        grid-template-areas:
            "main topics"
            "main cal"
            "main sidebar";
    }
}

.place-section {
    margin-bottom: var(--space-xl);
}

.place-section-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    /* Hairline divider sits on the wrapper (not the title) when the section
       has a side link - matches the divider on the standalone heading. */
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: 0.75rem;
}

.place-section-header .place-section-title {
    /* Title's own divider is suppressed inside the inline header - the
       wrapper above carries it. */
    padding-bottom: 0;
    border-bottom: none;
    margin-bottom: 0;
}

.x0bb1db-section-all-link {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-primary);
    text-decoration: none;
    text-decoration: none;
    white-space: nowrap;
}

.x0bb1db-section-all-link:hover {
    color: var(--color-primary-dark);
    text-decoration: none;
}

.place-section-title {
    /* Matches .dossier__section-heading (used on Home + Top 10 Topics) so
       every section label across the site reads as one heading rhythm.
       Includes the same hairline divider as that class for a consistent
       section-edge cue. */
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--v2-ink-muted);
    padding-bottom: 0.4rem;
    margin: 0 0 0.75rem 0;
    border-bottom: 1px solid var(--color-border);
}

/* Sub-heading used inside a section-with-multiple-groups (e.g. "Census
   Bureau Regions" / "BEA Regions" inside "Browse by Region"). Quieter
   than the section title - same color but no uppercase / no border. */
.place-section-subhead {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text);
    margin: 1.25rem 0 0.5rem;
}
.place-section > .place-section-subhead:first-of-type {
    /* Tighter top margin when the subhead immediately follows the section
       header divider. */
    margin-top: 0.5rem;
}

.meeting-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border-light);
    /* Default row color is text-color; the visual click signal (primary
       blue) lives on .meeting-title for body/people/legislation rows or
       on .meeting-row__when for event rows. The whole anchor stays
       clickable - the color treatment just signals which span is the
       primary affordance. */
    color: var(--color-text);
    text-decoration: none;
    transition: background 0.1s;
}

.meeting-row:hover {
    text-decoration: none;
    background: var(--color-bg-secondary);
    margin-inline: calc(-1 * var(--space-sm));
    padding-inline: var(--space-sm);
    border-radius: var(--radius-md);
}
/* Inside a row, .meeting-title / .meeting-row__when carry the primary blue
   click signal. Hover deepens them to primary-dark. */
.meeting-row:hover .meeting-title,
.meeting-row:hover .meeting-row__when {
    color: var(--color-primary-dark);
}

.meeting-row-today {
    background: var(--color-primary-light);
    margin-inline: calc(-1 * var(--space-sm));
    padding-inline: var(--space-sm);
    border-radius: var(--radius-md);
    border-bottom-color: transparent;
}

.meeting-title {
    /* Default: primary-blue clickable signal for body/people/legislation
       rows where the title is the only label. In event rows the body
       name is descriptive (date is the click anchor) - the
       .meeting-row--event override below demotes title to text color.
       Font + weight + size match .home-aside__hot-label so every clickable
       record across the page reads as one type system. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    color: var(--color-primary);
}

/* Event row: date/time leads (.meeting-row__when), body name is descriptive.
   Legislation row: file number leads (.meeting-row__id), title is descriptive.
   Same visual treatment - one primary-blue lead element + neutral title.
   Font + weight + size match .meeting-title and .home-aside__hot-label. */
.meeting-row__when,
.meeting-row__id {
    font-family: var(--font-sans);
    color: var(--color-primary);
    font-weight: 400;
    font-size: 1rem;
    white-space: nowrap;
    flex: 0 0 auto;
}
.meeting-row__what {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.meeting-row--event .meeting-title,
.meeting-row--legislation .meeting-title {
    /* Title is descriptive when a primary lead element (when / id) is
       present; the lead element carries the click signal. */
    color: var(--color-text);
    font-weight: 400;
}

.meeting-date {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
}

.meeting-meta {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.x0bb1db-section-more {
    margin-top: var(--space-sm);
    font-size: var(--text-sm);
}

.x0bb1db-section-empty {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    padding: var(--space-sm) 0;
}

/* ---- Mini Calendar ---- */

.cal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--space-sm) 0;
    margin-bottom: var(--space-sm);
}

.cal-month-label {
    font-weight: 600;
    font-size: var(--text-sm);
}

.cal-nav {
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text-secondary);
    text-decoration: none;
    font-size: 16px;
    line-height: 1;
}

.cal-nav:hover {
    background: var(--color-bg-secondary);
    text-decoration: none;
}

.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    text-align: center;
}

.cal-dow {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    padding: 4px 0;
}

.cal-cell {
    font-size: var(--text-xs);
    padding: 6px 2px;
    border-radius: var(--radius-sm);
}

.cal-empty {
    visibility: hidden;
}

.cal-today {
    background: var(--color-primary);
    color: #ffffff;
    font-weight: 700;
}

.cal-has-event {
    font-weight: 700;
    color: var(--color-primary);
    text-decoration: none;
    cursor: pointer;
}

.cal-has-event:hover {
    background: var(--color-primary-light);
    text-decoration: none;
}

.cal-has-event.cal-today {
    background: var(--color-primary);
    color: #ffffff;
}

/* ---- Sidebar Lists ---- */

.sidebar-list {
    display: flex;
    flex-direction: column;
}

.sidebar-link {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) 0;
    font-size: var(--text-sm);
    color: var(--color-primary);
    text-decoration: none;
    border-bottom: 1px solid var(--color-border-light);
}

.sidebar-link:hover {
    text-decoration: underline;
}

/* ---- Region Pages ---- */

.region-intro {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

.region-systems {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xl);
}

.region-system-heading {
    font-size: var(--text-xl);
    font-weight: 600;
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-xs);
}

.region-system-desc {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-md);
}

.region-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-md);
}

.region-card {
    /* Matches the home-aside / category-card / hot-topics card chrome:
       same warm-to-cool gradient + standard border so every clickable card
       on the geo pages reads as the same surface family. */
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-md) var(--space-lg);
    background: var(--gradient-panel-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    text-decoration: none;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}

.region-card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    text-decoration: none;
}

.region-card-name {
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--color-primary);
}

.region-card-meta {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.region-detail-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
}

/* Main + aside split, mirrors Home/StatePlaces. Collapses below 840px. */
.region-detail-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: var(--space-xl);
    align-items: start;
}
.region-detail-aside { min-width: 0; }
@media (max-width: 840px) {
    .region-detail-layout { grid-template-columns: 1fr; }
}

.region-state-list {
    margin-top: var(--space-md);
}

.region-browse-link {
    margin-top: var(--space-md);
    font-size: var(--text-sm);
}

/* ---- Tab Nav (inline) ---- */

.tab-nav {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-lg);
}

.tab-nav a {
    color: var(--color-text-secondary);
    text-decoration: none;
    padding: 10px 20px;
    font-size: 14px;
    font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.15s, border-color 0.15s;
}

.tab-nav a.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.tab-nav a:hover {
    color: var(--color-text);
    text-decoration: none;
}

/* ---- Pagination ---- */

.x0bb1db-pagination {
    display: flex;
    gap: var(--space-md);
    margin-top: var(--space-xl);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border);
}

.x0bb1db-pagination a {
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    background: var(--color-bg-card);
    transition: background 0.15s;
}

.x0bb1db-pagination a:hover {
    background: var(--color-bg-secondary);
    text-decoration: none;
}

/* ---- Breadcrumb ---- */

.x0bb1db-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    list-style: none;
    padding: 0;
    margin-bottom: var(--space-lg);
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.x0bb1db-breadcrumb li + li::before {
    content: "/";
    margin-right: var(--space-xs);
    color: var(--color-text-muted);
}

/* ---- Section ---- */

.x0bb1db-section {
    margin-bottom: var(--space-2xl);
}

.x0bb1db-section-title {
    font-size: var(--text-xl);
    font-weight: 600;
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border);
}

/* ---- Agenda ---- */

.x0bb1db-agenda-section {
    margin-bottom: var(--space-lg);
}

.x0bb1db-agenda-section-title {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text);
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-sm);
}

.x0bb1db-agenda-item {
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border-light);
}

.x0bb1db-agenda-item:last-child {
    border-bottom: none;
}

.x0bb1db-agenda-item-title {
    font-weight: 500;
}

.x0bb1db-agenda-item-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-top: var(--space-xs);
}

/* ---- Vote Tally ---- */

.x0bb1db-vote-tally {
    display: flex;
    gap: var(--space-lg);
    margin-bottom: var(--space-md);
}

.x0bb1db-vote-tally-bucket {
    text-align: center;
}

.x0bb1db-vote-tally-count {
    font-size: var(--text-2xl);
    font-weight: 700;
}

.x0bb1db-vote-tally-label {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.x0bb1db-vote-list {
    list-style: none;
    padding: 0;
}

.x0bb1db-vote-list li {
    padding: var(--space-xs) 0;
    font-size: var(--text-sm);
    display: flex;
    justify-content: space-between;
    border-bottom: 1px solid var(--color-border-light);
}

/* ---- Empty / Error States ---- */

.x0bb1db-empty-state {
    text-align: center;
    padding: var(--space-2xl);
    color: var(--color-text-secondary);
}

.x0bb1db-empty-state-title {
    font-size: var(--text-xl);
    font-weight: 600;
    margin-bottom: var(--space-sm);
}

.error-alert {
    background: var(--color-danger-light);
    border: 1px solid #fecaca;
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    color: var(--color-danger);
    margin-bottom: var(--space-md);
}

/* One-shot flash banner. Rendered by FlashBanner.razor at the top of every
   page, immediately above @Body. Compact (py 12px) so it doesn't shove
   page content visibly down on success cases; the icon column anchors a
   distinct shape per level so the banner reads at a glance. */
.flash-banner {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    padding: 12px var(--space-lg);
    margin-bottom: var(--space-md);
    font-size: var(--text-sm);
    font-weight: 500;
}

.flash-banner__icon {
    flex: 0 0 1.25rem;
    width: 1.25rem;
    height: 1.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 0.875rem;
    font-weight: 700;
    line-height: 1;
}

.flash-banner__text { flex: 1 1 auto; }

.flash-banner--success {
    background: var(--color-accent-light);
    border-color: #a7f3d0;
    color: #065f46;
}
.flash-banner--success .flash-banner__icon {
    background: var(--color-accent);
    color: #fff;
}

.flash-banner--error {
    background: var(--color-danger-light);
    border-color: #fecaca;
    color: var(--color-danger);
}
.flash-banner--error .flash-banner__icon {
    background: var(--color-danger);
    color: #fff;
}

.flash-banner--warning {
    background: var(--color-warning-light);
    border-color: #fde68a;
    color: #92400e;
}
.flash-banner--warning .flash-banner__icon {
    background: var(--color-warning);
    color: #fff;
}

.flash-banner--info {
    background: var(--color-primary-light);
    border-color: #bfdbfe;
    color: var(--color-primary-dark);
}
.flash-banner--info .flash-banner__icon {
    background: var(--color-primary);
    color: #fff;
}

.not-found {
    text-align: center;
    padding: var(--space-2xl);
}

.not-found h1 {
    font-size: 4rem;
    font-weight: 800;
    color: var(--color-text-muted);
}

/* ---- Detail Page ---- */

.x0bb1db-detail-header {
    margin-bottom: var(--space-xl);
}

.x0bb1db-detail-title {
    font-size: var(--text-3xl);
    margin-bottom: var(--space-sm);
}

.x0bb1db-detail-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    align-items: center;
}

.x0bb1db-detail-meta span + span::before {
    content: "\00b7\00a0";
    margin-right: 0.25rem;
    color: var(--color-text-muted);
}

/* ---- Event header: title → meta → location → artifacts → status ---- */

.event-header {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.event-location {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    line-height: 1.4;
}

/* Default sizing for any inline <svg class="icon-sm">. Without this, SVGs
   without explicit width/height fall back to the browser default (300x150)
   and render as enormous icons inside small kicker rows. Contextual rules
   below (.event-location .icon-sm, .meeting-artifact .icon-sm, etc.) keep
   their overrides via specificity. */
.icon-sm {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* /topics flat-list-by-category. One section per category with a heading
   that links to /categories/{slug}, then a wrapping pill list of topics
   each linking to /topics/{slug}. Same hierarchy as the data: category
   then topic. */
.topics-index {
    display: grid;
    gap: var(--space-xl);
    margin-top: var(--space-lg);
}
.topics-index__group { }
.topics-index__cat {
    margin: 0 0 var(--space-sm) 0;
    font-size: 1.05rem;
    letter-spacing: 0.02em;
    color: var(--color-text);
}
.topics-index__cat a {
    color: inherit;
    text-decoration: none;
    border-bottom: 2px solid var(--color-border);
    padding-bottom: 2px;
}
.topics-index__cat a:hover { border-bottom-color: var(--color-primary); }
.topics-index__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}
.topics-index__item { margin: 0; }
.topics-index__link {
    display: inline-block;
    padding: 4px 10px;
    background: var(--color-bg-card, #f8fafc);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    color: var(--color-text);
    text-decoration: none;
    font-size: 0.9rem;
}
.topics-index__link:hover {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

.event-location .icon-sm {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    margin-top: 2px;
    color: var(--color-text-muted);
}

.event-location a {
    color: var(--color-primary);
    word-break: break-all;
}

.event-artifacts,
.meeting-artifacts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.2rem;
}
/* AI-narrative buttons live in a POST form so clicking triggers generation
   on the destination page directly. The form wrapper would otherwise stack
   each button on its own row inside .event-artifacts; reset its display so
   it participates as a normal flex child carrying the button. */
.event-artifact-form {
    display: contents;
}
/* Card variant: tighter spacing inside list cards (EventCard) so the pill
   row doesn't dominate visually next to the title. */
.meeting-artifacts--card {
    margin-top: 0.4rem;
    gap: 0.35rem;
}
.meeting-artifacts--card .meeting-artifact {
    padding: 0.15rem 0.5rem;
    font-size: 0.75rem;
}
/* Row variant: aligned to the right of the wrapping container so the pill
   row sits with the date column rather than below the title. */
.meeting-artifacts--row {
    margin: 0.15rem 0 0.6rem 0;
    padding: 0 0.75rem 0 0.75rem;
}
@media (min-width: 768px) {
    /* Desktop: artifacts (Agenda / Minutes / Video pills) sit inline on
       the same line as the date+title row, aligned to the right edge.
       The mobile fallback margin-top doesn't apply once we're flex-row. */
    .meeting-row-with-artifacts > .meeting-artifacts--row {
        margin: 0;
        padding: 0;
        flex-shrink: 0;
    }
}
.meeting-artifacts--row .meeting-artifact {
    padding: 0.15rem 0.5rem;
    font-size: 0.75rem;
}
/* Container that wraps a meeting-row anchor + a sibling artifacts row.
   Needed because nested <a> is invalid HTML; the outer container just
   stacks them. */
.meeting-row-with-artifacts {
    display: flex;
    /* Mobile-first: stack the row link above its artifact pills. Desktop
       (>=768px) flips to row layout so the pills align to the right
       on the same line as date+title - avoids the doubled vertical
       footprint per meeting row when there's space. */
    flex-direction: column;
}
@media (min-width: 768px) {
    .meeting-row-with-artifacts {
        flex-direction: row;
        align-items: center;
        gap: 0.75rem;
    }
    .meeting-row-with-artifacts > .meeting-row {
        flex: 1 1 auto;
        min-width: 0;
    }
}

/* Section row count pill (e.g. "Sponsors (3 records)"). Previously .x0bb1db-section-count, but
   MapStaticAssets was auto-scoping that class with a hash prefix so the CSS never applied
   to the un-prefixed HTML. Renaming to .sec-count dodges the collision. */
.sec-count {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 400;
    color: var(--color-text-muted);
    margin-left: 0.35rem;
}
.sec-count::before { content: "("; }
.sec-count::after { content: ")"; }

/* Right-floating action link next to a section title. Class name is .sec-action (NOT
   .x0bb1db-section-action) because Blazor's static-assets pipeline auto-scopes classes matching
   .x0bb1db-section-* in CSS but not in the rendered HTML - an asymmetric rewrite that makes targeted
   classes silently stop matching. Same trap the earlier .x0bb1db-section-count rename dodged. */
.x0bb1db-section-title:has(.sec-action),
h2:has(> .sec-action) {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.sec-action {
    margin-left: auto;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 500;
    white-space: nowrap;
}

/* Compare screen: two-column picker with FROM on the left, TO on the right. Radio rows
   stack vertically; on narrow viewports the two columns collapse to a single column. */
.compare-picker__form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
    align-items: start;
}
.compare-picker__col {
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 0.5rem;
    padding: 0.75rem 1rem;
    background: #fafafa;
}
.compare-picker__row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0;
    cursor: pointer;
    font-size: var(--text-sm, 0.875rem);
    border-bottom: 1px solid var(--color-border-subtle, #f3f4f6);
}
.compare-picker__row:last-child { border-bottom: none; }
.compare-picker__row:hover { background: var(--color-bg-card); }
.compare-picker__actions {
    grid-column: 1 / -1;
    text-align: center;
    margin-top: 0.25rem;
}
@media (max-width: 700px) {
    .compare-picker__form { grid-template-columns: 1fr; }
}

/* ---- EventItemDetail: two-column header with outcome pinned right ---- */

.item-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.item-header__info {
    flex: 1 1 60%;
    min-width: 20rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.item-outcome {
    flex: 0 0 auto;
    min-width: 9rem;
    padding: 1rem 1.5rem;
    border-radius: 10px;
    text-align: center;
    border: 1px solid;
}

.item-outcome--passed {
    background: #ecfdf5;
    border-color: #6ee7b7;
    color: #065f46;
}

.item-outcome--failed {
    background: #fef2f2;
    border-color: #fca5a5;
    color: #991b1b;
}

.item-outcome--neutral {
    background: var(--color-surface-alt, #f4f4f5);
    border-color: var(--color-border, #e4e4e7);
    color: var(--color-text-secondary);
}

.item-outcome__label {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.item-outcome__sub {
    font-size: var(--text-xs);
    font-weight: 500;
    margin-top: 0.35rem;
    opacity: 0.85;
}

.vote-voice-note {
    padding: 0.75rem 1rem;
    background: var(--color-surface-alt, #f4f4f5);
    border-left: 3px solid var(--color-border, #e4e4e7);
    border-radius: 4px;
    margin: 0.5rem 0 1rem;
    color: var(--color-text-secondary);
}

.detail-list {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.4rem 1rem;
    margin: 0;
}
.detail-list dt {
    font-weight: 600;
    color: var(--color-text-secondary);
    white-space: nowrap;
}
.detail-list dd {
    margin: 0;
}

.details-link {
    font-size: var(--text-sm);
    color: var(--color-primary);
    white-space: nowrap;
    text-decoration: none;
}

.details-link:hover {
    text-decoration: underline;
}

/* Activity timeline table on ItemDetail. Slightly denser than .x0bb1db-data-table - this is
   history-in-one-place, not a browse surface, so we accept more rows per fold. */
.timeline-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm, 0.875rem);
}
.timeline-table th {
    text-align: left;
    font-weight: 600;
    color: var(--color-text-secondary);
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--color-border, #e5e7eb);
}
.timeline-table td {
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--color-border-subtle, #f3f4f6);
    vertical-align: top;
}
.timeline-table__date {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.timeline-table__action {
    display: inline-block;
    margin-left: 0.5rem;
    color: var(--color-text, inherit);
}
.timeline-table__tally {
    margin-left: 0.4rem;
    font-variant-numeric: tabular-nums;
}
.timeline-table__details {
    text-align: right;
    white-space: nowrap;
}
.timeline-table__ver {
    white-space: nowrap;
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}
.timeline-table__video {
    text-align: center;
    white-space: nowrap;
    font-size: 1rem;
}
.timeline-table__video a {
    text-decoration: none;
    color: var(--color-primary);
}
/* Matter-only rows (no meeting link). We used to dim the date for these but readers asked
   for the dates to remain primary text since they're still authoritative action dates - just
   without a clickable meeting. Keep the row background subtle so meeting-linked rows still
   visually pop as the primary read path. */
.timeline-table__row--matter-only td { background: #fafafa; }
/* Plain-text Action column - no pill, just small tracked-out caps for scannability. */
.timeline-table__action-type {
    font-size: var(--text-xs, 0.75rem);
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--color-text);
    text-transform: uppercase;
}

/* Per-appearance outcome chip - smaller sibling of .item-outcome. Inline with the row. */
.outcome-chip {
    display: inline-block;
    font-size: var(--text-xs, 0.75rem);
    font-weight: 600;
    padding: 0.15rem 0.45rem;
    border-radius: 0.25rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.outcome-chip--passed {
    background: #dcfce7;
    color: #166534;
}
.outcome-chip--failed {
    background: #fee2e2;
    color: #991b1b;
}

/* Attachment type grouping - keeps staff reports visible even when 40 exhibits are attached. */
.attachment-group + .attachment-group {
    margin-top: 1rem;
}
.attachment-group__title {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    color: var(--color-text-secondary);
    margin: 0 0 0.35rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Ordinance full-text block. Preserves monospace layout like the original <pre>, but uses
   a div (not <pre>) so section spans can render with their own typography. `..Header` lines
   in Legistar source become ordinance-text__section - uppercase bold, mini rule above, so
   the ..Number / ..Title / ..Sponsor / ..Analysis / ..Body sections visibly chunk the text. */
.ordinance-text {
    white-space: pre-wrap;
    word-break: break-word;
    background: #fafafa;
    padding: 1rem;
    border-radius: 6px;
    max-height: 520px;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85rem;
    line-height: 1.5;
}
.ordinance-text__section {
    display: block;
    margin-top: 0.9rem;
    padding-top: 0.4rem;
    border-top: 1px solid var(--color-border-subtle, #e5e7eb);
    font-family: var(--font-sans, system-ui);
    font-weight: 700;
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
}
/* First section has no top rule - it sits flush with the pane. */
.ordinance-text > .ordinance-text__section:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

/* Extracted attachment text - similar styling to ordinance-text but for any attachment file. */
.attach-text { border-top: 1px solid var(--color-border-subtle, #e5e7eb); padding-top: 0.5rem; }
.attach-text summary { cursor: pointer; font-size: var(--text-sm, 0.875rem); color: var(--color-primary); margin-bottom: 0.5rem; }
.attach-text__body {
    white-space: pre-wrap;
    word-break: break-word;
    background: #fafafa;
    padding: 1rem;
    border-radius: 6px;
    max-height: 600px;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85rem;
    line-height: 1.55;
}

/* Sponsor chips with per-version dots. Each chip shows sponsor name + an inline row of dots,
   one per matter-version this item ever had. Dot is filled + numbered when the sponsor was
   on that version, hollow + faded otherwise. Dropped sponsors (not on the latest version)
   get a muted chip color so the eye jumps to active sponsors first. */
.sponsor-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.sponsor-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.65rem;
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 999px;
    background: var(--color-bg-card);
    color: var(--color-text, #1f2937);
    text-decoration: none;
    font-size: var(--text-sm, 0.875rem);
    transition: border-color 120ms ease, box-shadow 120ms ease;
}
.sponsor-chip:hover {
    border-color: var(--color-primary);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
    text-decoration: none;
}
.sponsor-chip--dropped {
    background: #f9fafb;
    color: #6b7280;
    border-color: #e5e7eb;
}
.sponsor-chip__name { font-weight: 500; }
.sponsor-chip__badge {
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-secondary);
    padding: 0.05rem 0.35rem;
    border-radius: 3px;
    background: rgba(0,0,0,0.06);
}
.sponsor-chip__versions {
    display: inline-flex;
    gap: 2px;
    margin-left: 0.1rem;
}
.version-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.65rem;
    font-weight: 600;
    line-height: 1;
}
.version-dot--on {
    background: #2563eb;
    color: #fff;
}
.version-dot--off {
    background: transparent;
    color: #d1d5db;
    border: 1px solid #e5e7eb;
}
.sponsor-chips__hint {
    margin-top: 0.5rem;
    font-size: var(--text-xs, 0.75rem);
}

/* Attachment pills - clickable cards with file-type icon + human label + meta (pages/bytes).
   Grid keeps long document titles from collapsing to single-column on mobile; at desktop
   widths 2-3 pills sit side by side for scan-ability. */
.attachment-pills {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 0.5rem;
}
.attach-pill {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 0.5rem;
    text-decoration: none;
    color: var(--color-text, #1f2937);
    background: var(--color-bg-card);
    transition: border-color 120ms ease, box-shadow 120ms ease;
    min-width: 0;
}
.attach-pill:hover {
    border-color: var(--color-primary);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
    text-decoration: none;
}
.attach-pill__icon {
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    border-radius: 0.35rem;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
}
/* Per-kind chip backgrounds removed 2026-05-16: the file-type icon now carries
   its own native brand color (FileKindIcons - red PDF badge, blue Word, etc.)
   and renders identically everywhere. A saturated chip behind a self-colored
   badge is muddy, so the icon box stays transparent and the badge is the
   color signal. (The .attach-pill--{kind} class is still emitted - it keeps
   the .attach-pill__type label tint - just no longer paints the icon box.) */
.attach-pill__label {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    flex: 1 1 auto;
}
.attach-pill__name {
    font-size: var(--text-sm, 0.875rem);
    font-weight: 500;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.attach-pill__meta {
    font-size: var(--text-xs, 0.75rem);
    color: var(--color-text-secondary);
}

/* Primary action pills: crisp inline SVG icons, higher contrast than badges */
.meeting-artifact {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.8rem;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-primary);
    background: var(--color-primary-light);
    border: 1px solid var(--color-bg-tertiary, #e5e7eb);
    border-radius: 6px;
    text-decoration: none;
    transition: background 0.1s ease, border-color 0.1s ease;
}

.meeting-artifact:hover {
    background: var(--color-bg-tertiary, #e5e7eb);
    border-color: var(--color-primary);
    text-decoration: none;
}

/* Inline FileKind suffix on agenda/minutes pills when the file type is NOT the
   default PDF (e.g. "Agenda DOCX" or "Minutes HTML"). Plain colored uppercase
   monospace - matches the .attach-pill__type style used inside ItemDetail's
   attachment grid. Hidden by default for the common-case PDF; renders only
   when AnomalousFileKind() returns non-null (see MeetingArtifacts.razor). */
.meeting-artifact__filekind {
    margin-left: 0.35rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    opacity: 0.75;
}

/* AI / Ripple / Crystal Ball variants - all unified under the slate
   palette as of 2026-05-10. Distinguish via icon + label, not hue. The
   pre-2026-05-10 multi-color treatment (purple AI / teal Ripple / amber
   Crystal Ball) read as a rainbow on dense pages. Now they all default
   to the .meeting-artifact base style; the variant classes survive only
   so existing markup compiles and so we have hooks if a tiny tonal
   distinction (e.g. left-border accent) is ever wanted. */
.meeting-artifact--ai,
.meeting-artifact--ripple {
    /* base style inherited; no overrides */
}

/* ── The LGD Ripple page (R2-R3) ─────────────────────────────────────── */
.ripple-header { border-left: 4px solid #0d9488; padding-left: var(--space-md); }
.ripple-kicker {
    display: inline-flex; align-items: center; gap: 0.4rem;
    font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase;
    font-weight: 700; color: #0d9488;
    margin-bottom: var(--space-xs);
}
.ripple-place { font-weight: 600; color: var(--color-text-secondary); }
.ripple-date  { color: var(--color-text-secondary); font-variant-numeric: tabular-nums; }

.ripple-summary {
    margin: var(--space-lg) 0;
    padding: 0.9rem 1.1rem;
    background: #f8fafc;
    border-left: 3px solid #0d9488;
    border-radius: 4px;
}
.ripple-summary__headline { margin: 0; font-size: 1rem; line-height: 1.5; color: var(--color-text); }
.ripple-summary__empty { color: var(--color-text-secondary); }
.ripple-summary__headline strong { color: #0d9488; font-weight: 700; }
.ripple-summary__headline a { color: #0d9488; text-decoration: underline; }

/* A match = score badge on the left, card on the right. */
.ripple-match {
    display: grid;
    grid-template-columns: 70px minmax(0, 1fr);
    gap: var(--space-md);
    align-items: start;
    margin-bottom: var(--space-md);
}
.ripple-match__score {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 0.6rem 0.4rem;
    background: linear-gradient(180deg, #0d9488 0%, #0f766e 100%);
    color: #f0fdfa;
    border-radius: 8px;
    min-height: 74px;
}
.ripple-match__score-num   { font-size: 1.4rem; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.ripple-match__score-label { font-size: 0.65rem; letter-spacing: 0.1em; text-transform: uppercase; margin-top: 0.25rem; opacity: 0.85; }
.ripple-match__body { min-width: 0; }
.ripple-match__signals {
    margin-top: 0.25rem; padding-left: 0.4rem;
    font-size: 0.8rem; color: var(--color-text-muted);
    display: flex; flex-wrap: wrap; gap: 0.25rem 0.5rem;
}

/* Sub-800px: stack score above card. */
@media (max-width: 800px) {
    .ripple-match { grid-template-columns: 1fr; }
    .ripple-match__score { flex-direction: row; gap: 0.5rem; min-height: 0; padding: 0.4rem 0.75rem; }
}

/* ── R3: timeline + map ─────────────────────────────────────────────── */
.ripple-timeline {
    margin: var(--space-lg) 0;
}
.ripple-timeline__title {
    font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--color-text-muted); font-weight: 600; margin-bottom: 0.5rem;
}
.ripple-timeline__chart {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(8px, 1fr);
    align-items: end;
    gap: 2px;
    height: 120px;
    padding: 0.5rem;
    background: #f8fafc;
    border-radius: 6px;
    border: 1px solid #e5e7eb;
}
.ripple-timeline__bar {
    background: #0d9488;
    border-radius: 2px 2px 0 0;
    min-height: 2px;
    transition: background 0.12s;
    position: relative;
}
.ripple-timeline__bar--empty  { background: #e2e8f0; min-height: 1px; }
.ripple-timeline__bar--seed   { background: #dc2626; min-height: 6px; }
.ripple-timeline__bar:hover   { background: #0f766e; }
.ripple-timeline__axis {
    display: flex; justify-content: space-between;
    font-size: 0.7rem; color: #94a3b8; margin-top: 0.4rem;
    font-variant-numeric: tabular-nums;
}
.ripple-timeline__legend {
    display: flex; gap: 1rem; font-size: 0.75rem; color: var(--color-text-muted); margin-top: 0.35rem;
}
.ripple-timeline__legend-dot {
    display: inline-block; width: 8px; height: 8px; border-radius: 2px;
    vertical-align: middle; margin-right: 0.25rem;
}

.ripple-map {
    margin: var(--space-lg) 0;
    border-radius: 8px; overflow: hidden;
    border: 1px solid #e5e7eb;
    height: 360px;
}
.ripple-map__container {
    width: 100%; height: 100%;
}
.ripple-map__fallback {
    padding: 2rem; text-align: center; color: var(--color-text-muted); font-size: 0.9rem;
}

/* ── R4: per-state spread chart on topic ripple ─────────────────────── */
.ripple-states {
    margin: var(--space-lg) 0;
    padding: 0.75rem 1rem;
    background: #f8fafc;
    border-radius: 8px;
    border: 1px solid #e5e7eb;
}
.ripple-states__title {
    font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--color-text-muted); font-weight: 600; margin-bottom: 0.6rem;
}
.ripple-states__list { list-style: none; padding: 0; margin: 0; }
.ripple-states__row {
    display: grid;
    grid-template-columns: 44px 1fr 40px;
    gap: 0.6rem;
    align-items: center;
    padding: 0.2rem 0;
}
.ripple-states__state {
    font-weight: 700; color: var(--color-text);
    text-decoration: none; font-variant-numeric: tabular-nums;
}
.ripple-states__state:hover { color: #0d9488; text-decoration: underline; }
.ripple-states__bar-wrap {
    background: #e5e7eb; border-radius: 3px; height: 12px; overflow: hidden;
}
.ripple-states__bar {
    height: 100%;
    background: linear-gradient(90deg, #14b8a6 0%, #0d9488 100%);
    border-radius: 3px;
}
.ripple-states__count {
    font-variant-numeric: tabular-nums; color: var(--color-text-secondary);
    font-size: 0.85rem; text-align: right;
}

/* ── Unified embedded-component panel header (TrendingRipples + FeaturedTopics)
     Both panels render in the same kicker / heading / explanation rhythm and
     share neutral card chrome. Earlier each panel had its own rainbow-y
     gradient (teal vs amber), which fought the 3-color palette rule. Now
     both read as quiet white cards with a slate kicker label and a
     standard h2 + lede. The .trending-ripples__list / .featured-topics__grid
     bodies still differ - those are the actual content surfaces. */
.trending-ripples,
.featured-topics {
    margin: var(--space-xl) 0;
    padding: 1.5rem;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}
.trending-ripples__header { margin-bottom: 1rem; }
.trending-ripples__kicker,
.featured-topics__kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.7rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--color-secondary);
    /* Reset the old amber-pill treatment that .featured-topics__kicker
       carried; both kickers are now plain labels. */
    background: transparent;
    padding: 0;
    border-radius: 0;
}
.trending-ripples__title,
.featured-topics__title {
    margin: 0.4rem 0 0.35rem;
    font-size: 1.5rem;
    color: var(--color-text);
    line-height: 1.25;
}
.trending-ripples__sub,
.featured-topics__sub {
    /* No max-width: the panel itself is already constrained by the page
       container. Earlier 46rem clamp produced awkward wrap points
       (e.g. "where it's" then "spreading" on the next line). Let the sub
       fill the container width and wrap naturally. */
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 0.95rem;
    line-height: 1.55;
}
.trending-ripples__list { list-style: none; padding: 0; margin: 0; }
.trending-ripples__row {
    margin-bottom: 0.5rem;
}
.trending-ripples__link {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 0.75rem;
    align-items: center;
    padding: 0.7rem 0.9rem;
    background: var(--color-bg-card);
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.trending-ripples__link:hover {
    border-color: var(--color-primary);
    box-shadow: 0 2px 8px rgba(36, 108, 173, 0.12);
    text-decoration: none;
}
.trending-ripples__label {
    min-width: 0;
}
.trending-ripples__name {
    /* The row's primary clickable signal -> primary palette per the chrome rule. */
    display: block; font-size: 1.05rem; font-weight: 600; color: var(--color-primary);
}
.trending-ripples__category {
    display: block; font-size: 0.75rem; color: var(--color-text-muted); margin-top: 0.1rem;
}
.trending-ripples__stats {
    display: flex; flex-wrap: wrap; gap: 0.35rem 0.75rem;
    font-size: 0.8rem; color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
    justify-content: flex-end;
}
/* Inline stat emphasis is data, not a separate link - keep it on the
   text-color tone rather than a brand accent. */
.trending-ripples__stat strong { color: var(--color-text); }
.trending-ripples__cta {
    /* End-of-row "See map ->" - same link surface as the row, primary blue. */
    font-size: 0.85rem; color: var(--color-primary); font-weight: 600; white-space: nowrap;
}

@media (max-width: 680px) {
    .trending-ripples__link { grid-template-columns: 1fr; gap: 0.3rem; }
    .trending-ripples__stats { justify-content: flex-start; }
    .trending-ripples__cta { text-align: right; }
}

/* ── R6: subscription UI ────────────────────────────────────────── */

/* "Following" state of the ripple button - filled teal vs. the outline
   Follow state. Reuses meeting-artifact shell for layout parity. */
.meeting-artifact--ripple-on {
    background: #0d9488;
    border-color: #0d9488;
    color: #f0fdfa;
    cursor: default;
}
.meeting-artifact--ripple-on:hover {
    background: #0f766e; border-color: #0f766e; color: #f0fdfa;
}
/* When inside a <form>, the button inherits button styling from the browser;
   <button> has more user-agent defaults than <a> (text-align: center, its own
   color/font, vertical-align differences, default margins). Reset to match the
   sibling <a class="meeting-artifact"> rendering byte-for-byte so the AI/Source
   action row reads as one consistent control set. */
form button.meeting-artifact {
    /* CRITICAL: do NOT use `font: inherit` (or `color: inherit`) here. This
       selector has specificity 0,2,2 - higher than `.meeting-artifact` (0,1,0)
       and `.meeting-artifact--ai` (0,1,0). A shorthand `font: inherit` would
       win the font-size / font-weight cascade against `.meeting-artifact`
       (which sets 14px / 500) and the button would render at body 16px / 400.
       Same trap with `color: inherit` and the AI variant's purple.
       Only override the UA defaults `<button>` actually applies on top of
       what `.meeting-artifact` sets - notably the system font-family. */
    font-family: inherit;
    line-height: inherit;
    text-align: left;
    box-sizing: border-box;
    margin: 0;
    cursor: pointer;
    appearance: none;            /* strip native button chrome (Safari) */
    -webkit-appearance: none;
}
form button.meeting-artifact--ripple-on { cursor: pointer; }

/* /my/ripples page list */
.my-ripples__list { list-style: none; padding: 0; margin: 1.5rem 0 0; }
.my-ripples__row {
    display: flex; align-items: center; gap: 1rem;
    padding: 0.85rem 1rem;
    border: 1px solid #e2e8f0; border-radius: 8px;
    background: var(--color-bg-card);
    margin-bottom: 0.5rem;
}
.my-ripples__row:hover { border-color: #5eead4; }
.my-ripples__main { min-width: 0; flex: 1; }
.my-ripples__kind-chip {
    display: inline-block;
    padding: 0.1rem 0.5rem; border-radius: 999px;
    font-size: 0.65rem; font-weight: 700; letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-right: 0.5rem;
}
.my-ripples__kind-chip--topic { background: #f0fdfa; color: #0d9488; }
.my-ripples__kind-chip--item  { background: #eff6ff; color: #2563eb; }
.my-ripples__label { display: inline; }
.my-ripples__label a {
    font-weight: 600; color: var(--color-text); text-decoration: none;
}
.my-ripples__label a:hover { color: #0d9488; text-decoration: underline; }
.my-ripples__context {
    margin-left: 0.4rem; color: var(--color-text-muted); font-size: 0.85rem;
}
.my-ripples__meta {
    margin-top: 0.2rem; color: var(--color-text-muted); font-size: 0.8rem;
    display: flex; flex-wrap: wrap; gap: 0.2rem 0.4rem;
}
.my-ripples__unsub {
    padding: 0.4rem 0.85rem;
    background: var(--color-bg-card); color: var(--color-text-muted);
    border: 1px solid #e2e8f0; border-radius: 6px;
    cursor: pointer; font-size: 0.85rem;
    transition: all 0.12s;
}
.my-ripples__unsub:hover {
    background: #fef2f2; color: #b91c1c; border-color: #fecaca;
}

/* ── The LGD Crystal Ball ── unified under base meeting-artifact style. */
.meeting-artifact--cb { /* base style inherited */ }

.cb-header { border-left: 4px solid #d97706; padding-left: var(--space-md); }
.cb-kicker {
    display: inline-flex; align-items: center; gap: 0.4rem;
    font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase;
    font-weight: 700; color: #d97706;
    margin-bottom: var(--space-xs);
}
.cb-category { font-weight: 600; color: var(--color-text-secondary); }

.cb-summary {
    margin: var(--space-lg) 0;
    padding: 0.9rem 1.1rem;
    background: #fffbeb;
    border-left: 3px solid #d97706;
    border-radius: 4px;
}
.cb-summary__line { margin: 0; font-size: 1rem; line-height: 1.5; color: var(--color-text); }
.cb-summary__line strong { color: #b45309; }
.cb-summary__disclaimer { margin: 0.35rem 0 0; font-size: 0.85rem; }
.cb-summary__empty { color: var(--color-text-secondary); }
.cb-summary__line a { color: #b45309; text-decoration: underline; }

.cb-adopters {
    margin: var(--space-md) 0;
    padding: 0.75rem 1rem;
    background: #f8fafc; border-radius: 8px; border: 1px solid #e5e7eb;
}
.cb-adopters__title {
    font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--color-text-muted); font-weight: 600; margin-bottom: 0.5rem;
}
.cb-adopters__chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.cb-adopter-chip {
    display: inline-flex; align-items: baseline; gap: 0.25rem;
    padding: 0.3rem 0.65rem;
    background: #fee2e2; border: 1px solid #fecaca;
    color: #b91c1c; border-radius: 999px;
    font-size: 0.85rem; text-decoration: none;
    transition: background 0.12s;
}
.cb-adopter-chip:hover { background: #fecaca; text-decoration: none; color: #991b1b; }
.cb-adopter-chip__name { font-weight: 500; }
.cb-adopter-chip__state { font-size: 0.7rem; opacity: 0.75; }
.cb-adopter-chip__count { font-weight: 600; font-variant-numeric: tabular-nums; margin-left: 0.15rem; }
.cb-adopter-chip--more { background: #f1f5f9; border-color: #e2e8f0; color: var(--color-text-muted); cursor: default; }

.cb-map { position: relative; }
.cb-map__legend {
    position: absolute; bottom: 8px; left: 8px;
    background: rgba(255,255,255,0.95);
    padding: 0.3rem 0.6rem; border-radius: 6px;
    font-size: 0.75rem; color: var(--color-text-secondary);
    display: flex; flex-direction: column; gap: 0.2rem;
    box-shadow: 0 1px 3px rgba(0,0,0,0.15);
    z-index: 1000;
}
.cb-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; vertical-align: middle; margin-right: 0.35rem; }
.cb-dot--adopter    { background: #dc2626; }
.cb-dot--prediction { background: #f59e0b; border: 1px solid #d97706; }

/* Prediction cards: rank badge + content + factor breakdown */
.cb-prediction {
    display: grid;
    grid-template-columns: 54px minmax(0, 1fr);
    gap: var(--space-md);
    align-items: start;
    margin-bottom: var(--space-md);
    padding: 1rem 1.1rem;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    background: var(--color-bg-card);
    transition: border-color 0.12s;
}
.cb-prediction:hover { border-color: #fcd34d; }
.cb-prediction__rank {
    display: flex; align-items: center; justify-content: center;
    padding: 0.6rem 0;
    background: linear-gradient(180deg, #f59e0b 0%, #d97706 100%);
    color: #fffbeb;
    border-radius: 8px;
    font-size: 1.5rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
    min-height: 80px;
}
.cb-prediction__body { min-width: 0; }
.cb-prediction__head {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
    margin-bottom: 0.6rem;
}
.cb-prediction__name {
    font-size: 1.1rem; font-weight: 600; color: var(--color-text);
    text-decoration: none;
}
.cb-prediction__name:hover { color: #b45309; text-decoration: underline; }
.cb-prediction__state {
    font-size: 0.85rem; color: var(--color-text-muted); font-weight: 500;
}
.cb-prediction__pop {
    font-size: 0.8rem; color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    padding: 0.1rem 0.45rem; background: #f1f5f9; border-radius: 4px;
}
.cb-prediction__score {
    margin-left: auto;
    display: flex; flex-direction: column; align-items: flex-end;
}
.cb-prediction__score-num {
    font-size: 1.2rem; font-weight: 700; color: #b45309;
    line-height: 1; font-variant-numeric: tabular-nums;
}
.cb-prediction__score-label {
    font-size: 0.65rem; color: #94a3b8;
    letter-spacing: 0.08em; text-transform: uppercase;
}
.cb-prediction__reasoning {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.5rem;
    margin: 0.5rem 0;
}
.cb-factor { display: grid; grid-template-columns: auto 1fr auto; gap: 0.35rem; align-items: center; font-size: 0.78rem; color: var(--color-text-secondary); }
.cb-factor__label { min-width: 6rem; }
.cb-factor__bar { height: 6px; background: #fef3c7; border-radius: 3px; overflow: hidden; }
.cb-factor__fill { display: block; height: 100%; background: linear-gradient(90deg, #fbbf24 0%, #d97706 100%); border-radius: 3px; }
.cb-factor__value { font-variant-numeric: tabular-nums; font-weight: 500; color: var(--color-text); min-width: 2.2rem; text-align: right; }

.cb-prediction__evidence { font-size: 0.82rem; margin-top: 0.35rem; }

/* ── Featured Topics - curated hot-button issues. Container + kicker/title/sub
     styles now live in the unified .trending-ripples + .featured-topics block
     above (search this file for "Unified embedded-component panel header"). */
.featured-topics__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 0.75rem;
    margin-top: 1rem;
}
.featured-topic {
    background: var(--color-bg-card);
    border: 1px solid #f1f5f9;
    border-radius: 10px;
    padding: 0.9rem 1rem;
    display: flex; flex-direction: column;
}
.featured-topic__header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.35rem; }
.featured-topic__emoji { font-size: 1.4rem; }
.featured-topic__name { margin: 0; font-size: 1.05rem; color: var(--color-text); }
.featured-topic__desc {
    margin: 0 0 0.7rem; color: var(--color-text-secondary); font-size: 0.85rem;
    flex: 1; line-height: 1.4;
}
.featured-topic__actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }
/* Both action chips are clickable -> primary palette per the chrome rule.
   Earlier they used teal (ripple) + amber (crystal ball) for visual
   differentiation, but the rule wins: identical color, the labels
   ("See the Ripple" / "Crystal Ball") carry the meaning. */
.featured-topic__action {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.35rem 0.7rem;
    font-size: 0.8rem; font-weight: 500;
    border-radius: 6px;
    text-decoration: none;
    border: 1px solid var(--color-primary);
    background: var(--color-primary-light);
    color: var(--color-primary);
    transition: background 0.12s, color 0.12s;
}
.featured-topic__action:hover {
    background: var(--color-primary);
    color: #fff;
    text-decoration: none;
}
/* --ripple and --cb modifiers are now structural-only (kept on the markup
   in case future styling wants to differentiate them); no color overrides. */

@media (max-width: 680px) {
    .cb-prediction { grid-template-columns: 1fr; }
    .cb-prediction__rank { min-height: 0; padding: 0.3rem 0.7rem; font-size: 1rem; display: inline-flex; width: auto; }
    .cb-prediction__score { margin-left: 0; flex-direction: row; gap: 0.3rem; align-items: baseline; }
}

/* Narrative page (brief / analysis) */
.narrative-kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #6b21a8;
    margin-bottom: 0.25rem;
    white-space: nowrap;
}
.narrative-kicker .icon-sm { width: 16px; height: 16px; flex-shrink: 0; }
.narrative-section p {
    line-height: 1.6;
    margin: 0 0 0.9rem 0;
    max-width: 44rem;
}
.narrative-footer {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    border-top: 1px solid var(--color-border, #e4e4e7);
    margin-top: 1.5rem;
    padding-top: 0.75rem;
    max-width: 44rem;
}

.meeting-artifact .icon-sm {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* ---- Section header with view toggle on the right ---- */

.x0bb1db-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.view-toggle {
    display: inline-flex;
    font-size: var(--text-sm);
    border: 1px solid var(--color-border, #e4e4e7);
    border-radius: 6px;
    overflow: hidden;
}

.view-toggle a {
    padding: 0.3rem 0.75rem;
    color: var(--color-text-secondary);
    text-decoration: none;
    border-right: 1px solid var(--color-border, #e4e4e7);
}

.view-toggle a:last-child {
    border-right: none;
}

.view-toggle a.active {
    background: var(--color-primary);
    color: white;
}

.view-toggle a:not(.active):hover {
    background: var(--color-surface-alt, #f4f4f5);
}

/* ---- Agenda table (Legistar-parity render) ---- */

.agenda-table td {
    vertical-align: top;
    font-size: var(--text-sm);
}

.agenda-row-procedural td {
    color: var(--color-text-muted);
    background: var(--color-surface-alt, #fafafa);
}

/* In-page event search overlay (EventDetail.razor when ?q= present) */
.event-search-overlay {
    margin: 1rem 0 1.5rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--color-primary);
    border-radius: 4px;
    background: var(--color-surface-alt, #f5f7fa);
}
.event-search-overlay-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    font-size: var(--text-sm);
}
.event-search-overlay-count strong { font-weight: 600; }
.event-search-overlay-clear {
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--text-sm);
}
.event-search-overlay-clear:hover { text-decoration: underline; }
.event-search-banner {
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--color-border, #e0e3e8);
}
.event-search-banner-title {
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    margin-bottom: 0.5rem;
}
.event-search-snippet {
    font-size: var(--text-sm);
    line-height: 1.4;
    margin-bottom: 0.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.event-search-snippet .hit-source {
    font-weight: 600;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    margin-right: 0.5em;
}

/* Header row for a single hit: the source-document chip on the left,
   optional "(N matches)" count on the right when multiple chunks of
   that document matched. Stays on one line; chip wraps independently. */
.hit-source-line {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.hit-count {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    background: var(--color-surface-alt, #eef2f6);
    padding: 0.1rem 0.4rem;
    border-radius: 0.25rem;
    font-weight: 500;
}

/* Compact attach-pill used inside search-overlay snippets and per-row hit
   expansions. Same shape as the standard attach-pill but smaller text and
   tighter padding so it fits next to a snippet without dominating it. */
.attach-pill--inline {
    display: inline-flex;
    padding: 0.2rem 0.5rem 0.2rem 0.3rem;
    gap: 0.35rem;
    font-size: var(--text-xs);
    align-self: flex-start;
}
.attach-pill--inline .attach-pill__icon {
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    /* Transparent: the inline icon is now a self-colored FileKindIcons badge
       (was a muted grey chip). Keeps it consistent with the list pills. */
    background: transparent;
    font-size: 12px;
    border-radius: 0.25rem;
}
.attach-pill--inline .attach-pill__name {
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 32rem;
}
.attach-pill--text {
    color: var(--color-text-muted);
    background: var(--color-surface-alt, #f5f7fa);
    border-style: dashed;
    cursor: default;
}
.attach-pill--text:hover { box-shadow: none; border-color: var(--color-border, #e5e7eb); }

/* In-page-search decoration on the existing attachment-pill grid.
   Default state: each .attach-card uses `display: contents` so the
   wrapped <a class="attach-pill"> stays the grid item - non-matching
   pills behave exactly as before. When the wrapper carries --hit,
   it switches to a block that spans the full grid row, with the pill
   visually accented and the matching snippets stacked underneath. */
.attach-card { display: contents; }
.attach-card--hit {
    display: block;
    grid-column: 1 / -1;
    border: 1px solid var(--color-border, #e5e7eb);
    border-left: 3px solid var(--color-primary);
    border-radius: 6px;
    padding: 0.5rem 0.75rem;
    background: rgba(255, 243, 163, 0.12);
}
.attach-card--hit .attach-pill { display: inline-flex; background: var(--color-bg-card); }
.attach-pill--hit { border-color: var(--color-primary); }
.attach-card__hits {
    margin-top: 0.5rem;
    padding-left: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: var(--text-xs);
    line-height: 1.4;
}
.attach-card__hit-snippet { color: var(--color-text); }
.attach-card__hit-snippet mark { background: #fff3a3; padding: 0 1px; }
.attach-card__hit-more { color: var(--color-text-muted); font-style: italic; }

/* Compact top-of-page alert. Replaces the bigger event-search-overlay
   banner on Item / EventItem detail pages where the per-pill snippets
   carry the load instead. Stays one line: count on the left, jump
   link on the right. */
.search-alert {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0.75rem;
    margin: 0.75rem 0 1rem;
    background: var(--color-surface-alt, #f5f7fa);
    border: 1px solid var(--color-primary);
    border-radius: 6px;
    font-size: var(--text-sm);
}
.search-alert__count strong { font-weight: 600; }
.search-alert__actions { display: flex; gap: 1rem; align-items: center; }
.search-alert__jump { font-weight: 500; }
.search-alert__clear { color: var(--color-text-muted); text-decoration: none; }
.search-alert__clear:hover { text-decoration: underline; }

/* Inline list of Pass-2 item-text hits shown in the alert when chunks
   matched against c.ItemId without an AttachmentId behind them. Compact
   so it doesn't dominate the alert. */
.search-alert__itemtext {
    margin: 0.5rem 0 0;
    padding: 0.5rem 0 0;
    border-top: 1px dashed var(--color-border, #e5e7eb);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}
.search-alert__itemtext-title {
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.25rem;
}
.search-alert__itemtext-snippet {
    line-height: 1.4;
    margin-bottom: 0.25rem;
}

/* TopicDetail faceted-browse layout. Sidebar of year/state/place facets
   on the left, results on the right. Plain GET sidebar - each row is a
   link that toggles one CSV value, no JS. Mirrors /search's left-rail
   feel without pulling SearchContentStream's full machinery in. */
.topic-research { margin-top: 1.25rem; }
.topic-research__layout {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: 1.5rem;
}
@media (max-width: 768px) {
    .topic-research__layout { grid-template-columns: 1fr; }
}
.topic-research__sidebar {
    font-size: var(--text-sm);
    color: var(--color-text);
}
.topic-research__group { margin-bottom: 1rem; }
.topic-research__group-title {
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-bottom: 0.4rem;
}
.topic-research__list { list-style: none; padding: 0; margin: 0; }
.topic-research__row {
    display: flex;
    justify-content: space-between;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
    text-decoration: none;
    color: var(--color-primary);
}
.topic-research__row:hover { background: var(--color-primary-light); color: var(--color-primary-dark); }
.topic-research__row--on {
    background: var(--color-primary);
    color: #fff;
    font-weight: 500;
}
.topic-research__row--on .muted { color: rgba(255,255,255,0.85); }
.topic-research__clear { margin-bottom: 0.75rem; font-size: var(--text-xs); }
.topic-research__main { min-width: 0; }
.event-search-snippet-more {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    font-style: italic;
}
.event-search-overlay mark,
.agenda-table mark { background: #fff3a3; padding: 0 1px; }

/* "Show all 142 items" restore link below the agenda section header */
.agenda-search-restore {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0.75rem;
    margin: 0.25rem 0 0.5rem;
    background: var(--color-surface-alt, #f5f7fa);
    border-radius: 4px;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}
.agenda-search-restore a { font-weight: 500; }

/* Per-row search hit decoration on agenda items that matched */
.agenda-table tr.agenda-row-hit td {
    background: rgba(255, 243, 163, 0.18);
}
.agenda-table tr.agenda-row-hit-expand td {
    padding-top: 0.25rem;
    padding-bottom: 0.5rem;
    background: rgba(255, 243, 163, 0.18);
    border-bottom: 1px solid var(--color-border, #e0e3e8);
}
.agenda-row-hit-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.agenda-row-hit-snippet {
    font-size: var(--text-xs);
    line-height: 1.4;
    margin-bottom: 0.3rem;
}
.agenda-row-hit-snippet .hit-source {
    font-weight: 600;
    color: var(--color-text-muted);
    margin-right: 0.5em;
}
.agenda-row-hit-snippet .hit-text { color: var(--color-text); }
.agenda-row-hit-more {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    font-style: italic;
}

.action-details {
    margin-top: 0.25rem;
    font-size: var(--text-xs);
}

.action-details > summary {
    cursor: pointer;
    color: var(--color-text-muted);
    user-select: none;
    list-style: none;
    display: inline-block;
    padding: 0.1rem 0.25rem;
    border-radius: 3px;
}

.action-details > summary::before {
    content: "\25B8";
    margin-right: 0.25rem;
    display: inline-block;
    transition: transform 0.15s ease;
}

.action-details[open] > summary::before {
    transform: rotate(90deg);
}

.action-details > summary:hover {
    color: var(--color-text-primary);
    background: var(--color-surface-alt, #f4f4f5);
}

.action-details-body {
    margin: 0.35rem 0 0.5rem 0.9rem;
    padding: 0.4rem 0.6rem;
    border-left: 2px solid var(--color-border, #e4e4e7);
    display: grid;
    gap: 0.15rem;
}

/* ---- Grid ---- */

.x0bb1db-grid-2 {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-lg);
}

@media (min-width: 768px) {
    .x0bb1db-grid-2 {
        grid-template-columns: 1fr 1fr;
    }
}

/* ---- Month Selector ---- */

.month-selector {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
    font-size: var(--text-sm);
}

.month-selector a {
    padding: var(--space-xs) var(--space-sm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    transition: background 0.15s;
}

.month-selector a:hover {
    background: var(--color-bg-secondary);
    text-decoration: none;
}

.month-selector .current {
    font-weight: 600;
    color: var(--color-text);
}

/* ---- Blazor error boundary ---- */

.blazor-error-boundary {
    background: var(--color-danger);
    padding: var(--space-md) var(--space-md) var(--space-md) var(--space-2xl);
    color: #ffffff;
    border-radius: var(--radius-md);
}

.blazor-error-boundary::after {
    content: "An error has occurred.";
}

/* ── PersonDetail redesign ──────────────────────────────────────────────────
   Hero strip, signature sections, alignment pills, tenure timeline, filtered
   votes table. All additive to the existing layout system (no rewrites to
   shared tokens).
*/

/* Hero */
.person-hero {
    padding: 1.25rem 0 1.5rem;
    border-bottom: 1px solid var(--v2-rule, #e2e8f0);
    margin-bottom: 1.5rem;
}
.person-hero__title-row { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.person-hero__name { font-size: clamp(1.5rem, 3vw, 2.25rem); font-weight: 700; margin: 0; }
.person-hero__status {
    display: inline-block; padding: 0.15rem 0.55rem; font-size: 0.7rem;
    font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
    border-radius: 999px;
}
.person-hero__status--active   { background: #dcfce7; color: #166534; }
.person-hero__status--inactive { background: #e5e7eb; color: var(--color-text-secondary); }

.person-hero__lead {
    margin: 0.65rem 0 0.9rem; font-size: 1.05rem; line-height: 1.5;
    color: var(--color-text-secondary); max-width: 62ch;
}
.person-hero__lead--derived { color: var(--color-text-muted); font-style: italic; }
.person-hero__lead-tag {
    display: inline-block; margin-left: 0.35rem; padding: 0 0.4rem;
    font-size: 0.65rem; font-weight: 700; letter-spacing: 0.05em;
    background: #f1f5f9; color: var(--color-text-secondary); border-radius: 4px; vertical-align: middle;
}

.person-hero__counters {
    display: flex; flex-wrap: wrap; gap: 0.4rem 1.25rem;
    font-size: 0.85rem; color: var(--color-text-secondary);
}
.person-hero__counter strong { color: var(--color-text); font-weight: 700; margin-right: 0.2rem; }
.person-hero__counter em { font-style: normal; color: #94a3b8; font-variant-numeric: tabular-nums; }

/* Stand-for section */
.stand-for__block { margin-top: 1.25rem; }
.stand-for__block:first-child { margin-top: 0; }
.stand-for__subtitle {
    font-size: 0.95rem; font-weight: 600; margin: 0 0 0.6rem;
    display: flex; align-items: baseline; gap: 0.55rem; flex-wrap: wrap;
}

/* Signature issue tags */
.sigtag-chips { list-style: none; padding: 0; margin: 0;
    display: flex; flex-wrap: wrap; gap: 0.4rem; }
.sigtag-chip {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.3rem 0.7rem; background: #f8fafc; border: 1px solid #e2e8f0;
    border-radius: 999px; font-size: 0.85rem;
}
.sigtag-chip__label { color: var(--color-text); }
.sigtag-chip__count {
    background: #0f172a; color: #ffffff; padding: 0.05rem 0.45rem;
    border-radius: 999px; font-size: 0.7rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.code-refs { margin-top: 0.7rem; font-size: 0.85rem; color: var(--color-text-secondary);
    display: flex; flex-wrap: wrap; gap: 0.4rem 0.8rem; align-items: baseline; }
.code-refs__label { color: #94a3b8; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; }
.code-refs__ref { font-family: ui-monospace, Consolas, monospace; color: var(--color-text); }
.code-refs__ref .sec-count { margin-left: 0.2rem; }

/* Signature votes */
.sig-votes { list-style: none; padding: 0; margin: 0;
    display: flex; flex-direction: column; gap: 0.5rem; }
.sig-vote {
    display: grid; grid-template-columns: 130px minmax(140px, 1fr) 2fr auto;
    gap: 0.75rem; align-items: baseline;
    padding: 0.6rem 0.75rem; border-left: 3px solid #94a3b8; background: #f8fafc;
    border-radius: 0 6px 6px 0;
}
.sig-vote--lone-dissent   { border-left-color: #dc2626; background: #fef2f2; }
.sig-vote--tiebreaker     { border-left-color: #7c3aed; background: #f5f3ff; }
.sig-vote--sponsored-win  { border-left-color: #0d9488; background: #f0fdfa; }
.sig-vote__kind {
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em;
    color: inherit; white-space: nowrap;
}
.sig-vote--lone-dissent  .sig-vote__kind { color: #b91c1c; }
.sig-vote--tiebreaker    .sig-vote__kind { color: #6d28d9; }
.sig-vote--sponsored-win .sig-vote__kind { color: #0f766e; }
.sig-vote--dissent       .sig-vote__kind { color: var(--color-text-secondary); }
.sig-vote__rationale { font-size: 0.82rem; color: var(--color-text-secondary); }
.sig-vote__title a { color: var(--color-text); font-weight: 500; }
.sig-vote__date { font-size: 0.78rem; color: #94a3b8; white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
    .sig-vote { grid-template-columns: 1fr; gap: 0.25rem; }
}

/* Alignment pills */
.alignment-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.alignment-pair__col { display: flex; flex-direction: column; gap: 0.35rem; }
.alignment-pair__label {
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
    color: var(--color-text-muted); margin-bottom: 0.2rem;
}
.alignment-row {
    display: grid; grid-template-columns: 1fr auto auto;
    gap: 0.5rem; align-items: baseline;
    padding: 0.5rem 0.75rem; background: #f8fafc; border: 1px solid #e2e8f0;
    border-radius: 6px; text-decoration: none; color: inherit;
}
.alignment-row:hover { background: #f1f5f9; }
.alignment-row--close { border-left: 3px solid #16a34a; }
.alignment-row--sharp { border-left: 3px solid #dc2626; }
.alignment-row__name { font-weight: 500; color: var(--color-text); }
.alignment-row__pct { font-weight: 700; color: var(--color-text); font-variant-numeric: tabular-nums; }
.alignment-row__shared { font-size: 0.75rem; color: #94a3b8; font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
    .alignment-pair { grid-template-columns: 1fr; }
}

/* Tenure timeline */
.tenure-timeline { display: flex; flex-direction: column; gap: 0.35rem; margin: 0.5rem 0; }
.tenure-timeline__header {
    display: flex; justify-content: space-between;
    font-size: 0.7rem; color: #94a3b8; font-variant-numeric: tabular-nums;
    margin-left: calc(200px + 0.75rem); margin-right: 100px;
}
.tenure-timeline__row {
    display: grid; grid-template-columns: 200px 1fr 100px;
    gap: 0.75rem; align-items: center; min-height: 28px;
}
.tenure-timeline__body { font-size: 0.85rem; color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tenure-timeline__body a { color: inherit; }
.tenure-timeline__role { display: block; font-size: 0.7rem; color: #94a3b8; }
.tenure-timeline__track {
    position: relative; height: 12px; background: #f1f5f9;
    border-radius: 6px; overflow: hidden;
}
.tenure-timeline__bar {
    position: absolute; top: 0; bottom: 0;
    background: #334155; border-radius: 6px; min-width: 3px;
}
.tenure-timeline__bar--ongoing {
    background: linear-gradient(90deg, #334155 0%, #334155 85%, #16a34a 100%);
}
.tenure-timeline__dates { font-size: 0.75rem; color: var(--color-text-muted); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tenure-timeline__more summary {
    font-size: 0.82rem; color: #0369a1; cursor: pointer;
    padding: 0.35rem 0; margin-top: 0.3rem;
    list-style: none; user-select: none;
}
.tenure-timeline__more summary::before { content: "+ "; }
.tenure-timeline__more[open] summary::before { content: "- "; }
@media (max-width: 640px) {
    .tenure-timeline__row { grid-template-columns: 1fr; gap: 0.1rem; }
    .tenure-timeline__header { display: none; }
    .tenure-timeline__dates { text-align: left; }
}

/* Person meeting context */
.person-meetings__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    margin-bottom: 0.9rem;
}
.person-meetings__lede {
    margin: 0.35rem 0 0;
    max-width: 68ch;
    color: var(--color-text-secondary);
    font-size: 0.92rem;
    line-height: 1.5;
}
.person-meetings__all {
    flex: 0 0 auto;
    color: var(--color-primary);
    font-size: 0.86rem;
    font-weight: 600;
    text-decoration: none;
    margin-top: 0.15rem;
}
.person-meetings__all:hover { color: var(--color-primary-dark); text-decoration: none; }
.person-meetings__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.55rem;
}
.person-meetings__card {
    display: block;
    min-height: 4.2rem;
    padding: 0.7rem 0.8rem;
    border: 1px solid #e2e8f0;
    border-left: 3px solid var(--color-primary);
    border-radius: 6px;
    background: var(--color-bg-card);
    text-decoration: none;
}
.person-meetings__card:hover {
    border-color: #cbd5e1;
    border-left-color: var(--color-primary-dark);
    background: #f8fafc;
}
.person-meetings__name {
    display: block;
    color: var(--color-primary);
    font-weight: 600;
    line-height: 1.25;
}
.person-meetings__role {
    display: block;
    margin-top: 0.25rem;
    color: var(--color-text-muted);
    font-size: 0.78rem;
    line-height: 1.3;
}
@media (max-width: 640px) {
    .person-meetings__header { display: block; }
    .person-meetings__all { display: inline-block; margin-top: 0.65rem; }
}

/* Vote filter + table */
.votes-filter {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
    padding: 0.75rem; background: #f8fafc; border: 1px solid #e2e8f0;
    border-radius: 8px; margin-bottom: 1rem;
}
.votes-filter__q {
    flex: 1 1 200px; padding: 0.4rem 0.6rem; border: 1px solid #cbd5e1;
    border-radius: 6px; font-size: 0.9rem;
}
.votes-filter__select, .votes-filter__date {
    padding: 0.4rem 0.6rem; border: 1px solid #cbd5e1;
    border-radius: 6px; font-size: 0.9rem; background: var(--color-bg-card);
    /* Same overflow guard as .people-filter__select: native <select>
       width follows the widest option, and PersonDetail's body picker
       can carry long body names that would otherwise blow the mobile
       viewport. */
    max-width: 100%;
}
.votes-filter__check {
    display: inline-flex; align-items: center; gap: 0.35rem;
    font-size: 0.85rem; color: var(--color-text-secondary); white-space: nowrap;
}
.votes-filter__btn {
    padding: 0.4rem 0.9rem; background: var(--color-primary); color: #ffffff;
    border: none; border-radius: 6px; font-size: 0.85rem; font-weight: 600;
    cursor: pointer;
}
.votes-filter__btn:hover { background: var(--color-primary-dark); }
.votes-filter__reset {
    font-size: 0.8rem; color: var(--color-text-muted); text-decoration: underline;
    margin-left: 0.5rem;
}

.votes-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
/* Mobile responsive fallback: turn the table into a horizontally
   scrollable strip below 540px. Without this, the 5-column votes /
   attendance tables on PersonDetail overflowed the viewport by ~40px
   on mobile. `display: block` breaks auto-column-balancing but the
   table's short cell content (date / vote / item title / body /
   outcome) renders fine in content-width columns. */
@media (max-width: 540px) {
    .votes-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        max-width: 100%;
        white-space: nowrap;
    }
    .votes-table .meeting-title,
    .votes-table .resultcard__snippet { white-space: normal; }
}
.votes-table th {
    text-align: left; padding: 0.4rem 0.6rem; border-bottom: 2px solid #e2e8f0;
    font-weight: 600; color: var(--color-text-muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em;
}
.votes-table td { padding: 0.55rem 0.6rem; border-bottom: 1px solid #f1f5f9; vertical-align: top; }
.votes-table__date { white-space: nowrap; color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.votes-table__body { color: var(--color-text-muted); }
.votes-table__bucket {
    display: inline-block; padding: 0.1rem 0.5rem; font-size: 0.7rem; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase; border-radius: 4px;
}
.votes-table__bucket--for     { background: #dcfce7; color: #166534; }
.votes-table__bucket--against { background: #fee2e2; color: #b91c1c; }
.votes-table__bucket--other   { background: #e5e7eb; color: var(--color-text-secondary); }

/* Outcome pill (reused across pages) */
.outcome-pill {
    display: inline-block; padding: 0.1rem 0.5rem; font-size: 0.7rem; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase; border-radius: 4px;
}
.outcome-pill--passed { background: #dcfce7; color: #166534; }
.outcome-pill--failed { background: #fee2e2; color: #b91c1c; }

/* ── LLM topic tags ─────────────────────────────────────────────────────────
   Tag strip at top of ItemDetail, right-margin Hot Topics on Home, and
   PersonDetail signature tags reuse the existing .sigtag-chip styles.
*/

/* Item tag strip (above the title) */
.item-tag-strip {
    display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.65rem;
}
.item-tag-strip__chip {
    display: inline-block; padding: 0.2rem 0.6rem;
    font-size: 0.75rem; font-weight: 600; color: var(--color-text);
    background: #f1f5f9; border: 1px solid #cbd5e1;
    border-radius: 999px; text-decoration: none; letter-spacing: 0.01em;
}
.item-tag-strip__chip:hover { background: #e2e8f0; border-color: #94a3b8; }
/* Rank 1 = top pick, slightly more prominent */
.item-tag-strip__chip--rank1 { background: var(--color-primary); color: #ffffff; border-color: var(--color-primary); }
.item-tag-strip__chip--rank1:hover { background: var(--color-primary-dark); border-color: var(--color-primary-dark); }

/* Hot topics aside module */
.home-aside__hot-topics {
    /* Match the home-aside__card visual: same subtle warm-to-cool gradient,
       same border + radius + padding rhythm, so Top 10 Topics and Advanced
       Features read as paired panels in the aside rather than two
       different chrome systems. */
    background: var(--gradient-panel-soft);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 0.9rem 1rem;
    margin-bottom: 0.75rem;
}
.home-aside__hot-title {
    /* Section title - matches .dossier__section-heading (used by "Browse by
       place" on Home) so every section label across the page reads as the
       same heading rhythm. Flex layout retained so the "last N days" window
       label can ride to the right edge. */
    display: flex; align-items: baseline; justify-content: space-between;
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--v2-ink-muted);
    margin: 0 0 0.5rem 0;
}
.home-aside__hot-window {
    font-size: 0.7rem; font-weight: 500; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.04em;
}
.home-aside__hot-list { list-style: none; padding: 0; margin: 0; }
.home-aside__hot-row {
    display: flex; justify-content: space-between; align-items: baseline;
    padding: 0.3rem 0; border-bottom: 1px solid #f1f5f9;
}
.home-aside__hot-row:last-child { border-bottom: none; }
.home-aside__hot-label {
    /* Topic name is the clickable signal -> primary palette per the chrome rule.
       Same font / weight / size as .state-link and .category-card__name. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    color: var(--color-primary);
    text-decoration: none;
}
.home-aside__hot-label:hover { color: var(--color-primary-dark); text-decoration: none; }
.home-aside__hot-count {
    font-size: 0.75rem; font-weight: 600; color: var(--color-text-secondary); font-variant-numeric: tabular-nums;
    background: var(--color-bg-secondary); padding: 0.05rem 0.4rem; border-radius: 999px;
}
/* "All topics" footer link, surfaces below the top-10 list. Same primary
   color as the topic links themselves, set apart by margin-top + a small
   font weight bump so it reads as the panel's CTA, not another row. */
.home-aside__hot-all {
    display: inline-block;
    margin-top: 0.6rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--color-border);
    width: 100%;
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 600;
}
.home-aside__hot-all:hover { color: var(--color-primary-dark); text-decoration: none; }

/* Auth pages (signup, signin, profile). Single-column, narrow, focused. */
.auth-shell {
    max-width: 420px; margin: 2rem auto; padding: 1.5rem 1.75rem;
    background: var(--color-bg-card); border: 1px solid #e2e8f0; border-radius: 10px;
}
.auth-shell__title { font-size: 1.5rem; font-weight: 700; margin: 0 0 0.5rem; }
.auth-shell__sub   { color: var(--color-text-secondary); margin: 0 0 1.25rem; font-size: 0.9rem; line-height: 1.5; }
.auth-shell__error {
    background: #fee2e2; color: #b91c1c; padding: 0.6rem 0.85rem;
    border-radius: 6px; margin-bottom: 1rem; font-size: 0.88rem;
}
.auth-shell__ok {
    background: #dcfce7; color: #166534; padding: 0.6rem 0.85rem;
    border-radius: 6px; margin-bottom: 1rem; font-size: 0.88rem;
}
.auth-shell__alt { margin: 1rem 0 0; font-size: 0.85rem; color: var(--color-text-muted); text-align: center; }
.auth-form { display: flex; flex-direction: column; gap: 0.9rem; }
.auth-form label {
    display: flex; flex-direction: column; gap: 0.25rem;
    font-size: 0.85rem; font-weight: 600; color: var(--color-text-secondary);
}
.auth-form input, .auth-form select {
    padding: 0.55rem 0.7rem; border: 1px solid #cbd5e1;
    border-radius: 6px; font-size: 0.95rem; background: var(--color-bg-card);
    font-weight: 400; color: var(--color-text);
}
.auth-form input:disabled { background: #f8fafc; color: var(--color-text-muted); }
.auth-form__hint { font-size: 0.72rem; font-weight: 400; color: var(--color-text-muted); }
.auth-form__strength--weak   { color: #b91c1c; font-weight: 600; }
.auth-form__strength--ok     { color: #b45309; font-weight: 600; }
.auth-form__strength--strong { color: #15803d; font-weight: 600; }
.auth-form__btn {
    margin-top: 0.5rem; padding: 0.6rem 1rem;
    background: var(--color-primary); color: #ffffff; border: none;
    border-radius: 6px; font-size: 0.95rem; font-weight: 600; cursor: pointer;
}
.auth-form__btn:hover { background: var(--color-primary-dark); }
.auth-form__checkbox {
    flex-direction: row; flex-wrap: wrap; align-items: flex-start;
    gap: 0.5rem; font-size: 0.9rem;
}
.auth-form__checkbox input[type="checkbox"] { margin-top: 0.2rem; }
.auth-form__checkbox .auth-form__hint { flex-basis: 100%; margin-left: 1.75rem; }

/* Dev mode footer - renders for users with devmode=1 claim. */
.devmode-footer {
    margin: 2.5rem 0 0; padding: 1rem 1.25rem;
    background: #0f172a; color: #e2e8f0;
    border-radius: 10px; font-size: 0.85rem;
}
.devmode-footer summary {
    display: flex; align-items: center; gap: 0.6rem;
    cursor: pointer; user-select: none;
    font-weight: 600; list-style: none;
}
.devmode-footer summary::-webkit-details-marker { display: none; }
.devmode-footer__badge {
    background: #eab308; color: var(--color-text);
    padding: 0.1rem 0.5rem; border-radius: 4px;
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em;
}
.devmode-footer__count {
    background: #334155; padding: 0.1rem 0.5rem; border-radius: 999px;
    font-variant-numeric: tabular-nums; font-size: 0.75rem;
}
.devmode-footer__total { color: #94a3b8; font-weight: 400; font-size: 0.8rem; }
.devmode-footer__empty { color: #94a3b8; font-style: italic; margin: 0.75rem 0 0; }
.devmode-footer__docs { color: #94a3b8; margin: 0.75rem 0 0; font-size: 0.8rem; }
.devmode-footer__docs a { color: #38bdf8; }

.devmode-table { width: 100%; border-collapse: collapse; margin-top: 0.75rem; }
.devmode-table th, .devmode-table td {
    padding: 0.4rem 0.6rem; border-bottom: 1px solid #1e293b;
    text-align: left; vertical-align: middle;
}
.devmode-table th {
    color: #94a3b8; font-size: 0.7rem;
    text-transform: uppercase; letter-spacing: 0.04em;
    font-weight: 600;
}
.devmode-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.devmode-method {
    background: #1e293b; color: #38bdf8;
    padding: 0.1rem 0.4rem; border-radius: 4px;
    font-family: ui-monospace, Consolas, monospace; font-size: 0.75rem; font-weight: 700;
}
.devmode-path {
    color: #e2e8f0; font-family: ui-monospace, Consolas, monospace;
    font-size: 0.8rem; word-break: break-all;
}
.devmode-status {
    display: inline-block; padding: 0.1rem 0.45rem; border-radius: 4px;
    font-size: 0.72rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.devmode-status--ok  { background: #166534; color: #bbf7d0; }
.devmode-status--4xx { background: #854d0e; color: #fde68a; }
.devmode-status--5xx { background: #b91c1c; color: #fecaca; }
.devmode-status--err { background: #b91c1c; color: #fecaca; }
.devmode-tag {
    display: inline-block; padding: 0.05rem 0.4rem; border-radius: 4px;
    background: #1e293b; color: #94a3b8; font-size: 0.7rem; margin-right: 0.25rem;
}
.devmode-tag--err { background: #7f1d1d; color: #fecaca; }
.devmode-copy {
    background: #1e293b; color: #e2e8f0; border: 1px solid #334155;
    padding: 0.2rem 0.55rem; border-radius: 4px;
    font-size: 0.72rem; cursor: pointer; white-space: nowrap;
}
.devmode-copy:hover { background: #334155; }

/* Profile link inherits the primary-blue .header-link color; this rule
   keeps the heavier weight to mark "this is your account" without breaking
   the unified-blue chrome rule. */
.header-link-profile { font-weight: 600; }

/* Inline tag chips - compact, for list cards. Distinct from the prominent
   .item-tag-strip used at the top of ItemDetail. */
.tag-chips-inline { display: inline-flex; flex-wrap: wrap; gap: 0.25rem; align-items: center; }
.tag-chips-inline__chip {
    display: inline-block; padding: 0.05rem 0.4rem;
    font-size: 0.7rem; font-weight: 500; color: var(--color-text-secondary);
    background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 999px;
    text-decoration: none;
}
.tag-chips-inline__chip:hover { background: #e2e8f0; border-color: #94a3b8; }
.tag-chips-inline__more { font-size: 0.7rem; color: #94a3b8; }

/* Unified result card (Search + Feed + list pages). */
.resultcard {
    padding: 0.85rem 1rem; background: var(--color-bg-card);
    border: 1px solid #e2e8f0; border-radius: 8px;
    margin-bottom: 0.6rem;
    transition: border-color 0.12s ease;
}
.resultcard:hover { border-color: #cbd5e1; }
.resultcard__tags { margin-bottom: 0.4rem; }
.resultcard__title {
    font-size: 1rem; font-weight: 600; line-height: 1.35;
    margin-bottom: 0.35rem;
}
.resultcard__title a {
    color: var(--color-primary);
    text-decoration: underline;
    text-decoration-style: dotted;
    text-decoration-color: var(--color-primary);
    text-underline-offset: 3px;
}
.resultcard__title a:hover {
    color: var(--color-primary-dark);
    text-decoration-style: solid;
    text-decoration-color: var(--color-primary-dark);
}
.resultcard__itemkey {
    margin-left: 0.45rem; font-size: 0.75rem; font-weight: 500;
    color: var(--color-text-muted); font-family: ui-monospace, Consolas, monospace;
}
.resultcard__meta {
    display: flex; flex-wrap: wrap; gap: 0.3rem 0.75rem;
    font-size: 0.78rem; color: var(--color-text-muted);
    align-items: baseline;
}
.resultcard__type {
    background: #f1f5f9; color: var(--color-text-secondary);
    padding: 0.05rem 0.45rem; border-radius: 4px;
    font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
}
.resultcard__place { font-weight: 500; color: var(--color-text-secondary); }
.resultcard__body { color: var(--color-text-secondary); }
.resultcard__date { font-variant-numeric: tabular-nums; white-space: nowrap; }
.resultcard__outcome {
    padding: 0.05rem 0.5rem; border-radius: 4px;
    font-size: 0.7rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
}
.resultcard__outcome--passed   { background: #dcfce7; color: #166534; }
.resultcard__outcome--failed   { background: #fee2e2; color: #b91c1c; }
.resultcard__outcome--tabled   { background: #fef3c7; color: #854d0e; }
.resultcard__outcome--inactive { background: #f1f5f9; color: var(--color-text-muted); }
.resultcard__outcome--neutral  { background: #e5e7eb; color: var(--color-text-secondary); }

/* Consistent vertical rhythm for any list of ResultCards (PeopleList, BodyList,
   ItemList, EventList, Search, Feed, Ripple). Replaces the legacy <table>
   and <div class="card"> patterns across list pages. */
.resultcard-list { display: flex; flex-direction: column; gap: 0.5rem; }

/* Compare page - user-facing error state when the API rejects the request
   (topic too short, timeout, etc). Replaces the misleading "retrieving..."
   placeholder that used to hang when the API returned null. */
.compare__error {
    padding: 0.9rem 1rem; margin: 1rem 0;
    background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px;
    color: #991b1b;
}
.compare__error strong { display: block; margin-bottom: 0.3rem; font-size: 0.95rem; }
.compare__error p { margin: 0; font-size: 0.88rem; color: #b91c1c; }

/* Crystal Ball methodology footnote. Placed at the bottom of the page so the
   predictions are the headline; the "how we scored it" note is available for
   readers who want it but doesn't get in the way of the ranked list above. */
.cb-methodology {
    margin-top: 2.5rem; padding-top: 1.25rem;
    border-top: 1px solid #e2e8f0;
    font-size: 0.85rem; line-height: 1.5;
}
.cb-methodology__title {
    font-size: 0.82rem; font-weight: 600;
    color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.06em;
    margin: 0 0 0.5rem 0;
}
.cb-methodology p { margin: 0; max-width: 720px; }

/* Attendance section on PersonDetail. Inherits the .votes-table grid; only
   needs the filter bar spacing + the attendance-value pill. */
.attendance-filter {
    display: flex; align-items: center; gap: 1rem;
    margin: 0.5rem 0 1rem 0;
    padding: 0.6rem 0.85rem;
    background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px;
}
.attendance-pill {
    display: inline-block; padding: 0.12rem 0.6rem;
    background: #f1f5f9; color: var(--color-text-secondary);
    border-radius: 999px; font-size: 0.78rem; font-weight: 600;
    text-transform: capitalize;
}

/* Search-result hit highlighting inside ResultCard snippets, titles, and
   AI gloss. Subtle amber underline + background so the mark reads as
   emphasis, not as a toxic yellow block across half the paragraph.
   Applied to title + gloss as of 2026-05-10 so the visible card actually
   shows the match - the snippet `<details>` is collapsed by default and
   was hiding every highlight. */
.resultcard__snippet mark,
.resultcard__title mark,
.resultcard__gloss mark {
    background: #fef3c7; color: inherit;
    padding: 0 0.12rem; border-radius: 2px;
    box-shadow: inset 0 -2px 0 #fbbf24;
}

/* Crystal Ball - confidence tier pill, state filter chips, field-team queue
   highlight. All additive: the base .cb-prediction layout is untouched. */
.cb-queue-hint {
    margin: 0.25rem 0 0.9rem;
    font-size: 0.88rem; color: var(--color-text-secondary);
}
.cb-state-chips {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
    margin: 0.5rem 0 1.25rem;
    padding: 0.6rem 0.85rem;
    background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px;
}
.cb-state-chips__label {
    font-size: 0.78rem; color: var(--color-text-muted); margin-right: 0.25rem;
}
.cb-state-chip {
    padding: 0.22rem 0.7rem;
    background: var(--color-bg-card); color: var(--color-text-secondary);
    border: 1px solid #cbd5e1; border-radius: 999px;
    font-size: 0.78rem; text-decoration: none;
    transition: background-color 0.12s ease;
}
.cb-state-chip:hover { background: #f1f5f9; }
.cb-state-chip--active {
    background: #0f172a; color: #ffffff; border-color: #0f172a;
}
.cb-tier {
    display: inline-block; padding: 0.12rem 0.55rem;
    font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.04em; border-radius: 4px; margin-left: 0.3rem;
}
.cb-tier--high   { background: #dcfce7; color: #166534; }
.cb-tier--medium { background: #fef3c7; color: #854d0e; }
.cb-tier--low    { background: #f1f5f9; color: var(--color-text-muted); }
/* Field-team queue: amber left border + stronger rank badge on the top-3 so
   they read as "act on these first" without restructuring the list. */
.cb-prediction--queue {
    border-left: 3px solid #f59e0b;
    background: linear-gradient(to right, #fffbeb 0%, transparent 60%);
}
.cb-prediction__rank--queue {
    background: #f59e0b; color: #78350f; font-weight: 700;
}

/* Ripple - date-window chip row, outcome breakdown chips, bellwether callout. */
.ripple-window-chips {
    display: flex; flex-wrap: wrap; gap: 0.35rem;
    margin: 0.6rem 0 0.25rem;
}
.ripple-window-chip {
    padding: 0.2rem 0.75rem;
    background: var(--color-bg-card); color: var(--color-text-secondary);
    border: 1px solid #cbd5e1; border-radius: 999px;
    font-size: 0.78rem; text-decoration: none;
    font-variant-numeric: tabular-nums;
    transition: background-color 0.12s ease;
}
.ripple-window-chip:hover { background: #f1f5f9; }
.ripple-window-chip--active {
    background: #0d9488; color: #ffffff; border-color: #0d9488;
}
.ripple-outcomes {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
    margin: 0.9rem 0;
}
.ripple-outcomes__label {
    font-size: 0.78rem; color: var(--color-text-muted); margin-right: 0.25rem;
}
.ripple-outcomes__chip {
    padding: 0.15rem 0.65rem;
    border-radius: 999px;
    font-size: 0.78rem; font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.ripple-outcomes__chip--passed { background: #dcfce7; color: #166534; }
.ripple-outcomes__chip--failed { background: #fee2e2; color: #b91c1c; }
.ripple-outcomes__chip--tabled { background: #fef3c7; color: #854d0e; }
.ripple-outcomes__chip--other  { background: #f1f5f9; color: var(--color-text-muted); }
.ripple-bellwether {
    margin: 1rem 0 1.25rem;
    padding: 0.85rem 1rem;
    background: linear-gradient(to right, #ecfeff 0%, #f0fdfa 100%);
    border-left: 3px solid #0d9488;
    border-radius: 6px;
}
.ripple-bellwether__kicker {
    font-size: 0.74rem; font-weight: 700; color: #0f766e;
    text-transform: uppercase; letter-spacing: 0.06em;
    margin-bottom: 0.3rem;
}
.ripple-bellwether__body {
    font-size: 0.92rem; color: var(--color-text); line-height: 1.5;
}
.ripple-bellwether__city {
    white-space: nowrap;
}

/* PeopleList filter bar - "currently serving only" checkbox + body dropdown
   + sort. Same visual pattern as the votes-filter bar on PersonDetail so the
   filter-form language stays consistent across person surfaces. */
.people-filter {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem;
    margin: 0.5rem 0 1.25rem;
    padding: 0.65rem 0.85rem;
    background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px;
    font-size: 0.88rem;
}
.people-filter__check { display: inline-flex; align-items: center; gap: 0.35rem; color: var(--color-text-secondary); }
.people-filter__select, .people-filter__btn {
    padding: 0.25rem 0.55rem; font-size: 0.85rem;
    border: 1px solid #cbd5e1; border-radius: 5px;
    background: var(--color-bg-card); color: var(--color-text);
    /* Native <select> width = widest <option>. Long body names
       ("MILWAUKEE FIRE AND POLICE COMMISSION SUBCOMMITTEE: …") were
       blowing the select past 900px on a 500px mobile viewport, creating
       page-wide horizontal scroll. Cap at parent width so the wrapped
       filter row stays inside the viewport. */
    max-width: 100%;
}
.people-filter__btn {
    background: var(--color-primary); color: #ffffff; border-color: var(--color-primary);
    padding-inline: 0.9rem; cursor: pointer;
}
.people-filter__btn:hover { background: var(--color-primary-dark); border-color: var(--color-primary-dark); }
.people-filter__reset {
    color: var(--color-text-muted); font-size: 0.82rem; text-decoration: underline;
    text-decoration-style: dotted; text-underline-offset: 3px;
}
.cb-prediction__follow {
    margin-top: 0.5rem;
    display: flex; gap: 0.5rem;
}

/* Category landing page hero. Minimal - the page itself is mostly a list. */
.category-hero { margin-bottom: 1.25rem; }
.category-hero__kicker {
    font-size: 0.74rem; font-weight: 700; color: var(--color-text-muted);
    text-transform: uppercase; letter-spacing: 0.06em;
    margin-bottom: 0.35rem;
}
.category-hero__name { font-size: 1.9rem; margin: 0 0 0.35rem; }
.category-hero__stats { margin: 0; color: var(--color-text-secondary); font-size: 0.95rem; }

/* Profile page - tabs + Following section + Alerts placeholder. The profile
   is one of the few pages with real interactive state per user, so it gets
   its own dedicated shell + tab strip. Stays SSR-pure: tabs are just links,
   unfollow is a POST form. */
.profile-shell { max-width: 820px; margin: 0 auto; padding: 0 0 2rem; }
.profile-shell__title { font-size: 1.9rem; margin: 0 0 1rem; }
.profile-tabs {
    display: flex; gap: 0.25rem;
    margin: 0 0 1.5rem; padding: 0;
    border-bottom: 1px solid #e2e8f0;
}
.profile-tab {
    padding: 0.55rem 1rem;
    color: var(--color-text-secondary); text-decoration: none;
    font-size: 0.92rem; font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    display: inline-flex; align-items: center; gap: 0.4rem;
}
.profile-tab:hover { color: var(--color-text); }
.profile-tab--active {
    color: var(--color-text); font-weight: 600;
    border-bottom-color: #0f172a;
}
.profile-tab__badge {
    display: inline-block; padding: 0.05rem 0.45rem;
    background: #e0f2fe; color: #075985;
    border-radius: 999px;
    font-size: 0.72rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.profile-section { margin-bottom: 2rem; }
.profile-section__title { font-size: 1.25rem; margin: 0 0 0.3rem; }
.profile-section__lede { font-size: 0.92rem; margin: 0 0 1.25rem; }
.profile-section__foot { margin-top: 1.5rem; font-size: 0.88rem; }
.profile-empty {
    padding: 1.5rem 1.25rem;
    background: #f8fafc; border: 1px dashed #cbd5e1; border-radius: 8px;
    text-align: center;
}
.profile-empty p { margin: 0.25rem 0; }

.follow-group {
    margin-bottom: 1.75rem;
    padding: 1rem 1.15rem;
    background: var(--color-bg-card);
    border: 1px solid #e2e8f0; border-radius: 8px;
}
.follow-group__title {
    display: flex; align-items: baseline; gap: 0.55rem;
    margin: 0 0 0.2rem; font-size: 0.95rem;
}
.follow-group__kicker { font-weight: 600; color: var(--color-text); }
.follow-group__count {
    display: inline-block; padding: 0.05rem 0.5rem;
    background: #f1f5f9; color: var(--color-text-secondary);
    border-radius: 999px; font-size: 0.74rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.follow-group__hint { font-size: 0.82rem; margin: 0 0 0.75rem; }
.follow-list { list-style: none; padding: 0; margin: 0; }
.follow-item {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 0.5rem 0.75rem;
    align-items: baseline;
    padding: 0.55rem 0;
    border-top: 1px solid #f1f5f9;
}
.follow-item:first-child { border-top: none; }
.follow-item__name {
    font-weight: 600; color: var(--color-text);
    text-decoration: underline; text-decoration-style: dotted;
    text-decoration-color: #94a3b8; text-underline-offset: 3px;
}
.follow-item__name:hover { text-decoration-style: solid; text-decoration-color: #0f172a; }
.follow-item__scope { font-weight: 500; color: var(--color-text-secondary); }
.follow-item__meta { font-size: 0.78rem; color: var(--color-text-muted); }
.follow-item__form { margin: 0; display: inline; }
.follow-item__unfollow {
    padding: 0.2rem 0.7rem; font-size: 0.78rem;
    background: var(--color-bg-card); color: var(--color-text-secondary);
    border: 1px solid #cbd5e1; border-radius: 5px;
    cursor: pointer;
}
.follow-item__unfollow:hover { background: #fee2e2; color: #991b1b; border-color: #fecaca; }

.profile-alerts {
    display: flex; flex-direction: column; gap: 0.65rem;
}
.profile-alerts__row {
    display: grid; grid-template-columns: 1fr auto; gap: 1rem;
    align-items: center;
    padding: 0.9rem 1.15rem;
    background: var(--color-bg-card); border: 1px solid #e2e8f0; border-radius: 8px;
}
.profile-alerts__label strong { display: block; margin-bottom: 0.2rem; }
.profile-alerts__label p { margin: 0; font-size: 0.85rem; }
.profile-alerts__status {
    padding: 0.2rem 0.65rem; font-size: 0.76rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
    border-radius: 4px;
}
.profile-alerts__status--off { background: #fef3c7; color: #854d0e; }
.profile-alerts__status--on  { background: #dcfce7; color: #166534; }

/* PlaceHome "For officeholders" tools card (Serve digest entry point). */
.place-tools { margin: 2rem 0 1rem; }
.place-tools__card {
    display: block;
    padding: 1rem 1.15rem;
    background: linear-gradient(to right, #fff7ed 0%, #fffbeb 100%);
    border: 1px solid #fed7aa; border-left: 3px solid #f97316;
    border-radius: 8px;
    text-decoration: none; color: inherit;
}
.place-tools__card:hover { border-color: #fb923c; text-decoration: none; }
.place-tools__kicker {
    font-size: 0.74rem; font-weight: 700; color: #9a3412;
    text-transform: uppercase; letter-spacing: 0.06em;
    margin-bottom: 0.3rem;
}
.place-tools__title {
    font-size: 1.05rem; font-weight: 600; color: var(--color-text);
    margin-bottom: 0.3rem;
}
.place-tools__body { font-size: 0.9rem; color: var(--color-text-secondary); line-height: 1.5; max-width: 720px; }
.resultcard__ripple, .activity-feed__ripple {
    display: inline-flex; align-items: center; gap: 0.25rem;
    padding: 0.12rem 0.5rem;
    background: #f0fdfa; color: #0d9488;
    border: 1px solid #5eead4;
    border-radius: 999px;
    font-size: 0.72rem; font-weight: 500;
    white-space: nowrap;
    text-decoration: none;
}
.activity-feed__ripple:hover {
    background: #ccfbf1; color: #0f766e; text-decoration: none;
}
.resultcard__snippet {
    margin: 0.45rem 0 0; font-size: 0.88rem; color: var(--color-text-secondary); line-height: 1.5;
}

/* AI-generated one-liner explaining why a result matched. Slightly stronger
   weight than the raw snippet, soft accent tint, sparkle glyph as a subtle
   visual cue this is model-generated prose (not verbatim from the source). */
.resultcard__gloss {
    margin: 0.5rem 0 0;
    padding: 0.45rem 0.65rem;
    background: #f5f3ff; border-left: 3px solid #8b5cf6;
    color: var(--color-text); font-size: 0.9rem; line-height: 1.5;
    border-radius: 0 4px 4px 0;
}
.resultcard__gloss-sparkle {
    margin-right: 0.35rem; opacity: 0.75;
}
/* "Show source passage" collapse. Subtle so it doesn't compete with the gloss. */
.resultcard__passage { margin: 0.4rem 0 0; }
.resultcard__passage summary {
    cursor: pointer; font-size: 0.78rem; color: var(--color-text-muted);
    padding: 0.1rem 0; user-select: none;
}
.resultcard__passage summary:hover { color: var(--color-text-secondary); }
.resultcard__passage .resultcard__snippet { margin-top: 0.25rem; }

/* Streaming-render skeleton for ScopedSearchView during cold Haiku+FTS
   runs. Shows while OnParametersSetAsync awaits; swaps to results when
   the async work completes. Pattern matches /serve's "Generating digest…"
   block so the reader recognizes the shape. */
.scoped-search-loading {
    margin: 1rem 0;
    padding: 1.25rem;
    background: #f5f3ff; border: 1px solid #ddd6fe;
    border-radius: 8px; max-width: 720px;
}
.scoped-search-loading__spinner {
    width: 28px; height: 28px; border-radius: 50%;
    border: 3px solid #e9d5ff; border-top-color: #7c3aed;
    animation: serve-spin 0.9s linear infinite;
}
.scoped-search-loading__text {
    margin: 0.75rem 0 0 0; font-size: 0.95rem;
}
.scoped-search-loading__hint {
    margin: 0.5rem 0 0 0; font-size: 0.82rem; line-height: 1.5;
}

/* Scope chip on /search when a state filter is active. One-click "clear"
   removes the filter by linking to /search?q=<same-query> without the
   states parameter. */
.search-scope-chip {
    display: inline-flex; align-items: center; gap: 0.5rem;
    margin: 0.25rem 0 1rem;
    padding: 0.35rem 0.85rem; border-radius: 999px;
    background: #eff6ff; color: var(--color-primary);
    border: 1px solid #bfdbfe;
    font-size: 0.88rem;
}
.search-scope-chip__clear {
    color: var(--color-primary); text-decoration: none;
    font-weight: 500; cursor: pointer;
    border-left: 1px solid #bfdbfe; padding-left: 0.6rem;
}
.search-scope-chip__clear:hover { color: var(--color-primary-dark); }

/* Freshness filter chip on search results. Rendered whenever a query ran,
   so users understand what window covers the results. Mirrors the
   search-expanded-terms chip row pattern - flat, pill-shaped, inline. */
.search-freshness {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
    margin: 0.25rem 0 0.85rem;
    font-size: 0.88rem; color: var(--color-text-secondary);
}
.search-freshness__label { font-weight: 600; color: var(--color-text-secondary); }
.search-freshness__opt {
    padding: 0.25rem 0.7rem; border-radius: 999px;
    background: #f1f5f9; color: var(--color-text-secondary);
    border: 1px solid #e2e8f0;
    text-decoration: none;
}
.search-freshness__opt:hover { background: #e2e8f0; color: var(--color-text); }
.search-freshness__opt--active {
    background: #eff6ff; color: var(--color-primary); border-color: #bfdbfe;
    font-weight: 600;
}
.search-freshness__opt--active:hover { background: #dbeafe; color: var(--color-primary-dark); }

/* Serve page "generating digest" placeholder. Simple CSS-only spinner keeps
   the no-JS contract intact; page meta-refresh handles the polling. */
.serve-generating {
    margin-top: 1.5rem; padding: 1.25rem;
    background: #f5f3ff; border: 1px solid #ddd6fe;
    border-radius: 8px; max-width: 720px;
}
.serve-generating__spinner {
    width: 28px; height: 28px; border-radius: 50%;
    border: 3px solid #e9d5ff; border-top-color: #7c3aed;
    animation: serve-spin 0.9s linear infinite;
}
@keyframes serve-spin { to { transform: rotate(360deg); } }

/* Home-page category grid: 3 columns x 6 rows = 18 tiles, alphabetical. */
.category-grid {
    /* Fixed 3 cols x 6 rows on desktop / tablet (the canonical 3x6 of 18
       categories); collapse to 2 cols x 9 rows on phones, then 1 col on
       the very smallest viewports. Auto-fit was producing 4 cols at the
       user's desktop width which felt off-grid. */
    display: grid;
    gap: 0.5rem;
    grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 540px) {
    .category-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 360px) {
    .category-grid { grid-template-columns: 1fr; }
}
.category-card {
    /* Tightened padding/gap so the 18-tile grid fits cleanly in narrow
       columns. Background gradient + border match the Hot Topics + Advanced
       Features panels, so the home-page chrome reads as one unified
       surface family rather than three different card systems. */
    display: flex; flex-direction: row; align-items: center; gap: 0.5rem;
    padding: 0.5rem 0.6rem;
    background: var(--gradient-panel-soft);
    border: 1px solid var(--color-border);
    border-radius: 8px; text-decoration: none; color: var(--color-text);
    min-height: 0;
    transition: border-color 0.12s ease, transform 0.12s ease;
}
.category-card:hover { border-color: var(--color-primary); transform: translateY(-1px); }
.category-card__icon { font-size: 1.15rem; line-height: 1; flex: 0 0 auto; }
.category-card__text {
    display: flex; flex-direction: column; gap: 0.1rem;
    flex: 1 1 auto; min-width: 0;
}
/* Card name is the primary clickable signal -> primary palette.
   Long names wrap naturally to a second line rather than truncating with
   ellipsis - tile rows in the grid auto-size to the tallest card so a
   wrapped "Real Estate & Development" doesn't break alignment. */
.category-card__name {
    /* Same font / weight / size as .state-link and .home-aside__hot-label so
       the three Home-page link surfaces (states, topics, categories) read
       as one type system. Tile readability without weight comes from the
       icon + tile chrome around it. */
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1rem;
    line-height: 1.2;
    color: var(--color-primary);
    /* No nowrap / ellipsis - allow wrapping. */
    word-break: break-word;
}
.category-card__meta {
    /* Bumped 0.7rem -> 0.8rem for legibility under the 1rem name link.
       Still clearly subordinate (slate, ~80% of the name's size) but no
       longer squinting-small. */
    display: flex; gap: 0.3rem; align-items: baseline;
    font-size: 0.8rem; color: var(--color-text-muted); font-variant-numeric: tabular-nums;
}
.category-card__items { font-weight: 600; color: var(--color-text-secondary); }
.category-card__sep { color: #cbd5e1; }
.category-card--empty { opacity: 0.55; pointer-events: none; }

/* Inline hot-topics strip (PlaceHome, EventDetail): flatten the aside panel into
   a horizontal block that doesn't compete with the main title. Same content as
   the aside variant, different container shape. */
.place-hot-topics-strip { margin: 0.5rem 0 1rem; }
.place-hot-topics-strip .home-aside__hot-topics { background: #f8fafc; border-color: #cbd5e1; }
.place-hot-topics-strip .home-aside__hot-list {
    display: flex; flex-wrap: wrap; gap: 0.35rem 0.75rem;
}
.place-hot-topics-strip .home-aside__hot-row {
    border-bottom: none; padding: 0.15rem 0;
    display: inline-flex; gap: 0.4rem;
}

/* AI summary banner on /search. Subtle, indigo-tinted call-out above results. */
.ai-summary-banner {
    background: linear-gradient(135deg, #eef2ff 0%, #f5f3ff 100%);
    border: 1px solid #c7d2fe;
    border-radius: var(--radius-lg);
    padding: var(--space-md) var(--space-lg);
    margin-bottom: var(--space-lg);
    max-width: 64rem;
}
.ai-summary-banner__header {
    display: flex; align-items: center; gap: var(--space-sm);
    font-size: 0.85rem; color: #4338ca; font-weight: 600;
    margin-bottom: var(--space-xs);
    text-transform: uppercase; letter-spacing: 0.03em;
}
.ai-summary-banner__sparkle { font-size: 1rem; }
.ai-summary-banner__model {
    margin-left: auto; font-size: 0.7rem; font-weight: 500;
    color: var(--color-text-muted); text-transform: none; letter-spacing: 0;
}
.ai-summary-banner__text {
    color: var(--color-text);
    font-size: 0.95rem; line-height: 1.5;
}
/* Loading variant - auto-AI summary streams in 5-10s after content lands.
   The shimmer + "Synthesizing across N documents…" text is what the user
   sees during that gap, so the area reads as "something coming" rather
   than "empty space". Subtle; not a flashy spinner - this is informational
   chrome, not a status modal. */
.ai-summary-banner--loading {
    border-style: dashed;
    background: linear-gradient(135deg, #f5f7ff 0%, #fafafe 100%);
}
.ai-summary-banner__text--shimmer {
    color: var(--color-text-muted);
    font-style: italic;
    background: linear-gradient(90deg,
        rgba(99, 102, 241, 0.0) 0%,
        rgba(99, 102, 241, 0.10) 50%,
        rgba(99, 102, 241, 0.0) 100%);
    background-size: 200% 100%;
    animation: ai-shimmer 1.6s ease-in-out infinite;
}
@keyframes ai-shimmer {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
}
/* Turnstile human-verification gate on /search. Rendered in place of
   results when an anonymous user hits /search without a valid _tv or
   lgd_human_verified cookie. Cloudflare's invisible challenge auto-solves
   for real browsers in <1s; the page then reloads with the token query
   param and the middleware sets the cookies + redirects to the clean URL.
   For the small minority where the challenge surfaces UI, the centered
   layout keeps it clean. */
.turnstile-gate {
    max-width: 30rem;
    margin: 4rem auto;
    text-align: center;
    color: var(--color-text);
}
.turnstile-gate h1 {
    font-size: 1.4rem;
    margin-bottom: 0.5rem;
}
.turnstile-gate p {
    color: var(--color-text-muted);
    margin-bottom: 1.5rem;
}
.turnstile-gate .cf-turnstile {
    display: flex;
    justify-content: center;
    margin: 1rem 0;
}
.turnstile-gate__noscript {
    color: #b91c1c;
    font-size: 0.88rem;
}

/* Two-column /search layout: facet sidebar (left) + results (right). The
   sidebar only renders when the API returned at least one facet dimension
   with hits; otherwise the layout collapses to a single full-width column
   via the --no-sidebar modifier. Mobile: sidebar drops below results so
   the cards stay above the fold. */
.gsearch__layout {
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    gap: var(--space-lg);
    margin-top: var(--space-md);
}
.gsearch__layout--no-sidebar { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 768px) {
    .gsearch__layout { grid-template-columns: minmax(0, 1fr); }
    /* Filters first, then results. The sidebar IS the slicing UI - hiding
       it below the result list on mobile means users have to scroll past
       50 results to discover they can narrow. order:0 keeps the natural
       DOM order (sidebar before results); margin-bottom separates the
       two. Sticky positioning is opt-in via the min-width:769px rule
       above, so we don't need to unstick it here. */
    .gsearch__sidebar {
        order: 0;
        margin-bottom: var(--space-md);
    }
}
.gsearch__sidebar {
    font-size: 0.88rem;
    align-self: start; /* don't stretch full height of results column */
}
/* Sticky filters scoped to desktop only. The original `position: sticky`
   sat in the base rule and appeared AFTER the mobile @media block in the
   cascade - so it overrode the mobile `position: static` override at
   every width and froze the sidebar to the top on phones. Wrapping it in
   min-width keeps the sticky desktop-only without source-order games. */
@media (min-width: 769px) {
    .gsearch__sidebar {
        position: sticky;
        top: var(--space-md);
    }
}
.gsearch__sidebar-header {
    display: flex; align-items: baseline; justify-content: space-between;
    margin-bottom: var(--space-sm);
}
.gsearch__sidebar-title {
    font-weight: 600; font-size: 0.78rem; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--color-text-muted);
}
.gsearch__sidebar-clear {
    font-size: 0.78rem; color: var(--color-primary); text-decoration: none;
}
.gsearch__sidebar-clear:hover { text-decoration: underline; }
.gsearch__facet-group {
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid #e5e7eb;
}
.gsearch__facet-group:last-child { border-bottom: none; }
.gsearch__facet-label {
    font-weight: 600; font-size: 0.72rem; text-transform: uppercase;
    letter-spacing: 0.05em; color: var(--color-text-muted);
    margin-bottom: 0.4rem;
}
.gsearch__facet-row {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.3rem 0.4rem; margin: 0 -0.4rem;
    color: var(--color-text); text-decoration: none;
    border-radius: 4px;
    line-height: 1.3;
}
.gsearch__facet-row:hover {
    background: #f3f4f6;
    color: var(--color-text);
}
.gsearch__facet-row--selected {
    background: #eff6ff;
    color: var(--color-primary);
    font-weight: 500;
}
.gsearch__facet-row--selected:hover { background: #dbeafe; }
.gsearch__facet-check {
    flex: 0 0 auto;
    font-size: 0.95rem;
    width: 1rem; text-align: center;
}
.gsearch__facet-name {
    flex: 1 1 auto;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gsearch__facet-count {
    flex: 0 0 auto;
    color: var(--color-text-muted);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}
.gsearch__facet-row--selected .gsearch__facet-count { color: var(--color-primary); }

/* Place events browse: same faceted grammar as /search, but tuned for a
   deterministic meeting calendar rather than text search results. */
.event-browse__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--space-lg);
    padding-top: 1.25rem;
}
.event-browse__signal {
    min-width: 10rem;
    text-align: right;
    color: var(--color-text-muted);
}
.event-browse__signal strong {
    display: block;
    color: var(--color-text);
    font-size: 1.65rem;
    line-height: 1;
    font-weight: 650;
}
.event-browse__signal span {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.82rem;
}
.event-browse__month {
    margin-top: var(--space-md);
}
.event-browse__presets {
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    margin: var(--space-md) 0 0;
}
.event-browse__preset {
    color: var(--color-primary);
    text-decoration: none;
    border: 1px solid #d1d5db;
    border-radius: 999px;
    padding: 0.32rem 0.7rem;
    font-size: 0.88rem;
    background: var(--color-bg-card);
}
.event-browse__preset:hover {
    background: #f8fafc;
    text-decoration: none;
}
.event-browse__preset--active {
    color: #fff;
    background: var(--color-primary);
    border-color: var(--color-primary);
}
.event-browse__results {
    min-width: 0;
}
.event-browse__window {
    color: var(--color-text-muted);
    font-size: 0.9rem;
    font-weight: 600;
    padding-bottom: 0.45rem;
}
.event-browse__toolbar {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--space-md);
    margin-bottom: var(--space-sm);
}
.event-date-jump {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.event-window-search {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
}
.event-window-search input[type="search"] {
    width: min(18rem, 42vw);
    min-height: 2.35rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    padding: 0.35rem 0.55rem;
}
.event-browse__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0.25rem 0 0.75rem;
}
.event-browse__chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    border: 1px solid #d1d5db;
    border-radius: 999px;
    padding: 0.2rem 0.55rem;
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.82rem;
    background: var(--color-bg-card);
}
.event-browse__chip:hover {
    background: #f8fafc;
    text-decoration: none;
}
.event-browse__cards {
    display: grid;
    gap: var(--space-sm);
}
@media (max-width: 768px) {
    .event-browse__header,
    .event-browse__toolbar {
        align-items: stretch;
        flex-direction: column;
    }
    .event-browse__signal {
        text-align: left;
        min-width: 0;
    }
    .event-window-search input[type="search"] {
        width: 100%;
    }
}

/* Refinement chips. Same LLM call that generates the summary returns 4-5
   short drill-down phrases - rendered here as clickable pill chips below
   the summary prose. Click jumps to /search?q=<phrase> while preserving
   the current scope. Indigo accent matches the banner family. */
.ai-summary-banner__refinements {
    display: flex; flex-wrap: wrap; gap: 0.4rem;
    align-items: center;
    margin-top: 0.75rem;
}
.ai-summary-banner__refinements-label {
    font-size: 0.72rem; font-weight: 600;
    color: #4338ca; text-transform: uppercase; letter-spacing: 0.05em;
    margin-right: 0.25rem;
}
.ai-summary-banner__chip {
    display: inline-flex; align-items: center;
    background: white;
    border: 1px solid #c7d2fe;
    color: #4338ca; font-weight: 500; font-size: 0.82rem;
    padding: 0.3rem 0.75rem; border-radius: 999px;
    text-decoration: none;
    transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.ai-summary-banner__chip:hover {
    background: #eef2ff;
    border-color: #818cf8;
    transform: translateY(-1px);
}

/* Expanded-terms chip strip. Shown above /search results to make the query
   rewrite visible: when the user searches "solar panels" and sees results
   containing "photovoltaic", the chip row explains why. Muted styling so it
   doesn't compete with the actual result list. */
.search-expanded-terms {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
    font-size: 0.85rem;
    max-width: 64rem;
}
.search-expanded-terms__label {
    color: var(--color-text-muted);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    font-size: 0.72rem;
    margin-right: var(--space-xs);
}
.search-expanded-terms__chip {
    display: inline-block;
    padding: 2px 10px;
    background: var(--v2-accent-soft, #e8f0f7);
    color: var(--v2-accent, #246cad);
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 500;
    white-space: nowrap;
}

