/* ============================================
   COMMAND BAR (desktop shell)

   One 44 px row per panel: views · chips · controls · actions · overflow.
   Desktop only — every rule sits behind the min-width guard so the phone
   shell (bottom tabs, stacked toolbars, sticky summary strip) is untouched.
   Visual states of the buttons come from buttons.css, which loads last.
   ============================================ */

:root {
    --command-bar-height: 44px;
    --command-chip-height: 28px;
    --z-command-popover: 320;
    --nav-rail-width: 74px;
}

/* ── The bar itself ───────────────────────────────────────────────────
   One row of controls per panel, at every width. The phone shell uses the
   same bar as the desktop one and scrolls it sideways instead of folding
   its controls away; the rules that only make sense beside a navigation
   rail or a side pane are in the desktop block below. */

/* A bar with nothing left in it is not drawn. This happens to the
   narrower of two panes showing one panel: the chrome they would both
   draw goes to the roomier pane (`WorkspacePanes::draws_shared_chrome`),
   and a view that publishes no controls of its own is then left with an
   empty row. An empty slot holds only Leptos's placeholder comment, so
   "has an element in any slot" is the whole test, and the bar comes back
   by itself the moment one does. */

.command-bar:not(
    :has(
    .command-bar-identity > *,
    .command-bar-chips > *,
    .command-bar-controls > *,
    .command-bar-actions > *
    )
) {
    display: none;
}

/* ── Bar ─────────────────────────────────────────────────────────────── */

.command-bar {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: var(--command-bar-height);
    padding: 4px 10px;
    margin: 6px 0 8px;
    background: var(--widget-bg, var(--panel-bg));
    border: 1px solid var(--border-color);
    border-radius: 10px;
    flex-shrink: 0;
    white-space: nowrap;
    /* Visible so the popovers can hang below the row; scrollWidth still
       reports the content's width for the pressure check. */
    overflow: visible;
    z-index: 30;
}

/* The slots never shrink below their content. If they did, a crowded bar
   would overlap and clip its own buttons while its scrollWidth stayed
   equal to its clientWidth, and the width-pressure observer would never
   see the overflow it exists to relieve. Only the identity may shrink
   (its title truncates). */

.command-bar-identity,
.command-bar-chips,
.command-bar-controls,
.command-bar-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
}

/* The identity too: its title truncates at 26vw but never below its
   guaranteed characters, so a long title overflows the bar (measurably)
   instead of sliding under the chips. */

.command-bar-identity {
    flex: 0 0 auto;
}

.command-bar-identity:empty,
.command-bar-chips:empty,
.command-bar-controls:empty {
    display: none;
}

.command-bar-controls {
    justify-content: flex-start;
}

.command-bar-actions {
    margin-left: auto;
}

.command-bar-divider {
    width: 1px;
    height: 22px;
    background: var(--border-color);
    flex: 0 0 auto;
}

/* ── Chips: figures that act ─────────────────────────────────────────── */

.command-menu {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.command-chip,
.command-control {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: var(--command-chip-height);
    padding: 0 9px;
    border-radius: 999px;
    font-size: 12.5px;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
}

.command-chip strong {
    font-weight: 700;
    color: var(--text-color);
    font-variant-numeric: tabular-nums;
}

.command-chip .command-chip-label {
    color: var(--text-muted);
}

.command-caret {
    font-size: 10px;
    opacity: 0.75;
}

.command-chip .ms,
.command-chip .icon {
    font-size: 12px;
    opacity: 0.9;
}

.command-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--accent-color);
    color: var(--button-primary-text, #fff);
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
}

/* ── Controls: tools with a label that drops first ───────────────────── */

.command-control {
    border-radius: var(--ui-button-radius, 6px);
}

.command-control .text {
    font-size: 12.5px;
}

.command-control--icon {
    padding: 0 8px;
}

.command-control .icon {
    width: 14px;
    height: 14px;
}

/* Search: an icon until it is used, a 240 px field while it is. */

.command-search {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.command-search-field {
    width: 240px;
}

.command-search-input {
    height: var(--command-chip-height);
    padding: 0 10px;
    font-size: 12.5px;
}

.command-search-clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border-radius: 999px;
}

/* Primary actions keep their labels at every pressure level, and sit at
   the chips' height so the bar is exactly one row of one size. */

.command-bar .command-action {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: var(--command-chip-height);
    min-height: 0;
    padding: 0 10px;
    font-size: 12.5px;
    line-height: 1;
    white-space: nowrap;
}

.command-action.dirty {
    position: relative;
}

.command-action.dirty::after {
    content: "";
    position: absolute;
    top: -3px;
    right: -3px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--warning-color);
    border: 2px solid var(--widget-bg, var(--panel-bg));
}

/* ── Popovers ─────────────────────────────────────────────────────────── */

.command-popover {
    position: absolute;
    top: calc(100% + 6px);
    min-width: 220px;
    max-width: min(420px, calc(100vw - 24px));
    padding: 6px;
    /* Opaque: the content scrolling under a menu must not show through. */
    background: var(--panel-bg-opaque, var(--card-bg, var(--widget-bg)));
    border: 1px solid var(--border-color);
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
    z-index: var(--z-command-popover);
    white-space: normal;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.command-popover--start {
    left: 0;
}

.command-popover--end {
    right: 0;
}

.command-popover .menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 7px 10px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-color);
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}

.command-popover .menu-item.active {
    color: var(--accent-color);
}

.command-popover .menu-item.menu-item--danger {
    color: var(--danger-color);
}

.command-popover .menu-divider {
    height: 1px;
    margin: 4px 2px;
    background: var(--border-color);
}

.command-popover-section {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 6px 8px;
}

.command-popover-heading {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.command-popover-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    color: var(--text-secondary);
}

.command-popover-row strong {
    color: var(--text-color);
    font-variant-numeric: tabular-nums;
}

.command-popover-figure {
    font-size: 18px;
    font-weight: 700;
    color: var(--text-color);
}

/* A wide popover for the filter bar. */

.command-popover--wide {
    min-width: 560px;
    max-width: min(720px, calc(100vw - 24px));
}

.command-popover--wide .deck-filter-bar {
    position: relative;
    margin: 0;
}

/* Clear Filters sits bottom-right, on the Proxy / Owned row. */

.command-popover--wide .deck-filter-clear {
    position: absolute;
    right: 0;
    bottom: 0;
    margin: 0;
    height: 30px;
}

/* The search field, as a menu under its icon. */

.command-popover--search {
    min-width: 300px;
}

.command-search-popover {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 6px;
}

.command-search-popover .command-search-field {
    flex: 1;
    width: auto;
}

/* A toolbar that has published itself into the bar renders nothing inline. */

.synergy-action-bar.in-command-bar {
    display: none;
}

/* The Library's filters in one menu. */

.command-popover--library {
    min-width: 320px;
}

.library-filter-popover {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.command-popover .library-filter-popover .library-select {
    width: 100%;
    max-width: none;
}

.command-popover-clear {
    align-self: flex-end;
    margin: 2px 6px 4px;
}

/* Pages in the bar: small, ruleless. */

.command-bar .pagination-pages--compact {
    display: flex;
    align-items: center;
    gap: 3px;
}

.command-bar .pagination-pages--compact .pagination-btn {
    height: 24px;
    min-width: 24px;
    padding: 0 7px;
    font-size: 11.5px;
    border-radius: 6px;
}

.command-bar .pagination-pages--compact .pagination-ellipsis {
    font-size: 11px;
    padding: 0 2px;
}

/* The Trade filter menu: the member picker and the tradable toggle are
   one compact row. (`.deck-filter-section--pod` has a 260 px flex basis
   for the drawer, which in this column layout became 260 px of height.) */

.command-popover .pod-browser-person-filters {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: 10px;
    margin: 0;
}

.command-popover .pod-browser-person-filters .deck-filter-section--pod {
    flex: none;
    min-width: 0;
}

.command-popover .pod-filter-pill {
    min-height: 30px;
    padding: 0 10px;
}

/* The format chip beside the deck name. */

.command-identity .command-chip--format {
    flex: 0 0 auto;
}

.command-identity .command-chip--format .command-chip-label {
    color: var(--text-color);
    font-weight: 600;
}

/* Selects inside popovers share the bar's height. */

.command-popover select,
.command-popover .filter-select,
.command-popover .format-selector {
    width: 100%;
    min-width: 0;
    height: 30px;
    padding: 0 8px;
    font-size: 12.5px;
}

.command-popover .toolbar-view-toggles {
    width: 100%;
}

.command-popover .toolbar-view-btn {
    flex: 1;
    height: 30px;
}

/* The glyphs size from the button, not from the popover's font. */

.command-popover .toolbar-view-btn svg {
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
}

.command-popover .toolbar-card-scale {
    display: flex;
    justify-content: space-between;
}

/* Overflow twins of the controls: hidden until the controls slot is gone. */

.command-overflow-control {
    display: none;
}

/* The overflow trigger is as narrow as it can be, always: glyph only. */

.command-bar .command-control--overflow {
    padding: 0 7px;
}

.command-bar .command-control--overflow .command-caret {
    display: none;
}

/* The Type menu rows lead with the type glyph. */

.command-popover .menu-item--type i {
    width: 16px;
    text-align: center;
    opacity: 0.9;
}

/* The notepad as a drawer inside its pane (see notepad/component.rs): it
   hangs from the view area under the bar, over the right part of the
   list, leaving the rest of the workspace usable. */

.deck-notepad-panel.in-pane {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    height: auto;
    width: min(560px, 100%);
    max-width: 100%;
    z-index: 40;
    border-radius: 10px 0 0 10px;
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.25);
}

/* ── Identity: the deck's pips and name lead the Builder's bar ───────── */

/* No cap on the identity itself: its width must be its content, so the
   pressure observer measures it. The cap is on the title. */

.command-identity {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.command-identity .deck-title-pips {
    display: inline-flex;
    gap: 2px;
    flex: 0 0 auto;
}

.command-identity .deck-title,
.command-identity .deck-name-field {
    /* Shorter than the bar's 44px content box less its 8px of padding: the
       field needs room for its own border inside that, and on a phone the bar
       clips what does not fit. */
    height: 28px;
    font-size: 14px;
    font-weight: 700;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.command-identity .deck-title {
    padding: 0 8px;
}

/* The padding belongs to the input, not to the wrapper. The counter overlay is
   positioned against the wrapper's padding box, so padding out here put the
   overlay that far outside the input it describes. */
.command-identity .deck-name-field {
    padding: 0;
    /* Room to actually type a name in. */
    min-width: 22ch;
}

.command-identity .deck-name-input {
    height: 100%;
    padding: 0 8px;
}

/* A deck or pod name is not a piece of writing with a word budget, and a live
   count is not worth half the field. The clear button stays. */
.command-identity .standard-text-field-count {
    display: none;
}

.command-identity .standard-text-field-affix {
    padding: 0 4px 0 12px;
}

/* The title is guaranteed about sixteen characters and truncates at
   26vw; it shows itself in full while hovered or focused (the bar sheds
   labels to make room). */

.command-identity .deck-title {
    min-width: 16ch;
    max-width: 26vw;
}

.command-identity:hover .deck-title,
.command-identity:focus-within .deck-title {
    max-width: none;
}

/* ── Per-panel control groups ────────────────────────────────────────── */

.deck-command-controls,
.collection-command-controls,
.library-command-controls,
.analysis-command-controls,
.genome-command-controls {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.command-bar .library-select,
.command-bar .command-select {
    height: var(--command-chip-height);
    padding: 0 8px;
    font-size: 12.5px;
    max-width: 160px;
}

.command-zoom {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}

.command-popover .command-zoom {
    justify-content: center;
    gap: 6px;
}

.command-zoom-value {
    min-width: 48px;
    justify-content: center;
    font-variant-numeric: tabular-nums;
}

.command-chip--quota.danger strong {
    color: var(--danger-color);
}

.command-chip--warning strong {
    color: var(--warning-color);
}

.command-popover--genome {
    min-width: 300px;
}

.command-popover-row--sort .sort-control {
    flex: 1;
}

/* Opening: each view drops out from under the tab, just after the one
   above it. An animation rather than a transition because the rail
   rebuilds these buttons as the group opens, and a fresh element
   animates while it has nothing to transition from. */

@keyframes rail-subtab-drop {
    from {
    opacity: 0;
    transform: translateY(-10px);
    }

    to {
    opacity: 1;
    transform: translateY(0);
    }
}

@media (min-width: 769px) {

    /* ── The command palette (Ctrl/Cmd+K) ────────────────────────────────── */

    /* Hosted by the main pane's content area (`.panel-content`, positioned
       below); `top` is set on open to sit under the active panel's bar. */

    .right-panel.has-rail > .panel-content {
        position: relative;
    }

    .command-palette {
        position: absolute;
        top: 8px;
        left: 12px;
        right: 12px;
        display: flex;
        flex-direction: column;
        max-width: 640px;
        margin: 0 auto;
        padding: 6px;
        background: var(--panel-bg-opaque, var(--card-bg, var(--widget-bg)));
        border: 1px solid var(--border-color);
        border-radius: 10px;
        box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
        z-index: calc(var(--z-command-popover) + 1);
        white-space: normal;
    }

    .command-palette-input {
        width: 100%;
        height: 34px;
        padding: 0 12px;
        border: 1px solid var(--border-color);
        border-radius: 8px;
        background: var(--input-bg);
        color: var(--text-color);
        font-size: 13.5px;
        outline: none;
    }

    .command-palette-input:focus {
        border-color: var(--accent-color);
        box-shadow: 0 0 0 2px var(--accent-glow);
    }

    .command-palette-list {
        margin-top: 6px;
        max-height: min(420px, 60vh);
        overflow-y: auto;
        display: flex;
        flex-direction: column;
        gap: 4px;
    }

    .command-palette-heading {
        padding: 6px 10px 2px;
        font-size: 10px;
        font-weight: 700;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        color: var(--text-muted);
    }

    .command-palette-item {
        display: flex;
        align-items: center;
        gap: 10px;
        width: 100%;
        padding: 7px 10px;
        border: none;
        border-radius: 6px;
        background: transparent;
        color: var(--text-color);
        font-size: 13px;
        text-align: left;
        cursor: pointer;
    }

    .command-palette-item.selected {
        background: var(--accent-gradient);
        color: var(--button-primary-text, #fff);
    }

    .command-palette-label {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .command-palette-hint {
        flex: 0 0 auto;
        font-size: 11px;
        opacity: 0.7;
        font-variant-numeric: tabular-nums;
    }

    .command-palette-empty {
        padding: 14px 10px;
        color: var(--text-muted);
        font-size: 13px;
        text-align: center;
    }

    /* ── Width pressure: what goes at each level, least important first ── */

    /* 1: Save keeps only its glyph (its title still names it). */

    .command-bar:is(.pressure-1, .pressure-2, .pressure-3, .pressure-4, .pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-action .text {
        display: none;
    }

    .command-bar:is(.pressure-1, .pressure-2, .pressure-3, .pressure-4, .pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-action {
        padding: 0 8px;
    }

    /* 2: the utilities (Notepad, Research, Suggest). */

    .command-bar:is(.pressure-2, .pressure-3, .pressure-4, .pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-control--utility .text {
        display: none;
    }

    .command-bar:is(.pressure-2, .pressure-3, .pressure-4, .pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-control--utility {
        padding: 0 8px;
    }

    /* 3: Filter and View. */

    .command-bar:is(.pressure-3, .pressure-4, .pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) :is(.command-control--filter, .command-control--view) .text {
        display: none;
    }

    .command-bar:is(.pressure-3, .pressure-4, .pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) :is(.command-control--filter, .command-control--view) {
        padding: 0 8px;
    }

    /* 4: Type. */

    .command-bar:is(.pressure-4, .pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-chip--types .command-chip-label {
        display: none;
    }

    /* 5: the deck title narrows (never below eight characters). */

    .command-bar:is(.pressure-5, .pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-identity .deck-title {
        min-width: 8ch;
        max-width: 12ch;
    }

    /* 6: the colour-identity pips go. */

    .command-bar:is(.pressure-6, .pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-identity .deck-title-pips {
        display: none;
    }

    /* 7: "Bracket N" becomes "N". */

    .command-bar:is(.pressure-7, .pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-chip-label--bracket {
        display: none;
    }

    /* 8: the controls move into the overflow menu, where a view has one with
       twins for them (its trigger says so; the twins themselves only exist
       while the menu is open); a view without keeps its controls (glyph-only). */

    .command-bar:is(.pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12):has(.command-overflow--twins) .command-bar-controls {
        display: none;
    }

    .command-bar:is(.pressure-8, .pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-overflow-control {
        display: flex;
    }

    /* 9: the Type chip goes. */

    .command-bar:is(.pressure-9, .pressure-10, .pressure-11, .pressure-12) .command-chip--types {
        display: none;
    }

    /* 10: the count keeps its number and drops "main" and the board labels. */

    .command-bar:is(.pressure-10, .pressure-11, .pressure-12) .command-chip--count .command-chip-label {
        display: none;
    }

    /* 11: the synergy and combo counts go. */

    .command-bar:is(.pressure-11, .pressure-12) :is(.command-chip--synergies, .command-chip--combos) {
        display: none;
    }

    /* 12: the deck title goes; the format chip stays. */

    .command-bar.pressure-12 .command-identity .deck-title,
    .command-bar.pressure-12 .command-identity .deck-name-field,
    .command-bar.pressure-12 .command-identity .deck-title-pips {
        display: none;
    }

    /* An open utility (Notepad, Research, Suggest) or an engaged Filter stays
       filled until it is closed. Specific enough to beat the shared button
       contract in buttons.css, which loads after this file. */

    .right-panel .command-bar .command-bar-controls .command-control.active,
    .right-panel .command-bar .command-bar-controls .command-control.active:hover {
        background: var(--accent-gradient);
        color: var(--button-primary-text, #fff);
        border-color: transparent;
    }

    .right-panel .command-bar .command-control.active .icon,
    .right-panel .command-bar .command-control.active .text,
    .right-panel .command-bar .command-control.active .command-caret {
        color: inherit;
        opacity: 1;
    }

    /* ── Shell: navigation rail ──────────────────────────────────────────── */

    .right-panel.has-rail {
        display: grid;
        grid-template-columns: var(--nav-rail-width) minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr);
    }

    /* The content runs to the panel edge: the rail on the left and the
       panel frame on the other sides already bound it, and the old inset
       read as a horseshoe of dead space. */

    .right-panel.has-rail > .panel-content {
        grid-column: 2;
        padding: 0;
    }

    /* The bar keeps a small gutter of its own now that the content does not. */

    .right-panel.has-rail .command-bar {
        margin: 6px 6px 8px;
    }

    .panel-tabs.nav-rail {
        grid-column: 1;
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        gap: 6px;
        padding: 10px 6px;
        border-bottom: none;
        border-right: 1px solid var(--glass-border);
        overflow-y: auto;
        overflow-x: hidden;
    }

    /* The group: a primary tab and its subtabs, with room in the rail's
       padding for a line on either edge. `isolate` keeps the block below
       from sinking behind the rail's own background. */

    .panel-tabs.nav-rail .rail-group {
        display: flex;
        flex-direction: column;
        gap: 6px;
        position: relative;
        isolation: isolate;
    }

    /* What says "these belong together": one tinted block behind the whole
       group, the tint the subtab list used to carry on its own. It fades in
       and out with the subtabs rather than snapping, and follows the group's
       height as the list grows and collapses. */

    .panel-tabs.nav-rail .rail-group.has-views::before {
        content: "";
        position: absolute;
        inset: -4px;
        z-index: -1;
        border-radius: 12px;
        background: color-mix(in srgb, var(--accent-color) 8%, transparent);
        opacity: 0;
        pointer-events: none;
        transition: opacity 200ms ease;
    }

    .panel-tabs.nav-rail .rail-group.has-views.is-open::before,
    .panel-tabs.nav-rail .rail-group.has-views.is-docked::before {
        opacity: 1;
    }

    /* Which pane holds the group's open view: a bar down the block's edge,
       capped across the top. Right edge = main pane, left edge = side pane. */

    .rail-line {
        position: absolute;
        /* Runs the height of the block behind the group. */
        top: -4px;
        bottom: -4px;
        width: 2px;
        pointer-events: none;
        /* Gone by 24 px from the bottom, whatever the group's height: a bar
           that ran into the block's rounded corner read as a cut-off line. */
        background: linear-gradient(
            180deg,
            var(--accent-color) 0%,
            color-mix(in srgb, var(--accent-color) 55%, transparent) 50%,
            transparent calc(100% - 24px)
        );
    }

    /* The cap: it reaches well past the block's edge toward the middle of the
       rail and fades out as it gets there, so the group reads as capped
       rather than merely edged. */

    .rail-line::before {
        content: "";
        position: absolute;
        top: 0;
        width: 38px;
        height: 2px;
        border-radius: 2px;
    }

    .rail-line--main {
        right: -4px;
        border-top-right-radius: 2px;
    }

    .rail-line--main::before {
        right: 0;
        background: linear-gradient(
            270deg,
            var(--accent-color) 0%,
            color-mix(in srgb, var(--accent-color) 45%, transparent) 45%,
            transparent 100%
        );
    }

    .rail-line--side {
        left: -4px;
        border-top-left-radius: 2px;
    }

    .rail-line--side::before {
        left: 0;
        background: linear-gradient(
            90deg,
            var(--accent-color) 0%,
            color-mix(in srgb, var(--accent-color) 45%, transparent) 45%,
            transparent 100%
        );
    }

    .panel-tabs.nav-rail .panel-tab {
        flex: 0 0 auto;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        padding: 9px 4px;
        font-size: 10.5px;
        line-height: 1.1;
        border-radius: 10px;
    }

    .panel-tabs.nav-rail .tab-icon {
        margin: 0;
        width: 18px;
        height: 18px;
    }

    /* The rail tints the count with the group's own colour when its tab is
       the open one; everywhere else the count is styled with the tab bar
       (tabs.css). */

    .panel-tabs.nav-rail .panel-tab.active .deck-count-icon,
    .panel-tabs.nav-rail .panel-tab.docked .deck-count-icon {
        color: inherit;
    }

    /* The open group's tab wears the same surface as the views under it, so
       the block reads as one panel rather than a tab with a list stuck
       beneath it. (An open group's tab carries no `active` class: the open
       view is what is highlighted, see `primary_class`.) */

    .panel-tabs.nav-rail .rail-group.has-views.is-open > .panel-tab,
    .panel-tabs.nav-rail .rail-group.has-views.is-docked > .panel-tab {
        background: color-mix(in srgb, var(--accent-color) 8%, transparent);
        color: var(--text-color);
    }

    /* A panel's views, grouped under its tab. A panel that has never
       published any has nothing to show or animate. */

    .panel-tabs.nav-rail .rail-group:not(.has-views) .nav-rail-subtabs {
        display: none;
    }

    /* The list opens and closes by growing its row from nothing, which needs
       no height to be known in advance. The tint lives on the group's block
       now, so the list itself is only a clipping frame. */

    .nav-rail-subtabs {
        display: grid;
        grid-template-rows: 1fr;
        margin: 0;
        opacity: 1;
        visibility: visible;
        transition:
            grid-template-rows 220ms cubic-bezier(0.2, 0.7, 0.3, 1),
            margin-top 220ms cubic-bezier(0.2, 0.7, 0.3, 1),
            opacity 150ms ease,
            visibility 220ms;
    }

    .nav-rail-subtabs-inner {
        position: relative;
        display: flex;
        flex-direction: column;
        gap: 2px;
        min-height: 0;
        padding: 5px 1px 2px;
        overflow: hidden;
        transition: padding-block 220ms cubic-bezier(0.2, 0.7, 0.3, 1);
    }

    /* The hairline between the tab and its views. Drawn inside the clipped
       box, so it folds away with the list rather than outliving it. */

    .nav-rail-subtabs-inner::before {
        content: "";
        position: absolute;
        top: 0;
        left: 7px;
        right: 7px;
        height: 1px;
        background: color-mix(in srgb, var(--accent-color) 28%, transparent);
    }

    /* Closed: the row collapses to nothing and the group's own gap is taken
       back, so a closed group is exactly as tall as its tab. */

    .nav-rail-subtabs.empty {
        grid-template-rows: 0fr;
        margin-top: -6px;
        opacity: 0;
        visibility: hidden;
    }

    .nav-rail-subtabs.empty .nav-rail-subtabs-inner {
        padding-block: 0;
    }

    .nav-rail-subtab {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 6px 2px;
        border: none;
        border-radius: 6px;
        background: transparent;
        color: var(--text-muted);
        font-size: 9.5px;
        line-height: 1.1;
        cursor: pointer;
        transition: background 0.15s ease, color 0.15s ease;
    }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab {
        animation: rail-subtab-drop 200ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
    }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab:nth-child(2) { animation-delay: 26ms; }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab:nth-child(3) { animation-delay: 52ms; }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab:nth-child(4) { animation-delay: 78ms; }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab:nth-child(5) { animation-delay: 104ms; }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab:nth-child(6) { animation-delay: 130ms; }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab:nth-child(7) { animation-delay: 156ms; }

    .nav-rail-subtabs:not(.empty) .nav-rail-subtab:nth-child(n + 8) { animation-delay: 182ms; }

    /* Closed: tucked back up under the tab, all together, while the list's
       row collapses under them. */

    .nav-rail-subtabs.empty .nav-rail-subtab {
        transform: translateY(-10px);
        opacity: 0;
    }

    .nav-rail-subtab:hover {
        color: var(--text-color);
        background: color-mix(in srgb, var(--accent-color) 12%, transparent);
    }

    @media (prefers-reduced-motion: reduce) {
        .panel-tabs.nav-rail .rail-group.has-views::before,
        .nav-rail-subtabs,
        .nav-rail-subtabs-inner,
        .nav-rail-subtab {
            transition: none;
        }

        .nav-rail-subtabs:not(.empty) .nav-rail-subtab {
            animation: none;
        }
    }

    /* An open view, in either pane, reads like an open primary tab. */

    .nav-rail-subtab.active,
    .nav-rail-subtab.docked {
        color: var(--button-primary-text, white);
        background: var(--accent-gradient);
        font-weight: 600;
    }

    .nav-rail-subtab.btn-unavailable {
        opacity: 0.45;
        cursor: not-allowed;
    }

    /* The rail's tabs open and close the side pane, so the divider is a slim
       drag handle with a tight gap either side. */

    .main-layout {
        gap: 8px;
    }

    /* ── Shell: side pane (docs/layout/side-pane-plan.md) ─────────────── */

    .side-pane-header {
        display: flex;
        align-items: center;
        gap: 8px;
        flex: 0 0 auto;
        padding: 6px 6px 6px 10px;
        border-bottom: 1px solid var(--glass-border);
        color: var(--text-muted);
        font-size: 10.5px;
        font-weight: 600;
        letter-spacing: 0.06em;
        text-transform: uppercase;
    }

    .side-pane-title {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .side-pane-close {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 4px;
        border: none;
        border-radius: 6px;
        background: transparent;
        color: var(--text-muted);
        cursor: pointer;
    }

    .side-pane-close:hover {
        color: var(--text-color);
        background: var(--entry-hover-bg);
    }

    /* A rail button dragged over the pane. While any rail drag is in progress
       a collapsed pane opens a strip to drop on. */

    .side-pane {
        position: relative;
    }

    .side-pane-slot {
        display: flex;
        flex-direction: column;
        flex: 1;
        min-height: 0;
    }

    .side-pane-slot > .search-panel,
    .side-pane-slot > .tab-panel {
        flex: 1;
        min-height: 0;
        height: auto;
    }

    .side-pane-slot > .search-panel.collapsed {
        display: none;
    }

    /* The handle between a split pane's slots, dragged like the divider
       between the panes. */

    .side-pane-split-handle {
        flex: 0 0 8px;
        margin: -1px 0;
        cursor: row-resize;
        border-top: 1px solid var(--divider-border);
        border-bottom: 1px solid var(--divider-border);
        background: transparent;
        transition: background 0.2s ease;
    }

    .side-pane-split-handle:hover,
    .side-pane.splitting .side-pane-split-handle {
        border-color: var(--accent-color);
        background: color-mix(in srgb, var(--accent-color) 18%, transparent);
    }

    .side-pane.splitting {
        cursor: row-resize;
        user-select: none;
    }

    /* A rail button dragged over the pane: the third it is over says where
       it lands (top half, whole pane, bottom half). */

    .side-pane.drop-top::after,
    .side-pane.drop-middle::after,
    .side-pane.drop-bottom::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        pointer-events: none;
        outline: 2px dashed var(--accent-color);
        outline-offset: -2px;
        background: color-mix(in srgb, var(--accent-color) 12%, transparent);
        z-index: 5;
    }

    .side-pane.drop-top::after {
        top: 0;
        bottom: 50%;
    }

    .side-pane.drop-middle::after {
        top: 0;
        bottom: 0;
    }

    .side-pane.drop-bottom::after {
        top: 50%;
        bottom: 0;
    }

    .side-pane.collapsed.drop-middle::after {
        top: 0;
        bottom: 0;
    }

    .main-layout.rail-drag .side-pane.collapsed {
        width: 48px !important;
        outline: 2px dashed var(--accent-color);
        outline-offset: -2px;
    }

    .main-layout.rail-drag:has(.side-pane.collapsed) {
        grid-template-columns: 48px 0 1fr;
    }

    /* ── Rail: dock affordance and docked state ───────────────────────── */

    .nav-rail-subtab {
        position: relative;
    }

    /* The dock target: a soft gradient on the side-pane edge of the button,
       fading out so the label and icon stay readable beneath it. */

    .rail-dock {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 24px;
        display: flex;
        align-items: center;
        justify-content: flex-start;
        padding-left: 3px;
        border-radius: 10px 0 0 10px;
        background: linear-gradient(
            90deg,
            color-mix(in srgb, var(--accent-color) 60%, transparent) 0%,
            color-mix(in srgb, var(--accent-color) 25%, transparent) 55%,
            transparent 100%
        );
        color: var(--text-color);
        opacity: 0;
        cursor: pointer;
        transition: opacity 0.15s ease;
    }

    .nav-rail-subtab .rail-dock {
        width: 20px;
        border-radius: 6px 0 0 6px;
    }

    /* Revealed only while the pointer is over the target itself, so a plain
       hover on the button shows nothing. */

    .rail-dock:hover {
        opacity: 1;
        background: linear-gradient(
            90deg,
            var(--accent-color) 0%,
            color-mix(in srgb, var(--accent-color) 45%, transparent) 55%,
            transparent 100%
        );
        color: #fff;
    }

    /* A view its panel refuses right now cannot be docked either. */

    .nav-rail-subtab.btn-unavailable .rail-dock {
        display: none;
    }

    /* Which pane holds the open content: a bar on the edge facing it. The
       side pane is to the left of the rail, the main pane to the right. */

    .panel-tabs.nav-rail .panel-tab.active,
    .nav-rail-subtab.active {
        box-shadow: inset -3px 0 0 var(--button-primary-text, #fff), 0 4px 15px var(--accent-glow);
    }

    .panel-tabs.nav-rail .panel-tab.docked,
    .nav-rail-subtab.docked {
        color: var(--button-primary-text, white);
        background: var(--accent-gradient);
        font-weight: bold;
        box-shadow: inset 3px 0 0 var(--button-primary-text, #fff), 0 4px 15px var(--accent-glow);
    }

    .panel-tabs.nav-rail .panel-tab.active.docked,
    .nav-rail-subtab.active.docked {
        box-shadow: inset 3px 0 0 var(--button-primary-text, #fff),
            inset -3px 0 0 var(--button-primary-text, #fff),
            0 4px 15px var(--accent-glow);
    }
}

/* ── The bar on a phone ───────────────────────────────────────────────────
   A phone has no width to give up, so the bar does not fold its controls into
   a menu the way a narrow desktop pane does (see the pressure levels above).
   It stays one row, spans the screen, pins to the top of the content, and
   scrolls sideways. Everything the view can do stays reachable. */
@media (max-width: 768px) {
    .command-bar {
        /* Full bleed: the panels around it are padded, and a control row that
           stopped short of the screen edges would read as a card rather than
           as the chrome it is. `50% - 50vw` is the distance from this box's
           edge to the viewport's, whatever the ancestors' padding adds up to,
           so the rule does not have to know any of them. */
        margin: 0 calc(50% - 50vw) 8px;
        padding: 4px 10px;
        gap: 8px;
        position: sticky;
        top: 0;
        border-radius: 0;
        border-left: none;
        border-right: none;
        overflow-x: auto;
        /* The row is one line; nothing needs to overflow it vertically, and
           allowing it to would show a second scrollbar. Popovers are taken
           out of the flow instead, below. */
        overflow-y: hidden;
        scrollbar-width: none;
        /* No `-webkit-overflow-scrolling: touch` here, deliberately. On iOS it
           makes this element a containing block for `position: fixed`
           descendants, which put every popover back inside the bar to be
           clipped by the `overflow-y` above — the menus opened and were
           invisible. iOS has had momentum scrolling on ordinary overflow
           containers since 13, so the property buys nothing and costs that. */
    }

    .command-bar::-webkit-scrollbar {
        display: none;
    }

    /* A slot is as wide as its contents; the row is what scrolls. */
    .command-bar > * {
        flex: 0 0 auto;
    }

    /* One height for everything in the row, so the bar is as short as it can
       be and reads as a single line rather than a row of different pills. */
    .command-bar .command-chip,
    .command-bar .command-control,
    .command-bar .command-action,
    .command-bar .command-bar-actions > button,
    .command-bar .command-search input,
    .command-bar select {
        height: 32px;
        min-height: 32px;
        padding-top: 0;
        padding-bottom: 0;
    }

    /* The identity may not eat the row: the rest of the controls are what the
       reader came for, and the deck's name is editable in place anyway. */
    .command-identity .deck-title,
    .command-identity .deck-name-field {
        max-width: 40vw;
    }

    /* The affordance: while there is more row in a direction, that edge of
       the screen carries the accent colour with an arrow on it, solid where it
       meets the edge and fading to nothing a little way in. Drawn on a sticky
       pseudo-element rather than in the bar's own background, because the
       background sits *behind* the chips and a chip at the edge would cover
       it. The pair of `--more` classes comes from the bar itself, which
       watches its scroll position (see `command_bar/mod.rs`), so an edge that
       has nothing beyond it shows nothing. */
    .command-bar::before,
    .command-bar::after {
        position: sticky;
        align-self: stretch;
        flex: 0 0 auto;
        box-sizing: border-box;
        /* 34px of fade over the row, plus the 10px of the bar's own padding
           it is shifted out across. */
        width: 44px;
        /* `align-self: stretch` fills the row's content box, which stops short
           of the bar's own padding. The fade has to cover that too, or a sliver
           of the control underneath shows above and below it. */
        margin-top: -4px;
        margin-bottom: -4px;
        display: flex;
        align-items: center;
        /* The arrow rides right out at the screen edge, where the accent is
           at full strength and it has a solid ground to read against, rather
           than further in where the fade has already started. */
        color: var(--button-primary-text, #fff);
        font-size: 13px;
        line-height: 1;
        pointer-events: none;
        opacity: 0;
        transition: opacity 160ms ease;
        z-index: 1;
    }

    /* Each pins to its edge of the scroll port, points the way the rest of
       the row went, and paints inward. Its negative margins mean it takes no
       room from the row it sits over and reaches past the bar's padding to the
       edge of the screen.

       Two background layers: the accent on top, solid against the screen edge
       and gone by the far side of the strip, and the bar's own colour under
       it, so the control the fade crosses dims rather than being cut off
       mid-glyph. */
    .command-bar::before {
        content: "◂";
        left: 0;
        /* Takes no room from the row: it is as wide as it is, then pulls what
           follows back over itself. */
        margin-right: -44px;
        /* Sticky clamps a box inside the scroll port, which stops at the bar's
           padding — so the last few pixels before the screen edge would show
           the control underneath. A transform moves what is painted without
           moving what is laid out, and overflow clips at the padding edge, so
           this reaches the screen. */
        transform: translateX(-10px);
        justify-content: flex-start;
        padding-left: 7px;
        background:
            linear-gradient(to right,
                rgb(var(--accent-rgb, 88, 166, 255)) 0,
                rgb(var(--accent-rgb, 88, 166, 255)) 38%,
                rgba(var(--accent-rgb, 88, 166, 255), 0) 100%),
            linear-gradient(to right, var(--widget-bg, var(--panel-bg)) 40%, transparent);
    }

    .command-bar::after {
        content: "▸";
        right: 0;
        margin-left: -44px;
        transform: translateX(10px);
        justify-content: flex-end;
        padding-right: 7px;
        background:
            linear-gradient(to left,
                rgb(var(--accent-rgb, 88, 166, 255)) 0,
                rgb(var(--accent-rgb, 88, 166, 255)) 38%,
                rgba(var(--accent-rgb, 88, 166, 255), 0) 100%),
            linear-gradient(to left, var(--widget-bg, var(--panel-bg)) 40%, transparent);
    }

    .command-bar.more-before::before,
    .command-bar.more-after::after {
        opacity: 1;
    }

    @media (prefers-reduced-motion: reduce) {
        .command-bar::before,
        .command-bar::after {
            transition: none;
        }
    }

    /* A popover belongs to the screen, not to the scrolling row. On a phone it
       is not even a descendant of the bar: it is mounted on the document body
       (see `command_bar/menu.rs`), because iOS clips a `position: fixed` box to
       its nearest scrolling ancestor and the bar is one. So these are written
       against the popover itself rather than through the bar — on a phone,
       every `.command-popover` came from a command bar anyway. The bar hands
       each one a `left`/`top` inline; these are the parts that never vary. */
    /* A flex item's automatic minimum is its content's width, and a min/max
       number pair does not report a small one, so a range row would hold its
       menu open wider than the screen however the menu itself is capped. */
    .command-popover :is(.deck-filter-range, .range-inputs, .filter-group) {
        min-width: 0;
    }

    .command-popover {
        position: fixed;
        z-index: 1200;
        /* The wider popovers carry a `min-width` in the hundreds of pixels,
           and a minimum outranks a maximum, so the cap has to clear it or a
           560px menu would still be 560px on a 412px screen. Width then comes
           from the content, up to what the screen allows. */
        min-width: 0;
        max-width: calc(100vw - 16px);
    }
}
