/*
 * ZERG3RRBOT shared components.
 *
 * Linked from base_new.html after tailwind.min.css and style.css. These are
 * the component classes the macros in templates/macros/components.html emit;
 * when to use which is written down in Claude/UI_CONVENTIONS.md.
 *
 * They are plain rules, not Tailwind utilities, because tailwind.min.css is
 * precompiled and only carries the classes that existed when it was built.
 * They live here and not in style.css because style.css is the accessibility
 * layer and its tests forbid it from setting layout.
 *
 * No text below 12px and no !important in this file either
 * (tests/test_ui_components.py).
 */
/* 1. Page header: left-aligned title, optional icon square, optional
   one-line description, optional actions on the right. Below 640px the
   actions wrap under the title and share the row width evenly. */
.page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1rem;
}
.page-header__lead {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
    flex: 1 1 16rem;
}
.page-header__icon {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    padding: 0.5rem;
    border-radius: 12px;
    background-color: rgb(130 69 170 / 0.1);
    color: rgb(var(--text-purple-rgb));
}
.page-header__icon > svg,
.page-header__icon > i { width: 1.5rem; height: 1.5rem; }
.page-header__icon--danger { background-color: rgb(255 82 82 / 0.1); color: #FF5252; }
.page-header__icon--success { background-color: rgb(0 200 83 / 0.1); color: #00C853; }
.page-header__icon--warning { background-color: rgb(255 179 0 / 0.1); color: #FFB300; }
.page-header__icon--info { background-color: rgb(0 184 212 / 0.1); color: #00B8D4; }
.page-header__icon--cyan { background-color: rgb(0 245 212 / 0.1); color: #00F5D4; }
.page-header__icon--yellow { background-color: rgb(212 168 68 / 0.2); color: #D4A844; }
.page-header__icon--pink { background-color: rgb(247 37 133 / 0.1); color: #F72585; }
.page-header__icon--discord { background-color: rgb(88 101 242 / 0.2); color: #8E9BFF; }
.page-header__icon--kick { background-color: rgb(83 252 24 / 0.1); color: #53FC18; }
/* A header with several lines under the title keeps its icon by the title. */
.page-header__lead--top { align-items: flex-start; }
.page-header__text { min-width: 0; }
.page-header__title {
    margin: 0;
    font-size: 1.5rem;
    line-height: 2rem;
    font-weight: 700;
    color: #EFEFF1;
    overflow-wrap: anywhere;
}
.page-header__desc {
    margin: 0;
    font-size: 0.875rem;
    line-height: 1.25rem;
    color: rgb(var(--a11y-text-muted-rgb));
}
.page-header__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
}
@media (max-width: 639px) {
    .page-header__actions { width: 100%; }
    /* A single action fills the row; several share it. Status chips
       (`page-header__keep`) and icon-only buttons keep their own width. An
       icon-only button is one whose only child is its icon AND that carries
       an aria-label: CSS cannot see a text label, and a labelled icon button
       is the only kind the site allows. */
    .page-header__actions > :is(a, button):not(.page-header__keep) {
        flex: 1 1 auto;
        justify-content: center;
        text-align: center;
    }
    .page-header__actions > :is(a, button)[aria-label]:has(> :is(svg, i[data-lucide]):only-child) { flex: 0 0 auto; }
}

/* 2. Pro chip: the one marker for "this is a Pro feature". White on the
   brand purple is 6.2:1; the text is 12px, the smallest size the site uses.
   `--unlocked` makes an entitled channel's open-lock glyph green; its label
   remains white. This is feature access, independent of editing permissions.
   `--locked` adds a small lock glyph and is for
   locked cards and locked controls, next to the "See what Pro includes"
   link. The nav (`.nav-pro-badge`) and setup checklist (`.sc-pro`) carry the
   same values under their older names. */
.pro-chip {
    /* Keep sr-only status inside horizontally scrolling button/menu rows. */
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    gap: 0.25rem;
    padding: 0 0.375rem;
    border-radius: 0.375rem;
    vertical-align: 0.0625rem;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.125rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    color: #fff;
    background-color: #8245AA;
}
.pro-chip > svg,
.pro-chip > i { width: 0.75rem; height: 0.75rem; }
.pro-chip--unlocked > svg,
.pro-chip--unlocked > i { color: #4ade80; }
a.pro-chip:hover { background-color: #6B2D8E; color: #fff; }
/* The selected period uses the same purple as its chip. Keep its edge visible. */
.chip-row > .bg-twitch-purple .pro-chip { box-shadow: 0 0 0 1px rgb(255 255 255 / 0.35); }

/* The quiet link that goes with a locked card. */
.pro-more {
    color: rgb(var(--text-purple-rgb));
    font-size: 0.875rem;
    line-height: 1.25rem;
    white-space: nowrap;
}
.pro-more:hover { color: rgb(var(--text-purple-hover-rgb)); text-decoration: underline; }

/* 3. Empty state: one plain muted sentence, optionally one action. */
.empty-note {
    padding: 1.5rem 1rem;
    text-align: center;
    font-size: 0.875rem;
    line-height: 1.25rem;
    color: rgb(var(--a11y-text-muted-rgb));
}
.empty-note__lead { color: #ADADB8; }
.empty-note__action { margin-top: 0.75rem; }

/* 4. Stacking table: a settings table that is a normal table from 640px up
   and one block per row on a phone, so nothing scrolls sideways. Cells that
   need their column name on a phone carry it in `data-label`. The header row
   stays in the page for screen readers and is only moved out of sight. */
.stack-table__wrap { overflow-wrap: anywhere; }
@media (min-width: 640px) {
    .stack-table { min-width: 42rem; }
    .stack-table__wrap { max-width: 16rem; }
}
@media (max-width: 639px) {
    .stack-table,
    .stack-table > tbody { display: block; }
    .stack-table > thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
    }
    /* One row becomes: the setting's name and description across the top,
       then its current value, the new value and the button on one line. */
    .stack-table > tbody > tr {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        gap: 0.375rem 0.75rem;
        align-items: end;
        padding: 0.75rem 0;
    }
    .stack-table > tbody > tr > td { display: block; min-width: 0; padding: 0; }
    .stack-table > tbody > tr > td:first-child { grid-column: 1 / -1; }
    .stack-table > tbody > tr > td[colspan] { grid-column: span 2; }
    .stack-table > tbody > tr > td[data-label]::before {
        content: attr(data-label);
        display: block;
        margin-bottom: 0.125rem;
        font-size: 0.75rem;
        font-weight: 600;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: rgb(var(--a11y-text-muted-rgb));
    }
    .stack-table > tbody > tr > td :is(input[type="text"], select) { width: 100%; }
}

/* 5. Chip row: a row of filter or period chips. From 640px up it is whatever
   flex row the page wrote. On a phone it stays on one line and scrolls
   sideways inside itself, instead of wrapping to an uneven last line. The
   scrollbar is hidden; the cut-off chip at the edge shows there is more. */
@media (max-width: 639px) {
    .chip-row {
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
        scroll-padding-inline: 0.25rem;
    }
    .chip-row::-webkit-scrollbar { display: none; }
    .chip-row > * { flex-shrink: 0; }
}

/* 6. Chart frame: a fixed-height box for a Chart.js canvas that turns
   maintainAspectRatio off. The chart keeps one height at every width and
   still resizes with its card. */
.chart-frame { position: relative; height: 16rem; }
@media (min-width: 1024px) {
    .chart-frame { height: 20rem; }
}

/* -------------------------------------------------------------------------
   Analytics sample (partials/analytics_demo.html): the landing page's
   Analytics tab and the analytics feature page show the same block.
   ------------------------------------------------------------------------- */
.analytics-demo .lp-num { font-variant-numeric: tabular-nums; }
.analytics-demo .lp-question {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
}
.analytics-demo .lp-question .lp-pro-badge { flex: none; margin-top: 0.125rem; }
/* Three tiles in a row on a phone: one label wraps, so all take two lines. */
.analytics-demo .lp-figure-label { min-height: 2rem; line-height: 1rem; }
@media (min-width: 640px) {
    .analytics-demo .lp-figure-label { min-height: 0; }
}

/* Visible feature switches share the settings drawer save and retry behaviour. */
.feature-switch { min-width: 0; max-width: 100%; }
.feature-switch > button { min-height: 44px; min-width: 44px; text-align: left; }
.feature-switch > button > span:last-child { min-width: 0; overflow-wrap: anywhere; }

.feature-off-link { min-height: 44px; min-width: 44px; }

/* Per-control save feedback stays beside its setting at narrow widths. */
.setting-save-feedback { min-width: 0; flex-shrink: 1; display: inline-block; max-width: 100%; white-space: normal; overflow-wrap: anywhere; margin: .25rem; font-size: .875rem; }
.setting-save-feedback[data-state="saved"] { color: var(--status-success, #4ade80); }
.setting-save-feedback[data-state="error"] { color: var(--status-danger, #f87171); }
/* A form's shared status is its first child in the markup; it reads after the
   control, as in the drawer and the Mod Panel, not in front of it. */
form:is([data-settings-form], [data-autosave-form]) > [data-form-save-feedback] { order: 1; align-self: center; }
.setting-save-feedback button, [data-setting-control]:not([type="checkbox"]):not([type="radio"]), form[data-settings-form] :is(button, input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]), select), form[data-autosave-form] :is(button, input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]), select) { min-height: 44px; }
[data-setting-control]:is(button) { min-width: 44px; }
form[data-settings-form], form[data-autosave-form] { min-width: 0; max-width: 100%; flex-wrap: wrap; }
form[data-settings-form] :is(input, select, textarea), form[data-autosave-form] :is(input, select, textarea) { max-width: 100%; }

[data-setting]:is(select, input:not([type="checkbox"]):not([type="radio"]), button), .settings-dialog button { min-height: 44px; }
.setting-save-feedback button { min-width: 44px; padding: .25rem .5rem; }
[data-setting-control]:is(input, select, textarea) { max-width: 100%; }

/* The dashboard's "Bot is not a moderator" bar repeats step 1 of the setup
   checklist word for word. While that step is on screen it is the one place
   to act; once the checklist is hidden, the bar is back. */
body:has(#setup-checklist:not([hidden]) [data-setup-step="mod"][data-step-state="todo"]) [data-bot-moderator-notice] { display: none; }

/* Pending discovery links must remain absent from layout and keyboard order
   even where nav-link's authored display rule overrides the UA hidden rule. */
nav :is([data-moderator-link], [data-moderator-schedule], [data-moderator-commands])[hidden] {
    display: none;
}

/* Settings finder destinations clear the sticky navigation and stay visible
   to keyboard users. The brief outline does not move the page. */
[data-tool-section], [data-setting-row], #settings-drawer [id], [data-settings-section], #tools-page {
    scroll-margin-top: 5rem;
}
.tool-target-highlight {
    outline: 3px solid var(--text-purple, #B685DB);
    outline-offset: -3px;
}

/* Native controls keep their visual size; the clickable label supplies the
   touch area on desktop and phones, including autosaved Discover fields. */
:root input:is([type="checkbox"], [type="radio"]):not(.sr-only) {
    width: 1rem;
    height: 1rem;
    min-width: 0;
    min-height: 0;
    flex-shrink: 0;
}
:root label:has(input:is([type="checkbox"], [type="radio"])) {
    min-width: var(--a11y-tap-min);
    min-height: var(--a11y-tap-min);
}
:root label:has(input:is([type="checkbox"], [type="radio"])):not(.flex):not(.block) {
    display: inline-flex;
    align-items: center;
}
/* A switch button is the hit area; its nested track never inherits this floor. */
:root button[role="switch"] { min-width: var(--a11y-tap-min); min-height: var(--a11y-tap-min); }

/* Shared searchable time zone picker, including narrow profile columns. */
.timezone-picker { width: 100%; min-width: 0; max-width: 100%; }
.timezone-picker input, .timezone-picker select { min-height: 44px; width: 100%; max-width: 100%; min-width: 0; }
.timezone-picker [data-timezone-search-box] { margin-bottom: 0.5rem; }
.timezone-picker .setting-save-feedback:empty { display: none; }

/* Personal clip library and channel review share one compact row layout. */

    .sound-library { max-width: 72rem; margin: 0 auto; }
    .sound-library button, .sound-library input:not([type=file]), .sound-library .sound-link { min-height: 44px; }
    .sound-library input { min-width: 0; max-width: 100%; }
    .sound-library .sound-row { padding: 1rem 0; border-bottom: 1px solid var(--border-color, #323239); }
    .sound-library .sound-actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-top: .75rem; }
    .sound-library .sound-copy { overflow-wrap: anywhere; }
    .sound-library .sound-import { display: flex; flex-wrap: wrap; gap: .5rem; align-items: end; margin-top: .75rem; }
    .sound-library .sound-import label { flex: 1 1 14rem; }
    .sound-library audio { display: block; max-width: 100%; margin-top: .75rem; }
    .sound-library audio[hidden], .sound-library [hidden] { display: none; }
    .sound-library button:disabled { opacity: .5; cursor: not-allowed; }
    .sound-library .sound-upload-fields { display: grid; gap: 1rem; }
    @media (min-width: 640px) { .sound-library .sound-upload-fields { grid-template-columns: 1fr 1fr; } }

.sound-library-launcher { min-height: 44px; }

/* Clickable metric headers retain a full touch target in the wide data table. */
.game-engagement-table { min-width: 960px; }
.game-engagement-table th { padding: 0; }
.game-engagement-table [data-game-sort] {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    width: 100%;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-transform: inherit;
    cursor: pointer;
}
.game-engagement-table th:first-child [data-game-sort] { justify-content: flex-start; padding-left: 1rem; }
.game-engagement-table [data-sort-arrow] { flex-shrink: 0; }
.game-engagement-table [data-game-sort]:focus-visible {
    outline: 2px solid var(--twitch-purple, #a970ff);
    outline-offset: -3px;
    border-radius: 0.25rem;
}

/* -------------------------------------------------------------------------
   Join Messages feature page (public_feature.html with feature.showcase,
   partials/welcome_demo.html, static/js/public-welcome-demo.js). The demo,
   the numbered "How it works" strip, the accordion of questions and the
   example lines on the guide cards. Only this page uses them.
   ------------------------------------------------------------------------- */
.wv-demo {
    background: #1f1f23;
    border: 1px solid #26262c;
    border-radius: 1rem;
    overflow: hidden;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}
.wv-demo-head {
    display: flex;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    background: #18181b;
    border-bottom: 1px solid #26262c;
    font-size: 0.75rem;
    color: #adadb8;
}
.wv-tabs { display: flex; gap: 0.5rem; padding: 1rem 1.25rem 0; }
.wv-tab {
    min-height: 44px;
    padding: 0.5rem 1rem;
    border-radius: 0.75rem;
    border: 1px solid #3a3a42;
    background: transparent;
    color: #efeff1;
    font-weight: 600;
    font-size: 0.875rem;
    cursor: pointer;
}
.wv-tab[aria-pressed="true"] { background: #8245aa; border-color: #8245aa; color: #fff; }
.wv-body { padding: 1.25rem; }
.wv-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}
.wv-label {
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #adadb8;
    margin: 0;
    font-weight: 600;
}
.wv-replay {
    min-height: 44px;
    padding: 0.5rem 1.1rem;
    border-radius: 0.75rem;
    border: 0;
    background: #8245aa;
    color: #fff;
    font-weight: 700;
    font-size: 0.9rem;
    cursor: pointer;
}
.wv-replay:hover { background: #6c3a8e; }
.wv-chat {
    background: #0e0e10;
    border: 1px solid #26262c;
    border-radius: 0.75rem;
    padding: 0.9rem 1rem;
    font-size: 0.9rem;
    line-height: 1.5;
}
.wv-chat p { margin: 0.25rem 0; }
.wv-chatbox { height: 210px; overflow-y: auto; scroll-behavior: smooth; }
.wv-chatbox p { animation: wv-in 0.25s ease-out; }
@keyframes wv-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}
/* The names in the sample chat. The line's own text keeps the chat colour. */
.wv-name--coral { color: #ff7f50; }
.wv-name--green { color: #6ac46a; }
.wv-name--cyan { color: #00d6d6; }
.wv-name--bot { color: var(--text-purple); }
.wv-sys { color: #adadb8; font-style: italic; }
.wv-badge {
    display: inline-block;
    font-size: 0.75rem;
    padding: 0 0.35rem;
    border-radius: 0.25rem;
    background: #6c3a8e;
    color: #fff;
    margin-right: 0.35rem;
    vertical-align: middle;
}
.wv-obs {
    margin-top: 0.75rem;
    background: #0e0e10;
    border: 1px dashed #5a3d7a;
    border-radius: 0.75rem;
    padding: 0.9rem 1rem;
    display: flex;
    align-items: center;
    gap: 0.9rem;
}
.wv-obs-ico {
    flex: none;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: #26262c;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.2rem;
}
.wv-obs-main { min-width: 0; flex: 1; }
.wv-obs-cap { margin: 0.35rem 0 0; font-size: 0.8rem; color: #adadb8; }
.wv-demo-note { margin: 0.75rem 0 0; font-size: 0.75rem; color: #adadb8; }
.wv-wave { display: flex; align-items: center; gap: 3px; height: 28px; }
.wv-wave i { display: block; width: 4px; border-radius: 2px; background: var(--text-purple); opacity: 0.55; }
/* The playing bars carry the animation shorthand, so the staggered delays
   below must come after it. */
.wv-playing .wv-wave i { opacity: 1; animation: wv-bar 0.6s ease-in-out infinite alternate; }
.wv-wave i:nth-child(1), .wv-wave i:nth-child(11) { height: 10px; }
.wv-wave i:nth-child(2) { height: 18px; }
.wv-wave i:nth-child(3) { height: 26px; }
.wv-wave i:nth-child(4) { height: 14px; }
.wv-wave i:nth-child(5) { height: 22px; }
.wv-wave i:nth-child(6) { height: 28px; }
.wv-wave i:nth-child(7) { height: 12px; }
.wv-wave i:nth-child(8) { height: 20px; }
.wv-wave i:nth-child(9) { height: 16px; }
.wv-wave i:nth-child(10) { height: 24px; }
.wv-wave i:nth-child(2n) { animation-delay: 0.15s; }
.wv-wave i:nth-child(3n) { animation-delay: 0.3s; }
.wv-playing { border-color: var(--text-purple); border-style: solid; }
.wv-playing .wv-obs-ico { background: #8245aa; }
@keyframes wv-bar {
    from { transform: scaleY(0.4); }
    to { transform: scaleY(1.2); }
}
@media (prefers-reduced-motion: reduce) {
    .wv-playing .wv-wave i { animation: none; }
    .wv-chatbox { scroll-behavior: auto; }
    .wv-chatbox p { animation: none; }
}

.wv-steps {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    margin-top: 1.25rem;
    padding: 0;
    list-style: none;
}
.wv-step {
    display: flex;
    gap: 0.9rem;
    align-items: flex-start;
    background: #1f1f23;
    border: 1px solid #26262c;
    border-radius: 1rem;
    padding: 1rem;
}
.wv-step p { margin: 0.25rem 0 0; }
.wv-num {
    flex: none;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: #8245aa;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
}
.wv-link-cta {
    display: inline-flex;
    align-items: center;
    color: var(--text-purple-hover);
    text-decoration: underline;
    text-underline-offset: 4px;
    font-weight: 600;
}
/* These links end a sentence and keep its line height. Without this the phone
   tap-target default in style.css (:root a[href]) makes each one 44px tall. */
:root a.wv-link-cta { min-height: 0; }

/* A guide card with an example: the example sits on the card's bottom edge. */
.wv-card-aligned { display: flex; flex-direction: column; }
.wv-card-aligned > p:not(.wv-ex) { margin-bottom: 0.75rem; }
.wv-card-aligned > .wv-ex { margin-top: auto; }
.wv-ex {
    margin-top: 0.75rem;
    font-size: 0.85rem;
    color: #efeff1;
    background: #0e0e10;
    border-radius: 0.5rem;
    padding: 0.5rem 0.75rem;
}

.wv-faq-list { max-width: 48rem; }
.wv-faq { border-bottom: 1px solid #26262c; }
.wv-faq summary {
    cursor: pointer;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    font-weight: 600;
    color: #efeff1;
    list-style: none;
    padding: 0.5rem 0;
}
.wv-faq summary::-webkit-details-marker { display: none; }
.wv-faq summary::after { content: "+"; font-size: 1.4rem; color: var(--text-purple); }
.wv-faq[open] summary::after { content: "\2212"; }
.wv-faq p { margin: 0 0 1rem; font-size: 0.9rem; color: #c8c8d0; }

.wv-badge-founder {
    display: inline-block;
    margin-bottom: 1rem;
    padding: 0.35rem 0.9rem;
    border-radius: 999px;
    background: rgba(255, 221, 0, 0.12);
    border: 1px solid rgba(255, 221, 0, 0.4);
    color: #ffdd00;
    font-size: 0.85rem;
    font-weight: 600;
}

/* Viewer checklist text must shrink and wrap even an unbroken URL. */
.notes-wrap { overflow-wrap: anywhere; }
