/* Component layer built entirely on the tokens in tokens.css.
 *
 * Nothing here hardcodes a colour, radius, or shadow: every value is a token, so
 * the three variants and both themes are pure token swaps with zero markup or
 * component changes. These classes are namespaced `ui-` so they can be dropped
 * into the real pages alongside the existing Bootstrap/modern-style rules while
 * a migration is in progress, without either side colliding.
 */

/* ---------------------------------------------------------------- base */
.ui-root {
    background: var(--canvas);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: 1.55;
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
    transition: background var(--motion-base) var(--ease),
                color var(--motion-base) var(--ease);
}

.ui-container {
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--space-4);
}

/* An author-level `display: grid/flex` outranks the UA stylesheet's
 * [hidden] { display: none }, so overlays and skeleton twins that carry a layout
 * class would render despite being marked hidden. State it explicitly. */
[hidden] { display: none !important; }

.ui-num {
    font-family: var(--font-num);
    font-variant-numeric: tabular-nums;
}

/* Icon sizing. icon() emits an <svg> with no width/height, relying on CSS, so
 * these must live here as well as in modern-style.css — otherwise an SVG with no
 * intrinsic size falls back to the browser default of 300x150. */
.icon,
.icon-lg,
.icon-xl {
    display: inline-block;
    flex-shrink: 0;
    fill: none;
    stroke: currentColor;
    vertical-align: -0.125em;
}

.icon { width: 1rem; height: 1rem; }
.icon-lg { width: 1.25rem; height: 1.25rem; }
.icon-xl { width: 1.5rem; height: 1.5rem; }

/* ---------------------------------------------------------------- nav (glass surface #1) */
.ui-nav {
    position: sticky;
    top: 0;
    z-index: 30;
    height: var(--nav-height);
    display: flex;
    align-items: center;
    background: var(--nav-bg);
    color: var(--nav-fg);
    border-bottom: 1px solid var(--nav-border);
}

/* Full-bleed on purpose, matching the header this replaced (.header-container had
 * no max-width). Capping this at --container-max leaves only 1368px for a link
 * row that needs ~1540px, so the links had nowhere to go but on top of the user
 * menu. Page content stays capped; only the nav spans the viewport. */
.ui-nav-inner {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    width: 100%;
    padding-inline: var(--space-4);
}

.ui-brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-weight: var(--weight-bold);
    font-size: var(--text-md);
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}

.ui-brand-mark {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-md);
    background: var(--accent);
    color: var(--accent-fg);
    flex-shrink: 0;
}

.ui-navlinks {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin-inline-start: var(--space-3);
    /* Must stay visible: the "more" menu is a Bootstrap dropdown nested in here,
     * and a scroll container would clip the popup instead of letting it hang
     * below the nav. No min-width: 0 either — that would let these nowrap links
     * spill out of their box and sit on top of the user menu. */
    overflow: visible;
}

/* Tight horizontal padding buys ~70px across the nine links, which is the
 * difference between labels fitting and not on a 1366px laptop. */
.ui-navlink {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-md);
    color: inherit;
    opacity: 0.72;
    text-decoration: none;
    font-weight: var(--weight-medium);
    font-size: var(--text-sm);
    white-space: nowrap;
    /* The "more" trigger is a <button>, so without these resets it renders with
     * the UA's grey button background and light text on the dark bar. */
    appearance: none;
    background: transparent;
    border: 0;
    font-family: inherit;
    cursor: pointer;
    transition: opacity var(--motion-fast) var(--ease),
                background var(--motion-fast) var(--ease);
}

/* Labels are opt-in, switched on by UI's nav fitter once it has confirmed they
 * actually fit. Hiding them by default means the pre-JS paint can never overlap
 * the user menu, and whether they show is decided by real measured width rather
 * than a breakpoint guessed from font metrics. */
a.ui-navlink > span { display: none; }
.ui-nav-inner.is-roomy a.ui-navlink > span { display: inline; }

/* When the labels can't fit, the icon row is far narrower than the bar. Left
 * alone it huddles against the brand with a few hundred pixels of dead space
 * beside it, so let it take the free width and centre itself instead. The links
 * also get squarer padding here, since there is room to spare. */
.ui-nav-inner:not(.is-roomy) a.ui-navlink { padding-inline: var(--space-3); }

.ui-nav-inner:not(.is-roomy) .ui-navlinks {
    flex: 1;
    justify-content: center;
    gap: var(--space-2);
}

/* The spacer's job is to push the user menu right; .ui-navlinks does that itself
 * once it grows, and keeping both would split the free space in two. */
.ui-nav-inner:not(.is-roomy) .ui-nav-spacer { display: none; }

.ui-navlink:hover { opacity: 1; background: color-mix(in oklab, currentColor 10%, transparent); }
.ui-navlink.is-active { opacity: 1; background: color-mix(in oklab, currentColor 14%, transparent); }

.ui-nav-spacer { flex: 1; }

.ui-avatar {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: var(--radius-full);
    background: var(--accent);
    color: var(--accent-fg);
    font-weight: var(--weight-semibold);
    font-size: var(--text-sm);
    flex-shrink: 0;
}

/* ---------------------------------------------------------------- app nav extras */
.ui-brand-name { display: inline; }
.ui-brand-name-short { display: none; }

.ui-userbtn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    appearance: none;
    border: 0;
    border-radius: var(--radius-full);
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: var(--weight-medium);
    cursor: pointer;
    transition: background var(--motion-fast) var(--ease);
}

.ui-userbtn:hover { background: color-mix(in oklab, currentColor 12%, transparent); }
.ui-userbtn::after { display: none; } /* drop Bootstrap's caret; we ship an icon */

.ui-username { white-space: nowrap; }

/* Both nav triggers ship their own chevron icon, so drop Bootstrap's caret. */
.ui-navlink.dropdown-toggle::after { display: none; }

/* Scoped to .ui-nav on purpose, to outrank the single-class rules that also set
 * `display` on these same elements: the burger carries .ui-btn (inline-flex) and
 * the desktop list carries .ui-navlinks (flex), both declared later in this file.
 * A bare .ui-nav-burger loses on source order and the burger shows at every
 * width, jammed against the username. */
.ui-nav .ui-nav-burger { display: none; color: inherit; }

/* Below this the link row gives way to the burger, the breakpoint the old header
 * used. Above it, whether labels or bare icons show is measured at runtime by
 * UI's nav fitter, not decided here. */
@media (max-width: 1279.98px) {
    .ui-nav .ui-nav-desktop { display: none; }
    .ui-nav .ui-nav-burger { display: inline-flex; }
}

/* ---------------------------------------------------------------- mobile nav (offcanvas)
 * Purpose-built instead of reusing the legacy .mobile-nav, which is
 * `position: fixed` at z-index 40 and so escapes the offcanvas panel and lands
 * behind Bootstrap's backdrop.
 */
.ui-mobilenav {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.ui-mobilelink {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    font-weight: var(--weight-medium);
    text-decoration: none;
}

.ui-mobilelink:hover { background: var(--surface-hover); color: var(--text); }

.ui-mobilelink.is-active {
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: var(--weight-semibold);
}

.ui-mobilenav-sep {
    height: 1px;
    background: var(--border);
    margin: var(--space-2) 0;
}

@media (max-width: 640px) {
    .ui-brand-name { display: none; }
    .ui-brand-name-short { display: inline; }
    .ui-username { display: none; }
}

/* ---------------------------------------------------------------- buttons */
.ui-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    height: var(--control-h);
    padding-inline: var(--space-4);
    /* Safari keeps drawing native button chrome on <button> unless appearance is
     * cleared, even with a background declared. */
    appearance: none;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-weight: var(--weight-medium);
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    /* Buttons are often anchors, which would otherwise carry the link underline. */
    text-decoration: none;
    transition: background var(--motion-fast) var(--ease),
                border-color var(--motion-fast) var(--ease),
                box-shadow var(--motion-fast) var(--ease),
                transform var(--motion-fast) var(--ease);
}

.ui-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-ring);
}

.ui-btn:active { transform: translateY(1px); }

.ui-btn--primary {
    background: var(--accent);
    color: var(--accent-fg);
    box-shadow: var(--elev-2);
}
.ui-btn--primary:hover { background: var(--accent-hover); }

.ui-btn--outline {
    background: var(--surface);
    border-color: var(--border-strong);
    color: var(--text);
}
.ui-btn--outline:hover { background: var(--surface-hover); }

.ui-btn--ghost { background: transparent; color: var(--text-muted); }
.ui-btn--ghost:hover { background: var(--surface-hover); color: var(--text); }

.ui-btn--danger { background: var(--danger); color: #fff; }

.ui-btn--icon { width: var(--control-h); padding-inline: 0; }

/* ---------------------------------------------------------------- cards */
.ui-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-2);
    overflow: hidden;
}

.ui-card-head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--card-p);
    border-bottom: 1px solid var(--border);
    /* Wrap rather than push controls past the card edge: a title plus two
     * labelled buttons wants ~450px, which no phone has. */
    flex-wrap: wrap;
}

.ui-card-title {
    margin: 0;
    font-size: var(--text-md);
    font-weight: var(--weight-semibold);
}

/* Groups the header's controls so they wrap as one unit and stay together on
 * their own row, instead of the last one breaking away on its own. */
.ui-card-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-inline-start: auto;
    /* .ui-btn is nowrap and can't shrink below its label, so at 320px the pair
     * has to be allowed to stack rather than run past the card edge. */
    flex-wrap: wrap;
}

/* Only the narrowest phones. Between here and the desktop layout the buttons keep
 * their natural width and simply sit on their own right-aligned row, which reads
 * better than stretching them across 500px. */
@media (max-width: 479.98px) {
    .ui-card-actions {
        width: 100%;
        margin-inline-start: 0;
        gap: var(--space-2);
    }

    /* Tighter than the desktop --space-4 so a pair of labelled buttons still
     * shares one row on a 360px screen; they keep the full 40px height, so the
     * touch target is unaffected. */
    .ui-card-actions .ui-btn {
        flex: 1 1 auto;
        padding-inline: var(--space-2);
    }
}

.ui-card-body { padding: var(--card-p); }

.ui-card-foot {
    padding: var(--card-p);
    border-top: 1px solid var(--border);
    background: var(--surface-sunken);
}

/* Two panels side by side, stacking on narrow screens. */
.ui-split {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    align-items: start;
}

/* ---------------------------------------------------------------- lists */
.ui-list { display: flex; flex-direction: column; }

.ui-listitem {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
}

.ui-list > .ui-listitem:last-child { border-bottom: 0; }

.ui-listitem-main { flex: 1; min-width: 0; }
.ui-listitem-side { text-align: right; flex-shrink: 0; }

.ui-listitem--link {
    padding-inline: var(--space-3);
    margin-inline: calc(var(--space-3) * -1);
    border-radius: var(--radius-md);
    transition: background var(--motion-fast) var(--ease);
}

.ui-listitem--link:hover { background: var(--surface-hover); color: var(--text); }
.ui-listitem--link > .icon:last-child { color: var(--text-subtle); }

/* ---------------------------------------------------------------- links & row actions */
.ui-link {
    color: var(--accent);
    font-weight: var(--weight-medium);
    text-decoration: none;
}

.ui-link:hover { color: var(--accent-hover); text-decoration: underline; }

.ui-rowactions {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.ui-btn--danger-ghost { color: var(--danger); }
.ui-btn--danger-ghost:hover { background: var(--danger-soft); color: var(--danger); }

.ui-grid {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}

/* Wider tracks than .ui-grid, for cards carrying body copy and an action row
 * rather than a single stat. auto-fill keeps the track width stable when only
 * one or two cards exist, instead of stretching them across the whole row. */
.ui-cardgrid {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
}

/* ---------------------------------------------------------------- stat tiles */
.ui-stat {
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--card-p);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-2);
    transition: transform var(--motion-base) var(--ease-out),
                box-shadow var(--motion-base) var(--ease);
}

.ui-stat:hover { transform: translateY(-2px); box-shadow: var(--elev-3); }

.ui-stat-icon {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: var(--radius-md);
    background: var(--accent-soft);
    color: var(--accent);
    flex-shrink: 0;
}

/* Tone modifiers keep the dashboard's colour coding without inline styles. */
.ui-stat-icon--success { background: var(--success-soft); color: var(--success); }
.ui-stat-icon--warning { background: var(--warning-soft); color: var(--warning); }
.ui-stat-icon--danger  { background: var(--danger-soft);  color: var(--danger); }
.ui-stat-icon--info    { background: var(--info-soft);    color: var(--info); }

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

.ui-stat-value {
    font-family: var(--font-num);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-2xl);
    font-weight: var(--weight-bold);
    line-height: 1.15;
    color: var(--text);
}

.ui-stat-delta { font-size: var(--text-xs); color: var(--text-muted); }
.ui-stat-delta.is-up { color: var(--success); }
.ui-stat-delta.is-down { color: var(--danger); }

/* ---------------------------------------------------------------- table */
/* Deliberately its own scroll container rather than letting the page scroll:
 * that's what makes `position: sticky` on the header pin to the top of the table
 * instead of disappearing under the app nav, which is also sticky. */
.ui-table-wrap {
    max-height: min(70vh, 720px);
    overflow: auto;
    border-radius: var(--radius-lg);
}

.ui-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--row-font);
}

.ui-table th {
    /* Sticky header: the column labels stay put while the rows scroll under. */
    position: sticky;
    top: 0;
    z-index: 2;
    padding: var(--space-3) var(--cell-px);
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border);
    color: var(--text-muted);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    text-align: left;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
}

.ui-table td {
    padding: var(--row-py) var(--cell-px);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

.ui-table tbody tr { transition: background var(--motion-fast) var(--ease); }
.ui-table tbody tr:hover { background: var(--surface-hover); }
.ui-table tbody tr:last-child td { border-bottom: 0; }

.ui-table .is-num {
    font-family: var(--font-num);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.ui-cell-strong { font-weight: var(--weight-semibold); color: var(--text); }
.ui-cell-sub { font-size: var(--text-xs); color: var(--text-subtle); }

/* ---------------------------------------------------------------- badges */
.ui-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 2px var(--space-2);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    white-space: nowrap;
}

.ui-badge--success { background: var(--success-soft); color: var(--success); }
.ui-badge--warning { background: var(--warning-soft); color: var(--warning); }
.ui-badge--danger  { background: var(--danger-soft);  color: var(--danger); }
.ui-badge--info    { background: var(--info-soft);    color: var(--info); }
.ui-badge--neutral { background: var(--surface-sunken); color: var(--text-muted); }

.ui-dot { width: 6px; height: 6px; border-radius: var(--radius-full); background: currentColor; }

/* ---------------------------------------------------------------- forms */
.ui-field { display: flex; flex-direction: column; gap: var(--space-2); }

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

.ui-input,
.ui-select,
.ui-textarea {
    width: 100%;
    min-height: var(--control-h);
    padding: var(--space-2) var(--space-3);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    color: var(--text);
    font: inherit;
    transition: border-color var(--motion-fast) var(--ease),
                box-shadow var(--motion-fast) var(--ease);
}

.ui-input::placeholder { color: var(--text-subtle); }

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

.ui-input-group { position: relative; }
.ui-input-group .ui-input { padding-left: var(--space-10); }
.ui-input-icon {
    position: absolute;
    left: var(--space-3);
    top: 50%;
    translate: 0 -50%;
    color: var(--text-subtle);
    pointer-events: none;
}

/* ---------------------------------------------------------------- photo grid */
.ui-photo-grid {
    display: grid;
    gap: var(--space-3);
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}

.ui-photo {
    /* aspect-ratio reserves the box before the image decodes, so the grid never
     * reflows as photos stream in (the layout-shift fix). */
    aspect-ratio: 4 / 3;
    width: 100%;
    position: relative;
    display: block;
    overflow: hidden;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--surface-sunken);
    transition: transform var(--motion-base) var(--ease-out),
                box-shadow var(--motion-base) var(--ease);
}

.ui-photo > img,
.ui-photo > .ui-photo-fake {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.ui-photo:hover { transform: scale(1.02); box-shadow: var(--elev-3); z-index: 1; }

.ui-photo-badge {
    position: absolute;
    left: var(--space-2);
    bottom: var(--space-2);
    padding: 1px var(--space-2);
    border-radius: var(--radius-sm);
    background: rgb(0 0 0 / 0.55);
    color: #fff;
    font-size: var(--text-xs);
}

/* ---------------------------------------------------------------- skeletons */
.skel {
    background: var(--skeleton-base);
    border-radius: var(--radius-sm);
    background-image: linear-gradient(90deg,
        var(--skeleton-base) 0%,
        var(--skeleton-shine) 50%,
        var(--skeleton-base) 100%);
    background-size: 200% 100%;
    animation: skel-shimmer 1.4s ease-in-out infinite;
}

.skel-text { height: 0.7em; margin-block: 0.25em; }
.skel-line-60 { width: 60%; }
.skel-line-80 { width: 80%; }
.skel-line-40 { width: 40%; }

@keyframes skel-shimmer {
    from { background-position: 200% 0; }
    to   { background-position: -200% 0; }
}

/* ---------------------------------------------------------------- empty state */
.ui-empty {
    display: grid;
    place-items: center;
    gap: var(--space-3);
    padding: var(--space-12) var(--space-4);
    text-align: center;
    color: var(--text-muted);
}

.ui-empty-icon {
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    color: var(--text-subtle);
}

/* ---------------------------------------------------------------- toast (glass surface #2) */
.ui-toast-stack {
    position: fixed;
    right: var(--space-4);
    bottom: var(--space-4);
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    pointer-events: none;
}

.ui-toast {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 260px;
    padding: var(--space-3) var(--space-4);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-4);
    color: var(--text);
    pointer-events: auto;
    animation: toast-in var(--motion-slow) var(--ease-out);
}

.ui-toast.is-leaving { animation: toast-out var(--motion-base) var(--ease) forwards; }
.ui-toast-icon { color: var(--success); flex-shrink: 0; }

@keyframes toast-in {
    from { opacity: 0; transform: translateY(12px) scale(0.98); }
    to   { opacity: 1; transform: none; }
}
@keyframes toast-out {
    to { opacity: 0; transform: translateY(8px) scale(0.98); }
}

/* ---------------------------------------------------------------- modal (glass surface #3) */
.ui-scrim {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: grid;
    place-items: center;
    padding: var(--space-4);
    background: rgb(16 24 40 / 0.45);
    animation: fade-in var(--motion-base) var(--ease);
}

.ui-modal {
    width: min(520px, 100%);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: var(--elev-4);
    overflow: hidden;
    animation: modal-in var(--motion-slow) var(--ease-out);
}

.ui-modal-foot {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    padding: var(--card-p);
    border-top: 1px solid var(--border);
    background: var(--surface-sunken);
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in {
    from { opacity: 0; transform: translateY(16px) scale(0.97); }
    to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------- command palette (glass surface #4) */
.ui-palette-scrim {
    position: fixed;
    inset: 0;
    z-index: 70;
    display: grid;
    align-items: start;
    justify-items: center;
    padding: 12vh var(--space-4) var(--space-4);
    background: rgb(16 24 40 / 0.40);
    animation: fade-in var(--motion-fast) var(--ease);
}

.ui-palette {
    width: min(560px, 100%);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: var(--elev-4);
    overflow: hidden;
    animation: modal-in var(--motion-base) var(--ease-out);
}

.ui-palette-input-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
    color: var(--text-subtle);
}

.ui-palette-input {
    flex: 1;
    border: 0;
    background: none;
    color: var(--text);
    font: inherit;
    font-size: var(--text-md);
    outline: none;
}
.ui-palette-input::placeholder { color: var(--text-subtle); }

.ui-palette-list {
    max-height: 320px;
    overflow-y: auto;
    padding: var(--space-2);
    margin: 0;
    list-style: none;
}

.ui-palette-group {
    padding: var(--space-2) var(--space-3) var(--space-1);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    color: var(--text-subtle);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.ui-palette-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    color: var(--text);
    cursor: pointer;
}

.ui-palette-item[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); }
.ui-palette-item-sub { margin-left: auto; font-size: var(--text-xs); color: var(--text-subtle); }

.ui-palette-foot {
    display: flex;
    gap: var(--space-4);
    padding: var(--space-2) var(--space-4);
    border-top: 1px solid var(--border);
    background: var(--surface-sunken);
    font-size: var(--text-xs);
    color: var(--text-subtle);
}

.ui-kbd {
    display: inline-block;
    min-width: 18px;
    padding: 1px 5px;
    border: 1px solid var(--border-strong);
    border-bottom-width: 2px;
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text-muted);
    font-family: var(--font-num);
    font-size: 11px;
    text-align: center;
}

/* ---------------------------------------------------------------- FAB */
.ui-fab {
    position: fixed;
    right: var(--space-4);
    /* Sits above the thumb zone and clears the iOS home indicator. */
    bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    z-index: 40;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    height: 52px;
    padding-inline: var(--space-5);
    border: 0;
    border-radius: var(--radius-full);
    background: var(--accent);
    color: var(--accent-fg);
    font: inherit;
    font-weight: var(--weight-semibold);
    box-shadow: var(--elev-4);
    cursor: pointer;
    transition: transform var(--motion-base) var(--ease-out),
                box-shadow var(--motion-base) var(--ease);
}

.ui-fab:hover { transform: translateY(-2px) scale(1.02); }
.ui-fab:active { transform: translateY(0) scale(0.98); }

/* ===================================================================
   GLASS TREATMENT
   Applied ONLY to fixed/overlay chrome: nav, palette, toast, modal, FAB.
   Content surfaces (cards, tables, rows) stay opaque, which keeps text contrast
   predictable and keeps the compositor from re-blurring a large backdrop on
   every scroll frame.
   =================================================================== */
[data-variant="glass"] .ui-nav,
[data-variant="glass"] .ui-palette,
[data-variant="glass"] .ui-toast,
[data-variant="glass"] .ui-modal,
[data-variant="glass"] .ui-fab {
    background: color-mix(in oklab, var(--surface-raised) calc(var(--glass-opacity) * 100%), transparent);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
    backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
    /* The inset highlight is the "specular edge" that reads as a lit glass rim. */
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--elev-3);
    border-color: color-mix(in oklab, var(--border) 55%, transparent);
}

[data-variant="glass"] .ui-nav {
    background: color-mix(in oklab, var(--nav-bg) calc(var(--glass-opacity) * 100%), transparent);
}

[data-variant="glass"] .ui-fab {
    background: color-mix(in oklab, var(--accent) 82%, transparent);
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.35), var(--elev-4);
}

[data-variant="glass"] .ui-scrim,
[data-variant="glass"] .ui-palette-scrim {
    background: rgb(16 24 40 / 0.28);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
}

/* Fallback 1: browsers without backdrop-filter get fully opaque chrome rather
 * than a washed-out translucent panel with unreadable text over it. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    [data-variant="glass"] .ui-nav,
    [data-variant="glass"] .ui-palette,
    [data-variant="glass"] .ui-toast,
    [data-variant="glass"] .ui-modal,
    [data-variant="glass"] .ui-fab {
        background: var(--surface-raised);
    }
    [data-variant="glass"] .ui-nav { background: var(--nav-bg); }
    [data-variant="glass"] .ui-fab { background: var(--accent); }
}

/* Fallback 2: honour the OS "reduce transparency" accessibility setting. */
@media (prefers-reduced-transparency: reduce) {
    [data-variant="glass"] .ui-nav,
    [data-variant="glass"] .ui-palette,
    [data-variant="glass"] .ui-toast,
    [data-variant="glass"] .ui-modal,
    [data-variant="glass"] .ui-fab {
        background: var(--surface-raised);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
    [data-variant="glass"] .ui-nav { background: var(--nav-bg); }
    [data-variant="glass"] .ui-fab { background: var(--accent); }
}

/* ---------------------------------------------------------------- motion opt-out */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    .skel { animation: none; background-image: none; }
}
