/* patterns.css -- named multi-property recipes.
 *
 * "This is what a button looks like" lives here, in one file. Markup references
 * a pattern by a single class; the pattern composes utilities + tokens.
 * Components never re-declare the same paint -- they reach for the pattern.
 *
 * Patterns are the canonical mid-layer between atomic utilities and component
 * .js / .css. Components add structural CSS only (positioning, scroll lock,
 * native control mechanics).
 *
 * Grouped in PLAN.md order: surfaces, interactive, buttons, forms, layout,
 * content, status, rows, feedback, navigation, overlays, data, decoration.
 */

/* =====================================================================
 * surfaces
 *
 * Shadow stacks come from the active style theme (--shadow-card, --shadow-pop).
 * Flat style resolves them to none; precision style layers hairline + bloom +
 * inset highlight. See themes/styles/*.css.
 * =================================================================== */
.surface-1 {
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
}

.surface-2 {
    background-color: var(--color-surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
}

.surface-3 {
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-pop);
}

/* =====================================================================
 * interactive base + focus ring
 * =================================================================== */
.interactive {
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--motion-easing),
                color var(--motion-fast) var(--motion-easing),
                border-color var(--motion-fast) var(--motion-easing),
                box-shadow var(--motion-fast) var(--motion-easing);
}

.focus-ring:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* =====================================================================
 * buttons (variant: primary / secondary / ghost / destructive / link)
 *
 * Sizes via .btn-sm / .btn-lg (md default). Touch target floor enforced
 * by min-height (40px desktop default; mobile bumps via media query).
 * =================================================================== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    min-height: 2.5rem;             /* 40px desktop touch target */
    padding-inline: var(--space-lg);
    padding-block: var(--space-sm);
    font: inherit;
    font-weight: var(--weight-medium);
    line-height: 1;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: transparent;
    color: inherit;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--motion-fast) var(--motion-easing),
                color var(--motion-fast) var(--motion-easing),
                border-color var(--motion-fast) var(--motion-easing),
                transform var(--motion-fast) var(--motion-easing),
                box-shadow var(--motion-fast) var(--motion-easing);
    text-decoration: none;
}

.btn:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
    /* vivid style theme adds a brand-colored bloom on top of the outline;
     * precision and flat have --shadow-glow-focus: none (no-op). */
    box-shadow: var(--shadow-glow-focus);
}

.btn:disabled,
.btn[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

.btn-sm { min-height: 2rem;   padding-inline: var(--space-md); font-size: var(--text-sm); }
.btn-lg { min-height: 3rem;   padding-inline: var(--space-xl); font-size: var(--text-lg); }

/* Filled buttons consume --shadow-card + lift on hover / press on active +
 * background-image gradient overlay. Style theme decides whether those resolve
 * to anything visible -- flat zeroes out lift, shadow, and gradient; precision
 * layers the polish. The gradient overlay composites on top of the bg-color so
 * hover/active color shifts still apply cleanly underneath. */
.btn-primary {
    background-color: var(--color-brand);
    background-image: var(--gradient-fill-strong);
    color: var(--color-text-on-brand);
    box-shadow: var(--shadow-card);
}
.btn-primary:hover  {
    background-color: var(--color-brand-hover);
    box-shadow: var(--shadow-card-hover);
    transform: var(--lift-on-hover);
}
.btn-primary:active {
    background-color: var(--color-brand-active);
    transform: var(--lift-on-active);
}

.btn-secondary {
    background-color: var(--color-surface-1);
    color: var(--color-text);
    border-color: var(--color-border);
    box-shadow: var(--shadow-card);
}
.btn-secondary:hover  {
    background-color: var(--color-surface-2);
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-card-hover);
    transform: var(--lift-on-hover);
}
.btn-secondary:active {
    background-color: var(--color-surface-3);
    transform: var(--lift-on-active);
}

.btn-ghost {
    background-color: transparent;
    color: var(--color-text);
}
.btn-ghost:hover  { background-color: var(--color-surface-2); }
.btn-ghost:active { background-color: var(--color-surface-3); }

.btn-destructive {
    background-color: var(--color-danger);
    background-image: var(--gradient-fill-strong);
    color: var(--color-text-on-brand);
    box-shadow: var(--shadow-card);
}
.btn-destructive:hover  {
    background-color: var(--color-danger-hover);
    box-shadow: var(--shadow-card-hover);
    transform: var(--lift-on-hover);
}
.btn-destructive:active {
    background-color: var(--color-danger-active);
    transform: var(--lift-on-active);
}

.btn-link {
    background-color: transparent;
    color: var(--color-brand);
    min-height: auto;
    padding: 0;
    border: none;
    text-decoration: underline;
    text-underline-offset: 3px;
}
.btn-link:hover { color: var(--color-brand-hover); }

/* Loading spinner that replaces the leading icon when a button is in
 * aria-busy state. components-anatomy "don't customize floor" requires the
 * spinner to take the action slot, not overlay it. Sized in em so it tracks
 * the button's font-size across sm/md/lg. Animation respects the global
 * reduced-motion blanket from reset.css (D21). */
.btn-spinner {
    flex: none;
    width: 1em;
    height: 1em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: var(--radius-full);
    animation: btn-spinner-rotate 0.8s linear infinite;
}
@keyframes btn-spinner-rotate {
    to { transform: rotate(360deg); }
}

/* mobile touch target bump */
@media (max-width: 48rem) {
    .btn    { min-height: 3rem; }
    .btn-sm { min-height: 2.5rem; }
    .btn-lg { min-height: 3.5rem; }
}

/* =====================================================================
 * forms (field / input / textarea / select / combobox-shell)
 * =================================================================== */
.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.field-label {
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--color-text);
}

.field-help {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.field-error {
    font-size: var(--text-sm);
    color: var(--color-danger);
}

.input,
.textarea,
.select {
    display: block;
    width: 100%;
    min-height: 2.5rem;
    padding-inline: var(--space-md);
    padding-block: var(--space-sm);
    font: inherit;
    color: var(--color-text);
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: border-color var(--motion-fast) var(--motion-easing),
                box-shadow var(--motion-fast) var(--motion-easing);
}

.textarea { min-height: 6rem; resize: vertical; }

.input:hover,
.textarea:hover,
.select:hover {
    border-color: var(--color-border-strong);
}

.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible {
    outline: none;
    border-color: var(--color-brand);
    box-shadow: 0 0 0 3px var(--color-focus);
}

.input[aria-invalid="true"],
.textarea[aria-invalid="true"],
.select[aria-invalid="true"] {
    border-color: var(--color-danger);
}

.input:disabled,
.textarea:disabled,
.select:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.combobox-shell {
    position: relative;
    display: flex;
    align-items: stretch;
}

/* Select chevron color follows the muted text role -- the Icon element
 * paints via currentColor stroke, so setting color here is enough. */
.select-chevron { color: var(--color-text-muted); }

/* Fieldset: native default border is ugly; reset and treat as a grouping
 * stack. Legend keeps the semantic label role; .fieldset-legend paints it. */
.fieldset {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    margin: 0;
    padding: 0;
    border: none;
}
.fieldset-legend {
    padding: 0;
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--color-text);
}

/* Form section: titled grouping inside a long form. Header is the (title,
 * description) pair; body is whatever the consumer hands in. */
.form-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
}
.form-section-header {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}
.form-section-title { font-size: var(--text-lg); font-weight: var(--weight-bold); color: var(--color-text); }
.form-section-desc  { font-size: var(--text-sm); color: var(--color-text-muted); }

/* Bulleted error list rendered inside an Alert by ValidationSummary --
 * list-style + zero padding so the bullets sit flush with the alert body
 * column. Lives under forms because the only consumer is a form summary. */
.form-errors {
    margin: 0;
    padding: 0;
    list-style: disc inside;
}

@media (max-width: 48rem) {
    .input, .textarea, .select { min-height: 3rem; }
}

/* =====================================================================
 * controls (checkbox / radio / switch / slider paint)
 *
 * Native <input> kept in the DOM (a11y + form data) but renders with
 * appearance: none in the structural component .css. Paint lives here so
 * theme + style toggles flow through without component edits (D1).
 * =================================================================== */
.checkbox-input,
.radio-input {
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    transition: background-color var(--motion-fast) var(--motion-easing),
                border-color     var(--motion-fast) var(--motion-easing);
}
.checkbox-input { border-radius: var(--radius-sm); }
.radio-input    { border-radius: var(--radius-full); }

.checkbox-input:hover,
.radio-input:hover { border-color: var(--color-border-strong); }

.checkbox-input:focus-visible,
.radio-input:focus-visible,
.switch-input:focus-visible,
.slider:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

.checkbox-input:checked,
.checkbox-input:indeterminate,
.radio-input:checked,
.switch-input:checked {
    background-color: var(--color-brand);
    border-color: var(--color-brand);
}

.checkbox-input:checked::before,
.checkbox-input:indeterminate::before,
.radio-input:checked::before { background-color: var(--color-text-on-brand); }

.checkbox-input[aria-invalid="true"],
.radio-input[aria-invalid="true"] { border-color: var(--color-danger); }

.checkbox-input:disabled,
.radio-input:disabled,
.switch-input:disabled,
.slider:disabled { opacity: 0.5; }

.switch-input {
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    transition: background-color var(--motion-fast) var(--motion-easing),
                border-color     var(--motion-fast) var(--motion-easing);
}
.switch-input::before {
    background-color: var(--color-surface-1);
    box-shadow: var(--shadow-sm);
    transition: background-color var(--motion-fast) var(--motion-easing);
}
.switch-input:checked::before { background-color: var(--color-text-on-brand); }
.switch-input[aria-invalid="true"] { border-color: var(--color-danger); }

.slider::-webkit-slider-runnable-track {
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border);
}
.slider::-moz-range-track {
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border);
}
.slider::-webkit-slider-thumb {
    background-color: var(--color-brand);
    border: 2px solid var(--color-surface-1);
    box-shadow: var(--shadow-sm);
}
.slider::-moz-range-thumb {
    background-color: var(--color-brand);
    border: 2px solid var(--color-surface-1);
    box-shadow: var(--shadow-sm);
}

.checkbox-label,
.radio-label,
.switch-label {
    font-size: var(--text-sm);
    color: var(--color-text);
}

/* =====================================================================
 * layout primitives (Every Layout names per decisions.md D17)
 * =================================================================== */
.stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
}
.stack-sm  { gap: var(--space-sm); }
.stack-md  { gap: var(--space-md); }
.stack-lg  { gap: var(--space-lg); }
.stack-xl  { gap: var(--space-xl); }

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

.inline {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--space-md);
    align-items: center;
}

.center {
    display: flex;
    align-items: center;
    justify-content: center;
}

.container {
    width: 100%;
    max-width: 64rem;            /* 1024px */
    margin-inline: auto;
    padding-inline: var(--space-lg);
}

/* Minimum comfortable tap box. Centres its label so a short link still
 * fills the box instead of sitting in a corner of it. Composed onto links
 * and buttons that would otherwise be text-height. */
.touch-target {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    min-width: 44px;
}

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

/* =====================================================================
 * content (prose / code-inline / code-block)
 * =================================================================== */
.prose {
    max-width: 65ch;
    line-height: var(--leading-base);
}
.prose > * + * { margin-block-start: var(--space-lg); }
.prose h1, .prose h2, .prose h3 { font-weight: var(--weight-bold); line-height: var(--leading-tight); }
.prose h1 { font-size: var(--text-2xl); }
.prose h2 { font-size: var(--text-xl); }
.prose h3 { font-size: var(--text-lg); }
.prose code { font-family: var(--font-mono); font-size: 0.9em; }
.prose a { color: var(--color-brand); text-decoration: underline; text-underline-offset: 2px; }
.prose a:hover { color: var(--color-brand-hover); }
/* reset.css strips list markers app-wide; rendered content wants them. */
.prose ul, .prose ol { padding-inline-start: var(--space-xl); }
.prose ul > li { list-style: disc; }
.prose ol > li { list-style: decimal; }
.prose li + li { margin-block-start: var(--space-xs); }

/* prose-page -- a standalone content page (legal notices, docs) that renders
 * outside any app shell. Composed on .container for the centred column and
 * the page gutter; this only narrows the measure, because a sectioned
 * document reads better at ~720px than at .container's 1024px, and adds the
 * block padding a page with no shell above it needs. */
.prose-page {
    max-width: 45rem;            /* 720px */
    padding-block: var(--space-3xl);
}
/* .prose only spaces its direct children; a sectioned page needs the same
 * rhythm inside each <section>. */
.prose-page section > * + * { margin-block-start: var(--space-md); }

.code-inline {
    font-family: var(--font-mono);
    font-size: 0.9em;
    padding-inline: 0.35em;
    padding-block: 0.1em;
    background-color: var(--color-surface-2);
    border-radius: var(--radius-sm);
}

.code-block {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    line-height: 1.5;
    padding: var(--space-lg);
    background-color: var(--color-surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow-x: auto;
    white-space: pre;
}

/* =====================================================================
 * status (tag / chip / badge / status-dot / kbd)
 * decisions.md D15: tag / chip / badge are three different jobs.
 * =================================================================== */
.tag {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding-inline: var(--space-sm);
    padding-block: 0.15rem;
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    line-height: 1;
    color: var(--color-text-muted);
    background-color: var(--color-surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding-inline: var(--space-md);
    padding-block: var(--space-xs);
    font-size: var(--text-sm);
    line-height: 1;
    color: var(--color-text);
    background-color: var(--color-surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    cursor: pointer;
    user-select: none;
    transition: background-color var(--motion-fast) var(--motion-easing);
}
.chip:hover                       { background-color: var(--color-surface-3); }
.chip[aria-pressed="true"],
.chip[aria-selected="true"]       {
    background-color: var(--color-brand-bg);
    background-image: var(--gradient-fill-soft);
    border-color: var(--color-brand);
    color: var(--color-brand);
}
.chip-remove {
    display: inline-flex;
    margin-inline-start: var(--space-xs);
    cursor: pointer;
    opacity: 0.7;
}
.chip-remove:hover { opacity: 1; }

.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding-inline: var(--space-sm);
    padding-block: 0.1rem;
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    line-height: 1;
    border-radius: var(--radius-full);
    background-color: var(--color-surface-2);
    color: var(--color-text-muted);
}
.badge-info,
.badge-success,
.badge-warning,
.badge-danger    { background-image: var(--gradient-fill-soft); }
.badge-info      { background-color: var(--color-info-bg);    color: var(--color-info); }
.badge-success   { background-color: var(--color-success-bg); color: var(--color-success); }
.badge-warning   { background-color: var(--color-warning-bg); color: var(--color-warning); }
.badge-danger    { background-color: var(--color-danger-bg);  color: var(--color-danger); }

.status-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: var(--radius-full);
    background-color: var(--color-text-muted);
}
.status-dot-success { background-color: var(--color-success); }
.status-dot-warning { background-color: var(--color-warning); }
.status-dot-danger  { background-color: var(--color-danger); }
.status-dot-info    { background-color: var(--color-info); }

/* swatch -- 1/2/3-color preview disc. --swatch-c1..3 are set inline by the
 * Swatch component; the data-colors attribute picks the composition. The
 * outer border keeps near-bg fills visible against the surface. */
.swatch {
    display: inline-block;
    flex: none;
    width:  var(--swatch-size, 0.875rem);
    height: var(--swatch-size, 0.875rem);
    border-radius: var(--radius-full);
    border: 1px solid var(--color-border-strong);
    vertical-align: middle;
}
.swatch-sm { --swatch-size: 0.75rem; }
.swatch-md { --swatch-size: 1.125rem; }
.swatch-lg { --swatch-size: 1.5rem; }
.swatch[data-colors="1"] {
    background: var(--swatch-c1);
}
.swatch[data-colors="2"] {
    background: linear-gradient(
        135deg,
        var(--swatch-c1) 0% 50%,
        var(--swatch-c2) 50% 100%
    );
}
.swatch[data-colors="3"] {
    background: conic-gradient(
        from -30deg,
        var(--swatch-c1) 0deg 120deg,
        var(--swatch-c2) 120deg 240deg,
        var(--swatch-c3) 240deg 360deg
    );
}

.kbd {
    display: inline-flex;
    align-items: center;
    padding-inline: var(--space-sm);
    padding-block: 0.05rem;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-text);
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-bottom-width: 2px;
    border-radius: var(--radius-sm);
    line-height: 1.4;
}

/* =====================================================================
 * rows (list-row / kv-row / def-row)
 * =================================================================== */
.list-row {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding-inline: var(--space-md);
    padding-block: var(--space-sm);
    border-block-end: 1px solid var(--color-border);
    transition: background-color var(--motion-fast) var(--motion-easing);
}
.list-row:last-child         { border-block-end: none; }
.list-row:hover              { background-color: var(--color-surface-2); }
.list-row[aria-selected="true"] {
    background-color: var(--color-brand-bg);
    background-image: var(--gradient-fill-soft);
    color: var(--color-brand);
}

.kv-row {
    display: grid;
    grid-template-columns: minmax(8rem, auto) 1fr;
    gap: var(--space-md);
    padding-block: var(--space-xs);
}
.kv-row > :first-child { color: var(--color-text-muted); font-size: var(--text-sm); }

.def-row {
    display: grid;
    grid-template-columns: minmax(10rem, auto) 1fr;
    gap: var(--space-md);
    padding-block: var(--space-sm);
    border-block-end: 1px solid var(--color-border);
}
.def-row > :first-child { color: var(--color-text-muted); }

/* =====================================================================
 * feedback (alert / banner / toast / skeleton)
 *
 * Alerts use the intent vocabulary (info/success/warning/danger) -- distinct
 * from button variants per decisions.md D16.
 * =================================================================== */
.alert {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-surface-1);
}
.alert-info,
.alert-success,
.alert-warning,
.alert-danger  { background-image: var(--gradient-fill-soft); }
.alert-info    { background-color: var(--color-info-bg);    border-color: var(--color-info);    color: var(--color-text); }
.alert-success { background-color: var(--color-success-bg); border-color: var(--color-success); color: var(--color-text); }
.alert-warning { background-color: var(--color-warning-bg); border-color: var(--color-warning); color: var(--color-text); }
.alert-danger  { background-color: var(--color-danger-bg);  border-color: var(--color-danger);  color: var(--color-text); }

.alert-icon  { color: currentColor; flex: none; }
.alert-title { font-weight: var(--weight-bold); }
.alert-body  { color: var(--color-text); }

.banner {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding-block: var(--space-sm);
    padding-inline: var(--space-lg);
    background-color: var(--color-surface-2);
    border-block-end: 1px solid var(--color-border);
    font-size: var(--text-sm);
}

.toast {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-pop);
    min-width: 18rem;
    max-width: 28rem;
}

.skeleton {
    background: linear-gradient(
        90deg,
        var(--color-surface-2) 0%,
        var(--color-surface-3) 50%,
        var(--color-surface-2) 100%
    );
    background-size: 200% 100%;
    border-radius: var(--radius-sm);
    animation: skeleton-shimmer 1.4s ease-in-out infinite;
    min-height: 1em;
}
@keyframes skeleton-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
    .skeleton { animation: none; background: var(--color-surface-2); }
}

/* Determinate progress bar. Consumers set the bar's inline-size via inline
 * style (the only theme-invariant value), or add .progress-indeterminate to
 * the wrapper for the looping shimmer variant. */
.progress {
    display: block;
    inline-size: 100%;
    block-size: 0.5rem;
    background-color: var(--color-surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    overflow: hidden;
}
.progress-bar {
    display: block;
    block-size: 100%;
    background-color: var(--color-brand);
    background-image: var(--gradient-fill-strong);
    transition: inline-size var(--motion-fast) var(--motion-easing);
}
.progress-indeterminate .progress-bar {
    inline-size: 33%;
    animation: progress-indeterminate 1.4s ease-in-out infinite;
}
@keyframes progress-indeterminate {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(400%); }
}
@media (prefers-reduced-motion: reduce) {
    .progress-indeterminate .progress-bar { animation: none; inline-size: 100%; opacity: 0.6; }
}

/* Standalone spinner. Sized in em so it tracks the parent's font-size; the
 * button-slot variant lives as .btn-spinner above and shares the rotate
 * keyframe to avoid duplicating the animation. Reduced-motion falls back
 * to a solid ring -- the spinner is information (loading is happening),
 * so we keep it visible per D21 instead of zeroing motion outright. */
.spinner {
    display: inline-block;
    flex: none;
    width: 1em;
    height: 1em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: var(--radius-full);
    animation: btn-spinner-rotate 0.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
    .spinner, .btn-spinner {
        animation: none;
        border-right-color: currentColor;
        opacity: 0.6;
    }
}

/* Empty / error state surface. Both Empty and Error components compose this
 * paint -- only the icon and copy differ. The .empty-danger modifier shifts
 * icon and title to the danger hue for error variants. */
.empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-2xl) var(--space-lg);
    text-align: center;
    color: var(--color-text-muted);
}
.empty-icon    { color: var(--color-text-muted); }
.empty-title   { font-size: var(--text-lg); font-weight: var(--weight-bold); color: var(--color-text); }
.empty-desc    { font-size: var(--text-sm); color: var(--color-text-muted); max-width: 40ch; }
.empty-actions { display: flex; gap: var(--space-sm); margin-block-start: var(--space-sm); }

.empty-danger .empty-icon  { color: var(--color-danger); }
.empty-danger .empty-title { color: var(--color-danger); }

/* =====================================================================
 * navigation (tabs / breadcrumb / stepper / pill-nav)
 *
 * State via ARIA per D6: .tab[aria-selected="true"], .step[aria-current=
 * "step"], .pill-nav-item[aria-current="page"]. Step completion uses
 * data-state="completed" since there is no native ARIA hook for "done".
 * =================================================================== */
.tabs {
    display: flex;
    flex-direction: column;
}
.tab-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    border-block-end: 1px solid var(--color-border);
}
.tab {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    padding-inline: var(--space-md);
    padding-block: var(--space-sm);
    font: inherit;
    font-weight: var(--weight-medium);
    color: var(--color-text-muted);
    background: transparent;
    border: none;
    border-block-end: 2px solid transparent;
    cursor: pointer;
    margin-block-end: -1px;             /* overlap the tab-list border */
    transition: color var(--motion-fast) var(--motion-easing),
                border-color var(--motion-fast) var(--motion-easing);
}
.tab:hover { color: var(--color-text); }
.tab[aria-selected="true"] {
    color: var(--color-brand);
    border-block-end-color: var(--color-brand);
}
.tab:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}
.tab:disabled,
.tab[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}
.tab-panel { padding-block-start: var(--space-lg); }

.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    padding: 0;
    margin: 0;
    list-style: none;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}
.breadcrumb-item   { display: inline-flex; align-items: center; }
.breadcrumb-item a { color: var(--color-text-muted); text-decoration: none; }
.breadcrumb-item a:hover { color: var(--color-text); text-decoration: underline; }
.breadcrumb-item[aria-current="page"] { color: var(--color-text); font-weight: var(--weight-medium); }
.breadcrumb-sep    { color: var(--color-text-subtle); margin-inline-start: var(--space-sm); }

.stepper {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}
.stepper-horizontal { flex-direction: row; align-items: flex-start; }
.step {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    color: var(--color-text-muted);
}
.stepper-horizontal .step { flex: 1; }
.step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    flex: none;
    border-radius: var(--radius-full);
    background-color: var(--color-surface-2);
    border: 1px solid var(--color-border);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--color-text-muted);
}
.step[aria-current="step"]                { color: var(--color-text); }
.step[aria-current="step"] .step-num      {
    background-color: var(--color-brand);
    background-image: var(--gradient-fill-strong);
    border-color: var(--color-brand);
    color: var(--color-text-on-brand);
}
.step[data-state="completed"]             { color: var(--color-text); }
.step[data-state="completed"] .step-num   {
    background-color: var(--color-success);
    border-color: var(--color-success);
    color: var(--color-text-on-brand);
}
.step-label { font-size: var(--text-sm); font-weight: var(--weight-medium); }

.pill-nav {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    padding: var(--space-xs);
    background-color: var(--color-surface-2);
    border-radius: var(--radius-full);
}
.pill-nav-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding-inline: var(--space-md);
    padding-block: var(--space-xs);
    font: inherit;
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--color-text-muted);
    text-decoration: none;
    background: transparent;
    border: none;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background-color var(--motion-fast) var(--motion-easing),
                color var(--motion-fast) var(--motion-easing);
}
.pill-nav-item:hover { color: var(--color-text); background-color: var(--color-surface-3); }
.pill-nav-item[aria-current="page"],
.pill-nav-item[aria-pressed="true"] {
    background-color: var(--color-surface-1);
    color: var(--color-text);
    box-shadow: var(--shadow-sm);
}
.pill-nav-item:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* =====================================================================
 * overlays (backdrop / modal / drawer / popover / tooltip / menu /
 * command-palette / toast-region)
 *
 * Paint only -- positioning mechanics (scroll-lock, slide transforms,
 * fixed-input scroll list) live in each component's structural .css.
 * Z-stack uses the token ramp: backdrop/popover at --z-overlay, modal/
 * drawer at --z-modal, menu/tooltip at --z-dropdown, toast region at
 * --z-toast.
 * =================================================================== */
.backdrop {
    background-color: var(--color-backdrop);
}

.modal {
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    max-block-size: calc(100vh - 4rem);
    inline-size: min(90vw, 32rem);
}
.modal-sm { inline-size: min(90vw, 24rem); }
.modal-md { inline-size: min(90vw, 32rem); }
.modal-lg { inline-size: min(90vw, 48rem); }

.modal-header,
.drawer-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-md);
    padding: var(--space-lg);
    border-block-end: 1px solid var(--color-border);
}
.modal-title,
.drawer-title { font-size: var(--text-lg); font-weight: var(--weight-bold); color: var(--color-text); }
.modal-body,
.drawer-body {
    padding: var(--space-lg);
    overflow-y: auto;
    flex: 1;
}
.modal-footer,
.drawer-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-sm);
    padding: var(--space-lg);
    border-block-start: 1px solid var(--color-border);
}

.drawer {
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
}

.popover {
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-pop);
    padding: var(--space-md);
    color: var(--color-text);
}

.tooltip {
    background-color: var(--color-tooltip-bg);
    color: var(--color-tooltip-fg);
    border-radius: var(--radius-sm);
    padding-inline: var(--space-sm);
    padding-block: var(--space-xs);
    font-size: var(--text-sm);
    box-shadow: var(--shadow-md);
    max-inline-size: 18rem;
}

.menu {
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-pop);
    padding-block: var(--space-xs);
    min-inline-size: 10rem;
    list-style: none;
    margin: 0;
}
.menu-item {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding-inline: var(--space-md);
    padding-block: var(--space-sm);
    font: inherit;
    color: var(--color-text);
    background: transparent;
    border: none;
    text-align: start;
    inline-size: 100%;
    cursor: pointer;
    text-decoration: none;
    transition: background-color var(--motion-fast) var(--motion-easing);
}
.menu-item:hover,
.menu-item[data-active="true"] {
    background-color: var(--color-surface-2);
}
.menu-item[aria-disabled="true"],
.menu-item:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}
.menu-item-danger { color: var(--color-danger); }
.menu-item[aria-current="true"] {
    color: var(--color-brand);
    font-weight: var(--weight-medium);
}

/* picker-trigger -- dropdown trigger that holds a stable width across
 * selection changes. Ghost labels stack into the same grid cell as the
 * active label; visibility:hidden keeps them off-screen but they still
 * contribute intrinsic width so the cell sizes to the widest possible
 * label. max-inline-size caps the budget for runaway labels.
 *
 * text-align override: <button> defaults to text-align:center, which
 * would center the shorter active label inside the ghost-sized cell.
 * Dropdowns conventionally read left-aligned -- match that. */
.picker-trigger-label {
    display: grid;
    grid-template-areas: "cell";
    max-inline-size: 18rem;
    min-inline-size: 0;
    text-align: start;
}
.picker-trigger-label > * {
    grid-area: cell;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.picker-trigger-label > .is-ghost {
    visibility: hidden;
    pointer-events: none;
}
.menu-separator {
    block-size: 1px;
    background-color: var(--color-border);
    margin-block: var(--space-xs);
}

.command-palette {
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    inline-size: min(90vw, 40rem);
}
.command-palette-input {
    inline-size: 100%;
    padding: var(--space-md) var(--space-lg);
    border: none;
    border-block-end: 1px solid var(--color-border);
    font: inherit;
    font-size: var(--text-base);
    background: transparent;
    color: var(--color-text);
    outline: none;
}
.command-palette-list {
    list-style: none;
    margin: 0;
    padding-block: var(--space-xs);
    max-block-size: 24rem;
    overflow-y: auto;
}
.command-palette-item {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding-inline: var(--space-lg);
    padding-block: var(--space-sm);
    color: var(--color-text);
    cursor: pointer;
}
.command-palette-item[data-active="true"] {
    background-color: var(--color-surface-2);
}
.command-palette-empty {
    padding: var(--space-lg);
    text-align: center;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.toast-region {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    list-style: none;
    margin: 0;
    padding: 0;
}
.toast-info    { border-inline-start: 3px solid var(--color-info);    }
.toast-success { border-inline-start: 3px solid var(--color-success); }
.toast-warning { border-inline-start: 3px solid var(--color-warning); }
.toast-danger  { border-inline-start: 3px solid var(--color-danger);  }

/* =====================================================================
 * data (tables, lists, trees, pagination, filter chips, bulk actions)
 *
 * Base .table chrome is shared by reference-table and data-table.
 * DataTable layers per-cell modifiers on top (.table-th-sortable,
 * .table-row-selected, .table-row-clickable) -- no table-level modifier
 * for sortability/selectability since those are column-by-column knobs.
 * No striped row backgrounds -- borders carry the rhythm
 * (tables.md "Avoid").
 * =================================================================== */
.table {
    inline-size: 100%;
    border-collapse: collapse;
    color: var(--color-text);
    font-size: var(--text-sm);
}

.table caption {
    text-align: start;
    padding-block: var(--space-sm);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.table thead {
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.table th,
.table td {
    padding-inline: var(--space-md);
    border-block-end: 1px solid var(--color-border);
    text-align: start;
    vertical-align: middle;
}

.table th {
    background-color: var(--color-surface-1);
    border-block-end: 1px solid var(--color-border-strong);
    font-weight: var(--weight-medium);
}

/* density modifiers -- pad vertical only; horizontal stays uniform */
.table-comfortable th,
.table-comfortable td { padding-block: var(--space-md); }

.table-normal th,
.table-normal td      { padding-block: var(--space-sm); }

.table-compact th,
.table-compact td     { padding-block: var(--space-xs); }

/* drop trailing row border so the table ends clean against a card edge */
.table tbody tr:last-child td { border-block-end: none; }

/* sticky header -- requires the table to live in a scroll container */
.table-sticky thead th {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--z-sticky);
}

/* Numeric column: tabular-nums + end-aligned in one class. The plain
 * end / center alignment helpers live in atomic.css as .text-end /
 * .text-center -- ReferenceTable threads those directly. */
.col-num { font-variant-numeric: tabular-nums; text-align: end; }

/* full-width empty / loading cell with vertical breathing room */
.table-empty-cell {
    padding-block: var(--space-2xl);
    text-align: center;
    color: var(--color-text-muted);
}

/* full-width error cell -- pads tight against the ErrorState centered
 * inside; ErrorState already brings its own vertical rhythm */
.table-error-cell {
    padding-block: var(--space-lg);
}

/* selection column -- narrow, centered checkbox slot, no padding fight
 * with the surrounding cells */
.table-select-cell {
    inline-size: 2.5rem;
    padding-inline: var(--space-sm);
    text-align: center;
    vertical-align: middle;
}

/* sortable header: the <th> stays a styled container; the <button> on
 * the inside is the click target. Strip native button chrome so the
 * header looks unbroken, but keep the focus ring for keyboard reach. */
.table-th-sortable { padding: 0; }

.table-th-button {
    inline-size: 100%;
    padding-inline: var(--space-md);
    padding-block: inherit;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    background: transparent;
    color: inherit;
    border: none;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    text-align: inherit;
    cursor: pointer;
}
.table-th-button:hover { color: var(--color-text); }
.table-th-button:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}

/* idle sort chevron is dimmed so the user knows the column is sortable
 * without it competing with the live header label. Active chevron uses
 * the strong text color. */
.table-sort-idle   { color: var(--color-text-subtle); }
.table-sort-active { color: var(--color-text); }

/* clickable rows -- pointer affordance + hover wash. Selected rows
 * tint independently so the two states layer cleanly. */
.table-row-clickable    { cursor: pointer; }
.table-row-clickable:hover td {
    background-color: var(--color-surface-2);
}
.table-row-selected td {
    background-color: color-mix(in srgb, var(--color-brand) 8%, var(--color-surface-1));
}
.table-row-selected.table-row-clickable:hover td {
    background-color: color-mix(in srgb, var(--color-brand) 14%, var(--color-surface-1));
}

/* filter chip row -- horizontal cluster sitting above a table. The
 * Chip primitive carries its own paint; this just lays them out. */
.filter-chip-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    padding-block: var(--space-sm);
}

/* bulk action bar -- floating selection-driven toolbar. Position is
 * fixed at the viewport's bottom edge, centered with a max-width so
 * it doesn't stretch across ultrawide displays. Surface-3 + shadow-pop
 * lift it visually above the table beneath. */
.bulk-action-bar {
    position: fixed;
    inset-block-end: var(--space-lg);
    inset-inline-start: 50%;
    transform: translateX(-50%);
    z-index: var(--z-sticky);
    display: flex;
    align-items: center;
    gap: var(--space-md);
    max-inline-size: min(48rem, calc(100% - var(--space-2xl)));
    padding-inline: var(--space-lg);
    padding-block: var(--space-sm);
    background-color: var(--color-surface-3);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-pop);
    color: var(--color-text);
    font-size: var(--text-sm);
}

.bulk-action-summary {
    color: var(--color-text-muted);
    font-weight: var(--weight-medium);
    margin-inline-end: auto;
}

.bulk-action-buttons {
    display: inline-flex;
    gap: var(--space-sm);
}

/* pagination */
.pagination {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding-block: var(--space-sm);
    color: var(--color-text);
    font-size: var(--text-sm);
}

.pagination-summary {
    color: var(--color-text-muted);
    margin-inline-end: auto;   /* push the page bar to the trailing edge */
}

.pagination-pages {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
}

.pagination-item {
    min-inline-size: 2rem;
    min-block-size: 2rem;
    padding-inline: var(--space-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: inherit;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font: inherit;
    cursor: pointer;
    user-select: none;
}

.pagination-item:hover { background-color: var(--color-surface-2); }
.pagination-item:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

.pagination-item[aria-current="page"] {
    background-color: var(--color-surface-3);
    border-color: var(--color-border-strong);
    color: var(--color-text);
    font-weight: var(--weight-medium);
}

.pagination-item:disabled,
.pagination-item[aria-disabled="true"] {
    color: var(--color-text-muted);
    cursor: default;
    opacity: 0.5;
}
.pagination-item:disabled:hover,
.pagination-item[aria-disabled="true"]:hover { background: transparent; }

.pagination-ellipsis {
    color: var(--color-text-muted);
    padding-inline: var(--space-xs);
    user-select: none;
}

.pagination-sm .pagination-item {
    min-inline-size: 1.75rem;
    min-block-size: 1.75rem;
    font-size: var(--text-xs);
}

/* list -- DataSource-driven row list (data/list.js). Vertical stack
 * with optional leading select column and row separators. Selection
 * paint mirrors the table row-selected wash so a list and a table
 * sit side-by-side without competing intensity. */
.list {
    list-style: none;
    margin: 0;
    padding: 0;
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: var(--text-sm);
}
.list > li                    { border-block-end: 1px solid var(--color-border); }
.list > li:last-child         { border-block-end: 0; }

.list-row {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md);
}

.list-rows-clickable .list-row-clickable { cursor: pointer; }
.list-row-clickable:hover     { background-color: var(--color-surface-2); }

.list-row-selected {
    background-color: color-mix(in srgb, var(--color-brand) 8%, var(--color-surface-1));
}
.list-row-selected.list-row-clickable:hover {
    background-color: color-mix(in srgb, var(--color-brand) 14%, var(--color-surface-1));
}

.list-select-cell             { flex: 0 0 auto; }
.list-row-body                { flex: 1 1 auto; min-inline-size: 0; }

.list-empty,
.list-error {
    padding: var(--space-lg);
    text-align: center;
    color: var(--color-text-muted);
}

/* tree -- TreeSource-driven hierarchical list (data/tree.js). Indent
 * driven by --tree-depth set per row by tree.js; chevron is a
 * borderless button sized to its icon. Selected + focused are
 * separate visual states so they layer (a focused-but-not-selected
 * node shows the focus ring without the brand wash). */
.tree,
.tree-children {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;
}

.tree {
    padding-block: var(--space-xs);
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: var(--text-sm);
}

.tree:focus                   { outline: none; }   /* focus rides on the focused treeitem */

.tree-row,
.tree-row-loading,
.tree-row-error {
    padding-inline-start: calc(var(--tree-depth, 0) * var(--space-md) + var(--space-sm));
    padding-inline-end:   var(--space-md);
}

.tree-row {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    padding-block: var(--space-xs);
    cursor: pointer;
    user-select: none;
}
.tree-row:hover               { background-color: var(--color-surface-2); }

.tree-row-selected {
    background-color: color-mix(in srgb, var(--color-brand) 8%, var(--color-surface-1));
}
.tree-row-selected:hover {
    background-color: color-mix(in srgb, var(--color-brand) 14%, var(--color-surface-1));
}

.tree-row-focused {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}

.tree-row-body                { flex: 1 1 auto; min-inline-size: 0; }

.tree-chevron,
.tree-chevron-spacer {
    flex: 0 0 auto;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.tree-chevron {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    color: inherit;
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.tree-chevron:hover           { background-color: var(--color-surface-3); }
.tree-chevron:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

.tree-row-loading,
.tree-row-error {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding-block: var(--space-xs);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.tree-empty {
    padding: var(--space-lg);
    text-align: center;
    color: var(--color-text-muted);
}

.tree-error {
    padding: var(--space-lg);
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

/* ---- virtual list ------------------------------------------------ */
.virtual-list {
    background-color: var(--color-surface-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: var(--text-sm);
    position: relative;
}
.virtual-list:focus               { outline: none; }   /* visual focus rides on the focused row */
.virtual-list:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: -2px;
}

/* spacer carries total height so the scrollbar reflects all rows;
 * rows position themselves absolutely inside. */
.virtual-list-spacer {
    list-style: none;
    margin: 0;
    padding: 0;
    position: relative;
}

/* `position: absolute` + `block-size: var(--vl-row-h)` live here so
 * the per-row inline style only needs to emit the dynamic `top` --
 * the visible loop allocates `{ top: ... }` instead of a 3-key object
 * on every redraw. The root sets `--vl-row-h` once per instance. */
.virtual-list-row {
    box-sizing: border-box;
    position: absolute;
    block-size: var(--vl-row-h, 40px);
    display: flex;
    align-items: center;
    gap: var(--space-md);
    inline-size: 100%;
    padding-inline: var(--space-md);
    border-block-end: 1px solid var(--color-border);
}

.virtual-list-row-clickable    { cursor: pointer; }
.virtual-list-row-clickable:hover { background-color: var(--color-surface-2); }

.virtual-list-row-selected {
    background-color: color-mix(in srgb, var(--color-brand) 8%, var(--color-surface-1));
}
.virtual-list-row-selected.virtual-list-row-clickable:hover {
    background-color: color-mix(in srgb, var(--color-brand) 14%, var(--color-surface-1));
}

.virtual-list-row-focused {
    box-shadow: inset 2px 0 0 var(--color-brand);
}

.virtual-list-select-cell        { flex: 0 0 auto; }
.virtual-list-row-body           { flex: 1 1 auto; min-inline-size: 0; }

.virtual-list-row-error {
    background-color: color-mix(in srgb, var(--color-danger) 4%, var(--color-surface-1));
    justify-content: center;
}

.virtual-list-empty,
.virtual-list-error {
    padding: var(--space-lg);
    text-align: center;
    color: var(--color-text-muted);
}

/* =====================================================================
 * decoration (divider / scrollbar)
 * =================================================================== */
.divider {
    block-size: 1px;
    inline-size: 100%;
    background-color: var(--color-border);
    border: none;
}

.divider-vertical {
    inline-size: 1px;
    block-size: 100%;
    background-color: var(--color-border);
    border: none;
}

/* opt-in slim scrollbar; consumers add `.scrollbar` to a scroll container */
.scrollbar {
    scrollbar-width: thin;
    scrollbar-color: var(--color-border-strong) transparent;
}
.scrollbar::-webkit-scrollbar      { width: 8px; height: 8px; }
.scrollbar::-webkit-scrollbar-track { background: transparent; }
.scrollbar::-webkit-scrollbar-thumb {
    background-color: var(--color-border-strong);
    border-radius: var(--radius-full);
}

/* ---- marketing-surface gradient patterns ----
 * Hero / card decorative gradients for landing pages. Resolve via the
 * --color-gradient-hero / --color-gradient-card slots in the active color
 * theme. Default themes (light, dark) provide a low-chroma brand mist;
 * koud themes use the teal/gold pair. Constraints (3 stops max, low chroma,
 * subtle) live in marketing-pages.md.
 *
 * Apply as a background layer behind content -- the gradient is the room,
 * not the furniture.
 */
.gradient-hero {
    background-image: var(--color-gradient-hero);
    background-repeat: no-repeat;
    background-size: cover;
}
.gradient-card {
    background-image: var(--color-gradient-card);
    background-repeat: no-repeat;
    background-size: cover;
}

/* ---- landing-page section recipes ----
 * Marketing-page surface frames. Hero: 80svh min-height (per
 * marketing-pages.md -- never 100vh, svh not vh for mobile address-bar
 * safety), flex-centered, padding-block only (the .container inside
 * carries horizontal padding). Section: a non-hero band with
 * padding-block + optional top border for separation.
 *
 * Compose with .gradient-hero / .gradient-card / .bg-surface-2 for the
 * paint; this layer owns SHAPE only.
 */
.hero-section {
    min-height: 80svh;
    display: flex;
    align-items: center;
    padding-block: var(--space-2xl);
}
.landing-section {
    padding-block: var(--space-3xl);
}
.landing-section-bordered {
    border-block-start: 1px solid var(--color-border);
}
