/* Conference Library — single-theme CSS.
 *
 * All theme tokens live in :root as CSS custom properties so swapping the
 * palette / typography is a one-edit job. The rest of the file uses those
 * tokens; do NOT hard-code colours below.
 *
 * Layout is intentionally simple:
 *   - body is a centered max-width column
 *   - <header>/<main>/<footer> are siblings
 *   - cards/lists use CSS grid
 * No frameworks, no preprocessor, no build step.
 */

:root {
    /* Palette — neutral with a single accent. Tweak these eight values to retheme. */
    --c-bg:           #fafafa;
    --c-surface:      #ffffff;
    --c-surface-alt:  #f1f1f3;
    --c-border:       #e3e3e6;
    --c-text:         #1a1a1d;
    --c-text-muted:   #555a63;
    --c-accent:       #0066d8;
    --c-accent-soft:  #e6f0fc;

    /* Typography — system fonts only; nothing to fetch. */
    --font-sans:  ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono:  ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "Liberation Mono", monospace;
    --fs-xs:      0.8125rem;
    --fs-sm:      0.9375rem;
    --fs-md:      1rem;
    --fs-lg:      1.125rem;
    --fs-xl:      1.5rem;
    --fs-2xl:     2rem;
    --fs-3xl:     2.5rem;

    /* Spacing scale (4-pt grid). */
    --s-1:   0.25rem;
    --s-2:   0.5rem;
    --s-3:   0.75rem;
    --s-4:   1rem;
    --s-5:   1.5rem;
    --s-6:   2rem;
    --s-8:   3rem;
    --s-10:  4rem;

    --radius: 8px;
    --radius-sm: 4px;
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.04);
    --shadow-md: 0 4px 12px rgba(0,0,0,0.06);

    --max-w: 1080px;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--c-bg);
    color: var(--c-text);
    font-family: var(--font-sans);
    font-size: var(--fs-md);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

a {
    color: var(--c-accent);
    text-decoration: none;
}
a:hover { text-decoration: underline; }

code, pre {
    font-family: var(--font-mono);
    font-size: 0.9em;
}

pre {
    background: var(--c-surface-alt);
    border: 1px solid var(--c-border);
    padding: var(--s-4);
    border-radius: var(--radius-sm);
    overflow-x: auto;
}

/* ---- layout ---- */

.page {
    max-width: var(--max-w);
    margin: 0 auto;
    padding: var(--s-6) var(--s-5);
}

.site-header {
    border-bottom: 1px solid var(--c-border);
    background: var(--c-surface);
}
.site-header .page {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--s-3) var(--s-5);
    padding-block: var(--s-4);
}
.site-header h1 {
    font-size: var(--fs-lg);
    margin: 0;
}
.site-header h1 a { color: var(--c-text); font-weight: 700; }
.site-header nav {
    display: flex;
    gap: var(--s-4);
    font-size: var(--fs-sm);
}
.site-header .breadcrumb {
    flex-basis: 100%;
    font-size: var(--fs-xs);
    color: var(--c-text-muted);
    margin-bottom: var(--s-1);
}
.site-header .breadcrumb a {
    color: var(--c-text-muted);
    text-decoration: none;
}
.site-header .breadcrumb a:hover {
    color: var(--c-accent);
    text-decoration: underline;
}

.site-footer {
    border-top: 1px solid var(--c-border);
    background: var(--c-surface);
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
    margin-top: var(--s-10);
}
.site-footer .page {
    padding-block: var(--s-5);
}
.site-footer p { margin: var(--s-1) 0; }

/* ---- index page: filter bar + session cards ---- */

.hero {
    margin-bottom: var(--s-6);
}
.hero h2 {
    font-size: var(--fs-2xl);
    margin: 0 0 var(--s-2);
}
.hero p {
    color: var(--c-text-muted);
    margin: 0;
    max-width: 60ch;
}

.filters {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-3);
    padding: var(--s-4);
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    margin-bottom: var(--s-5);
}
@media (min-width: 720px) {
    .filters { grid-template-columns: 2fr 1fr 1fr 1fr; }
}
.filters input,
.filters select {
    width: 100%;
    padding: var(--s-2) var(--s-3);
    font: inherit;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    background: var(--c-bg);
    color: var(--c-text);
}
.filters input:focus,
.filters select:focus {
    outline: 2px solid var(--c-accent);
    outline-offset: 1px;
}

.results-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin: var(--s-4) 0 var(--s-3);
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
}

.session-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-3);
    list-style: none;
    padding: 0;
    margin: 0;
}
@media (min-width: 720px) {
    .session-list { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1280px) {
    .session-list { grid-template-columns: 1fr 1fr 1fr; }
}

/* Session card on the index. Compact horizontal layout: thumbnail on the
   left, metadata stacked on the right. Whole card is hover-elevated, the
   title and thumbnail both deep-link to the per-session page. */
.session-card {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    display: grid;
    grid-template-columns: 144px 1fr;
    gap: var(--s-3);
    padding: var(--s-3);
    transition: box-shadow 120ms ease, transform 120ms ease, border-color 120ms ease;
}
.session-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    border-color: var(--c-accent);
}
.session-card .card-thumb-link {
    display: block;
    line-height: 0; /* removes inline-image baseline gap */
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.session-card .card-thumb {
    width: 144px;
    height: 81px;            /* 16:9 */
    object-fit: cover;
    background: var(--c-surface-alt);
    display: block;
}
.session-card .card-thumb-empty {
    /* Placeholder pattern for cards with no captured frames. */
    background: repeating-linear-gradient(
        45deg, var(--c-surface-alt), var(--c-surface-alt) 6px,
        var(--c-surface) 6px, var(--c-surface) 12px);
}
.session-card .card-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;            /* lets text truncate inside the grid cell */
}
.session-card .card-row-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-2);
    flex-wrap: wrap;
}
/* Right-side badges (Repo + status) sit in a single inline-flex group so
   they wrap to a new line together when the code+type text takes the
   full first line. Without this, "Ended" overflowed the card on narrow
   cards where the code text was already wide and the Repo badge ate
   the remaining horizontal space. */
.session-card .card-badges {
    display: inline-flex;
    align-items: center;
    gap: var(--s-1);
    flex-shrink: 0;
}
.session-card .code {
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    color: var(--c-text-muted);
    letter-spacing: 0.04em;
    /* min-width:0 lets the .code shrink inside the flex row so the badges
       stay visible. Without it, .code would push the badges off. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.session-card h3 {
    margin: 0;
    font-size: var(--fs-md);
    line-height: 1.3;
    /* Two-line clamp so very long titles don't blow up card height. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.session-card h3 a { color: var(--c-text); }
.session-card .speakers {
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.session-card .when {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-1) var(--s-3);
    font-size: var(--fs-xs);
    color: var(--c-text-muted);
    margin-top: 2px;
}
.session-card .when .when-start { font-weight: 600; color: var(--c-text); }
.session-card .when .when-dur   { font-family: var(--font-mono); }
.session-card .when .when-rel   { font-style: italic; }
.session-card .card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-1);
    margin-top: auto;
}
/* Smaller-than-default tag pill specifically for the card grid. */
.tag-tiny {
    padding: 1px 6px;
    font-size: 11px;
    background: var(--c-surface-alt);
    color: var(--c-text-muted);
    border-radius: 4px;
}

/* Stack the card vertically on very narrow screens (phones). */
@media (max-width: 480px) {
    .session-card {
        grid-template-columns: 1fr;
    }
    .session-card .card-thumb,
    .session-card .card-thumb-link {
        width: 100%;
        height: auto;
        aspect-ratio: 16 / 9;
    }
}

.tag {
    display: inline-block;
    padding: 2px var(--s-2);
    background: var(--c-surface-alt);
    color: var(--c-text-muted);
    border-radius: 999px;
    font-size: var(--fs-xs);
    text-decoration: none;
}
.tag.accent {
    background: var(--c-accent-soft);
    color: var(--c-accent);
}
.tag:hover { background: var(--c-accent-soft); color: var(--c-accent); }

.no-results {
    text-align: center;
    color: var(--c-text-muted);
    padding: var(--s-8);
    background: var(--c-surface);
    border: 1px dashed var(--c-border);
    border-radius: var(--radius);
}

/* ---- session page ---- */

.session-hero {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    margin-bottom: var(--s-6);
}
.session-hero .code {
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
    letter-spacing: 0.06em;
}
.session-hero h1 {
    margin: 0;
    font-size: var(--fs-3xl);
    line-height: 1.2;
}
.session-hero .speakers {
    font-size: var(--fs-lg);
    color: var(--c-text-muted);
}
.session-hero .meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-3);
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
}
.session-hero .meta > * {
    display: inline-flex;
    align-items: center;
    gap: var(--s-1);
}
.session-hero .tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    margin-top: var(--s-2);
}

.session-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    margin: var(--s-4) 0 var(--s-6);
    padding: var(--s-4);
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
}
.session-actions a {
    display: inline-block;
    padding: var(--s-2) var(--s-4);
    background: var(--c-surface-alt);
    color: var(--c-text);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    border: 1px solid var(--c-border);
}
.session-actions a:hover {
    background: var(--c-accent-soft);
    border-color: var(--c-accent);
    color: var(--c-accent);
    text-decoration: none;
}
.session-actions a.primary {
    background: var(--c-accent);
    color: white;
    border-color: var(--c-accent);
}
.session-actions a.primary:hover { background: #0058bd; }

.section {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--s-5);
    margin-bottom: var(--s-5);
}
.section h2 {
    margin: 0 0 var(--s-3);
    font-size: var(--fs-xl);
}
.section h3 { font-size: var(--fs-lg); margin: var(--s-4) 0 var(--s-2); }

.section .summary {
    /* Constrain summary line length for readability. */
    max-width: 70ch;
}
.section .summary blockquote {
    border-left: 3px solid var(--c-border);
    margin-left: 0;
    padding-left: var(--s-4);
    color: var(--c-text-muted);
    font-style: italic;
}

.frames-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: var(--s-3);
}
/* Tighter grid for the per-announcement 4-frame mini-galleries; lets the
   whole 4-frame strip fit comfortably on one row at typical viewport
   widths while staying tappable on phones. */
.frames-grid.frames-grid-tight {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: var(--s-2);
}
/* Per-announcement sub-grouping below the main 15-frame grid. */
.ann-frames {
    margin-top: var(--s-5);
}
.section-subhead {
    margin: var(--s-5) 0 var(--s-3) 0;
    font-size: var(--fs-md);
    color: var(--c-text-muted);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border-top: 1px solid var(--c-border);
    padding-top: var(--s-3);
}
.ann-group {
    margin-bottom: var(--s-4);
}
.ann-group .ann-ts {
    margin: 0 0 var(--s-2) 0;
    font-size: var(--fs-sm);
    font-family: var(--font-mono);
    color: var(--c-accent);
}
.frames-grid figure {
    margin: 0;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--c-surface-alt);
}
.frames-grid img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}
.frames-grid figcaption {
    padding: var(--s-1) var(--s-2);
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    color: var(--c-text-muted);
    background: var(--c-surface);
    border-top: 1px solid var(--c-border);
}

details.transcript {
    margin-top: var(--s-2);
}
details.transcript summary {
    cursor: pointer;
    color: var(--c-accent);
    padding: var(--s-2) 0;
    font-weight: 500;
}
details.transcript .transcript-body {
    margin-top: var(--s-3);
    padding: var(--s-3);
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    max-height: 600px;
    overflow-y: auto;
    font-size: var(--fs-sm);
    white-space: pre-wrap;
    line-height: 1.7;
}

.refs-list { list-style: none; padding: 0; margin: 0; }
.refs-list li { padding: var(--s-2) 0; border-bottom: 1px solid var(--c-border); }
.refs-list li:last-child { border-bottom: none; }

/* Multi-year landing (docs/index.html). */
.year-list {
    list-style: none;
    padding: 0;
    margin: var(--s-6) 0 0 0;
    display: grid;
    gap: var(--s-4);
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.year-card a {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    padding: var(--s-5);
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    color: var(--c-text);
    transition: border-color 120ms ease, transform 120ms ease;
}
.year-card a:hover {
    border-color: var(--c-accent);
    transform: translateY(-1px);
}
.year-card strong { font-size: var(--fs-xl); color: var(--c-accent); }
.year-card span   { color: var(--c-text-muted); font-size: var(--fs-sm); }
.year-card small  { color: var(--c-text-muted); font-size: var(--fs-xs); font-family: var(--font-mono); }

/* In-page recording-availability notice (.notice-info for "by-policy not
   recorded", .notice-warning for "should be recorded but isn't uploaded
   yet"). Sits between the session-hero and the rest of the page so the
   visitor immediately understands why there's no player below. */
.notice {
    margin: var(--s-4) 0;
    padding: var(--s-3) var(--s-4);
    border-radius: var(--radius);
    border-left: 4px solid;
    font-size: var(--fs-sm);
    line-height: 1.5;
}
.notice strong {
    display: block;
    margin-bottom: 2px;
    font-weight: 600;
}
.notice-info {
    background: var(--c-accent-soft);
    border-color: var(--c-accent);
    color: var(--c-text);
}
.notice-warning {
    background: #fff8e6;
    border-color: #d4a017;
    color: #6b4f00;
}

/* Session-page cover frame: oversized hero image above the player. */
.cover {
    margin: var(--s-5) 0;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--c-surface-alt);
}
.cover .cover-link {
    display: block;
    cursor: zoom-in;
}
.cover img {
    width: 100%;
    height: auto;
    max-height: 60vh;
    object-fit: cover;
    display: block;
}

/* Embedded video / iframe player. 16:9 responsive wrapper. */
.player {
    margin: var(--s-5) 0;
    background: #000;
    border-radius: var(--radius);
    overflow: hidden;
    aspect-ratio: 16 / 9;
}
.player video,
.player iframe {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

/* Status badge - upcoming / live / ended. Filled in by client JS via
   data-start / data-end attributes on .status-line. */
.status-line {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    margin-top: var(--s-2);
    font-size: var(--fs-sm);
}
.status-line:empty { display: none; }
.status-badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--c-surface-alt);
    color: var(--c-text-muted);
}
.status-badge:empty { display: none; }
.status-badge.is-upcoming { background: #fff3cd; color: #7a5b00; }
.status-badge.is-live     { background: #d4edda; color: #155724; animation: pulse 1.6s ease-in-out infinite; }
.status-badge.is-ended    { background: #e2e3e5; color: #383d41; }
/* Demo-repo badge sits beside the status badge on the session card.
   Light blue tint distinguishes it from the live/upcoming/ended trio,
   and the <a> hover lifts it to full accent so it reads as clickable. */
.status-badge.is-demo-repo { background: #ddeaff; color: #1a4f9c; text-decoration: none; }
.status-badge.is-demo-repo:hover { background: #1a4f9c; color: #fff; text-decoration: none; }
.status-detail { color: var(--c-text-muted); }
@keyframes pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(40,167,69,0.4); }
    50%      { box-shadow: 0 0 0 6px rgba(40,167,69,0); }
}

/* Multi-select tag pills on the per-event index. Top-N tags shown by
   default with a "Show all" expand toggle to keep vertical density low. */
.filters-pills {
    margin: var(--s-2) 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    /* Hard cap on pill row height so a "Show all" expansion of 150 tags
       doesn't push the session grid below the fold; vertical scroll is the
       fallback. */
    max-height: 14em;
    overflow-y: auto;
    padding: 2px 0;
}
.filters-pills .pill-label {
    font-size: var(--fs-xs);
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-right: var(--s-2);
}
.filter-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 10px;
    border: 1px solid var(--c-border);
    border-radius: 999px;
    background: var(--c-surface);
    color: var(--c-text);
    font-size: var(--fs-xs);
    line-height: 1.4;
    cursor: pointer;
    user-select: none;
    transition: all 100ms ease;
}
.filter-pill:hover { border-color: var(--c-accent); }
.filter-pill.is-on {
    background: var(--c-accent);
    color: white;
    border-color: var(--c-accent);
}
.filter-pill .pill-count {
    opacity: 0.65;
    font-size: 0.85em;
}
.filter-pill.is-on .pill-count { opacity: 0.85; }
.filter-pill .pill-icon {
    /* Small check-mark prefix for boolean toggle pills like "Recorded only".
       Hidden when the pill is off; visible (and white-on-accent) when on. */
    display: inline-block;
    width: 1em;
    text-align: center;
    opacity: 0;
    transition: opacity 100ms ease;
}
.filter-pill.is-on .pill-icon { opacity: 1; }
.pills-toggle {
    background: none;
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    padding: 2px 10px;
    font-size: var(--fs-xs);
    color: var(--c-text-muted);
    cursor: pointer;
}
.pills-toggle:hover { color: var(--c-accent); border-color: var(--c-accent); }

/* Lightbox: full-viewport modal overlay (vanilla, no library). */
.lightbox-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.85);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9999;
    cursor: zoom-out;
}
.lightbox-backdrop img {
    max-width: 95vw;
    max-height: 95vh;
    object-fit: contain;
    box-shadow: 0 8px 32px rgba(0,0,0,0.5);
}
.lightbox-backdrop .lightbox-close {
    position: absolute;
    top: var(--s-4);
    right: var(--s-5);
    background: none;
    border: 0;
    color: white;
    font-size: 2rem;
    cursor: pointer;
    line-height: 1;
}

/* Frames in the gallery: clickable anchors with zoom cursor. */
.frames-grid a { display: block; cursor: zoom-in; text-decoration: none; }
.frames-grid a img { transition: transform 100ms ease; }
.frames-grid a:hover img { transform: scale(1.02); }

/* Inline announcement-frame strips next to each [HH:MM:SS] timestamp in
   the summary. Two trigger modes:
     - hover (desktop quick-peek): the strip pops out below on :hover
     - click (.is-open class added by JS): the strip becomes sticky-open
   The sticky mode is the primary interaction because:
     1) hover doesn't work on touch devices
     2) the absolutely-positioned strip has a tiny gap from the anchor that
        broke hover transitions, especially when the user moves their cursor
        down to click a thumbnail
   Click-to-toggle (handled in session.js) routes around both problems. */
.anchor {
    position: relative;
    /* inline-block guarantees the absolutely-positioned strip is positioned
       against a properly-sized box even when the anchor straddles a line
       break in the surrounding <li>/<p>. */
    display: inline-block;
    cursor: pointer;
    color: var(--c-accent);
    font-family: var(--font-mono);
    font-size: 0.9em;
    /* Subtle visual hint that the text is interactive. */
    border-bottom: 1px dotted var(--c-accent);
}
.anchor:hover { background: var(--c-accent-soft); }
.anchor .af-strip {
    position: absolute;
    top: 100%;
    left: 0;
    /* No margin here - any vertical gap turns into a hover-trap area where
       the cursor leaves the anchor and the strip vanishes. Use padding on
       the parent or absorb the space via the strip's own top padding. */
    margin-top: 0;
    display: none;
    gap: var(--s-2);
    padding: var(--s-2);
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    z-index: 50;
}
.anchor:hover .af-strip,
.anchor:focus-within .af-strip,
.anchor.is-open .af-strip {
    display: flex;
}
.anchor.is-open {
    background: var(--c-accent-soft);
    /* Brighter outline so the active anchor is obvious among siblings. */
    border-bottom-style: solid;
}
.af-cell {
    display: block;
    text-decoration: none;
    color: var(--c-text-muted);
    text-align: center;
    cursor: zoom-in;
}
.af-cell img {
    width: 140px;
    height: 78px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--c-border);
    display: block;
    transition: transform 100ms ease, border-color 100ms ease;
}
.af-cell:hover img {
    transform: scale(1.03);
    border-color: var(--c-accent);
}
.af-cell .af-cap {
    display: block;
    font-size: var(--fs-xs);
    font-family: var(--font-mono);
    margin-top: 2px;
}

/* Inline play-button injected next to every [HH:MM:SS] timestamp in the
   summary by Build-Book.ps1's Inject-AnnouncementFrames. Clicking it tells
   session.js to seek the page's session-video to (ts - 5s) and play.
   Visually paired with the timestamp (no gap), small enough to read as an
   affordance without dominating the prose. Subtle by default; goes
   accent-coloured on hover / focus to confirm interactivity. */
.ts-play {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.2em;
    height: 1.2em;
    margin-left: 2px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 3px;
    background: transparent;
    color: var(--c-text-muted);
    font-size: 0.7em;
    line-height: 1;
    cursor: pointer;
    vertical-align: middle;
    transition: color 100ms ease, background 100ms ease, border-color 100ms ease, transform 80ms ease;
}
.ts-play:hover,
.ts-play:focus-visible {
    color: var(--c-accent);
    background: var(--c-accent-soft);
    border-color: var(--c-accent);
    outline: none;
}
.ts-play:active {
    transform: scale(0.9);
}

/* Inline link next to .ts-play that jumps to the per-entity announcement
   page when this timestamp resolves to a canonical announcement entity.
   Identical sizing + colour treatment to .ts-play so the pair reads as a
   single 2-button control next to each timestamp; rendered as <a> so the
   browser's native right-click / middle-click open-in-new-tab work. The
   arrow glyph (U+2197) signals "go to a detail page", contrasting with the
   play triangle so they're visually distinguishable at a glance. */
.ts-open-entity {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.2em;
    height: 1.2em;
    margin-left: 2px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 3px;
    background: transparent;
    color: var(--c-text-muted);
    font-size: 0.85em;
    line-height: 1;
    vertical-align: middle;
    text-decoration: none;
    transition: color 100ms ease, background 100ms ease, border-color 100ms ease, transform 80ms ease;
}
.ts-open-entity:hover,
.ts-open-entity:focus-visible {
    color: var(--c-accent);
    background: var(--c-accent-soft);
    border-color: var(--c-accent);
    outline: none;
    text-decoration: none;
}
.ts-open-entity:active {
    transform: scale(0.9);
}

/* Lightweight "ts" wrapper for the case where a timestamp has no frames on
   disk - just provides the same inline-baseline alignment as .anchor + .ts-play
   so the play button doesn't visually drift. */
.ts {
    display: inline;
    white-space: nowrap;
}

/* ============================================================
   Announcements view
   - Landing page (docs/<Conf>/<Event>/announcements/index.html)
   - Per-entity page (docs/<Conf>/<Event>/announcements/<slug>.html)
   - "Announcements introduced here" sidebar on session pages
   Mirrors the existing session-list visual language: same card surface,
   border radius, hover lift, accent treatment. The category chip palette
   is the only new colour; everything else reuses the theme tokens at
   :root.
   ============================================================ */

/* ---- landing: card grid ---- */

.entity-list {
    list-style: none;
    margin: var(--s-5) 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-4);
}
@media (min-width: 720px) {
    .entity-list { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1080px) {
    .entity-list { grid-template-columns: 1fr 1fr 1fr; }
}

.entity-card {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}
.entity-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--c-accent);
}
.entity-card a {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
    padding: var(--s-4);
    color: var(--c-text);
    text-decoration: none;
}
.entity-card a:hover { text-decoration: none; }
.entity-card strong {
    font-size: var(--fs-lg);
    color: var(--c-accent);
    line-height: 1.25;
}
.entity-card small {
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
}
.entity-tagline-card {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
    line-height: 1.45;
    /* Cap to 4 lines so cards stay equal-ish heights without truncating
       on the entity detail page. */
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.entity-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-2);
}
.entity-card-badges {
    display: inline-flex;
    gap: var(--s-1);
    flex-wrap: wrap;
}

/* ---- per-entity page: hero ---- */

.entity-hero {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--s-5) var(--s-5);
    margin-bottom: var(--s-5);
}
.entity-hero h1 {
    margin: var(--s-2) 0 var(--s-3);
    font-size: var(--fs-2xl);
    line-height: 1.15;
    color: var(--c-text);
}
.entity-hero-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-2);
}
.entity-tagline {
    color: var(--c-text-muted);
    font-size: var(--fs-lg);
    margin: 0 0 var(--s-3);
}
.entity-stats {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-4);
    margin-top: var(--s-3);
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
}
.entity-stats span strong { color: var(--c-text); font-weight: 600; }
.entity-aliases {
    margin-top: var(--s-3);
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
}
.entity-aliases code {
    background: var(--c-surface-alt);
    padding: 0 var(--s-1);
    border-radius: var(--radius-sm);
}

/* ---- per-entity page: sections ---- */

.entity-section {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--s-5);
    margin-bottom: var(--s-4);
}
.entity-section h2 {
    margin: 0 0 var(--s-3);
    font-size: var(--fs-xl);
}
.entity-section h3 {
    margin: var(--s-4) 0 var(--s-2);
    font-size: var(--fs-md);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--c-text-muted);
    font-weight: 600;
}
.entity-section p { margin: 0 0 var(--s-3); }
.entity-section p:last-child { margin-bottom: 0; }

/* "Get started" link groups */
.link-group {
    list-style: none;
    margin: 0 0 var(--s-3);
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-1);
}
.link-group li {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    flex-wrap: wrap;
}
.link-group a { word-break: break-all; }
.link-kind {
    display: inline-block;
    min-width: 5.5rem;
    text-align: center;
    background: var(--c-accent-soft);
    color: var(--c-accent);
    padding: 0 var(--s-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.source-badge {
    display: inline-block;
    padding: 0 var(--s-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1.6;
    border: 1px solid var(--c-border);
    background: var(--c-surface-alt);
    color: var(--c-text-muted);
}
.source-badge[data-src="manual"]     { background: #e6f7eb; color: #1f6f3b; border-color: #cfe9d6; }
.source-badge[data-src="transcript"] { background: var(--c-accent-soft); color: var(--c-accent); border-color: #cfe0f5; }
.source-badge[data-src="search"]     { background: #fff1d6; color: #8a5a00; border-color: #f1dfb0; }
.source-badge[data-src="model"]      { background: #fff1d6; color: #8a5a00; border-color: #f1dfb0; }
.source-detail {
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
}

/* Code snippets section reuses the global <pre> styling. */
.entity-snippet {
    margin: 0 0 var(--s-3);
}
.entity-snippet figcaption {
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
    margin-bottom: var(--s-1);
}
.entity-snippet pre {
    margin: 0;
}

/* Sessions / mentions list on the per-entity page. */
.mention-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-3);
}
@media (min-width: 720px) {
    .mention-list { grid-template-columns: 1fr 1fr; }
}
.mention-card {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--s-3);
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}
.mention-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-2);
}
.mention-card-head .mention-ts {
    font-family: var(--font-mono);
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
}
.mention-card strong {
    font-size: var(--fs-md);
    color: var(--c-accent);
}
.mention-card .mention-speakers {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
}
.mention-card .mention-frames {
    display: flex;
    gap: var(--s-1);
    overflow-x: auto;
}
.mention-card .mention-frames img {
    width: 96px;
    height: 54px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--c-border);
    flex: 0 0 96px;
}
.mention-card .mention-desc {
    color: var(--c-text);
    font-size: var(--fs-sm);
    line-height: 1.45;
    /* Cap to 5 lines; full text is on the session page. */
    display: -webkit-box;
    -webkit-line-clamp: 5;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.mention-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    margin-top: auto;
}
.mention-actions a {
    background: var(--c-accent-soft);
    color: var(--c-accent);
    padding: 0 var(--s-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1.8;
}
.mention-actions a:hover { background: var(--c-accent); color: white; text-decoration: none; }

/* ---- category chips (12-bucket fixed taxonomy from Get-SessionAnnouncements.cs) ---- */

.entity-cat {
    display: inline-block;
    padding: 0 var(--s-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1.6;
    text-transform: lowercase;
    letter-spacing: 0.03em;
    border: 1px solid transparent;
}
/* Distinct hues per category, hand-picked for accessible contrast on
   the neutral surface and easy at-a-glance scanning of mixed grids.
   Values are intentionally muted so the chip blends into the card. */
.entity-cat-model     { background: #ecdcff; color: #4d2680; }
.entity-cat-service   { background: #d6ecff; color: #1f4f8a; }
.entity-cat-SDK       { background: #fde6d3; color: #8a4a00; }
.entity-cat-framework { background: #ffe0e6; color: #8a1f3a; }
.entity-cat-library   { background: #d6e8d2; color: #2b6326; }
.entity-cat-tool      { background: #d6e8d2; color: #2b6326; }
.entity-cat-runtime   { background: #ddd8d2; color: #3f342a; }
.entity-cat-hardware  { background: #ffdcdc; color: #872020; }
.entity-cat-spec      { background: #e6e6e6; color: #3f3f3f; }
.entity-cat-feature   { background: #e6f0fc; color: #0066d8; }
.entity-cat-platform  { background: #ecdcff; color: #4d2680; }
.entity-cat-concept   { background: #f1f1f3; color: #555a63; }
.entity-cat-speaker   { background: #e6e6ff; color: #2b2b8a; }
.entity-cat-theme     { background: #d6efe6; color: #0c5e3f; }

.link-badge {
    display: inline-block;
    padding: 0 var(--s-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1.6;
    background: var(--c-accent-soft);
    color: var(--c-accent);
}

.pill-label {
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
    margin-right: var(--s-1);
    line-height: 2;
}

/* ---- session-page sidebar: "Announcements introduced here" ---- */

.session-ann-sidebar {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--s-4);
    margin: var(--s-4) 0;
}
.session-ann-sidebar h2 {
    margin: 0 0 var(--s-3);
    font-size: var(--fs-lg);
}
.session-ann-sidebar ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
}
.session-ann-sidebar li {
    display: inline-flex;
    align-items: center;
    gap: var(--s-1);
}
.session-ann-sidebar li a {
    display: inline-flex;
    align-items: center;
    gap: var(--s-1);
    padding: var(--s-1) var(--s-2);
    background: var(--c-surface-alt);
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--c-text);
    font-size: var(--fs-sm);
    border: 1px solid var(--c-border);
}
.session-ann-sidebar li a:hover {
    border-color: var(--c-accent);
    color: var(--c-accent);
}

/* ---- top nav link to Announcements (added inside .site-header > .page > nav) ---- */

.site-header nav a + a { margin-left: var(--s-3); }

/* ---- error inside list views ---- */
.entity-list .error,
.session-list .error {
    grid-column: 1 / -1;
    background: #fff7e6;
    border: 1px solid #f1dfb0;
    color: #8a5a00;
    padding: var(--s-4);
    border-radius: var(--radius);
}

/* ============================================================
   Per-event hub page (docs/<Conf>/<Event>/index.html)
   Two co-equal entry points (Sessions, Announcements) plus an
   inline federated search drop-down.
   ============================================================ */

.hub-hero {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--s-6) var(--s-5);
    margin-bottom: var(--s-5);
    text-align: center;
}
.hub-hero h2 {
    font-size: var(--fs-3xl);
    margin: 0 0 var(--s-3);
    color: var(--c-text);
}
.hub-context {
    color: var(--c-text-muted);
    font-size: var(--fs-lg);
    line-height: 1.55;
    margin: 0 auto var(--s-5);
    max-width: 720px;
}

/* Federated search box + inline drop-down */
.hub-search-wrap {
    max-width: 720px;
    margin: 0 auto;
    position: relative;
}
.hub-search-input {
    width: 100%;
    padding: var(--s-3) var(--s-4);
    font-size: var(--fs-lg);
    font-family: inherit;
    border: 2px solid var(--c-border);
    border-radius: var(--radius);
    background: var(--c-bg);
    color: var(--c-text);
    transition: border-color 120ms ease, box-shadow 120ms ease;
}
.hub-search-input:focus {
    outline: none;
    border-color: var(--c-accent);
    box-shadow: 0 0 0 3px var(--c-accent-soft);
}
.hub-search-results {
    position: absolute;
    top: calc(100% + var(--s-2));
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    max-height: 70vh;
    overflow-y: auto;
    text-align: left;
}
.hub-search-meta {
    padding: var(--s-2) var(--s-4);
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
    border-bottom: 1px solid var(--c-border);
    background: var(--c-surface-alt);
}
.hub-search-footer {
    padding: var(--s-2) var(--s-4);
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
    border-top: 1px solid var(--c-border);
    background: var(--c-surface-alt);
}
.hub-search-empty {
    padding: var(--s-4);
    color: var(--c-text-muted);
    text-align: center;
}
.hub-search-error {
    padding: var(--s-4);
    color: #8a1f3a;
    text-align: center;
}

.hub-result-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.hub-result {
    border-bottom: 1px solid var(--c-border);
}
.hub-result:last-child { border-bottom: none; }
.hub-result a {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding: var(--s-3) var(--s-4);
    color: var(--c-text);
    text-decoration: none;
    transition: background 80ms ease;
}
.hub-result a:hover {
    background: var(--c-accent-soft);
    text-decoration: none;
}
.hub-result strong {
    flex: 1;
    color: var(--c-accent);
    font-size: var(--fs-md);
    line-height: 1.3;
}
.hub-result small {
    color: var(--c-text-muted);
    font-size: var(--fs-xs);
    display: block;
    margin-top: 2px;
}
.hub-result-badge {
    display: inline-block;
    padding: 0 var(--s-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1.6;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    flex-shrink: 0;
    min-width: 7rem;
    text-align: center;
}
.hub-result-badge-session      { background: var(--c-accent-soft); color: var(--c-accent); }
.hub-result-badge-announcement { background: #fff1d6;              color: #8a5a00; }
.hub-result-badge-speaker      { background: #e6e6ff;              color: #2b2b8a; }
.hub-result-badge-theme        { background: #d6efe6;              color: #0c5e3f; }

/* Two-card grid */
.hub-card-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-5);
}
/* Hub card grids — split into two tiers.
   Primary (Sessions + Announcements): full-size cards with description
   paragraph + accent CTA. Always 2-up at >=720px so the two co-equal
   entry points sit side by side. Below 720px stacks vertically.
   Secondary (Speakers + Themes): compact horizontal tiles below the
   primary row, conveying that they are derived views built on top of
   the primaries rather than top-level entry points. The secondary <ul>
   collapses to display:none when empty (events without either pipeline),
   so the layout stays clean across configs. */
.hub-card-grid-primary {
    grid-template-columns: 1fr;
}
.hub-card-grid-secondary {
    list-style: none;
    margin: var(--s-4) 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-3);
}
.hub-card-grid-secondary:empty { display: none; }

@media (min-width: 720px) {
    .hub-card-grid-primary   { grid-template-columns: 1fr 1fr; }
    .hub-card-grid-secondary { grid-template-columns: 1fr 1fr; }
}

.hub-card {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease;
}
.hub-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--c-accent);
}
.hub-card a {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    padding: var(--s-5);
    color: var(--c-text);
    text-decoration: none;
    height: 100%;
}
.hub-card a:hover { text-decoration: none; }
.hub-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-3);
    border-bottom: 1px solid var(--c-border);
    padding-bottom: var(--s-3);
}
.hub-card-label {
    font-size: var(--fs-xl);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--c-text);
}
.hub-card-stat {
    font-size: var(--fs-3xl);
    font-weight: 700;
    color: var(--c-accent);
    line-height: 1;
}
.hub-card-desc {
    color: var(--c-text);
    font-size: var(--fs-md);
    line-height: 1.55;
    margin: 0;
}
.hub-card-cta {
    margin-top: auto;
    color: var(--c-accent);
    font-weight: 600;
    padding-top: var(--s-3);
    border-top: 1px solid var(--c-border);
}

/* Accent the two primary cards distinctly so they're visually
   distinguishable at a glance even before reading the label. Sessions
   uses the brand accent (blue); announcements uses amber. The two
   secondary cards (speakers + themes) deliberately do NOT carry a
   per-card hover accent - their demotion comes from layout + muted
   tone, not from a color rotation. */
.hub-card-sessions:hover      { border-color: var(--c-accent); }
.hub-card-announcements:hover { border-color: #8a5a00; }
.hub-card-announcements:hover .hub-card-stat { color: #8a5a00; }
.hub-card-announcements:hover .hub-card-cta  { color: #8a5a00; }

/* Secondary card variant: compact horizontal tile, muted background,
   no shadow, smaller fonts. Applied to speakers + themes cards by
   Build-Book.ps1 (it adds the .hub-card-secondary class to each <li>).
   Rendered inside .hub-card-grid-secondary below the primary row. */
.hub-card-secondary {
    background: var(--c-surface-alt);
    box-shadow: none;
}
.hub-card-secondary a {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-3);
    padding: var(--s-3) var(--s-4);
}
.hub-card-secondary .hub-card-head {
    border-bottom: none;
    padding-bottom: 0;
    flex: 1 1 auto;
}
.hub-card-secondary .hub-card-label {
    font-size: var(--fs-md);
}
.hub-card-secondary .hub-card-stat {
    font-size: var(--fs-xl);
    color: var(--c-text-muted);
}
.hub-card-secondary .hub-card-cta {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
}
.hub-card-secondary:hover {
    background: var(--c-surface);
    border-color: var(--c-text-muted);
    transform: none;
}
.hub-card-secondary:hover .hub-card-stat,
.hub-card-secondary:hover .hub-card-cta {
    color: var(--c-text);
}

/* Per-session theme chip row. Sits just under the meta row in the hero,
   chips themselves are .tag.tag-theme to reuse the tag pill geometry. */
.session-themes {
    margin-top: var(--s-3);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-1) var(--s-2);
    font-size: var(--fs-sm);
}
.session-themes-label {
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: var(--fs-xs);
    font-weight: 600;
}
.tag-theme {
    background: #d6efe6;
    color: #0c5e3f;
    border-radius: 999px;
    padding: 2px var(--s-2);
    font-size: var(--fs-xs);
    text-decoration: none;
}
.tag-theme:hover {
    background: #0c5e3f;
    color: #fff;
    text-decoration: none;
}

/* ============================================================
   View-switcher tab strip on both catalog landings
   (sessions/index.html and announcements/index.html)
   ============================================================ */

.view-switcher {
    display: flex;
    align-items: stretch;
    gap: var(--s-2);
    margin: 0 0 var(--s-4);
    flex-wrap: wrap;
}
.view-switcher-tab,
.view-switcher-home {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    padding: var(--s-2) var(--s-4);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    background: var(--c-surface);
    color: var(--c-text);
    text-decoration: none;
    font-size: var(--fs-sm);
    font-weight: 600;
    transition: background 100ms ease, border-color 100ms ease, color 100ms ease;
}
.view-switcher-tab:hover,
.view-switcher-home:hover {
    background: var(--c-accent-soft);
    border-color: var(--c-accent);
    color: var(--c-accent);
    text-decoration: none;
}
.view-switcher-tab.is-active {
    background: var(--c-accent);
    border-color: var(--c-accent);
    color: white;
    cursor: default;
    pointer-events: none;
}
.view-switcher-tab .view-switcher-count {
    background: rgba(255,255,255,0.25);
    padding: 0 var(--s-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
}
.view-switcher-tab:not(.is-active) .view-switcher-count {
    background: var(--c-surface-alt);
    color: var(--c-text-muted);
}
.view-switcher-home {
    color: var(--c-text-muted);
    font-weight: 500;
}

/* ============================================================
   Chapter strip — list of key announcements as quick-jump
   timestamps under the session player. Each row is a single
   <button class="ts-play chapter-jump"> so session.js's existing
   click handler (data-ts -> video.currentTime - 5; play) works
   without any new wiring; the .chapter-jump modifier here just
   undoes the tiny 1.2em-square sizing inherited from .ts-play
   and lays out the timestamp + title inline.
   ============================================================ */
.chapters {
    margin: var(--s-3) 0 var(--s-5);
    padding: var(--s-3) var(--s-4);
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
}
.chapters h3 {
    margin: 0 0 var(--s-2);
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.chapter-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.chapter-list li { margin: 0; }
/* Override the inherited .ts-play box sizing: chapters use a full-width
   row with a monospaced timestamp pill on the left and the label text
   on the right. Hover and focus colours match the existing accent
   treatment so the row reads as part of the same vocabulary. */
.chapter-list .chapter-jump {
    width: 100%;
    height: auto;
    padding: var(--s-1) var(--s-2);
    margin: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    border: 1px solid transparent;
    color: var(--c-text);
    font-size: var(--fs-sm);
    line-height: 1.4;
    text-align: left;
    display: flex;
    align-items: baseline;
    gap: var(--s-3);
    cursor: pointer;
    transition: background 100ms ease, border-color 100ms ease;
}
.chapter-list .chapter-jump:hover,
.chapter-list .chapter-jump:focus-visible {
    background: var(--c-accent-soft);
    border-color: var(--c-accent);
    color: var(--c-accent);
    outline: none;
}
.chapter-list .chapter-ts {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    color: var(--c-text-muted);
    min-width: 6ch;
}
.chapter-list .chapter-jump:hover .chapter-ts,
.chapter-list .chapter-jump:focus-visible .chapter-ts {
    color: var(--c-accent);
}
.chapter-list .chapter-title {
    flex: 1 1 auto;
    /* Allow up to two lines on desktop instead of hard-truncating with a
       single-line ellipsis: 38% of mention labels are >40 chars and ~6%
       are >60 chars, so a single line was clipping a lot of signal. The
       chapter-jump button (.chapter-list .chapter-jump) is the parent
       flex container and already has height:auto, so the row grows to
       fit the second line cleanly. Mobile keeps full wrap (rule below
       in the @media (max-width: 720px) block). */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}

/* ============================================================
   Mobile refinements — narrow viewports (≤ 720px).
   The catalog/hub grids already collapse to a single column via
   their own min-width queries; these rules tighten typography,
   page padding, and pill-row sizing so the hero / header / filter
   bar feel appropriately sized on phones. Long URLs in
   announcement card snippets get overflow-wrap so they don't
   force horizontal scroll.
   ============================================================ */
@media (max-width: 720px) {
    .page                  { padding: var(--s-4) var(--s-3); }
    .hero h2               { font-size: var(--fs-xl); }
    .session-hero h1       { font-size: var(--fs-2xl); }
    .hub-hero h2           { font-size: var(--fs-xl); }
    .site-header h1        { font-size: var(--fs-md); }
    .site-header nav       { gap: var(--s-3); }
    .site-header .page     { padding-block: var(--s-3); }
    .filters               { padding: var(--s-3); }
    .filters-pills         { max-height: 11em; }
    .view-switcher         { gap: var(--s-2); }
    .session-actions       { padding: var(--s-3); }
    .section               { padding: var(--s-4); }
    /* Long URLs in entity-link cards / mention-card actions / session
       resources should break inside the card instead of forcing
       horizontal scroll on a 360px viewport. */
    .entity-snippet,
    .entity-snippet pre,
    .mention-card a,
    .session-actions a,
    .link-group a {
        overflow-wrap: anywhere;
    }
    /* Chapter row trims the title with ellipsis on a narrow screen
       only when needed - allow wrap on small viewports instead so
       longer announcement names stay readable. */
    .chapter-list .chapter-title { white-space: normal; }
}

/* ============================================================
   Dark mode — opt-in via OS-level `prefers-color-scheme: dark`.
   The whole site reads from the same eight palette tokens in
   :root, so a single redefinition under this query flips every
   page. Component-specific accent colours (status badges, entity
   category chips, link-badges) keep their hue but get nudged
   lightness so they pop on a dark surface.
   ============================================================ */
@media (prefers-color-scheme: dark) {
    :root {
        --c-bg:           #14161a;
        --c-surface:      #1c1f24;
        --c-surface-alt:  #262a31;
        --c-border:       #353a44;
        --c-text:         #e6e8eb;
        --c-text-muted:   #a3aab5;
        --c-accent:       #5aa3ff;
        --c-accent-soft:  #1c3b66;

        --shadow-sm: 0 1px 2px rgba(0,0,0,0.4);
        --shadow-md: 0 4px 12px rgba(0,0,0,0.5);
    }

    /* Status badges: existing pastel fills look washed-out on dark; swap
       to inverted variants that retain semantic hue (yellow/green/grey). */
    .status-badge.is-upcoming { background: #4a3b00; color: #ffe28a; }
    .status-badge.is-live     { background: #134221; color: #a0e0b0; }
    .status-badge.is-ended    { background: #303338; color: #b0b3b8; }
    .status-badge.is-demo-repo       { background: #13345e; color: #a7c7ff; }
    .status-badge.is-demo-repo:hover { background: #a7c7ff; color: #0d2748; }

    /* Entity category chips are already small + pastel; their light
       backgrounds read as "blown-out" on dark, so dim them. */
    .entity-cat-model,
    .entity-cat-service,
    .entity-cat-SDK,
    .entity-cat-framework,
    .entity-cat-library,
    .entity-cat-tool,
    .entity-cat-runtime,
    .entity-cat-hardware,
    .entity-cat-spec,
    .entity-cat-feature,
    .entity-cat-platform,
    .entity-cat-concept {
        filter: brightness(0.55) saturate(0.85);
    }

    /* Hub announcement card hue (orange) was tuned for light surfaces;
       make the hover border + accent text shift to a softer amber. */
    .hub-card-announcements:hover               { border-color: #d6a86b; }
    .hub-card-announcements:hover .hub-card-stat,
    .hub-card-announcements:hover .hub-card-cta,
    .hub-result-badge-announcement              { color: #d6a86b; background: #3a2a10; }

    /* Theme palette (teal) was tuned for light surfaces too. Invert the
       fill to a deep teal and lift the text to a soft mint so the per-
       session theme chips, the themes entity-cat chip on each /themes/
       page, and the themes federated-search badge all stay legible on
       dark. The hub-card-themes:hover accent block from the four-up
       layout was dropped along with the per-card color rotation when
       the hub moved to a two-tier primary/secondary design. */
    .tag-theme,
    .entity-cat-theme,
    .hub-result-badge-theme        { background: #103a28; color: #8fd4b3; }
    .tag-theme:hover               { background: #8fd4b3; color: #0c2e1f; }

    /* Speakers palette (blue-violet) needs the same treatment so the
       per-event view-switcher Speakers tab + the speaker entity-cat chip
       + the federated-search speaker badge read clearly on dark. */
    .entity-cat-speaker,
    .hub-result-badge-speaker      { background: #1f1f4a; color: #c5c5ff; }

    /* Hub two-tier: in dark mode --c-surface-alt is slightly LIGHTER
       than --c-surface (subtle raise) so the secondary tiles wouldn't
       feel demoted. Swap to --c-bg (the page background) so the
       secondaries instead feel like they sit IN the page surface
       rather than raised cards - preserving the "demoted" intent. */
    .hub-card-secondary       { background: var(--c-bg); }
    .hub-card-secondary:hover { background: var(--c-surface); }

    /* Lightbox / dialog overlay backdrop stays dark — no change needed. */
    /* Primary button keeps the accent fill; just darken the hover. */
    .session-actions a.primary:hover { background: #3b87e6; }
}
