@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url('../fonts/dmsans-v17-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url('../fonts/dmsans-v17-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Design Tokens --- */
:root {
    /* Surfaces */
    --bg-window: #ececec;
    --bg-panel: #f6f6f6;
    --bg-card: #ffffff;
    --bg-sidebar: #e4e4e7;
    --bg-inset: #e9e9ec;
    --bg-input: #ffffff;
    --bg-row: #f0f0f3;
    --bg-row-hover: #ededf1;
    /* Deployed chip surface. Off the white of the panel behind it, so a card
       reads as a thing sitting on the list rather than a hole in it. */
    --bg-chip-deployed: #f7f7f9;
    --bg-chip-deployed-hover: #f2f2f5;
    /* Open, the chip is two surfaces: a head that still answers a click, on a
       fill darker again than the shut card's — that step down is what says the
       head is still the control — and the spec sheet under it, which stays
       white and is not a control at all. */
    --bg-chip-head: #e8e8ed;
    --bg-chip-head-hover: #e1e1e8;
    --bg-row-selected: #e6e8f0;
    --bg-row-selected-border: rgba(0, 0, 0, 0.11);

    /* Borders */
    --border-hairline: rgba(0, 0, 0, 0.07);
    --border-subtle: rgba(0, 0, 0, 0.1);
    --border-input: rgba(0, 0, 0, 0.14);
    --border-focus: rgba(229, 50, 44, 0.22);

    /* Text */
    --text-primary: #1d1d1f;
    --text-secondary: #6e6e73;
    --text-tertiary: #a1a1a6;
    --text-quaternary: #c7c7cc;

    /* Accent — brand red, softened from neon so it reads refined rather than
       aggressive. Reserved for primary actions (Deploy) and small accents
       (thin rings, active text); not used as a surface fill. */
    --accent: #e5322c;
    --accent-hover: #c62a25;
    --accent-subtle-grey: #f0b4b1;
    --accent-subtle-grey-hover: #e39b97;
    --accent-subtle: rgba(229, 50, 44, 0.09);
    --accent-very-subtle: rgba(229, 50, 44, 0.05);
    --accent-muted: rgba(229, 50, 44, 0.14);

    /* Semantic */
    --red: #e5484d;
    --red-subtle: rgba(229, 72, 77, 0.1);
    --green: #46a758;
    --green-subtle: rgba(70, 167, 88, 0.12);
    --orange: #e5a000;
    --orange-subtle: rgba(229, 160, 0, 0.12);
    --blue-subtle: rgba(74, 111, 165, 0.1);

    /* Elevation */
    --shadow-card: 0 0 0 1px var(--border-hairline), 0 1px 2px rgba(0,0,0,0.04);
    --shadow-card-hover: 0 0 0 1px var(--border-subtle), 0 2px 6px rgba(0,0,0,0.06);
    --shadow-panel: 0 0 0 1px var(--border-hairline);
    --shadow-overlay: 0 16px 48px rgba(0,0,0,0.14), 0 4px 12px rgba(0,0,0,0.08);

    /* Shape */
    --radius-xs: 4px;
    --radius-sm: 6px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 16px;

    /* Type */
    --font-body: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    --font-mono: 'SF Mono', 'Menlo', 'Monaco', 'Consolas', monospace;

    /* Motion */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --duration-fast: 0.12s;
    --duration-med: 0.2s;
}

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { overflow: hidden; }

/* Number fields are typed into, not stepped through — every one of them here
   holds a port, a size or a count that is entered whole. The stepper arrows
   only eat the width the value needs, so they are dropped everywhere. */
input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

body {
    background: var(--bg-window);
    font-family: var(--font-body);
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-primary);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    min-height: 100vh;
}

/* --- App Shell --- */
.body-layout {
    height: 100vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.app-shell {
    flex: 1;
    display: flex;
    overflow: hidden;
}

/* --- Vertical Nav Rail --- */
.nav-rail {
    width: 56px;
    flex-shrink: 0;
    background: #2c2c2e;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 12px 0;
    border-right: 1px solid rgba(255,255,255,0.06);
}

.nav-rail-top {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

.nav-rail-logo {
    border-radius: var(--radius-sm);
    margin-bottom: 16px;
}

.nav-rail-bottom {
    margin-top: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

.nav-rail-user {
    font-size: 9px;
    font-weight: 600;
    color: rgba(255,255,255,0.45);
    text-align: center;
    max-width: 48px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-bottom: 8px;
}

.nav-rail-btn {
    position: relative;
    width: 40px;
    height: 40px;
    border: none;
    background: transparent;
    color: rgba(255,255,255,0.45);
    border-radius: var(--radius-md);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.nav-rail-btn:hover {
    background: rgba(255,255,255,0.08);
    color: rgba(255,255,255,0.8);
}

.nav-rail-btn-active {
    background: rgba(255,255,255,0.12);
    color: #ffffff;
}

/* Red warning sign overlaid on a nav icon (machines not connected). */
.nav-rail-alert {
    position: absolute;
    top: -3px;
    right: -3px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #ff1a1a;
    color: #ffffff;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    pointer-events: none;
}

.nav-rail-btn-danger:hover {
    background: rgba(229,72,77,0.2);
    color: var(--red);
}

/* --- Main Area (views + log panel) --- */
.main-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* --- View Container --- */
.view-container {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
}

.view-panel {
    display: none;
    flex: 1;
    min-height: 0;
    flex-direction: column;
    overflow: hidden;
    background: var(--bg-panel);
}

.view-panel-active {
    display: flex;
}

/* --- View Header --- */
.view-header {
    flex-shrink: 0;
    height: 56px;
    padding: 0 24px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: var(--bg-sidebar);
    border-bottom: 1px solid var(--border-hairline);
}

.view-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.view-header-right {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* --- Deployment Layout --- */
.deployment-layout {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 20px 24px;
}


/* --- Legacy compat (old classes still referenced) --- */
.main-content {
    flex: 1;
    display: flex;
    overflow: hidden;
}

.center-panel {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 20px 24px;
    overflow: hidden;
    background: var(--bg-panel);
}

.section-title {
    font-size: 18px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.4px;
    margin-bottom: 14px;
    margin-left:auto;
    margin-right:auto;
}

.section-subtitle {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

/* (machines-grid styles moved below with machines-view-body) */

.machines-grid > .empty-state {
    grid-column: 1 / -1;
}

.machines-grid:has(> .empty-state) {
    display: flex;
    min-height: 100%;
    align-items: center;
    justify-content: center;
}

.machine-full-card {
    background: var(--bg-card);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: box-shadow var(--duration-fast);
}

.machine-full-card:hover {
    box-shadow: var(--shadow-card-hover);
}

.machine-full-card-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border-hairline);
    background: var(--bg-row);
}

.machine-full-card-status {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.machine-full-card-status-connected { background: var(--green); }
.machine-full-card-status-connecting { background: var(--orange); animation: pulse 2s ease infinite; }
.machine-full-card-status-failed { background: var(--red); }
.machine-full-card-status-unknown { background: var(--text-quaternary); }

.machine-full-card-addr {
    flex: 1;
    min-width: 0;
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.machine-full-card-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}

.machine-full-card-actions button {
    width: 28px;
    height: 28px;
    border: none;
    background: none;
    color: var(--text-tertiary);
    border-radius: var(--radius-xs);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.machine-full-card-actions .machine-cfg-btn:hover {
    background: var(--accent-subtle);
    color: var(--accent);
}

.machine-full-card-actions .machine-remove-btn:hover {
    background: var(--red-subtle);
    color: var(--red);
}

/* Fills what the card has left under the header, so that what is pinned to the
   bottom of the body is pinned to the bottom of the card. Cards in a grid row
   are already the same height as each other. */
.machine-full-card-body {
    flex: 1;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* GPU info inside full machine cards */
.machine-full-gpus {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.machine-full-gpu {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.machine-full-gpu .gpu-name-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.machine-full-gpu .gpu-name {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.machine-full-gpu .gpu-vram-label {
    font-size: 11px;
    font-family: var(--font-mono);
    color: var(--text-tertiary);
    white-space: nowrap;
    flex-shrink: 0;
}

.machine-full-gpu .gpu-vram-track {
    height: 6px;
    background: rgba(0,0,0,0.08);
    border-radius: 3px;
    overflow: hidden;
}

/* The last line of the card, and always the last line: one machine has three
   GPUs and the next has one, and the endpoint should still be found in the same
   place along the row. `margin-top: auto` takes whatever height the GPUs left
   over, so the line sits on the bottom of the card rather than under the last
   bar. */
.machine-endpoint-info {
    margin-top: auto;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--text-secondary, #888);
    padding: 4px 0;
    min-width: 0;
}

.machine-endpoint-label {
    flex-shrink: 0;
}

/* The bearer token's field, to the letter: the endpoint is the same kind of
   thing — a value that is there to be selected and taken away, never typed into
   — so it reads the same way, and the two do not want to be two designs. See
   `.model-chip-deployed .auth-token`. */
.machine-endpoint-value {
    /* The width comes from the endpoint's own length, in `ch`, set inline where
       it is rendered. */
    flex: 0 0 auto;
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
    height: 22px;
    margin: 0;
    padding: 2px 7px;
    cursor: text;
    user-select: text;
    -webkit-user-select: text;
    text-overflow: ellipsis;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-secondary, #555);
    background-color: var(--bg-input);
    border: 1px solid var(--border-input);
    border-radius: var(--radius-sm);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
    outline: none;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
}

.machine-endpoint-value:hover {
    border-color: var(--text-tertiary);
}

/* Focus says "this is yours to select from", not "type here" — no accent ring,
   which on every other field on the page promises an edit this one refuses. */
.machine-endpoint-value:focus {
    border-color: var(--text-tertiary);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
}

/* Beside the endpoint and the same height as it, so the pair reads as one row.
   Quieter than the field it sits next to: the endpoint is what the card is
   telling you, this is somewhere else to go. */
.machine-logs-btn {
    flex-shrink: 0;
    height: 22px;
    margin: 0;
    padding: 0 9px;
    font-size: 12px;
    font-family: inherit;
    color: var(--text-secondary, #555);
    background: var(--bg-inset);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    cursor: pointer;
    white-space: nowrap;
    transition: color var(--duration-fast), background var(--duration-fast),
                border-color var(--duration-fast);
}

.machine-logs-btn:hover {
    color: var(--text-primary);
    background: var(--bg-row-hover);
    border-color: var(--text-tertiary);
}

/* Machine config preview */
.machine-config-preview {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px 16px;
    padding: 10px 12px;
    background: var(--bg-inset);
    border-radius: var(--radius-sm);
}

.machine-config-item {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.machine-config-item-label {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.machine-config-item-value {
    font-size: 12px;
    font-family: var(--font-mono);
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.machine-no-gpu-full {
    font-size: 12px;
    color: var(--text-tertiary);
    font-style: italic;
}

.machine-status-connecting-full {
    font-size: 12px;
    color: var(--text-tertiary);
    font-style: italic;
}

.machine-status-failed-full {
    font-size: 12px;
    color: var(--red);
    font-style: italic;
}

.machine-status-failed-detail {
    margin-top: 4px;
    font-size: 11px;
    font-style: normal;
    color: var(--text-muted, #888);
    word-break: break-word;
}

/* --- Machines View --- */
.machines-grid-wrap {
    flex: 1;
    overflow-y: auto;
    min-height: 0;
}

.machines-grid {
    padding: 20px 24px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
    gap: 16px;
    align-content: start;
}

/* --- Machines List Mode --- */
.machines-grid.machines-list-mode {
    grid-template-columns: 1fr;
    gap: 0;
}

.machines-list-mode .machine-full-card {
    border-radius: 0;
    box-shadow: none;
    border-left: none;
    border-right: none;
    border-bottom: none;
}

.machines-list-mode .machine-full-card:last-child {
    border-bottom: 1px solid var(--border-hairline);
}

.machines-list-mode .machine-full-card:hover {
    box-shadow: none;
    background: var(--bg-row-hover);
}

/* Row 1: address + actions on the same line */
.machines-list-mode .machine-full-card-header {
    padding: 8px 16px;
    border-bottom: none;
    background: none;
}

/* Row 2: GPUs + config flow horizontally, wrapping as needed */
.machines-list-mode .machine-full-card-body {
    padding: 0 16px 8px;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 24px;
}

.machines-list-mode .machine-full-gpus {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 8px 16px;
    flex: 1;
    min-width: 150px;
}

.machines-list-mode .machine-full-gpu {
    flex: 1;
    min-width: 140px;
    max-width: 300px;
}

/* In a row the endpoint sits beside the GPU bars rather than under them, so
   there is no bottom to push it to. */
.machines-list-mode .machine-endpoint-info {
    margin-top: 0;
    flex-shrink: 0;
}

.machines-list-mode .machine-config-preview {
    grid-template-columns: repeat(4, auto);
    gap: 2px 14px;
    padding: 4px 8px;
    flex-shrink: 0;
}


/* View toggle buttons */
.view-toggle {
    display: flex;
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.view-toggle-btn {
    width: 32px;
    height: 32px;
    border: none;
    background: none;
    color: var(--text-tertiary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.view-toggle-btn:not(:last-child) {
    border-right: 1px solid var(--border-hairline);
}

.view-toggle-btn:hover {
    background: var(--bg-row-hover);
    color: var(--text-secondary);
}

.view-toggle-btn-active {
    background: var(--bg-card);
    color: var(--accent);
    box-shadow: var(--shadow-card);
}

.view-toggle-btn-active:hover {
    background: var(--bg-card);
    color: var(--accent);
}

/* --- Machines Stats Bar --- */
.machines-stats-bar {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 24px;
    padding: 12px 24px;
    background: var(--bg-card);
    border-bottom: 1px solid var(--border-hairline);
    min-height: 0;
}

.machines-stats-bar:empty {
    display: none;
}

.stats-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}

.stats-item-wide {
    flex: 0 0 120px;
}

.stats-item-alert .stats-value {
    color: var(--red);
}

.stats-value {
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.stats-value-sub {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-tertiary);
}

.stats-label {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.stats-vram-track {
    width: 100%;
    height: 6px;
    background: rgba(0,0,0,0.08);
    border-radius: 3px;
    overflow: hidden;
}

.stats-vram-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.4s var(--ease-out);
}

/* Dialog wide variant */
/* Both class names, so the modifier outranks the .dialog-card width that comes
   later in this file. */
.dialog-card.dialog-card-wide {
    width: 420px;
}

.dialog-subtitle {
    font-size: 13px;
    font-family: var(--font-mono);
    color: var(--text-secondary);
    margin: -8px 0 16px;
}

/* --- Dual List --- */
.dual-list-container {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: 12px;
    overflow: hidden;
}

/* --- List Panel (Available / Deployed) --- */
.list-panel {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg-card);
    border-radius: var(--radius-lg);
    border: 1px solid #eaeaea;
    overflow: hidden;
    padding: 0;
}

.list-panel-top {
    flex-shrink: 0;
    padding: 14px 16px 0;
}

.list-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px 0;
    flex-shrink: 0;
}

.list-panel-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

/* Search */
.search-wrap {
    position: relative;
    display: block;
    margin: 10px 8px 2px;
}

.search-wrap .search-input {
    width: 100%;
    margin: 0;
    padding-right: 30px;
}

.search-clear {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-tertiary);
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast);
}

.search-clear:hover {
    color: var(--text-primary);
    background: var(--bg-row-hover);
}

.search-input {
    display: block;
    width: calc(100% - 16px);
    margin: 10px 8px 2px;
    padding: 8px 12px;
    font-size: 12px;
    background: var(--bg-input);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    outline: none;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast), background var(--duration-fast);
    font-family: var(--font-body);
}

.search-input:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.12);
    background: var(--bg-input);
}

.search-input::placeholder {
    color: var(--text-tertiary);
}

/* Scrollable model list */
.list-scroll {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* --- Model Row Items --- */
.list-scroll > div,
.list-scroll > label,
.list-scroll > a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    border-radius: var(--radius-md);
    font-size: 13px;
    font-weight: 450;
    color: var(--text-primary);
    cursor: pointer;
    user-select: none;
    min-height: 40px;
    border: 1px solid var(--border-hairline);
    transition: background var(--duration-fast), border-color var(--duration-fast), box-shadow var(--duration-fast);
}

/* Prevent empty-state from looking like a row */
.list-scroll > .empty-state {
    border: none;
    cursor: default;
    min-height: unset;
    padding: 36px 16px;
}


/* A deployed card is not a selectable row — clicking it opens its details, so
   it keeps its hover shade all the way through the press instead of flashing
   the selected-row colour. */
.list-scroll > div.selected,
.list-scroll > div:active:not(.model-chip-deployed) {
    background: var(--bg-row-selected);
    border-color: var(--bg-row-selected-border);
}

/* Keep × / remove button on the same line, never wrap */
.list-scroll > div {
    flex-wrap: nowrap;
}

.list-scroll > div > button,
.list-scroll > label > button {
    flex-shrink: 0;
    margin-left: auto;
    background: none;
    color: var(--text-quaternary);
    border: none;
    border-radius: var(--radius-xs);
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast);
}

.list-scroll > div > button:hover,
.list-scroll > label > button:hover {
    background: var(--red-subtle);
    color: var(--red);
}

/* Bigger checkboxes inside list rows */
.list-scroll input[type="checkbox"] {
    width: 18px;
    height: 18px;
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--accent);
    cursor: pointer;
    border-radius: 4px;
}

/* Model name text — take remaining space, don't push × to next line */
.list-scroll > div > span,
.list-scroll > div > label,
.list-scroll > label > span {
    /*flex: 1;*/
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Deploy Controls (arrow + settings) --- */
.deploy-controls {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    padding: 0 2px;
    gap: 10px;
}

.deploy-settings {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.deploy-setting-field {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}

.deploy-setting-label {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.deploy-setting-input {
    width: 80px;
    padding: 4px 6px;
    font-size: 12px;
    font-family: var(--font-mono);
    text-align: center;
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-xs);
    background: var(--bg-input);
    color: var(--text-primary);
    outline: none;
    transition: border-color var(--duration-fast);
}

.deploy-setting-input:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.12);
}

.deploy-btn-wrap {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* Menu that rolls out below the Deploy button when the selected model isn't
   downloaded yet, letting the user pick the quant level to download & deploy. */
.deploy-quant-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 30;
    display: flex;
    flex-direction: column;
    min-width: 116px;
    padding: 4px;
    gap: 2px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
}

.deploy-quant-menu-title {
    padding: 4px 8px 5px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    color: var(--text-tertiary);
}

.deploy-quant-menu .deploy-quant-item {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 7px 10px;
    border: none;
    background: none;
    border-radius: var(--radius-xs);
    color: var(--text-secondary);
    font-size: 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: left;
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.deploy-quant-menu .deploy-quant-item:hover {
    background: var(--accent);
    color: #fff;
}

.deploy-arrow-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 14px 14px;
    /* Deploy keeps the pure neon red (#ff0000) rather than the softened brand
       accent, so the primary CTA stays punchy. */
    background: #ff0000;
    border: 1px solid #ff0000;
    border-radius: var(--radius-md);
    color: #fff;
    cursor: pointer;
    transition: all var(--duration-med) var(--ease-out);
    font-family: var(--font-body);
    box-shadow: var(--shadow-card);
}

.deploy-arrow-btn:hover {
    background: #dd0000;
    border-color: #dd0000;
    box-shadow: var(--shadow-card-hover);
}

.deploy-arrow-btn .arrow-icon {
    font-size: 20px;
    line-height: 1;
}

.deploy-arrow-btn .arrow-label {
    font-size: 12px;
    font-weight: 1000;
    text-transform: uppercase;
    letter-spacing: 0.6px;
}

/* --- Empty state --- */
.empty-state {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--text-quaternary);
    font-size: 12px;
    padding: 36px 16px;
    font-weight: 450;
}

.empty-state-machines {
    flex-direction: column;
    gap: 6px;
}

.empty-state-machines .empty-state-title {
    color: var(--text-secondary);
    font-size: 14px;
    font-weight: 600;
}

.empty-state-machines .empty-state-hint {
    color: var(--text-tertiary);
    font-size: 12px;
}

/* --- Deployment Options --- */
.options-card {
    flex-shrink: 0;
    margin: 0;
    padding: 18px 16px;
    background: var(--bg-card);
    border-radius: 0;
    border-top: 1px solid var(--border-hairline);
    box-shadow: none;
    /* Push to bottom */
    margin-top: auto;
}

.options-toggle {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: none;
    border: none;
    cursor: pointer;
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    padding: 0;
    text-align: left;
}

.options-toggle svg {
    width: 16px;
    height: 16px;
    color: var(--text-tertiary);
    transition: transform var(--duration-med) var(--ease-out);
}

/* Upward-expanding collapsible: content appears above the toggle */
.collapsible-content {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.35s var(--ease-out);
}

.collapsible-content.active {
    max-height: 1000px;
}

/* Flip the arrow when open: points down (closed state = up arrow, open state = rotate to down) */
.collapsible-content.active ~ .options-toggle svg,
.options-card .collapsible-content.active + .options-body-placeholder {
    /* handled via JS rotate-180 */
}

.options-body {
    margin-bottom: 14px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Option row */
.option-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    background: var(--bg-inset);
    border-radius: var(--radius-md);
}

.option-row-label p { margin: 0; }

.option-row-label .label-main {
    font-weight: 600;
    font-size: 13px;
    color: var(--text-primary);
}

.option-row-label .label-sub {
    font-size: 11px;
    color: var(--text-secondary);
    margin-top: 2px;
    display: flex;
    align-items: center;
    gap: 4px;
}

.option-row-label .label-sub input {
    width: 62px;
    padding: 2px 6px;
    font-size: 11px;
    background: var(--bg-input);
    border: 1px solid var(--border-input);
    border-radius: var(--radius-xs);
    font-family: var(--font-mono);
    color: var(--text-primary);
    outline: none;
}

.option-row-label .label-sub input:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 2px rgba(74, 111, 165, 0.1);
}

/* Settings grid */
.settings-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

.settings-grid > div > label {
    display: block;
    font-size: 10px;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    margin-bottom: 4px;
}

.settings-grid input {
    width: 100%;
    min-width: 0;
    padding: 6px 8px;
    font-size: 12px;
    background: var(--bg-inset);
    border: 1px solid transparent;
    border-radius: var(--radius-xs);
    color: var(--text-primary);
    font-family: var(--font-body);
    outline: none;
    box-sizing: border-box;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast), background var(--duration-fast);
}

.settings-grid input:focus {
    background: var(--bg-input);
    border-color: var(--border-focus);
    box-shadow: 0 0 0 2px rgba(74, 111, 165, 0.1);
}

/* Checkboxes row */
.checkbox-row {
    display: flex;
    gap: 20px;
    padding-top: 4px;
    padding-bottom: 2px;
}

.checkbox-label {
    display: inline-flex;
    align-items: center;
    font-size: 12px;
    color: var(--text-secondary);
    cursor: pointer;
    gap: 6px;
    line-height: 1;
}

.checkbox-label input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--accent);
    border-radius: 3px;
    cursor: pointer;
}

/* --- Toggle Switch --- */
.toggle-switch {
    position: relative;
    display: inline-block;
    width: 38px;
    height: 22px;
}

.toggle-switch input { opacity: 0; width: 0; height: 0; }

.toggle-slider {
    position: absolute;
    cursor: pointer;
    inset: 0;
    background-color: #c7c7cc;
    transition: background-color var(--duration-med);
    border-radius: 22px;
}

.toggle-slider::before {
    position: absolute;
    content: "";
    height: 18px;
    width: 18px;
    left: 2px;
    bottom: 2px;
    background-color: #fff;
    transition: transform var(--duration-med) var(--ease-out);
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
}

input:checked + .toggle-slider {
    background-color: var(--green);
}

input:checked + .toggle-slider::before {
    transform: translateX(16px);
}

/* --- Right Sidebar (legacy / deployment sidebar) --- */
.sidebar {
    width: 300px;
    flex-shrink: 0;
    border-left: 1px solid var(--border-hairline);
    background: var(--bg-sidebar);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.sidebar-section {
    padding: 18px 16px;
    border-bottom: 1px solid var(--border-hairline);
    flex-shrink: 0;
}

.sidebar-section-grow {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    border-bottom: none;
}

.sidebar-section-title {
    font-size: 18px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.4px;
    margin-bottom: 12px;
    margin-left:auto;
    margin-right:auto;
}

.btn-add-machine {
    width: 100%;
    margin-bottom: 12px;
    padding: 7px 12px;
    font-size: 12px;
    font-weight: 500;
    color: var(--accent);
    background: transparent;
    border: 1px dashed var(--accent);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.btn-add-machine:hover {
    background: rgba(74, 111, 165, 0.08);
}

.machines-display {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.machines-display .empty-text {
    font-size: 12px;
    color: var(--text-quaternary);
}

/* --- Chips (Model + IP) --- */
.model-chip {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 10px 14px;
    /*background: var(--bg-inset);*/
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-md);
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
    margin: 0;
    min-height: 40px;
    transition: background var(--duration-fast), border-color var(--duration-fast), box-shadow var(--duration-fast);
}

/* Stack the two lines vertically and left-align them. Specificity bumped
   with .list-scroll to override the generic .list-scroll > div row rules
   (which force align-items:center and a single flex row). */
.list-scroll > .model-chip {
    flex-direction: column;
    align-items: stretch;
    flex-wrap: nowrap;
    gap: 8px;
    min-width: 0;
    height: auto;
    min-height: auto;
    flex-shrink: 0;
}

/* First line of an available-model chip: checkbox + model name. */
.model-chip > .model-chip-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    width: 100%;
}

/* Selection checkbox before the model name. Clicks are handled by the whole
   chip, so it's a passive indicator that mirrors the selection state. */
.model-chip > .model-chip-row > .model-chip-check {
    width: 14px;
    height: 14px;
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--accent);
    border-radius: 3px;
    pointer-events: none;
}

.model-chip > .model-chip-row > .model-chip-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Per-quant-level availability boxes, shown inline on the model's row and
   pushed to the right (the name flexes to fill the space before them). Boxes
   keep their natural size and wrap when they don't fit. */
.model-chip-quants {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 3px;
    padding-left: 0;
    flex-shrink: 0;
}

.model-chip-quants .quant-box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    box-sizing: border-box;
    flex: 0 0 auto;
    width: auto;
    min-width: 58px;
    height: 28px;
    padding: 0 11px;
    margin: 0;
    border-radius: var(--radius-xs);
    border: 1px solid var(--border-subtle);
    background: var(--bg-card);
    color: var(--text-tertiary);
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
}

/* Hover feedback: a soft neutral lift — the border firms up to a neutral tone
   and the surface darkens very slightly (over whatever state colour it has).
   No brand red here. Suppressed while the icon inside is hovered, since that's
   a distinct target. */
.model-chip-quants .quant-box:hover:not(:has(.quant-box-btn:hover)) {
    border-color: rgba(0, 0, 0, 0.28);
    box-shadow: inset 2px 0 0 var(--accent);
}

/* The selected quant level: unmistakably the active choice among its clickable
   siblings — a solid brand-red fill with a white label. A filled (rather than
   tinted) treatment reads as "picked/active" and avoids being confused with the
   subtle red-tinted corrupted/error state, while the neutral-looking boxes
   beside it stay clearly selectable. The second rule keeps the look while the
   cursor is on the box (overriding the generic hover darken). */
.model-chip-quants .quant-box.quant-box-selected {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
    box-shadow: none;
}

.model-chip-quants .quant-box.quant-box-selected:hover:not(:has(.quant-box-btn:hover)) {
    background: var(--accent);
    border-color: var(--accent);
    box-shadow: none;
}

/* The box is static; only the icon beside the label is interactive. */
.model-chip-quants .quant-box-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    padding: 0;
    margin: 0 -4px 0 0;
    border: none;
    background: none;
    border-radius: var(--radius-xs);
    color: inherit;
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.model-chip-quants span.quant-box-btn {
    cursor: default;
}

.model-chip-quants .quant-box-icon {
    display: block;
}

.model-chip-quants .quant-box-spinner {
    animation: spin 0.9s linear infinite;
}

/* Icons get a solid background with a white glyph on hover, so it's clear the
   icon itself (not the box) is the target: green to download, red to remove. */
.model-chip-quants .quant-box-btn-dl:hover {
    color: #ffffff;
    background: var(--green);
}

.model-chip-quants .quant-box-btn-rm:hover,
.model-chip-quants .quant-box-btn-cancel:hover {
    color: #ffffff;
    background: var(--red);
}

/* On disk / ready — neutral slate chip rather than a saturated green, so it
   reads as a calm "available" state. */
.model-chip-quants .quant-box-present {
    background: #eef0f4;
    border-color: rgba(0, 0, 0, 0.11);
    color: var(--text-secondary);
}

.model-chip-quants .quant-box-partial {
    background: var(--orange-subtle);
    border-color: rgba(229, 160, 0, 0.45);
    color: var(--orange);
}

/* Downloading — yellow/amber, matching a model's "deploying" state. */
.model-chip-quants .quant-box-downloading {
    background: var(--orange-subtle);
    border-color: rgba(229, 160, 0, 0.4);
    color: #996100;
}

.model-chip-quants .quant-box-removing {
    color: var(--text-quaternary);
}

.model-chip-quants .quant-box-corrupted {
    background: var(--red-subtle);
    border-color: rgba(229, 72, 77, 0.45);
    color: var(--red);
}

.quant-checking {
    font-size: 11px;
    color: var(--text-tertiary);
}

/* Download dropdown: pushed to the right edge of the quant row. */
.model-chip-quants .quant-dl-wrap {
    position: relative;
    margin-left: auto;
    padding-left: 10px;
    display: inline-flex;
    align-items: center;
}

.model-chip-quants .quant-dl-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xs);
    background: var(--bg-card);
    color: var(--text-tertiary);
    cursor: pointer;
    transition: background var(--duration-fast), border-color var(--duration-fast), color var(--duration-fast);
}

.model-chip-quants .quant-dl-toggle:hover,
.model-chip-quants .quant-dl-toggle.open {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
}

.model-chip-quants .quant-dl-menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    min-width: 96px;
    padding: 4px;
    gap: 2px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
}

.model-chip-quants .quant-dl-menu .quant-dl-item {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 6px 10px;
    border: none;
    background: none;
    border-radius: var(--radius-xs);
    color: var(--text-secondary);
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: left;
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.model-chip-quants .quant-dl-menu .quant-dl-item:hover {
    background: var(--green-subtle);
    color: var(--green);
}

.model-chip:hover {
    background: var(--bg-row-hover);
    border-color: var(--border-subtle);
    box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}

.model-chip.selected {
    background: var(--bg-row-selected);
    border-color: var(--bg-row-selected-border);
    box-shadow: inset 2px 0 0 var(--accent);
}

/* Deployed model helpers */
.deployed-model-status {
    color: var(--green);
    font-size: 15px;
    flex-shrink: 0;
    line-height: 1;
}

.deployed-instance-count {
    font-size: 11px;
    color: var(--text-tertiary);
    font-weight: 400;
}

/* How many instances serve this model, and the controls that change it: fewer,
   the count, more, in one unbroken pill. No rules between them and one surface
   under all three — what separates them is the space around each, and hovering
   a button is what draws its edges, only for as long as you are on it.

   Nothing in here is sized by a fixed width, a fixed height or a margin. Every
   cell is padding around its own content and the box adds up to whatever they
   need. The buttons are what set the height, and their padding is chosen so the
   total lands on the 28px of the name field beside it: no cell in here may be
   taller than its own content plus that padding. */
.instance-stepper {
    display: flex;
    /* Every cell runs the full height of the tallest, so a hover fill covers
       its end of the pill rather than floating in the middle of it. */
    align-items: stretch;
    flex-shrink: 0;
    border: 1px solid var(--border-subtle);
    /* Far past half the height, so it stays a pill whatever the contents do to
       the box. */
    border-radius: 999px;
    background: rgba(120, 120, 120, 0.06);
    /* No padding of its own: the air between a glyph and the end of the pill
       belongs to the button, so the button's box reaches that end and its hover
       fills the whole half. This then clips the two of them to the pill —
       curved where they meet its caps, straight where they meet the number. */
    overflow: hidden;
    /* The card around this one is now a hand — click it anywhere and it opens.
       The stepper is not part of that: its buttons do their own thing, and the
       count between them does nothing at all. Cursor inherits, so saying so
       here is what stops the count from promising a click it will not answer. */
    cursor: default;
}

.instance-n {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 7px;
    /* Big, but under the 26px the buttons give the box — a taller number would
       push the whole control past the name field it sits beside. */
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    /* No surface and no rules of its own: the pill is one background, and this
       cell sits on it like the buttons do. What still marks it out as the one
       part that does nothing is the cursor, and that it never fills on hover.

       Padding gives the cell its width, but the content sets the floor: one
       digit is narrower than two, and narrower again than the spinner that
       replaces it. Holding it to the widest of those keeps the buttons either
       side from stepping sideways as the count changes. */
    min-width: 20px;
}

/* `.deploying-spinner-icon` is 18px in CSS, which beats the width/height on the
   SVG itself. In this cell it stands in for a digit, so it takes a digit's
   size. */
.instance-stepper-busy .instance-n .deploying-spinner-icon {
    width: 16px;
    height: 16px;
}

/* Beats `.model-chip button`, which is a fixed 22px square with a negative
   margin — both wrong for a cell in a ruled box, where the padding is the
   size and a margin would pull the cell off its own border.

   These two are what set the height: 12px of glyph between 7px above and
   below is 26px, which with the box's own top and bottom border is the 28px of
   the name field this sits next to. */
.model-chip-deployed .instance-stepper > .instance-step {
    margin: 0;
    /* The horizontal padding is what used to sit on the pill. Here instead, it
       is inside the button's box, so the hover fill takes in the space between
       the glyph and the end of the pill rather than stopping short of it. */
    padding: 7px 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    color: var(--text-secondary);
    background: none;
    border: none;
    /* Square. Each button runs from the end of the pill to the number, and the
       pill's own rounding is what shapes the outer end — so a hover covers that
       whole half, curved against the cap and cut straight where the count
       begins. Rounding them here would shrink the fill back to a disc. */
    border-radius: 0;
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast);
}

/* The cell holding the bin. Its padding is whatever the 17px icon needs to come
   out the same 26 × 32 as the + half across the pill, so swapping − for the bin
   changes neither the height of the control nor the balance of its two halves.
   The halves are the odd number, hence the halved pixels. */
.model-chip-deployed .instance-stepper > .instance-step-undeploy {
    padding: 4.5px 6px;
}

.model-chip-deployed .instance-stepper .instance-bin-icon {
    width: 17px;
    height: 17px;
    display: block;
}

/* The cropped viewBox scales the drawing up by about 1.6, and the stroke with
   it — 1.3 as drawn would land at over 2px here, heavier than anything else on
   the card. This is the weight the icon was drawn to look like. */
.model-chip-deployed .instance-stepper .instance-bin-icon path {
    stroke-width: 1;
}

/* Both buttons hover the same way: a grey disc under whichever one the cursor
   is on. Overrides `.model-chip button:hover`, which goes red — that belongs to
   controls whose whole job is deleting something, and it would mean two
   different things on the two ends of this pill.

   Which button does what is left to the glyphs. The bin is what says the minus
   has stopped scaling down and started undeploying. */
.model-chip-deployed .instance-stepper > .instance-step:hover:not(:disabled) {
    color: var(--text-primary);
    background: rgba(120, 120, 120, 0.20);
}

/* Inert while a scale is in flight — the spinner in the count's cell is what
   says why. */
.model-chip-deployed .instance-stepper > .instance-step:disabled {
    color: var(--text-tertiary);
    opacity: 0.45;
    background: none;
    cursor: default;
}

/* The stepper is the last thing on the row and sits at its right edge. */
.model-chip-deployed .deployed-model-info > .instance-stepper {
    margin-left: auto;
}

/* Status sits with the name now, not down in the label row — the labels below
   only show on hover, and whether the model is up should not have to be gone
   looking for. It keeps its full width whatever the name field does. */
.model-chip-deployed .deployed-model-info > .deployed-status-label {
    flex-shrink: 0;
    white-space: nowrap;
}

.deployed-model-info {
    display: flex;
    flex: 1;
    min-width: 0;
    gap: 1px;
}

/* Deployed chip: stack main row and status labels vertically.
   Specificity bumped with .list-scroll to override .list-scroll > div rules. */
.list-scroll > .model-chip-deployed {
    flex-direction: column;
    align-items: stretch;
    flex-wrap: nowrap;
    gap: 6px;
    min-width: 0;
    height: auto;
    min-height: auto;
    flex-shrink: 0;
    background: var(--bg-chip-deployed);
}

/* Open, the card is two surfaces and the padding belongs to each of them
   separately — the head's fill has to reach the card's edges, and it cannot do
   that from inside the card's own padding. `overflow: hidden` is what crops it
   back to the rounded corners. */
.list-scroll > .model-chip-deployed {
    padding: 0;
    gap: 0;
    overflow: hidden;
}

.model-chip-deployed .model-chip-row {
    padding: 10px 14px;
    min-height: 40px;
}

/* The head is the control now, so hover is its to show, not the card's. It
   barely moves — enough to say the row is live, not enough to promise more than
   the details it opens. */
.model-chip-deployed:hover {
    background: var(--bg-chip-deployed);
    box-shadow: none;
}

.model-chip-deployed .model-chip-head:hover {
    background: var(--bg-chip-deployed-hover);
}

/* Open, the head is on its own surface: darker than the sheet it opened onto,
   because after the click it is still the one part of the card that answers
   one. Shut, there is nothing to tell apart and it stays white. */
.model-chip-open > .model-chip-head {
    background: var(--bg-chip-head);
    border-bottom: 1px solid var(--border-hairline);
}

.model-chip-open > .model-chip-head:hover {
    background: var(--bg-chip-head-hover);
}

/* The sheet is not a control and says so: white — the card's own surface is
   grey now, so this has to name the white rather than inherit it — and the
   pointer stays an arrow over it. Nothing here toggles anything: the id lives
   on the head. */
.model-chip-open > .model-chip-labels {
    background: var(--bg-card);
    cursor: default;
    padding: 10px 14px 12px;
}

.model-chip-deployed .model-chip-row,
.model-chip-deployed .model-chip-labels {
    flex: 0 0 auto;
}

.model-chip-deployed .model-chip-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    width: 100%;
}

.model-chip-deployed .deployed-model-info {
    flex: 1;
    display: flex;
    align-items: center;
    min-width: 0;
    /* The field now spans the row, so the gap is the only thing keeping it off
       the undeploy ×. */
    gap: 8px;
}

.model-chip-deployed .deployed-model-name {
    flex: 1;
    text-align: left;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* No `margin-left: auto` here any more. It existed to send the undeploy × to
   the far right, and that button is gone — the instance stepper is what sits at
   the row's right edge now, and it pushes itself there. Left in, this would
   catch the details chevron and throw it across the row. */
.model-chip-deployed .deployed-model-info > button {
    flex-shrink: 0;
}

/* A deployed card opens its details wherever you click its head, so the head
   offers a hand across its whole width — the chevron is the affordance that
   says so, not the only thing that answers. On the head and not on the card,
   because below the head nothing answers a click at all.

   Cursor inherits, so the two things inside that are not "open this card" have
   to say what they are themselves: the name field is for typing, and the
   deploying placeholder has no details to open. */
.list-scroll > .model-chip-deployed {
    cursor: default;
}

.model-chip-deployed .model-chip-head {
    cursor: pointer;
}

.list-scroll > .model-chip-deploying {
    cursor: default;
}

.model-chip-deployed .rename-input {
    cursor: text;
}

.model-chip-deployed .deployed-model-info > button {
    cursor: pointer;
}

.model-chip-deployed .model-chip-labels {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
}

.model-chip-deployed .model-chip-labels .deployed-status-label {
    max-width: 100%;
    overflow-wrap: anywhere;
    white-space: normal;
}

/* The chevron that opens a card. Quiet until wanted — it is a way in, not
   something to read — and turns to point down at what it has opened. */
.model-chip-deployed .chip-details-toggle {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    margin: 0 2px 0 -2px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-tertiary);
    background: none;
    border: none;
    border-radius: var(--radius-xs);
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast),
                transform var(--duration-fast);
}

/* `.model-chip button:hover` goes red, which here would read as "this deletes
   something". Opening a card destroys nothing. */
.model-chip-deployed .chip-details-toggle:hover {
    color: inherit;
    background: inherit;
}

.model-chip-deployed .chip-details-toggle.open {
    color: var(--text-secondary);
    transform: rotate(90deg);
}

/* Open: the details sit under the line they belong to, indented past the
   chevron so they read as its contents rather than as a second row. 42px is the
   card's own 14px edge, which the sheet now carries itself, plus the 28px the
   chevron takes on the head above. */
.model-chip-deployed .model-chip-labels {
    padding-left: 42px;
}

/* The settings a deployment runs under, as a spec sheet: one setting per line,
   its name on the left and its value on the right of a shared column edge, so
   the values line up and can be read down. Chips were the wrong shape for this
   — they put every setting on the same footing as the status pills above and
   left the numbers to explain themselves. */
.model-chip-deployed .model-chip-labels .deploy-spec {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: stretch;
    column-gap: 14px;
    row-gap: 2px;
    margin: 0 0 3px;
    padding: 0;
    width: 100%;
    min-width: 0;
    border-left: 2px solid var(--border-subtle, rgba(120, 120, 120, 0.22));
    padding-left: 10px;
}

/* Each row spans both columns of the grid it lives in — the <div> wrapper is
   what keeps a key with its own value in the DOM, and `display: contents` is
   what stops it from becoming a cell of its own. */
.deploy-spec-row {
    display: contents;
}

/* Every line of the sheet is the same height, whether it holds text or the auth
   switch — a row that grows around its control breaks the even rhythm the list
   is read down. 22px clears the tallest thing in a value cell (the 17px switch,
   the 20px copy button), so the controls sit inside the line instead of setting
   it. Both cells are centred on it, which is also what keeps a key level with a
   control rather than with the top of its box. */
.deploy-spec-key,
.deploy-spec-value {
    display: flex;
    align-items: center;
    min-height: 22px;
    margin: 0;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.2;
}

.deploy-spec-key {
    color: var(--text-tertiary, #888);
    white-space: nowrap;
}

.deploy-spec-value {
    color: var(--text-secondary, #555);
    font-variant-numeric: tabular-nums;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Authentication is the one spec that is set from here rather than read, so its
   value cell holds a switch. Kept under the 22px the rows are all locked to, so
   turning a line into a control does not make it taller than its neighbours. */
.auth-toggle-wrap {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

/* Scoped to the card, not just `.auth-toggle`: `.model-chip button` is a fixed
   22px square with a negative right margin — right for the icon buttons on the
   chip's main row, and what was turning this switch back into a box. */
.model-chip-deployed .auth-toggle {
    flex-shrink: 0;
    width: 30px;
    height: 17px;
    min-width: 30px;
    margin: 0;
    padding: 0;
    border: 1px solid var(--border-subtle, rgba(0, 0, 0, 0.1));
    border-radius: 9px;
    background: rgba(120, 120, 120, 0.18);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    transition: background var(--duration-fast), border-color var(--duration-fast);
}

.auth-toggle-knob {
    width: 13px;
    height: 13px;
    margin-left: 1px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    transition: transform var(--duration-fast);
}

.model-chip-deployed .auth-toggle.on {
    background: #1f8a3f;
    border-color: #1f8a3f;
}

.model-chip-deployed .auth-toggle.on .auth-toggle-knob {
    transform: translateX(13px);
}

/* `.model-chip button:hover` goes red — that reads as "this deletes something",
   and neither a switch nor a copy deletes anything. It is later in the file at
   equal weight, so both properties have to be named back. */
.model-chip-deployed .auth-toggle:hover {
    color: inherit;
    background: rgba(120, 120, 120, 0.28);
}

.model-chip-deployed .auth-toggle.on:hover {
    background: #1a7636;
}

/* "Disabled" is a value like any other on the sheet, so it is coloured like
   one — inherited from the cell, not greyed back. Only the on state departs
   from that, and it earns the green by being the state that does something. */
.auth-toggle-state {
    color: inherit;
}

.auth-toggle.on + .auth-toggle-state {
    color: #1f8a3f;
}

/* The token is long and the card is narrow: it takes the width the row has and
   gives the rest to an ellipsis, with the whole of it on the element's title
   and behind the copy button. */
.auth-token-wrap {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* A field, and it reads as one — inset, bordered, I-beam under the pointer, so
   the token looks like something to select rather than something to read. The
   rows of the list are `user-select: none`, right for a chip you click and
   wrong for the one thing on it you are meant to take away with you.

   Read-only is enforced by the element (`readonly` on the input), not by this;
   what is here only makes sure it does not *look* disabled while it is. */
.model-chip-deployed .auth-token {
    flex: 0 1 340px;
    min-width: 0;
    box-sizing: border-box;
    height: 22px;
    margin: 0;
    padding: 2px 7px;
    cursor: text;
    user-select: text;
    -webkit-user-select: text;
    text-overflow: ellipsis;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-secondary, #555);
    background-color: var(--bg-input);
    border: 1px solid var(--border-input);
    border-radius: var(--radius-sm);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
    outline: none;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
}

.model-chip-deployed .auth-token:hover {
    border-color: var(--text-tertiary);
}

/* Focus says "this is yours to select from", not "type here" — no accent ring,
   which on every other field on the page promises an edit this one refuses. */
.model-chip-deployed .auth-token:focus {
    border-color: var(--text-tertiary);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
}

/* Same story as the switch: `.model-chip button` would make these 22px squares
   hanging off the row on a negative margin. */
.model-chip-deployed .auth-token-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    margin: 0;
    padding: 0;
    border: none;
    background: none;
    border-radius: var(--radius-xs);
    color: var(--text-tertiary, #888);
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast);
}

.model-chip-deployed .auth-token-btn:hover {
    color: var(--text-secondary, #555);
    background: rgba(120, 120, 120, 0.18);
}

/* One turn of the icon as the new token arrives — long enough to see that the
   field changed on purpose, short enough not to be an animation anyone waits
   on. It is the regeneration that is instant, not the reading of it. */
.model-chip-deployed .auth-token-regen.spinning svg {
    animation: spin 0.45s ease-in-out;
}

/* A copy changes nothing on screen, so for two seconds the button says it
   worked: the icon turns to a check and goes green. The green is what carries
   it — a check mark alone, in the same grey the copy icon was, is a change too
   quiet to catch. */
.model-chip-deployed .auth-token-copy.copied,
.model-chip-deployed .auth-token-copy.copied:hover {
    color: #1f8a3f;
    background: none;
}

.model-chip-deployed .auth-token-copy.copied svg {
    animation: auth-copied-in var(--duration-med) ease-out;
}

@keyframes auth-copied-in {
    from { opacity: 0; transform: scale(0.8); }
    to   { opacity: 1; transform: none; }
}

.deployed-model-name {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The name of a deployed model is an open text field, always — there is nothing
   to click to start editing, the field itself says the name can be changed. It
   takes the width it needs and no more, so it reads as part of the chip rather
   than as a form. */
.model-chip-deployed .deployed-model-name {
    flex: 0 1 auto;
}

/* The field carries the whole affordance: white against the chip's grey, a real
   border, a little depth, and a pencil in the gutter. Nothing else on the chip
   says the name can be typed over, so this has to. */
.model-chip-deployed .rename-input {
    flex: 0 1 250px;
    max-width: 250px;
    min-width: 0;
    box-sizing: border-box;
    height: 28px;
    padding: 3px 9px 3px 27px;
    font-size: 13px;
    font-weight: 500;
    font-family: inherit;
    color: var(--text-primary);
    background-color: var(--bg-input);
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23a1a1a6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 8px center;
    background-size: 12px 12px;
    border: 1px solid var(--border-input);
    border-radius: var(--radius-sm);
    box-shadow: inset 0 1px 2px rgba(0,0,0,0.05);
    outline: none;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
}

.model-chip-deployed .rename-input:hover {
    border-color: var(--text-tertiary);
}

.model-chip-deployed .rename-input:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--border-focus);
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23e5322c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg%3E");
}

/* Appears the moment the field says something other than the current name, and
   goes again once the rename lands. Sits right against the field — it belongs
   to it, not to the chip. */
.model-chip-deployed .deployed-model-info > .rename-apply {
    flex-shrink: 0;
    /* This button belongs beside the field, not out at the edge of the card.
       The row's gap does the spacing. */
    margin-left: 0;
    /* `.model-chip button` is a 22px square — right for an icon, wrong for a
       button with a word in it. Take the width back and let the text set it. */
    width: auto;
    margin-right: 0;
    padding: 3px 10px;
    /* Same height as the field it belongs to. */
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 500;
    font-family: inherit;
    color: #ffffff;
    background: var(--accent);
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--duration-fast);
}

.model-chip-deployed .deployed-model-info > .rename-apply:hover {
    background: var(--accent-hover);
}

/* Cancel, beside Rename. It appears and goes with it, and puts the name on
   record back in the field. Quiet next to the accent button — undoing is the
   way out, not the thing to do — but a real target, not a link. */
.model-chip-deployed .deployed-model-info > .rename-cancel {
    flex-shrink: 0;
    margin-left: 0;
    margin-right: 0;
    width: 28px;
    height: 28px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    background: var(--bg-input);
    border: 1px solid var(--border-input);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast),
                border-color var(--duration-fast);
}

.model-chip-deployed .deployed-model-info > .rename-cancel:hover {
    color: var(--text-primary);
    background: var(--bg-row-hover);
    border-color: var(--text-tertiary);
}

/* Renamed. The field is back to looking like every other one, so the check is
   the only thing saying it worked — it holds for a moment, then goes. */
.model-chip-deployed .deployed-model-info > .rename-apply-done,
.model-chip-deployed .deployed-model-info > .rename-apply-done:disabled {
    width: 28px;
    padding: 0;
    color: #ffffff;
    background: var(--green);
    opacity: 1;
    cursor: default;
}

/* Deploying state. Written to beat the deployed chip's own grey surface (and its
   hover), which a deploying chip also carries. */
.model-chip-deploying,
.list-scroll > .model-chip-deploying,
.model-chip-deploying:hover {
    background: var(--orange-subtle);
    border-color: rgba(229, 160, 0, 0.2);
}

/* Deploying spinner — inline SVG, sized to match the ✓ icon */
.deploying-spinner-icon {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    animation: spin 0.9s linear infinite;
}

.deployed-status-label {
    font-size: 11px;
    font-weight: 500;
}

.deploying-label {
    color: #996100;
    animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.deployed-label {
    color: #2f5fb3;
    background: rgba(47, 95, 179, 0.12);
    border: 1px solid rgba(47, 95, 179, 0.25);
    padding: 1px 6px;
    border-radius: 5px;
}

.serving-label {
    color: #1f8a3f;
    background: rgba(31, 138, 63, 0.12);
    border: 1px solid rgba(31, 138, 63, 0.25);
    padding: 1px 6px;
    border-radius: 5px;
}

.broken-label {
    color: #b03030;
    background: rgba(176, 48, 48, 0.12);
    border: 1px solid rgba(176, 48, 48, 0.30);
    padding: 1px 6px;
    border-radius: 5px;
}

.loading-label {
    color: #996100;
    background: rgba(229, 160, 0, 0.12);
    border: 1px solid rgba(229, 160, 0, 0.30);
    padding: 1px 6px;
    border-radius: 5px;
    animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.instances-label {
    color: #8a6d1f;
    background: rgba(218, 165, 32, 0.12);
    border: 1px solid rgba(218, 165, 32, 0.30);
    padding: 1px 6px;
    border-radius: 5px;
}

.offline-label {
    color: #888;
    background: rgba(136, 136, 136, 0.12);
    border: 1px solid rgba(136, 136, 136, 0.25);
    padding: 1px 6px;
    border-radius: 5px;
}

.needs-update-label {
    color: #2f5fb3;
    background: rgba(47, 95, 179, 0.12);
    border: 1px solid rgba(47, 95, 179, 0.25);
    padding: 2px 6px;
    border-radius: 5px;
    /* One line, and the spinner centred on it. */
    display: inline-flex;
    align-items: center;
    gap: 4px;
    line-height: 1.25;
}

/* Room to breathe from the status it sits beside. One line like every other
   label, so it keeps the nowrap the rule above gives them all. */
.model-chip-deployed .deployed-model-info > .deployed-status-label.needs-update-label {
    margin-left: 4px;
}

/* The spinner the label wears: it keeps its size in the flex row rather than
   being squeezed by the text beside it. */
.needs-update-label .deploying-spinner-icon {
    flex-shrink: 0;
}

.removing-label {
    color: #b03030;
    background: rgba(176, 48, 48, 0.12);
    border: 1px solid rgba(176, 48, 48, 0.30);
    padding: 1px 6px;
    border-radius: 5px;
    animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.corrupted-label {
    color: #b03030;
    background: rgba(176, 48, 48, 0.12);
    border: 1px solid rgba(176, 48, 48, 0.30);
    padding: 1px 6px;
    border-radius: 5px;
}

/* Undeploying state — red tint with spinner. Same specificity dance as the
   deploying tint: it sits on a chip that is still a deployed chip. */
.model-chip-undeploying,
.list-scroll > .model-chip-undeploying,
.model-chip-undeploying:hover {
    background: rgba(220, 60, 60, 0.06);
    border-color: rgba(220, 60, 60, 0.15);
    opacity: 0.8;
}

.undeploying-label {
    color: #b03030;
    font-size: 11px;
    font-weight: 500;
    animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.undeploy-spinner {
    width: 16px;
    height: 16px;
    margin-left: auto;
    flex-shrink: 0;
}

/* Backup button */
.backup-btn {
    width: 22px;
    height: 22px;
    border-radius: 4px;
    border: 1px solid rgba(76, 175, 80, 0.3);
    background: rgba(76, 175, 80, 0.08);
    color: #4caf50;
    font-size: 16px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    flex-shrink: 0;
    transition: all 0.15s ease;
}

.backup-btn:hover {
    background: rgba(76, 175, 80, 0.18);
    border-color: rgba(76, 175, 80, 0.5);
}

.backup-spinner {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

/* Model name inside chip — fill space, truncate.
   Only .model-chip-name and label get flex:1, not icon wrappers. */
.model-chip > .model-chip-name,
.model-chip > label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.model-chip button {
    flex-shrink: 0;
    /*margin-left: -2px;*/
    margin-right: -4px;

    background: none;
    /*color: inherit;*/
    border-radius: var(--radius-xs);
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    cursor: pointer;
    border: none;
    line-height: 1;
    transition: color var(--duration-fast), background var(--duration-fast);
}

.model-chip button:hover {
    background: var(--red);
    color: #ffffff;
}

/* Bigger checkbox in chips */
.model-chip input[type="checkbox"] {
    width: 18px;
    height: 18px;
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--accent);
    cursor: pointer;
}

.ip-chip {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 10px;
    padding: 10px 14px;
    background: var(--accent-subtle-grey);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-md);
    font-size: 13px;
    font-weight: 600;
    color: #444444;
    font-family: var(--font-mono);
    margin: 0;
    min-height: 40px;
    transition: background var(--accent), border-color var(--accent), box-shadow var(--accent);
}

.ip-chip:hover {
    background: var(--accent-subtle-grey-hover);
    border-color: var(--accent-subtle-grey-hover);
    box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}

/* IP text — fill space, truncate */
.ip-chip > span {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ip-chip button {
    flex-shrink: 0;
    margin-left: auto;
    background: none;
    color: #ffffff;
    border-radius: var(--radius-xs);
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    cursor: pointer;
    border: none;
    line-height: 1;
    transition: color var(--duration-fast), background var(--duration-fast);
}

.ip-chip button:hover {
    background: #ffffff;
    color: var(--red);
}

/* --- Machine Cards (replaces ip-chip) --- */
.machine-card {
    background: #ffffff;
    border: 1px solid #cccccc;
    border-radius: var(--radius-md);
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 7px;
    transition: background var(--duration-fast), box-shadow var(--duration-fast);
}

.machine-card:hover {
    background: #eeeeee;
    box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}

.machine-card-header {
    display: flex;
    align-items: center;
    gap: 8px;
}

.machine-addr {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 600;
    color: #444444;
}

.machine-card-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
    flex-shrink: 0;
}

.machine-edit-btn,
.machine-remove-btn {
    flex-shrink: 0;
    background: none;
    color: #999999;
    border-radius: var(--radius-xs);
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    cursor: pointer;
    border: none;
    line-height: 1;
    transition: color var(--duration-fast), background var(--duration-fast);
}

.machine-remove-btn {
    font-size: 15px;
}

.machine-edit-btn:hover {
    background: #ffffff;
    color: #4a6fa5;
}

.machine-remove-btn:hover {
    background: #ffffff;
    color: var(--red);
}



.machine-gpus {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.machine-gpu {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.gpu-name-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.gpu-name {
    font-size: 11px;
    font-weight: 500;
    color: #555555;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}

.gpu-vram-label {
    font-size: 10px;
    font-family: var(--font-mono);
    color: #777777;
    white-space: nowrap;
    flex-shrink: 0;
}

.gpu-vram-track {
    height: 5px;
    background: rgba(0,0,0,0.12);
    border-radius: 3px;
    overflow: hidden;
}

.gpu-vram-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.4s var(--ease-out);
}

.gpu-vram-fill-green  { background: var(--green); }
.gpu-vram-fill-orange { background: var(--orange); }
.gpu-vram-fill-red    { background: var(--red); }

/* --- Add Machine Dialog: GPU VRAM sliders --- */
/* Wider than a plain dialog: the advanced settings are laid out two to a row,
   and one of those cells holds the two ends of the system port range. */
.dialog-card.dialog-card-add-machine {
    width: 480px;
}

.add-machine-gpu-section {
    margin-bottom: 14px;
}

.add-machine-advanced {
    margin-bottom: 14px;
}

.add-machine-advanced summary {
    cursor: pointer;
    font-size: 14px;
    color: var(--text-secondary, #888);
    user-select: none;
    margin-bottom: 8px;
    list-style: none;
}

.add-machine-advanced summary::before {
    content: '\25B6';
    display: inline-block;
    margin-right: 6px;
    font-size: 12px;
    transition: transform 0.15s;
}

.add-machine-advanced[open] summary::before {
    transform: rotate(90deg);
}

.add-machine-advanced-fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 16px;
    align-items: end;
}

.add-machine-advanced-fields .dialog-field {
    margin-bottom: 0;
}

.add-machine-gpu-status {
    font-size: 12px;
    color: var(--text-secondary);
    margin-bottom: 8px;
}

.add-machine-spinner {
    display: inline-block;
    width: 12px;
    height: 12px;
    border: 2px solid rgba(255,255,255,0.2);
    border-top-color: var(--orange);
    border-radius: 50%;
    animation: add-machine-spin 0.6s linear infinite;
    vertical-align: middle;
    margin-right: 6px;
}

@keyframes add-machine-spin {
    to { transform: rotate(360deg); }
}

#add-machine-ip.input-loading {
    border-color: var(--orange);
}

.add-machine-gpu-status.connecting {
    color: var(--orange);
}

.add-machine-gpu-status.failed {
    color: var(--accent);
}

.add-machine-gpu-status.connected {
    color: var(--green);
}

.add-machine-gpu-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.add-machine-gpu-item {
    background: var(--bg-inset);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
}

.add-machine-gpu-item .gpu-name {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 6px;
    display: block;
}

.add-machine-gpu-slider-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.add-machine-gpu-slider-row input[type="range"] {
    flex: 1;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: rgba(0,0,0,0.12);
    border-radius: 3px;
    outline: none;
    border: none;
    padding: 0;
    margin: 0;
}

.add-machine-gpu-slider-row input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--green);
    cursor: pointer;
    border: 2px solid var(--bg-card);
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}

.add-machine-gpu-slider-row input[type="range"]::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--green);
    cursor: pointer;
    border: 2px solid var(--bg-card);
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}

.add-machine-gpu-slider-label {
    font-size: 11px;
    font-family: var(--font-mono);
    color: var(--text-secondary);
    white-space: nowrap;
    min-width: 70px;
    text-align: right;
}

.add-machine-vram-total {
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-primary);
    text-align: right;
}

.machine-no-gpu {
    font-size: 11px;
    color: var(--text-tertiary);
    font-style: italic;
}

.machine-status-connecting {
    font-size: 11px;
    color: var(--text-tertiary);
    font-style: italic;
}

.machine-status-failed {
    font-size: 11px;
    color: var(--red);
    font-style: italic;
}

/* --- Buttons --- */
.btn {
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 600;
    padding: 7px 14px;
    border-radius: var(--radius-sm);
    border: none;
    cursor: pointer;
    transition: all var(--duration-fast);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    letter-spacing: 0.1px;
}

.btn-primary {
    background: var(--accent);
    color: #fff;
}

.btn-primary:hover {
    background: var(--accent-hover);
}

.btn-secondary {
    background: var(--bg-inset);
    color: var(--text-primary);
    border: 1px solid var(--border-subtle);
}

.btn-secondary:hover {
    background: var(--bg-row-hover);
}

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

.btn-danger:hover {
    background: var(--red);
}

.btn-ghost {
    background: none;
    border: none;
    color: var(--accent);
    padding-top: 6px;
    padding-right:4px;
    padding-left:4px;
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast);
    border-radius: var(--radius-xs);
}

.btn-ghost:hover {
    color: var(--accent-hover);
    background: var(--accent-subtle);
}

.btn-ghost-danger {
    background: none;
    border: none;
    color: var(--text-tertiary);
    padding: 4px 8px;
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: color var(--duration-fast), background var(--duration-fast);
    border-radius: var(--radius-xs);
}

.btn-ghost-danger:hover {
    color: var(--red);
    background: var(--red-subtle);
}

button:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

/* --- Badges --- */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}

.badge-success { background: var(--green-subtle); color: var(--green); }
.badge-warning { background: var(--orange-subtle); color: #996100; }
.badge-error   { background: var(--red-subtle);    color: var(--red); }
.badge-info    { background: var(--blue-subtle); }

.nav-rail-version {
    font-size: 11px;
    font-weight: 600;
    color: rgba(255,255,255,0.7);
    font-variant-numeric: tabular-nums;
    margin-top: 8px;
    text-align: center;
}

.update-band {
    position: relative;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3px 28px;
    font-size: 11px;
    font-weight: 500;
    background: var(--orange-subtle);
    color: #996100;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.update-band-close {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    background: transparent;
    border: none;
    color: inherit;
    font-size: 14px;
    line-height: 1;
    padding: 0 4px;
    cursor: pointer;
    opacity: 0.7;
}

.update-band-close:hover { opacity: 1; }

.update-band-link {
    color: inherit;
    text-decoration: underline;
    font-weight: 600;
}

.update-band-link:hover { opacity: 0.8; }

/* --- Logs --- */
.logs-section {
    flex: 0.3;
    display: flex;
    flex-direction: column;
    /*padding: 16px;*/
    overflow: hidden;
}

.logs-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 8px;

}

.logs-title {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.4px;
}

.log-container {
    background: #1c1c1e;
    color: #a8a8ad;
    font-family: var(--font-mono);
    font-size: 11px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    flex: 1;
    overflow-y: auto;
    white-space: pre-wrap;
    word-break: break-word;
    line-height: 1.65;
}

.log-info    { color: #6cb4ee; }
.log-success { color: #6cc070; }
.log-error   { color: #e8685e; }
.log-warning { color: #d4b95e; }

/* --- Global Collapsible Log Panel --- */
.log-panel {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--border-subtle);
    background: #1c1c1e;
    transition: max-height 0.25s var(--ease-out);
}

.log-panel-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 16px;
    background: #2a2a2c;
    border: none;
    border-bottom: 1px solid rgba(255,255,255,0.06);
    cursor: pointer;
    color: #a8a8ad;
    font-family: var(--font-body);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    width: 100%;
    text-align: left;
}

.log-panel-toggle:hover {
    background: #333335;
}

/* A panel that can be dismissed carries a × beside its toggle, so the two share
   a row and the toggle keeps the border under both. */
/* The row collapses the panel wherever it is pressed, so it takes the toggle's
   pointer and its hover — the strip past the controls is part of the same
   control, and has to look like it. */
.log-panel-header {
    display: flex;
    align-items: stretch;
    background: #2a2a2c;
    border-bottom: 1px solid rgba(255,255,255,0.06);
    cursor: pointer;
}

.log-panel-header:hover {
    background: #333335;
}

/* The two exceptions keep their own ground while the row lights up, which is
   what says a press there does something else. */
.log-panel-header:hover .log-panel-toggle {
    background: #333335;
}

/* The toggle takes the width of what it says rather than the whole row, so what
   comes after it sits beside the name instead of out at the far edge. */
.log-panel-header .log-panel-toggle {
    flex: 0 1 auto;
    width: auto;
    border-bottom: none;
}

/* Whatever else is in the header stays beside the name; only the × is pushed to
   the end of the row, where a dismiss belongs. */
.log-panel-header .log-panel-close {
    margin-left: auto;
}

/* Which machine the panel is showing. White, brighter than the label beside it:
   the address is the half of the header that says which panel this is. In the
   address's own typeface, since it is a machine address and not a heading. */
.log-panel-subject {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    color: #fff;
}

/* Between the panel's name and the endpoint it is showing — the same rule that
   stands between the endpoint and the verbosity, so the header reads as three
   parts separated one way rather than two ways.

   The negative vertical margin takes back the toggle's 6px of padding, which is
   what lets the rule run the full height of the row like the controls' border
   does, rather than floating in the middle of it. */
.log-panel-divider {
    align-self: stretch;
    width: 1px;
    margin: -6px 4px;
    background: rgba(255, 255, 255, 0.12);
}

/* Beside the name the panel carries, not off at the edge of the row: it belongs
   to the logs being named, and the eye finds it where it stopped reading.
   Behind a rule, because being next to the name is not the same as being part
   of it — the name says what you are looking at, this changes it. */
.log-panel-controls {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 12px;
    border-left: 1px solid rgba(255, 255, 255, 0.12);
    background: #2a2a2c;
    color: #a8a8ad;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}

.log-panel-control-label {
    color: #fff;
}

.log-panel-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    background: #3a3a3d;
    border: none;
    border-radius: var(--radius-xs);
    color: #d8d8dd;
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.log-panel-step:hover:not(:disabled) {
    background: #4a4a4e;
    color: #fff;
}

/* At either end of the range the button is spent: dimmed, and it no longer
   answers a click. */
.log-panel-step:disabled {
    background: #2f2f32;
    color: #5a5a5f;
    cursor: default;
}

.log-panel-step-value {
    min-width: 10px;
    text-align: center;
    color: #fff;
    font-variant-numeric: tabular-nums;
}

.log-panel-close {
    flex-shrink: 0;
    width: 32px;
    padding: 0;
    background: #2a2a2c;
    border: none;
    color: #a8a8ad;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.log-panel-close:hover {
    background: #333335;
    color: #fff;
}

.log-panel-arrow {
    transition: transform 0.2s var(--ease-out);
    flex-shrink: 0;
}

.log-panel.collapsed .log-panel-arrow {
    transform: rotate(180deg);
}

.log-panel-body {
    height: 160px;
    overflow: hidden;
    transition: height 0.25s var(--ease-out);
}

.log-panel.collapsed .log-panel-body {
    height: 0;
}

.log-panel-body .log-container {
    height: 100%;
    border-radius: 0;
}

.log-unread-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 16px;
    padding: 0 5px;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.log-unread-badge.hidden {
    display: none;
}

/* --- Deployment VRAM Bar --- */
.deployment-vram-bar {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 8px 24px;
    background: var(--bg-card);
    border-bottom: 1px solid var(--border-hairline);
    min-height: 0;
}

.deployment-vram-bar:empty {
    display: none;
}

.vram-bar-item {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-secondary);
}

.vram-bar-value {
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.vram-bar-track {
    width: 80px;
    height: 5px;
    background: rgba(0,0,0,0.08);
    border-radius: 3px;
    overflow: hidden;
}

.vram-bar-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.4s var(--ease-out);
}

.vram-bar-fill-green { background: var(--green); }
.vram-bar-fill-orange { background: var(--orange); }
.vram-bar-fill-red { background: var(--red); }

/* --- Dialog --- */
.dialog-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.25);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
}

.dialog-card {
    position: relative;
    width: 360px;
    padding: 24px;
    background: var(--bg-card);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-overlay);
}

.dialog-close-btn {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-tertiary);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
}

.dialog-close-btn:hover {
    background: var(--bg-inset);
    color: var(--text-primary);
}

.dialog-card h3 {
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0 0 16px;
}

.dialog-field {
    margin-bottom: 14px;
}

.dialog-field input {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

.dialog-field-label {
    display: block;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary);
    margin-bottom: 5px;
}

.port-range-inputs {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* The two ends share the cell evenly, whatever the cell is worth. */
.port-range-inputs input {
    flex: 1 1 0;
    min-width: 0;
}

.port-range-sep {
    color: var(--text-quaternary);
}

.dialog-field-hint {
    font-weight: 400;
    color: var(--text-quaternary);
}

.field-info {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--text-quaternary);
    color: #fff;
    font-family: Georgia, serif;
    font-size: 10px;
    font-style: italic;
    font-weight: 700;
    margin-left: 6px;
    position: relative;
    top: -1px;
    vertical-align: middle;
    user-select: none;
}

.field-info:hover {
    background: var(--text-secondary);
}

.field-info::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: #f5f5f7;
    color: #1d1d1f;
    border: 1px solid #d2d2d7;
    padding: 7px 11px;
    border-radius: 5px;
    font-size: 12px;
    font-style: normal;
    font-weight: 400;
    font-family: inherit;
    line-height: 1.45;
    white-space: normal;
    width: max-content;
    max-width: 260px;
    text-align: left;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.15s ease;
    z-index: 1000;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
}

.field-info:hover::after {
    opacity: 1;
    visibility: visible;
}

.dialog-card input {
    width: 100%;
    padding: 10px 12px;
    margin-bottom: 0;
    font-size: 14px;
    background: var(--bg-inset);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: var(--font-body);
    outline: none;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast), background var(--duration-fast);
}

.dialog-card input:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.12);
    background: var(--bg-input);
}

.dialog-card input::placeholder { color: var(--text-tertiary); }

.dialog-buttons {
    display: flex;
    gap: 8px;
}

.dialog-buttons .btn {
    flex: 1;
    padding: 9px 16px;
    font-size: 13px;
}

/* --- Spinner --- */
.spinner {
    border: 2px solid rgba(0, 0, 0, 0.06);
    border-radius: 50%;
    border-top: 2px solid var(--accent);
    width: 16px;
    height: 16px;
    animation: spin 0.8s linear infinite;
    display: inline-block;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.pulse {
    animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* --- Deployed count --- */
.deployed-count-text {
    font-size: 11px;
    color: var(--text-tertiary);
    margin: 0;
    padding: 0 16px;
}

/* --- Role-based visibility --- */
body:not(.role-admin) .admin-only { display: none !important; }
body.role-admin .non-admin-only { display: none !important; }

/* --- Login Overlay --- */
.login-overlay {
    position: fixed;
    inset: 0;
    background: var(--bg-window);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 200;
}

.login-card {
    width: 340px;
    padding: 32px;
    background: var(--bg-card);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-overlay);
}

.login-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-bottom: 24px;
}

.login-header h2 {
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
}

.login-logo {
    border-radius: var(--radius-md);
}

.login-submit-btn {
    width: 100%;
    padding: 10px 16px;
    font-size: 13px;
    margin-top: 4px;
}

.change-password-reason {
    font-size: 13px;
    color: var(--text-secondary);
    margin: 0 0 16px 0;
    text-align: center;
}

.login-error {
    font-size: 12px;
    color: var(--red);
    background: var(--red-subtle);
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    margin-bottom: 10px;
}

.login-success {
    font-size: 12px;
    color: var(--green);
    background: var(--green-subtle);
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    margin-bottom: 10px;
}

.error-text {
    font-size: 13px;
    color: var(--red);
    margin: 0;
    padding: 8px 0;
}

/* --- Current user label (legacy) --- */
.current-user-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    padding: 2px 8px;
    background: var(--bg-inset);
    border-radius: 10px;
}

/* Options grid inside deployment sidebar */

/* --- Login form reset --- */
#login-form {
    margin: 0;
    padding: 0;
}

/* --- User Management Panel (tabbed sidebar) --- */
.usermgmt-panel {
    position: relative;
    width: 520px;
    max-height: 80vh;
    display: flex;
    background: var(--bg-card);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-overlay);
    overflow: hidden;
}

.usermgmt-sidebar {
    width: 160px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    padding: 20px 10px;
    background: var(--bg-sidebar);
    border-right: 1px solid var(--border-hairline);
}

.usermgmt-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0 6px 14px;
}

.usermgmt-tab {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 10px;
    font-size: 12px;
    font-weight: 500;
    font-family: var(--font-body);
    color: var(--text-secondary);
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast);
    margin-bottom: 2px;
}

.usermgmt-tab:hover {
    background: var(--bg-row-hover);
    color: var(--text-primary);
}

.usermgmt-tab-active {
    background: var(--bg-card);
    color: var(--text-primary);
    font-weight: 600;
    box-shadow: var(--shadow-card);
}


.usermgmt-content {
    flex: 1;
    padding: 24px;
    overflow-y: auto;
    min-height: 300px;
}

.usermgmt-panel-heading {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 16px;
}

.usermgmt-tab-panel.hidden {
    display: none;
}

.users-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    overflow-y: auto;
}

.user-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    background: var(--bg-inset);
    border-radius: var(--radius-sm);
}

.user-name {
    flex: 1;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
}

.user-delete-btn {
    padding: 2px 6px !important;
    font-size: 14px !important;
}

.usermgmt-create-btn {
    width: 100%;
    margin-top: 6px;
}

/* Select inside usermgmt panel */
.usermgmt-content select,
.dialog-card select {
    width: 100%;
    padding: 10px 12px;
    padding-right: 36px;
    font-size: 13px;
    background: var(--bg-inset);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: var(--font-body);
    outline: none;
    cursor: pointer;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 12px;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast), background var(--duration-fast);
}

.usermgmt-content select:focus,
.dialog-card select:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.12);
    background: var(--bg-input);
}

/* Input styling inside usermgmt panel */
.usermgmt-content input {
    width: 100%;
    padding: 10px 12px;
    font-size: 13px;
    background: var(--bg-inset);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: var(--font-body);
    outline: none;
    transition: border-color var(--duration-fast), box-shadow var(--duration-fast), background var(--duration-fast);
}

.usermgmt-content input:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.12);
    background: var(--bg-input);
}

.usermgmt-content input::placeholder {
    color: var(--text-quaternary);
}


/* --- Profile info rows --- */
.profile-info-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px;
    background: var(--bg-inset);
    border-radius: var(--radius-sm);
    margin-bottom: 6px;
}

.profile-info-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
}

.profile-info-value {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

/* --- User row action buttons --- */
.user-chpw-btn {
    padding: 4px 6px !important;
    font-size: 12px !important;
    display: inline-flex;
    align-items: center;
}

/* --- Reset password panel --- */
.usermgmt-panel-heading-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 16px;
}

.usermgmt-panel-heading-row .usermgmt-panel-heading {
    margin: 0;
}

.resetpw-back-btn {
    padding: 4px !important;
    display: inline-flex;
    align-items: center;
}

.resetpw-info {
    font-size: 12px;
    color: var(--text-secondary);
    margin: 0 0 12px;
    line-height: 1.5;
}

.resetpw-password-box {
    background: var(--bg-inset);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
    font-size: 14px;
    font-family: var(--font-mono, monospace);
    color: var(--text-primary);
    word-break: break-all;
    user-select: all;
}

/* --- Utilities --- */
.hidden       { display: none !important; }
.rotate-180   { transform: rotate(180deg); }
.flex-shrink-0 { flex-shrink: 0; }

/* glass-card kept for dialog backward compat */
.glass-card {
    background: var(--bg-card);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

.glass-card-dark {
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.1);
}

/* --- Services Panel (top-right dropdown) --- */

.services-container {
    position: fixed;
    top: 10px;
    right: 12px;
    z-index: 50;
}

.services-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 11px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    box-shadow: var(--shadow-card);
    transition: background var(--duration-fast), color var(--duration-fast),
                border-color var(--duration-fast), box-shadow var(--duration-fast);
}

.services-btn:hover {
    background: var(--bg-row-hover);
    color: var(--text-primary);
    box-shadow: var(--shadow-card-hover);
}

.services-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    width: 270px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-overlay);
    overflow: hidden;
}

.services-panel-title {
    padding: 10px 14px 9px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-tertiary);
    border-bottom: 1px solid var(--border-hairline);
}

.service-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 14px;
}

.service-row + .service-row {
    border-top: 1px solid var(--border-hairline);
}

.app-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
    transition: background var(--duration-med);
}

.app-dot-running { background: var(--green); }
.app-dot-stopped { background: var(--text-quaternary); }

.service-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.service-name {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-primary);
}

.service-url {
    font-size: 10px;
    color: var(--text-tertiary);
    font-family: var(--font-mono);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    transition: color var(--duration-fast);
}

.service-url:hover {
    color: var(--accent);
    text-decoration: underline;
}

/* --- Load Balancer On/Off Button --- */
.lb-action-btn {
    font-family: var(--font-body);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 5px 14px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--duration-fast), color var(--duration-fast), border-color var(--duration-fast);
    white-space: nowrap;
    flex-shrink: 0;
}

.lb-action-btn.lb-stopped {
    background: var(--bg-input);
    color: var(--text-secondary);
    border: 1px solid var(--border-subtle);
}

.lb-action-btn.lb-stopped:hover {
    background: var(--green-subtle);
    color: var(--green);
    border-color: rgba(70, 167, 88, 0.35);
}

.lb-action-btn.lb-running {
    background: var(--green-subtle);
    color: var(--green);
    border: 1px solid rgba(70, 167, 88, 0.35);
}

.lb-action-btn.lb-running:hover {
    background: var(--red-subtle);
    color: var(--red);
    border-color: rgba(229, 72, 77, 0.35);
}

.remove-disk-warning {
    font-size: 12px;
    color: var(--text-tertiary);
    margin: 6px 0 16px;
}

/* Ensure model name still fills space when icon is present */
.model-chip-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Scrollbars --- */
::-webkit-scrollbar       { width: 6px; height: 6px; }
::-webkit-scrollbar-track  { background: transparent; }
::-webkit-scrollbar-thumb  { background: rgba(0, 0, 0, 0.12); border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.22); }

.list-scroll,
.machines-display,
.machines-grid,
.machines-grid-wrap,
.log-container {
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 0, 0, 0.12) transparent;
}

/* --- Load Balancer View --- */
.lb-view-content {
    flex: 1;
    padding: 24px;
    overflow-y: auto;
}

.lb-card {
    max-width: 480px;
    background: var(--bg-card);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    padding: 20px 24px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.lb-card-row {
    display: flex;
    align-items: flex-end;
    gap: 16px;
}

.lb-card-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.lb-card-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.lb-card-input {
    width: 120px;
    padding: 8px 10px;
    font-size: 13px;
    font-family: var(--font-mono);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-sm);
    background: var(--bg-input);
    color: var(--text-primary);
    outline: none;
    transition: border-color var(--duration-fast);
}

.lb-card-input:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.12);
}

.lb-card-desc {
    font-size: 12px;
    color: var(--text-tertiary);
    line-height: 1.5;
    margin: 0 0 12px 0;
}

.endpoint-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-sm);
    background: var(--bg-card);
    margin-bottom: 8px;
}

.endpoint-status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #4caf50;
    flex-shrink: 0;
}

.endpoint-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.endpoint-url {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-primary);
    word-break: break-all;
}

.endpoint-detail {
    font-size: 11px;
    color: var(--text-tertiary);
}

#endpoints-list {
    margin-top: 4px;
}

/* --- Stats View --- */
.stats-view-content {
    flex: 1;
    padding: 24px;
    overflow-y: auto;
    display: flex;
    gap: 20px;
    align-items: stretch;
}

.stats-col {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.stats-col-left {
    flex: 1 1 0;
    min-width: 0;
}

.stats-col-right {
    flex: 0 0 340px;
}

@media (max-width: 900px) {
    .stats-view-content {
        flex-direction: column;
    }

    .stats-col-right {
        flex: 0 0 auto;
    }
}

.stats-chart-card {
    position: relative;
    background: var(--bg-card);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    padding: 20px 24px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex: 1;
    min-height: 0;
}

.stats-chart-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.stats-chart-toggle {
    flex-shrink: 0;
}

.stats-chart-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
}


.stats-total-tokens-card {
    position: relative;
    background: var(--bg-card);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
    padding: 20px 24px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    flex: 1;
}

.stats-total-tokens-value {
    font-size: 48px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    letter-spacing: -1px;
    text-align: center;
}

.stats-pie-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin-top: 8px;
    position: relative;
}

.stats-pie-tooltip {
    position: absolute;
    pointer-events: none;
    background: rgba(255,255,255,0.95);
    border: 1px solid #ddd;
    border-radius: 6px;
    padding: 4px 10px;
    font-size: 12px;
    white-space: nowrap;
    box-shadow: 0 2px 6px rgba(0,0,0,0.1);
    z-index: 10;
}

.stats-pie-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px 16px;
    font-size: 12px;
    color: var(--text-secondary);
}

.stats-pie-legend-item {
    display: flex;
    align-items: center;
    gap: 6px;
}

.stats-pie-legend-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

.stats-chart-wrap {
    position: relative;
    width: 100%;
    overflow: hidden;
    flex: 1;
    min-height: 180px;
}

.stats-chart-wrap canvas:first-child {
    display: block;
    width: 100%;
}

.stats-chart-wrap canvas:last-child {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    pointer-events: none;
}

.chart-tooltip {
    position: absolute;
    pointer-events: none;
    background: var(--bg-card, #fff);
    border: 1px solid var(--border-hairline, #ddd);
    border-radius: 6px;
    box-shadow: 0 2px 8px rgba(0,0,0,.15);
    padding: 6px 10px;
    font-size: 11px;
    line-height: 1.5;
    color: var(--text-primary, #333);
    white-space: nowrap;
    z-index: 10;
    transform: translateX(-50%);
}

.chart-tooltip.hidden {
    display: none;
}

.chart-tooltip-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.chart-tooltip-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.stats-summary {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

.stats-summary-card {
    background: var(--bg-card);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-lg);
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.stats-summary-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.stats-summary-addr {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

.stats-summary-pct {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 600;
    color: var(--accent);
}

.stats-summary-detail {
    font-size: 12px;
    color: var(--text-tertiary);
}

/* =========================================================================
   Responsive
   ========================================================================= */

@media (max-width: 960px) {
    .deployment-layout {
        padding: 16px;
    }

    .machines-grid {
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
        padding: 16px;
    }
}

@media (max-width: 720px) {
    .dual-list-container {
        flex-direction: column;
        overflow: visible;
    }

    .list-panel {
        min-height: 180px;
        max-height: 300px;
    }

    .deploy-controls {
        flex-direction: row;
        align-self: stretch;
        justify-content: center;
        padding: 6px 0;
    }

    .deploy-settings {
        flex-direction: row;
        gap: 12px;
    }

    .deploy-arrow-btn {
        flex-direction: row;
        padding: 10px 20px;
        justify-content: center;
    }

    .deploy-arrow-btn .arrow-icon {
        font-size: 16px;
        transform: rotate(90deg);
    }

    .machines-grid {
        grid-template-columns: 1fr;
        padding: 12px;
        gap: 12px;
    }

    .view-header {
        padding: 12px 16px;
    }

    .machines-stats-bar {
        padding: 10px 16px;
        gap: 16px;
        flex-wrap: wrap;
    }

    .machines-list-mode .machine-full-card-header {
        min-width: 140px;
    }

    .deployment-layout {
        padding: 12px;
    }

    .lb-view-content {
        padding: 16px;
    }
}

@media (max-width: 520px) {
    .deployment-layout {
        padding: 10px;
    }

    .list-panel {
        min-height: 140px;
    }

    .view-title {
        font-size: 13px;
    }

    .view-header-right {
        gap: 4px;
    }

    .btn {
        font-size: 11px;
        padding: 6px 10px;
    }

    .machine-full-card-body {
        padding: 10px 12px;
    }

    .machine-config-preview {
        grid-template-columns: 1fr 1fr;
    }
}

/* ── Toast Notifications ── */

.toast-container {
    position: fixed;
    bottom: 24px;
    right: 16px;
    z-index: 10000;
    display: flex;
    flex-direction: column-reverse;
    align-items: flex-end;
    gap: 8px;
    pointer-events: none;
}

.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    min-width: 280px;
    max-width: 420px;
    padding: 12px 14px;
    border-radius: 8px;
    background: #ffffff;
    border: 1px solid #e0e0e0;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
    font-size: 13px;
    line-height: 1.4;
    color: #1a1a1a;
    opacity: 0;
    transform: translateY(20px);
    animation: toast-in 0.25s ease forwards;
}

.toast.toast-out {
    animation: toast-out 0.2s ease forwards;
}

.toast-icon {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin-top: 1px;
}

.toast-body {
    flex: 1;
    min-width: 0;
}

.toast-title {
    font-weight: 600;
    margin-bottom: 2px;
}

.toast-message {
    color: #555;
    word-break: break-word;
}

.toast-close {
    flex-shrink: 0;
    background: none;
    border: none;
    color: #999;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
    margin-top: -2px;
}

.toast-close:hover {
    color: #333;
}

.toast-error {
    border-color: #e74c3c;
    border-left: 3px solid #e74c3c;
}

.toast-error .toast-icon {
    color: #e74c3c;
}

.toast-warning {
    border-color: #f39c12;
    border-left: 3px solid #f39c12;
}

.toast-warning .toast-icon {
    color: #f39c12;
}

.toast-info {
    border-color: #3498db;
    border-left: 3px solid #3498db;
}

.toast-info .toast-icon {
    color: #3498db;
}

@keyframes toast-in {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes toast-out {
    to {
        opacity: 0;
        transform: translateY(20px);
    }
}
