/* =============================================================
   Network Inventory — stylesheet

   Custom properties at :root let you re-theme in one place.
   The orange accent is a placeholder you said could be tuned later.
   ============================================================= */

:root {
    /* Colors */
    --c-bg:           #ffffff;
    --c-bg-muted:     #f7f7f8;
    --c-bg-hover:     #eef0f3;
    --c-bg-active:    #e2e6eb;
    --c-border:       #e1e4e8;
    --c-border-strong:#c8ccd2;
    --c-text:         #1d2025;
    --c-text-muted:   #6a737d;
    --c-text-subtle:  #8a929c;
    --c-accent:       #e07a1f;        /* placeholder orange */
    --c-accent-hover: #c66a14;
    --c-danger:       #c43838;
    --c-success:      #2c8a3e;

    /* Typography */
    --font-ui:    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-mono:  "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
    --fs-sm:      0.85rem;
    --fs-base:    0.95rem;
    --fs-lg:      1.05rem;
    --fs-xl:      1.25rem;

    /* Spacing scale */
    --sp-1: 0.25rem;
    --sp-2: 0.5rem;
    --sp-3: 0.75rem;
    --sp-4: 1rem;
    --sp-5: 1.5rem;
    --sp-6: 2rem;

    /* Layout */
    --header-h:    52px;
    --tree-w:      400px;
    --radius:      6px;
    --shadow-sm:   0 1px 2px rgba(0,0,0,0.06);
    --shadow-md:   0 4px 12px rgba(0,0,0,0.08);
    --shadow-lg:   0 12px 32px rgba(0,0,0,0.18);
}

/* ===== Reset & base ===== */
*, *::before, *::after { box-sizing: border-box; }
html, body              { height: 100%; margin: 0; }
body {
    font-family: var(--font-ui);
    font-size:   var(--fs-base);
    color:       var(--c-text);
    background:  var(--c-bg);
    line-height: 1.45;
}

/* ===== Header ===== */
.app-header {
    height: var(--header-h);
    border-bottom: 1px solid var(--c-border);
    background: var(--c-bg);
    display: flex;
    align-items: center;
    padding: 0 var(--sp-4);
    gap: var(--sp-4);
}
.brand {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-weight: 600;
    font-size: var(--fs-lg);
}
.brand i { color: var(--c-accent); font-size: 1.25rem; }
.header-nav {
    margin-left: auto;
    display: flex;
    gap: var(--sp-4);
}
.header-nav a {
    color: var(--c-text-muted);
    text-decoration: none;
    font-size: var(--fs-sm);
}
.header-nav a:hover { color: var(--c-text); }

/* ===== Workspace (two-pane) ===== */
.workspace {
    display: grid;
    grid-template-columns: var(--tree-w) 4px 1fr;
    height: calc(100vh - var(--header-h));
}
.pane            { overflow: hidden; display: flex; flex-direction: column; }
.pane-tree       { background: var(--c-bg); }
.pane-details    { background: var(--c-bg-muted); padding: var(--sp-5); overflow: auto; }

/* The divider is 4px wide for a comfortable mouse hit target, but the
   visible line is just 1px in the middle — keeps the chrome quiet
   while still being easy to grab. Hover bumps the visible line so the
   draggable affordance is obvious. */
.pane-divider {
    background: transparent;
    cursor: col-resize;
    position: relative;
    user-select: none;
}
.pane-divider::before {
    content: '';
    position: absolute;
    top: 0; bottom: 0;
    left: 50%;
    width: 1px;
    margin-left: -0.5px;
    background: var(--c-border);
    transition: background 0.12s ease, width 0.12s ease, margin-left 0.12s ease;
}
.pane-divider:hover::before {
    width: 3px;
    margin-left: -1.5px;
    background: var(--c-accent, #ea580c);
}

/* ===== Tree pane ===== */
.pane-toolbar {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    padding: var(--sp-2) var(--sp-3);
    border-bottom: 1px solid var(--c-border);
    background: var(--c-bg);
}
.toolbar-spacer { flex: 1; }
.tree-filter {
    width: 140px;
    padding: 4px 8px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    font-size: var(--fs-sm);
    background: var(--c-bg);
}
.tree-filter:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; border-color: var(--c-accent); }
.tree-container {
    flex: 1;
    overflow: auto;
    padding: var(--sp-2) var(--sp-1);
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
}
.tree-loading {
    padding: var(--sp-4);
    color: var(--c-text-subtle);
    font-style: italic;
}

/* Tree nodes */
.tree-container ul {
    list-style: none;
    padding-left: 1.25rem;
    margin: 0;
}
.tree-container > ul { padding-left: 0.25rem; }
.tree-container li { line-height: 1.6; }

.node-row {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 1px 4px;
    border-radius: 4px;
    cursor: default;
    user-select: none;
}
.node-row:hover    { background: var(--c-bg-hover); }
.node-row.selected { background: var(--c-bg-active); }
.node-row .caret {
    width: 14px;
    text-align: center;
    color: var(--c-text-subtle);
    cursor: pointer;
    font-size: 0.75rem;
}
.node-row .caret.empty { visibility: hidden; }
.node-row .icon {
    color: var(--c-accent);
    font-size: 1rem;
    width: 1.1rem;
    text-align: center;
}
.node-row .label {
    padding-left: 2px;
    cursor: pointer;
}

/* Subtle position suffix for rack-mounted devices */
.node-row .rack-pos {
    margin-left: 0.6em;
    color: var(--c-text-subtle);
    font-size: 0.85em;
    font-style: normal;
}

/* Filter highlighting */
.node-row.filter-match .label    { background: rgba(224, 122, 31, 0.18); }
.node-row.filter-hidden          { display: none; }

/* ===== Details pane ===== */
.empty-state {
    color: var(--c-text-subtle);
    text-align: center;
    margin-top: 4rem;
}
.empty-state i { font-size: 3rem; display: block; margin-bottom: var(--sp-3); }

.details-card {
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--sp-4) var(--sp-5);
    box-shadow: var(--shadow-sm);
    /* Fill the right pane horizontally; on very wide screens cap so
       the data grid doesn't sprawl impractically wide. */
    width: 100%;
    max-width: 1200px;
    box-sizing: border-box;
}
.details-header {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--c-border);
}
.details-header .icon {
    color: var(--c-accent);
    font-size: 1.75rem;
}
.details-header h2 {
    margin: 0;
    font-size: var(--fs-xl);
    font-weight: 600;
}
.details-subtitle {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
    margin-top: 2px;
}
.details-actions {
    margin-left: auto;
    display: flex;
    gap: 4px;
    align-items: center;
}

/* Icon-only action buttons in the details header. Quiet by default,
   coloured on hover, with an emphasised primary and danger variant. */
.action-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid transparent;
    background: transparent;
    border-radius: var(--radius);
    color: var(--c-text-muted);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.action-btn i { font-size: 1.05rem; }
.action-btn:hover {
    background: var(--c-bg-hover);
    border-color: var(--c-border);
    color: var(--c-text);
}
.action-btn:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 1px;
}

.action-btn.is-primary {
    color: var(--c-accent);
}
.action-btn.is-primary:hover {
    background: rgba(224,122,31,0.10);
    border-color: rgba(224,122,31,0.35);
    color: var(--c-accent-hover);
}

.action-btn.is-danger {
    color: var(--c-danger);
}
.action-btn.is-danger:hover {
    background: rgba(196,56,56,0.08);
    border-color: rgba(196,56,56,0.30);
    color: var(--c-danger);
}

.details-grid {
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: var(--sp-5);
    row-gap: var(--sp-2);
    margin-bottom: var(--sp-4);
}
.details-grid dt {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
    font-weight: 500;
}
.details-grid dd {
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
}

/* ===== Buttons ===== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.45rem 0.9rem;
    border: 1px solid var(--c-border-strong);
    border-radius: var(--radius);
    background: var(--c-bg);
    color: var(--c-text);
    font: inherit;
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: background 0.1s, border-color 0.1s;
}
.btn:hover    { background: var(--c-bg-hover); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 1px;
}
.btn-primary {
    background: var(--c-accent);
    border-color: var(--c-accent);
    color: white;
}
.btn-primary:hover { background: var(--c-accent-hover); border-color: var(--c-accent-hover); }
.btn-secondary { /* uses default */ }
.btn-danger {
    background: var(--c-danger);
    border-color: var(--c-danger);
    color: white;
}
.btn-icon {
    padding: 0.35rem;
    width: 30px;
    height: 30px;
    border-color: transparent;
    background: transparent;
}
.btn-icon i { font-size: 1.1rem; }
.btn-icon:hover { background: var(--c-bg-hover); border-color: var(--c-border); }

/* ===== Modal (<dialog>) ===== */
.modal {
    border: none;
    border-radius: var(--radius);
    padding: 0;
    box-shadow: var(--shadow-lg);
    max-width: 480px;
    width: calc(100vw - 2rem);
}
.modal::backdrop { background: rgba(15, 18, 22, 0.55); }
.modal[open]     { animation: modal-in 120ms ease-out; }
@keyframes modal-in {
    from { transform: translateY(-12px); opacity: 0; }
    to   { transform: translateY(0);     opacity: 1; }
}
.modal-form     { display: flex; flex-direction: column; max-height: 85vh; }
.modal-header {
    display: flex;
    align-items: center;
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--c-border);
}
.modal-header h2 { margin: 0; font-size: var(--fs-lg); flex: 1; font-weight: 600; }
.modal-close { margin-left: auto; }
.modal-body  {
    padding: var(--sp-4);
    overflow-y: auto;
    flex: 1;
}
.modal-footer {
    padding: var(--sp-3) var(--sp-4);
    border-top: 1px solid var(--c-border);
    background: var(--c-bg-muted);
    border-bottom-left-radius: var(--radius);
    border-bottom-right-radius: var(--radius);
}
.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-2);
}
.modal-errors {
    color: var(--c-danger);
    font-size: var(--fs-sm);
    min-height: 1.2em;
    margin-bottom: var(--sp-2);
    white-space: pre-line;
}

/* ===== Form fields inside the modal ===== */
.field {
    display: block;
    margin-bottom: var(--sp-3);
}
.field-label {
    display: block;
    font-size: var(--fs-sm);
    font-weight: 600;
    margin-bottom: 4px;
    color: var(--c-text);
}
.field-label .req { color: var(--c-danger); margin-left: 2px; }
.field-input,
.field-select,
.field-textarea {
    width: 100%;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--c-border-strong);
    border-radius: var(--radius);
    font: inherit;
    font-size: var(--fs-base);
    background: var(--c-bg);
}
.field-input:focus,
.field-select:focus,
.field-textarea:focus {
    outline: 2px solid var(--c-accent);
    outline-offset: -1px;
    border-color: var(--c-accent);
}
.field-textarea  { resize: vertical; min-height: 4rem; font-family: var(--font-mono); }
.field-hint {
    margin-top: 4px;
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
}
.field-confirm {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-3);
    background: rgba(196, 56, 56, 0.06);
    border: 1px solid rgba(196, 56, 56, 0.2);
    border-radius: var(--radius);
}
.field-confirm input { margin-top: 3px; }
.field-confirm label { font-size: var(--fs-sm); }

/* ===== Context menu ===== */
.ctx-menu {
    position: fixed;
    z-index: 1000;
    min-width: 200px;
    background: var(--c-bg);
    border: 1px solid var(--c-border-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    padding: var(--sp-1) 0;
    font-size: var(--fs-sm);
}
.ctx-menu[aria-hidden="true"] { display: none; }
.ctx-menu-header {
    padding: var(--sp-2) var(--sp-3);
    color: var(--c-text-muted);
    font-weight: 500;
    border-bottom: 1px solid var(--c-border);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-1);
}
.ctx-menu-header i { color: var(--c-accent); }
.ctx-menu-item {
    padding: 6px 14px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--c-text);
    background: none;
    border: none;
    width: 100%;
    text-align: left;
    font: inherit;
}
.ctx-menu-item:hover,
.ctx-menu-item:focus {
    background: var(--c-bg-hover);
    outline: none;
}
.ctx-menu-item.danger { color: var(--c-danger); }
.ctx-menu-item i      { font-size: 1rem; color: var(--c-text-subtle); }
.ctx-menu hr {
    border: 0;
    border-top: 1px solid var(--c-border);
    margin: var(--sp-1) 0;
}

/* ===== Toast (for non-modal feedback) ===== */
.toast-region {
    position: fixed;
    bottom: var(--sp-4);
    right: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    z-index: 2000;
}
.toast {
    background: var(--c-text);
    color: white;
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    font-size: var(--fs-sm);
    animation: toast-in 200ms ease-out;
    max-width: 320px;
}
.toast.error   { background: var(--c-danger); }
.toast.success { background: var(--c-success); }
@keyframes toast-in {
    from { transform: translateY(8px); opacity: 0; }
    to   { transform: translateY(0);   opacity: 1; }
}

/* =============================================================
   Rack elevation visualization (SVG — rack_view.js)

   The SVG uses CSS classes rather than presentation attributes
   so the look can be themed alongside the rest of the app.
   Exported .svg files get a minimal inlined copy of these rules
   (see EXPORT_STYLES in rack_view.js).
   ============================================================= */

/* Side-by-side layout for rack details: info card (left) + diagram (right). */
.rack-layout {
    display: flex;
    gap: var(--sp-5);
    align-items: flex-start;
    flex-wrap: wrap;             /* wrap to stacked on narrow viewports */
}
.rack-layout-info {
    flex: 1 1 320px;
    min-width: 0;
}
.rack-layout-info .details-card {
    /* Inside the row, let the card size to its content instead of
       eating the viewport. */
    min-height: 0;
    max-width: none;
}
.rack-layout-viz {
    flex: 0 0 560px;
    max-width: 560px;
}

/* Legacy wrap (in case anything else mounts a rack view outside of the
   rack-layout row). Kept for backward compat. */
.rack-view-wrap {
    margin-top: var(--sp-5);
    max-width: 560px;
    margin-left: auto;
    margin-right: auto;
}

.rack-view-header {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-bottom: var(--sp-3);
}
.rack-view-title {
    flex: 1;
    font-weight: 600;
    color: var(--c-text);
    font-size: var(--fs-sm);
}

.rack-svg {
    display: block;
    width: 100%;
    height: auto;
}

/* Column chrome */
.rack-col-frame     { fill: var(--c-bg-muted); stroke: var(--c-border-strong); stroke-width: 1; }
.rack-col-header-bg { fill: var(--c-bg);       stroke: var(--c-border);        stroke-width: 1; }
.rack-col-header    { font-size: 12px; font-weight: 600; fill: var(--c-text-muted); }
.rack-slot-divider  { stroke: var(--c-border); stroke-dasharray: 2 2; }

/* U labels */
.rack-u-label {
    font-family: var(--font-mono);
    font-size: 10px;
    fill: var(--c-text-subtle);
}

/* Click targets over empty slots. Invisible by default; gently highlight
   on hover so users can see they're interactive. */
.rack-slot-target {
    fill: transparent;
    cursor: pointer;
    transition: fill 0.08s;
}
.rack-slot-target:hover { fill: rgba(224,122,31,0.08); }

/* Device rectangles */
.rack-device-bg {
    fill:   #f3c993;   /* accent-tinted */
    stroke: #d28a3e;
    stroke-width: 1;
    transition: stroke-width 0.08s, filter 0.08s;
}
.rack-device:hover .rack-device-bg {
    stroke-width: 1.5;
    filter: drop-shadow(0 1px 3px rgba(0,0,0,0.12));
}

.rack-device-span .rack-device-bg {
    fill:   #e0ccac;
    stroke: #b5996a;
    stroke-dasharray: 3 2;
}

.rack-device-host {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    fill: #5a3d1d;
    pointer-events: none;        /* let clicks fall through to the <g> */
}
.rack-device-model {
    font-family: var(--font-mono);
    font-size: 9px;
    fill: #7c5a30;
    pointer-events: none;
}

/* States */
.rack-view-loading,
.rack-view-error {
    padding: var(--sp-4);
    color: var(--c-text-subtle);
    text-align: center;
    font-size: var(--fs-sm);
}
.rack-view-error { color: var(--c-danger); }

/* =============================================================
   Trunks & strands (shown inside the details pane)
   ============================================================= */

.details-section {
    margin-top: var(--sp-5);
}
.details-section-title {
    margin: 0 0 var(--sp-3) 0;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.trunk-list, .strand-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--c-bg);
}

.trunk-row {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 8px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--c-border);
    transition: background 0.08s;
}
.trunk-row:last-child  { border-bottom: none; }
.trunk-row:hover       { background: var(--c-bg-hover); }
.trunk-row i           { color: var(--c-accent); flex-shrink: 0; }
.trunk-row-label       { font-weight: 500; flex-shrink: 0; }
.trunk-row-meta        {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
    margin-left: auto;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.strand-row {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: 6px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--c-border);
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    transition: background 0.08s;
}
.strand-row:last-child { border-bottom: none; }
.strand-row:hover      { background: var(--c-bg-hover); }
.strand-num {
    color: var(--c-text-muted);
    font-weight: 600;
    flex: 0 0 3em;
}
.strand-ends {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.strand-label {
    color: var(--c-text-subtle);
    font-style: italic;
    flex-shrink: 0;
}

/* =============================================================
   Circuit planner page (circuits.php + circuits.js)
   ============================================================= */

.circuits-page { max-width: 1100px; margin: 2rem auto; padding: 0 1rem; }
.circuits-toolbar h1 { margin: 0 0 0.4rem 0; font-size: 1.5rem; }
.circuits-intro {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
    margin: 0 0 var(--sp-5) 0;
    max-width: 60ch;
}

.circuits-form {
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--sp-4);
    margin-bottom: var(--sp-5);
}
.circuits-form-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)) auto;
    gap: var(--sp-3);
    align-items: end;
}
.circuits-form .field { margin-bottom: 0; }

.plan-error {
    color: var(--c-danger);
    min-height: 1.4em;
    margin-bottom: var(--sp-3);
    font-size: var(--fs-sm);
}
.plan-loading,
.plan-empty {
    color: var(--c-text-subtle);
    padding: var(--sp-4);
    text-align: center;
}
.plan-summary {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
    margin: 0 0 var(--sp-3) 0;
}

.path-card {
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: var(--sp-4);
    margin-bottom: var(--sp-4);
    box-shadow: var(--shadow-sm);
}
.path-card.path-incompatible { border-left: 3px solid var(--c-danger); }

.path-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-3);
    padding-bottom: var(--sp-2);
    border-bottom: 1px solid var(--c-border);
}
.path-n { font-weight: 600; }
.path-stat {
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
    background: var(--c-bg-muted);
    padding: 2px 10px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.path-stat i { font-size: 0.95em; }
.path-compat.ok  { background: rgba(44,138,62,0.12);  color: var(--c-success, #2c8a3e); }
.path-compat.bad { background: rgba(196,56,56,0.10);  color: var(--c-danger); }

.path-notes {
    margin: 0 0 var(--sp-3);
    padding-left: 1.2em;
    color: var(--c-danger);
    font-size: var(--fs-sm);
}

/* --- Path diagram: vertical node+edge flow ---

   Layout model: two CSS grid columns. The left column (40px) holds
   decoration — the vertical line connecting consecutive nodes. The right
   column holds the node cards and edge-descriptor chips. Nodes center on
   the line; edges are flanked by two short line segments (so the line
   stays continuous through the chip). This lets us put meaningful labels
   next to each edge without breaking the "flow" visual. */
.path-diagram {
    margin-top: var(--sp-3);
    display: flex;
    flex-direction: column;
}

.path-node {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
.path-node-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: rgba(224,122,31,0.10);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--c-accent);
    font-size: 1.4em;
}
.path-node-body {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.path-node-host {
    font-weight: 600;
    font-size: var(--fs-base);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.path-node-port {
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
}
.path-node-loc {
    font-size: 0.75rem;
    color: var(--c-text-subtle);
    margin-top: 2px;
}

/* The edge chip sits between two nodes. The line-segments on top and
   bottom connect visually to the nodes above/below. */
.path-edge {
    display: grid;
    grid-template-rows: 18px auto 18px;
    align-items: center;
    justify-items: center;
    min-height: 56px;
}
.path-edge-line {
    width: 2px;
    background: var(--c-border);
    height: 100%;
}
.path-edge-body {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 6px 12px;
    border-radius: 999px;
    background: var(--c-bg-muted);
    border: 1px solid var(--c-border);
    font-size: var(--fs-sm);
    max-width: 100%;
}
.path-edge-body i {
    color: var(--c-accent);
    flex-shrink: 0;
}
.path-edge-label {
    font-weight: 500;
    white-space: nowrap;
}
.path-edge-meta {
    color: var(--c-text-muted);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    white-space: nowrap;
}

/* Kind-specific tinting */
.path-edge.seg-patchable .path-edge-body {
    background: rgba(224, 122, 31, 0.08);
    border-color: rgba(224, 122, 31, 0.30);
}
.path-edge.seg-patchable .path-edge-body i { color: var(--c-accent); }

.path-edge.seg-cable .path-edge-body {
    background: rgba(44, 138, 62, 0.08);
    border-color: rgba(44, 138, 62, 0.25);
}
.path-edge.seg-cable .path-edge-body i { color: var(--c-success, #2c8a3e); }

.path-edge.seg-pass_through .path-edge-body {
    background: var(--c-bg-muted);
    opacity: 0.75;
}
.path-edge.seg-pass_through .path-edge-body i { color: var(--c-text-muted); }


/* Warning banner shown inside a details-card when something needs the
   user's attention (e.g. an under-populated trunk). */
.details-warning {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    margin-top: var(--sp-4);
    padding: var(--sp-3) var(--sp-4);
    background: rgba(224, 122, 31, 0.08);
    border-left: 3px solid var(--c-accent);
    border-radius: var(--radius);
    font-size: var(--fs-sm);
    color: var(--c-text);
}
.details-warning i {
    color: var(--c-accent);
    font-size: 1.2em;
    flex-shrink: 0;
    margin-top: 2px;
}
.details-warning em {
    font-style: normal;
    font-weight: 600;
    color: var(--c-accent);
}

/* --- Reserve path UI ---

   Sits below each path-diagram. Starts as a single primary button; when
   clicked, swaps in-place for an inline mini-form. */
.path-actions {
    margin-top: var(--sp-4);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--c-border);
    display: flex;
    gap: var(--sp-3);
    align-items: center;
    flex-wrap: wrap;
}
.path-card.path-reserved .path-diagram {
    opacity: 0.55;
    pointer-events: none;
}
.path-card.path-reserved .path-header {
    opacity: 0.7;
}

.reserve-form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-3);
    width: 100%;
}
.reserve-form label {
    display: flex;
    flex-direction: column;
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
    gap: 4px;
}
.reserve-form label.wide { grid-column: 1 / -1; }
.reserve-form input,
.reserve-form select {
    padding: 6px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    font: inherit;
}
.reserve-actions {
    grid-column: 1 / -1;
    display: flex;
    gap: var(--sp-2);
}
.reserve-error {
    grid-column: 1 / -1;
    color: var(--c-danger);
    font-size: var(--fs-sm);
    min-height: 1em;
}
.reserve-success {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--c-success, #2c8a3e);
    font-size: var(--fs-sm);
    padding: 8px 12px;
    background: rgba(44, 138, 62, 0.08);
    border: 1px solid rgba(44, 138, 62, 0.2);
    border-radius: var(--radius);
}
.reserve-success i { font-size: 1.2em; }

.btn-secondary {
    background: transparent;
    border: 1px solid var(--c-border);
    color: var(--c-text-muted);
    padding: 6px 14px;
    border-radius: var(--radius);
    cursor: pointer;
    font: inherit;
}
.btn-secondary:hover { background: var(--c-bg-muted); }

/* =============================================================
   Domain tab bar (Inventory / IPAM / VLANs / Circuits)

   Sits between the header and the main content. Each top-level
   domain has its own tab; click navigates to that page. The active
   tab is marked with a coloured underline and primary text.
   ============================================================= */

.domain-tabs {
    display: flex;
    align-items: stretch;
    gap: 0;
    padding: 0 var(--sp-4);
    background: var(--c-bg);
    border-bottom: 1px solid var(--c-border);
    overflow-x: auto;
}

.domain-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    color: var(--c-text-muted);
    text-decoration: none;
    font-size: var(--fs-sm);
    font-weight: 500;
    border-bottom: 2px solid transparent;
    transition: color 0.08s, border-color 0.08s, background 0.08s;
    white-space: nowrap;
}

.domain-tab i {
    font-size: 1em;
}

.domain-tab:hover {
    color: var(--c-text);
    background: var(--c-bg-hover);
}

.domain-tab.is-active {
    color: var(--c-accent);
    border-bottom-color: var(--c-accent);
}

.domain-tab.is-active:hover {
    background: transparent;
}

/* The shell's user-name label sits in the header-nav with
   muted styling and a small font; the link siblings inherit
   the existing header-nav rules. */
.header-user-label {
    color: var(--c-text-muted);
    font-size: var(--fs-sm);
}

/* =============================================================
   Stub pages (IPAM, VLANs, before they're built out)
   ============================================================= */

.stub-page {
    max-width: 700px;
    margin: 4rem auto;
    padding: 0 1rem;
}

.stub-card {
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    padding: 2rem 2.5rem;
    text-align: center;
}

.stub-card i {
    font-size: 2.5rem;
    color: var(--c-accent);
    margin-bottom: 1rem;
    display: inline-block;
}

.stub-card h1 {
    margin: 0 0 1rem;
    font-size: 1.6rem;
}

.stub-card p {
    color: var(--c-text-muted);
    line-height: 1.5;
    margin: 0 0 0.8rem;
}

.stub-card p.stub-meta {
    font-size: var(--fs-sm);
    color: var(--c-text-subtle);
    margin-top: 1.5rem;
    font-style: italic;
}

.stub-card code {
    background: var(--c-bg-muted);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 0.9em;
}

/* =============================================================
   IPAM tab — scopes + subnet trees
   ============================================================= */

.ipam-scope {
    margin-bottom: 4px;
}

.ipam-scope-head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    cursor: pointer;
    border-radius: var(--radius);
    user-select: none;
    font-weight: 500;
}
.ipam-scope-head:hover { background: var(--c-bg-hover); }

.ipam-scope-name { flex: 1; }

.ipam-scope-count {
    font-size: 0.75rem;
    background: var(--c-bg-muted);
    color: var(--c-text-muted);
    padding: 1px 8px;
    border-radius: 999px;
    font-weight: 500;
}

.ipam-icon {
    color: var(--c-accent);
    font-size: 1em;
}

.ipam-toggle {
    cursor: pointer;
    color: var(--c-text-subtle);
    width: 14px;
    text-align: center;
    flex-shrink: 0;
}
.ipam-toggle:hover { color: var(--c-text); }

.ipam-toggle-spacer {
    width: 14px;
    flex-shrink: 0;
}

.ipam-scope-body {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.ipam-empty-scope {
    padding: 8px 28px 12px 36px;
    color: var(--c-text-subtle);
    font-size: var(--fs-sm);
    display: flex;
    gap: 8px;
    align-items: center;
}

.link-btn {
    background: none;
    border: none;
    padding: 0;
    color: var(--c-accent);
    cursor: pointer;
    font: inherit;
    text-decoration: underline;
}

.ipam-subnet-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px 4px 4px;
    cursor: pointer;
    border-radius: var(--radius);
    user-select: none;
    font-size: var(--fs-sm);
}
.ipam-subnet-row:hover { background: var(--c-bg-hover); }
.ipam-subnet-row.is-selected {
    background: rgba(224, 122, 31, 0.10);
    color: var(--c-text);
}
.ipam-subnet-row.is-selected .ipam-icon { color: var(--c-accent); }

.ipam-prefix {
    font-family: var(--font-mono);
    font-weight: 500;
    flex-shrink: 0;
}

.ipam-desc {
    color: var(--c-text-muted);
    margin-left: 8px;
    font-size: 0.85em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ipam-role-badge {
    font-size: 0.7rem;
    background: rgba(224,122,31,0.10);
    color: var(--c-accent);
    padding: 1px 7px;
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
    flex-shrink: 0;
}

/* Child-subnet list inside subnet detail card */
.ipam-child-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.ipam-child-list li {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-radius: var(--radius);
    background: var(--c-bg);
    border: 1px solid var(--c-border);
}
.ipam-child-list li.muted {
    background: transparent;
    border: none;
    color: var(--c-text-subtle);
    font-style: italic;
}
.ipam-child-list a {
    font-family: var(--font-mono);
    font-weight: 500;
    color: var(--c-accent);
    text-decoration: none;
}
.ipam-child-list a:hover { text-decoration: underline; }
.ipam-child-desc {
    color: var(--c-text-muted);
    font-size: 0.85em;
    margin-left: auto;
}

/* =============================================================
   IPAM IP-assignment table
   ============================================================= */

.ipam-ip-loading {
    color: var(--c-text-subtle);
    padding: 8px 0;
    font-size: var(--fs-sm);
}

.ipam-ip-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    overflow: hidden;
    font-size: var(--fs-sm);
}
.ipam-ip-table th,
.ipam-ip-table td {
    padding: 8px 12px;
    text-align: left;
    border-bottom: 1px solid var(--c-border);
}
.ipam-ip-table tbody tr:last-child td { border-bottom: none; }
.ipam-ip-table th {
    background: var(--c-bg-muted);
    color: var(--c-text-muted);
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.ipam-ip-table tbody tr:hover { background: var(--c-bg-hover); }

.ipam-ip-table .ip-address {
    font-family: var(--font-mono);
    font-weight: 500;
    white-space: nowrap;
    /* IPv6 addresses are long. Keep the cell from collapsing the rest
       of the table by letting the address column dominate width. */
}

.ipam-ip-table .actions-col {
    width: 1%;
    white-space: nowrap;
    text-align: right;
}

.action-btn.small {
    width: 26px;
    height: 26px;
    padding: 0;
    font-size: 0.85rem;
}

/* Status pills */
.ipam-status {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.ipam-status.status-active     { background: rgba(44,138,62,0.12); color: var(--c-success, #2c8a3e); }
.ipam-status.status-reserved   { background: rgba(224,122,31,0.10); color: var(--c-accent); }
.ipam-status.status-deprecated { background: rgba(150,150,150,0.10); color: var(--c-text-subtle); }

.ipam-flag-gateway {
    display: inline-block;
    padding: 0 6px;
    border-radius: 4px;
    font-size: 0.65rem;
    font-weight: 700;
    background: rgba(224,122,31,0.15);
    color: var(--c-accent);
    margin-left: 6px;
    vertical-align: middle;
}

/* =============================================================
   VLANs tab — container → scope → VLAN tree
   ============================================================= */

.vlan-container-node { margin-bottom: 2px; }

.vlan-container-head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px 6px 4px;
    cursor: default;
    user-select: none;
    font-weight: 500;
    border-radius: var(--radius);
}
.vlan-container-head:hover { background: var(--c-bg-hover); }
.vlan-container-icon { color: var(--c-accent); font-size: 1em; }
.vlan-container-name { flex: 1; }

.vlan-toggle {
    cursor: pointer;
    color: var(--c-text-subtle);
    width: 14px;
    text-align: center;
    flex-shrink: 0;
}
.vlan-toggle:hover { color: var(--c-text); }

.vlan-scope-block { margin-bottom: 2px; }

.vlan-scope-head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px 4px 4px;
    cursor: pointer;
    user-select: none;
    border-radius: var(--radius);
    font-size: var(--fs-sm);
}
.vlan-scope-head:hover { background: var(--c-bg-hover); }
.vlan-scope-head.is-selected {
    background: rgba(224,122,31,0.10);
}
.vlan-scope-icon {
    color: var(--c-accent);
    font-size: 1em;
}
.vlan-scope-name { flex: 1; }
.vlan-scope-count {
    font-size: 0.75rem;
    background: var(--c-bg-muted);
    color: var(--c-text-muted);
    padding: 1px 8px;
    border-radius: 999px;
}

.vlan-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 12px 3px 4px;
    cursor: pointer;
    user-select: none;
    border-radius: var(--radius);
    font-size: var(--fs-sm);
}
.vlan-row:hover { background: var(--c-bg-hover); }
.vlan-row.is-selected {
    background: rgba(224,122,31,0.10);
}
.vlan-vid {
    font-family: var(--font-mono);
    font-weight: 600;
    min-width: 48px;
    color: var(--c-text);
}
.vlan-name {
    color: var(--c-text);
}
.vlan-desc {
    color: var(--c-text-muted);
    font-size: 0.85em;
    margin-left: 8px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vlan-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 3px;
    flex-shrink: 0;
    border: 1px solid var(--c-border);
}
.vlan-swatch-empty {
    background: transparent;
    border-color: var(--c-border);
    border-style: dashed;
}

.vlan-name-large {
    font-weight: 400;
    color: var(--c-text-muted);
    margin-left: 6px;
}

/* =============================================================
   Models tab — vendor groups → model list, components tree
   ============================================================= */

.models-vendor-block { margin-bottom: 4px; }

.models-vendor-head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    cursor: pointer;
    user-select: none;
    border-radius: var(--radius);
    font-weight: 500;
}
.models-vendor-head:hover { background: var(--c-bg-hover); }
.models-vendor-head.is-selected { background: rgba(224,122,31,0.10); }

.models-toggle {
    cursor: pointer;
    color: var(--c-text-subtle);
    width: 14px;
    text-align: center;
    flex-shrink: 0;
}
.models-toggle:hover { color: var(--c-text); }

.models-vendor-icon { color: var(--c-accent); font-size: 1em; }
.models-vendor-name { flex: 1; }

.models-count {
    font-size: 0.75rem;
    background: var(--c-bg-muted);
    color: var(--c-text-muted);
    padding: 1px 8px;
    border-radius: 999px;
    font-weight: 500;
}

.models-list {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.models-empty-vendor {
    padding: 8px 28px 12px 36px;
    color: var(--c-text-subtle);
    font-size: var(--fs-sm);
    display: flex;
    gap: 8px;
    align-items: center;
}

.models-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 12px 4px 48px;
    cursor: pointer;
    border-radius: var(--radius);
    user-select: none;
    font-size: var(--fs-sm);
}
.models-row:hover { background: var(--c-bg-hover); }
.models-row.is-selected { background: rgba(224,122,31,0.10); }

.models-icon { color: var(--c-accent); font-size: 1em; flex-shrink: 0; }
.models-name { font-weight: 500; flex-shrink: 0; }
.models-height {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    color: var(--c-text-muted);
    background: var(--c-bg-muted);
    padding: 1px 6px;
    border-radius: 4px;
    flex-shrink: 0;
}
.models-desc {
    color: var(--c-text-muted);
    font-size: 0.85em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-left: 4px;
}

/* Components tree on the model detail card */

.models-comp-list {
    list-style: none;
    padding: 0 0 0 1rem;
    margin: 0;
}
.models-comp-list .models-comp-list {
    border-left: 1px solid var(--c-border);
    margin-left: 8px;
    padding-left: 16px;
}

.comp-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px;
    font-size: var(--fs-sm);
    border-radius: var(--radius);
    transition: background 0.08s ease;
}
.comp-row:hover { background: var(--c-bg-hover); }
.comp-icon { color: var(--c-accent); font-size: 1em; flex-shrink: 0; }
.comp-type {
    font-size: 0.7rem;
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    min-width: 36px;
}
.comp-slot {
    font-family: var(--font-mono);
    font-weight: 500;
}
.comp-media {
    font-size: 0.7rem;
    color: var(--c-text-muted);
    background: var(--c-bg-muted);
    padding: 1px 6px;
    border-radius: 4px;
}
.comp-installed {
    font-size: 0.85em;
    color: var(--c-text-muted);
    font-style: italic;
}
.comp-accepts {
    font-size: 0.75rem;
    color: var(--c-text-muted);
    margin-left: 4px;
}

/* =============================================================
   Component row action buttons (Slice B)
   ============================================================= */

.details-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}

.details-section-actions {
    display: flex;
    gap: 4px;
}

.action-btn.xsmall {
    width: 22px;
    height: 22px;
    padding: 0;
    font-size: 0.75rem;
}

/* Push the per-row action cluster to the right edge of the comp row. */
.comp-actions {
    margin-left: auto;
    display: flex;
    gap: 2px;
    /* Hide the cluster until the row is hovered, so the table doesn't
       look like a battery of buttons at rest. */
    opacity: 0;
    transition: opacity 0.08s ease;
}
.comp-row:hover .comp-actions { opacity: 1; }

/* Always show on touch devices where hover doesn't apply. */
@media (hover: none) {
    .comp-actions { opacity: 1; }
}

/* Indent nested component lists so the hierarchy is visible. */
.models-comp-list .models-comp-list {
    margin-left: 24px;
    border-left: 1px dashed var(--c-border);
    padding-left: 12px;
}

/* =============================================================
   Per-type component visual differentiation (slot/module pivot)
   ============================================================= */

.comp-accepts-cat {
    font-size: 0.7rem;
    background: rgba(99, 102, 241, 0.10);
    color: #4c4eb8;
    padding: 1px 8px;
    border-radius: 4px;
    font-weight: 500;
    white-space: nowrap;
}

/* Subtle left-border tint per type, so the eye can scan slot/module/port
   without reading every label. */
.comp-row-slot   { border-left: 2px solid rgba(99, 102, 241, 0.4); padding-left: 8px; }
.comp-row-module { border-left: 2px solid rgba(34, 197, 94, 0.4);  padding-left: 8px; }
.comp-row-port   { border-left: 2px solid transparent;             padding-left: 8px; }

/* Icon tint follows the same hue. */
.comp-row-slot   .comp-icon { color: #6366f1; }
.comp-row-module .comp-icon { color: #22c55e; }

/* =============================================================
   Kind chip — used wherever device_models.kind or accepts_kind
   is displayed (model rows, model detail subtitle, etc.)
   ============================================================= */

.kind-chip {
    font-size: 0.7rem;
    background: rgba(34, 197, 94, 0.10);
    color: #1d8348;
    padding: 1px 8px;
    border-radius: 4px;
    font-weight: 500;
    white-space: nowrap;
}

/* =============================================================
   Module ports section — surfaces a filled slot's module ports
   inline so the operator can patch / unplug / edit them without
   drilling into module → port two layers down.
   ============================================================= */

.module-ports-section {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--c-border-subtle, #e5e7eb);
}

.module-ports-heading {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--c-text-subtle, #6b7280);
    margin: 0 0 8px 0;
}

.module-ports-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.module-port-row {
    display: grid;
    grid-template-columns: auto auto auto 1fr auto;
    gap: 10px;
    align-items: center;
    padding: 6px 8px;
    border-radius: 4px;
    background: var(--c-surface-subtle, #f9fafb);
}

.module-port-row:hover {
    background: var(--c-surface-hover, #f3f4f6);
}

.module-port-icon {
    color: var(--c-accent, #ea580c);
}

.module-port-label {
    font-weight: 500;
    font-family: var(--font-mono, ui-monospace, monospace);
}

.module-port-media {
    font-size: 0.75rem;
    color: var(--c-text-subtle, #6b7280);
}

.module-port-status {
    font-size: 0.875rem;
}

.module-port-actions {
    display: flex;
    gap: 4px;
}

.module-port-btn {
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-surface, #fff);
    color: var(--c-text, #111827);
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.module-port-btn:hover { background: var(--c-surface-hover, #f3f4f6); }
.module-port-btn.primary { border-color: var(--c-accent, #ea580c); color: var(--c-accent, #ea580c); }
.module-port-btn.primary:hover { background: rgba(234, 88, 12, 0.08); }
.module-port-btn.danger  { border-color: var(--c-danger, #dc2626); color: var(--c-danger, #dc2626); }
.module-port-btn.danger:hover  { background: rgba(220, 38, 38, 0.08); }

/* =============================================================
   Components tree — collapse / expand
   ============================================================= */

.comp-chevron {
    cursor: pointer;
    color: var(--c-text-subtle, #6b7280);
    width: 14px;
    text-align: center;
    flex-shrink: 0;
    user-select: none;
    transition: color 0.08s ease;
}
.comp-chevron:hover { color: var(--c-text, #111827); }

/* Spacer keeps the icon column aligned across rows that have
   children and rows that don't. Same width as the chevron, no
   visible glyph. */
.comp-chevron-spacer {
    width: 14px;
    flex-shrink: 0;
    visibility: hidden;
}

/* Collapsed state: hide the immediate child <ul> of the collapsed
   <li>. The double-arrow `> ul` ensures we only collapse one level —
   nested module-with-collapsed-module wouldn't accidentally hide
   grandchildren if their own <li> wasn't collapsed. */
.models-comp-list > li.is-collapsed > ul.models-comp-list {
    display: none;
}

/* Small grey chip showing how many children a collapsed module/slot
   hides. Helps the operator know "Front (24)" without expanding. */
.comp-child-count {
    font-size: 0.7rem;
    background: var(--c-bg-muted, #f3f4f6);
    color: var(--c-text-muted, #6b7280);
    padding: 1px 8px;
    border-radius: 999px;
    font-weight: 500;
}

/* =============================================================
   Multiselect field — VLAN picker (and future shared use)
   ============================================================= */

.field-multiselect {
    border: 1px solid var(--c-border, #d1d5db);
    border-radius: var(--radius, 4px);
    background: var(--c-bg, #fff);
    overflow: hidden;
}

.field-multiselect-search {
    width: 100%;
    box-sizing: border-box;
    border: none;
    border-bottom: 1px solid var(--c-border-subtle, #e5e7eb);
    border-radius: 0;
    padding: 8px 10px;
    font-size: 0.875rem;
    outline: none;
}
.field-multiselect-search:focus {
    border-bottom-color: var(--c-accent, #ea580c);
}

.field-multiselect-summary {
    padding: 6px 10px;
    font-size: 0.75rem;
    color: var(--c-text-subtle, #6b7280);
    background: var(--c-bg-muted, #f9fafb);
    border-bottom: 1px solid var(--c-border-subtle, #e5e7eb);
}

.field-multiselect-list {
    max-height: 280px;
    overflow-y: auto;
}

.field-multiselect-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    cursor: pointer;
    font-size: 0.875rem;
    border-bottom: 1px solid var(--c-border-subtle, #e5e7eb);
}
.field-multiselect-row:last-child { border-bottom: none; }
.field-multiselect-row:hover     { background: var(--c-bg-hover, #f3f4f6); }

.field-multiselect-empty {
    padding: 12px 10px;
    text-align: center;
    font-size: 0.875rem;
}

/* =============================================================
   Port detail — VLAN memberships section
   ============================================================= */

.port-vlan-section {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--c-border-subtle, #e5e7eb);
}

.port-vlan-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
}

.port-vlan-heading {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--c-text-subtle, #6b7280);
    margin: 0;
}

.port-vlan-add {
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
    color: var(--c-text, #111827);
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 0.75rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.port-vlan-add:hover { background: var(--c-bg-hover, #f3f4f6); }

.port-vlan-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.port-vlan-row {
    display: grid;
    grid-template-columns: auto auto 1fr auto auto;
    gap: 10px;
    align-items: center;
    padding: 6px 8px;
    border-radius: 4px;
    background: var(--c-bg-muted, #f9fafb);
}
.port-vlan-row:hover { background: var(--c-bg-hover, #f3f4f6); }

.port-vlan-mode {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 1px 8px;
    border-radius: 999px;
    font-weight: 600;
}
.port-vlan-row-access .port-vlan-mode {
    background: rgba(234, 88, 12, 0.10);
    color: #c2410c;
}
.port-vlan-row-tagged .port-vlan-mode {
    background: rgba(99, 102, 241, 0.10);
    color: #4338ca;
}

.port-vlan-vid {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.8rem;
    font-weight: 500;
}

.port-vlan-name { font-size: 0.875rem; }

.port-vlan-scope { font-size: 0.7rem; }

.port-vlan-remove {
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
    color: var(--c-danger, #dc2626);
    padding: 2px 6px;
    border-radius: 4px;
    cursor: pointer;
}
.port-vlan-remove:hover {
    background: rgba(220, 38, 38, 0.08);
}

/* =============================================================
   VLAN chips on tree port rows
   ============================================================= */

.vlan-chip {
    display: inline-flex;
    align-items: center;
    font-size: 0.65rem;
    font-weight: 600;
    font-family: var(--font-mono, ui-monospace, monospace);
    padding: 1px 6px;
    border-radius: 4px;
    margin-left: 4px;
    line-height: 1.4;
    white-space: nowrap;
    cursor: help;
}

.vlan-chip-access {
    background: rgba(234, 88, 12, 0.10);
    color: #c2410c;
}

.vlan-chip-tagged {
    background: rgba(99, 102, 241, 0.10);
    color: #4338ca;
}

/* =============================================================
   Settings dialog (lightweight — separate from Forms modal stack
   because app_shell.js can't depend on the Forms module)
   ============================================================= */

.settings-dialog-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 80px;
    z-index: 1100;  /* above Forms modal at 1000 if both open somehow */
}

.settings-dialog {
    background: var(--c-bg, #fff);
    border-radius: 8px;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.18);
    width: 480px;
    max-width: calc(100vw - 32px);
    max-height: calc(100vh - 120px);
    overflow: auto;
    display: flex;
    flex-direction: column;
}
.settings-dialog header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    border-bottom: 1px solid var(--c-border, #e1e4e8);
}
.settings-dialog h2 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
}
.settings-close {
    border: none;
    background: transparent;
    font-size: 1.6rem;
    line-height: 1;
    color: var(--c-text-subtle, #8a929c);
    cursor: pointer;
    padding: 0 4px;
}
.settings-close:hover { color: var(--c-text, #1d2025); }

.settings-body {
    padding: 16px 20px;
    flex: 1;
}
.settings-body section { margin-bottom: 20px; }
.settings-body section:last-child { margin-bottom: 0; }
.settings-body h3 {
    margin: 0 0 8px;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--c-text-subtle, #8a929c);
    font-weight: 600;
}
.settings-section-tag {
    display: inline-block;
    background: var(--c-bg-muted, #f7f7f8);
    color: var(--c-text-muted, #6a737d);
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 1px 6px;
    border-radius: 3px;
    margin-left: 6px;
    font-weight: 500;
}

.settings-field { margin-bottom: 12px; }
.settings-field > label {
    display: block;
    font-size: 0.85rem;
    font-weight: 500;
    margin-bottom: 6px;
}
.settings-radios {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.settings-radio {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.85rem;
}
.settings-radio:hover { background: var(--c-bg-hover, #eef0f3); }

.settings-hint {
    margin: 6px 0 0;
    font-size: 0.75rem;
    color: var(--c-text-subtle, #8a929c);
}

.settings-dialog footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 20px;
    border-top: 1px solid var(--c-border, #e1e4e8);
    background: var(--c-bg-muted, #f7f7f8);
}
.settings-btn {
    border: 1px solid var(--c-border-strong, #c8ccd2);
    background: var(--c-bg, #fff);
    color: var(--c-text, #1d2025);
    padding: 6px 14px;
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.85rem;
}
.settings-btn:hover { background: var(--c-bg-hover, #eef0f3); }

/* =============================================================
   VLAN tab — add-scope button on container rows
   ============================================================= */

.vlan-container-head {
    /* Already has display:flex/etc from existing styles; we only
       need to make room for the trailing button and reveal it on
       hover. */
    position: relative;
}

.vlan-container-add-scope {
    margin-left: auto;
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--c-text-subtle, #8a929c);
    padding: 2px 6px;
    border-radius: 3px;
    opacity: 0;
    transition: opacity 0.1s ease, background 0.1s ease;
    font-size: 0.9rem;
}
.vlan-container-head:hover .vlan-container-add-scope {
    opacity: 1;
}
.vlan-container-add-scope:hover {
    background: var(--c-bg-hover, #eef0f3);
    color: var(--c-text, #1d2025);
}

/* =============================================================
   IPAM — subnet utilization chips
   ============================================================= */

/* Make the description take available space so utilization can dock right. */
.ipam-subnet-row .ipam-desc {
    flex: 1 1 auto;
    min-width: 0;
}

.ipam-util {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    cursor: help;
    font-family: var(--font-mono);
    font-size: 0.7rem;
}

.ipam-util-bar {
    width: 70px;
    height: 6px;
    background: var(--c-bg-active, #e2e6eb);
    border-radius: 3px;
    overflow: hidden;
    flex-shrink: 0;
}

.ipam-util-bar-fill {
    display: block;
    height: 100%;
    border-radius: 3px;
    transition: width 0.2s ease;
}

.ipam-util-pct {
    min-width: 36px;
    text-align: right;
    font-weight: 500;
}

/* Three utilization tiers — colours follow the access/tagged
   convention to keep the IPAM tab visually consistent with VLAN chips
   in the inventory tree, while still being scannable. */
.ipam-util-low.ipam-util-bar-fill   { background: #16a34a; }   /* green */
.ipam-util-mid.ipam-util-bar-fill   { background: #d97706; }   /* amber */
.ipam-util-high.ipam-util-bar-fill  { background: #dc2626; }   /* red */
.ipam-util-low.ipam-util-pct        { color: var(--c-text-muted, #6a737d); }
.ipam-util-mid.ipam-util-pct        { color: #b45309; }
.ipam-util-high.ipam-util-pct       { color: #b91c1c; font-weight: 600; }

/* Worst-descendant hint — small chip pointing to the most-full child. */
.ipam-util-max {
    display: inline-flex;
    align-items: center;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 0.65rem;
    font-family: var(--font-mono);
    cursor: help;
}
.ipam-util-max.ipam-util-mid  { background: rgba(217, 119, 6, 0.10);  color: #b45309; }
.ipam-util-max.ipam-util-high { background: rgba(220, 38, 38, 0.10);  color: #b91c1c; font-weight: 600; }

/* v6 chip — count only, no bar. */
.ipam-util-v6 {
    background: var(--c-bg-muted, #f7f7f8);
    color: var(--c-text-muted, #6a737d);
    padding: 2px 8px;
    border-radius: 3px;
    font-size: 0.7rem;
    font-family: var(--font-mono);
}

.ipam-util-detail {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-mono);
    font-size: 0.8rem;
}

/* =============================================================
   Models tab — kind groups within vendors
   ============================================================= */

.models-kind-group {
    /* No background or border — visual hierarchy comes from the
       header style and indentation, not boxes. */
}

.models-kind-head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px 4px 24px;       /* indent under vendor row */
    cursor: pointer;
    user-select: none;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--c-text-subtle, #8a929c);
    font-weight: 600;
    border-radius: var(--radius);
}
.models-kind-head:hover {
    background: var(--c-bg-hover, #eef0f3);
    color: var(--c-text-muted, #6a737d);
}

.models-kind-toggle {
    width: 14px;
    text-align: center;
    flex-shrink: 0;
    color: var(--c-text-subtle, #8a929c);
}

.models-kind-name {
    font-family: var(--font-mono, ui-monospace, monospace);
}

.models-kind-count {
    margin-left: 4px;
    font-family: var(--font-mono, ui-monospace, monospace);
    background: var(--c-bg-muted, #f7f7f8);
    color: var(--c-text-muted, #6a737d);
    padding: 0 6px;
    border-radius: 999px;
    font-size: 0.65rem;
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
}

/* Indent model rows under their kind group. */
.models-kind-group .models-row {
    padding-left: 56px;
}

/* =============================================================
   Attribute sections on detail cards (devices and components)
   ============================================================= */

.attr-section {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--c-border-subtle, #e5e7eb);
}

.attr-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
}

.attr-heading {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--c-text-subtle, #6b7280);
    margin: 0;
}

.attr-add {
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
    color: var(--c-text, #111827);
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 0.75rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.attr-add:hover { background: var(--c-bg-hover, #f3f4f6); }

.attr-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.attr-row {
    display: grid;
    grid-template-columns: 160px 1fr auto auto;
    gap: 10px;
    align-items: center;
    padding: 6px 10px;
    border-radius: 4px;
    background: var(--c-bg-muted, #f9fafb);
}
.attr-row:hover { background: var(--c-bg-hover, #f3f4f6); }

.attr-key {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--c-text, #1d2025);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.attr-value {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.8rem;
    color: var(--c-text-muted, #6a737d);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.attr-edit, .attr-remove {
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
    padding: 2px 6px;
    border-radius: 4px;
    cursor: pointer;
    color: var(--c-text-muted, #6b7280);
}
.attr-edit:hover  { background: var(--c-bg-hover, #f3f4f6); color: var(--c-text, #1d2025); }
.attr-remove:hover { background: rgba(220, 38, 38, 0.08); color: var(--c-danger, #dc2626); }

.field-input-readonly {
    background: var(--c-bg-muted, #f9fafb);
    color: var(--c-text-muted, #6a737d);
    cursor: not-allowed;
}

/* =============================================================
   Settings → Device kinds admin
   ============================================================= */

.kinds-table {
    margin-top: 12px;
}

.kinds-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.kind-row {
    display: grid;
    grid-template-columns: 36px 1fr auto;
    gap: 10px;
    align-items: center;
    padding: 6px 8px;
    border-radius: 4px;
    background: var(--c-bg-muted, #f7f7f8);
}
.kind-row:hover { background: var(--c-bg-hover, #eef0f3); }

.kind-row.is-missing {
    background: rgba(217, 119, 6, 0.08);
    border-left: 3px solid #d97706;
    padding-left: 5px;
}

.kind-icon-btn {
    background: var(--c-bg, #fff);
    border: 1px solid var(--c-border, #d1d5db);
    border-radius: 4px;
    width: 36px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--c-text, #1d2025);
    font-size: 1.1rem;
}
.kind-icon-btn:hover {
    background: var(--c-bg-hover, #eef0f3);
    border-color: var(--c-accent, #ea580c);
}

.kind-meta {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.kind-name {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.85rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kind-usage {
    font-size: 0.7rem;
}

.kind-actions {
    display: flex;
    gap: 4px;
}

.kind-edit {
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
    color: var(--c-text-muted, #6b7280);
    padding: 2px 6px;
    border-radius: 4px;
    cursor: pointer;
}
.kind-edit:hover {
    background: var(--c-bg-hover, #eef0f3);
    color: var(--c-text, #1d2025);
}

/* =============================================================
   Icon picker (modal-on-modal, opened from kind row)
   ============================================================= */

.icon-picker-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 60px;
    z-index: 1200;  /* above settings dialog (1100) */
}

.icon-picker-dialog {
    background: var(--c-bg, #fff);
    border-radius: 8px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.25);
    width: 640px;
    max-width: calc(100vw - 32px);
    max-height: calc(100vh - 100px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.icon-picker-dialog header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--c-border, #e1e4e8);
}
.icon-picker-dialog h3 {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}
.icon-picker-close {
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--c-text-subtle, #8a929c);
    padding: 0 4px;
}
.icon-picker-close:hover { color: var(--c-text, #1d2025); }

.icon-picker-body {
    flex: 1;
    overflow: auto;
    padding: 16px 18px;
}

.icon-picker-search-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
}

.icon-picker-search { flex: 1; }

.icon-picker-current {
    font-size: 0.8rem;
    color: var(--c-text-muted, #6a737d);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.icon-picker-current i {
    font-size: 1.2rem;
    color: var(--c-text, #1d2025);
}

.icon-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 6px;
}

.icon-picker-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 6px;
    border: 1px solid var(--c-border-subtle, #e5e7eb);
    background: var(--c-bg, #fff);
    border-radius: 6px;
    cursor: pointer;
    text-align: center;
}
.icon-picker-tile i {
    font-size: 1.5rem;
    color: var(--c-text, #1d2025);
}
.icon-picker-tile span {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.65rem;
    color: var(--c-text-muted, #6a737d);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}
.icon-picker-tile:hover {
    border-color: var(--c-accent, #ea580c);
    background: var(--c-bg-hover, #eef0f3);
}
.icon-picker-tile.is-selected {
    border-color: var(--c-accent, #ea580c);
    background: rgba(234, 88, 12, 0.08);
}
.icon-picker-tile.is-selected i { color: var(--c-accent, #ea580c); }

.icon-picker-hint {
    margin-top: 14px;
    font-size: 0.75rem;
}
.icon-picker-hint code {
    background: var(--c-bg-muted, #f7f7f8);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 0.8em;
}

.role-badge-bootstrap {
    display: inline-block;
    margin-left: 4px;
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--c-bg-muted, #f7f7f8);
    color: var(--c-text-muted, #6a737d);
    border: 1px solid var(--c-border-subtle, #e5e7eb);
    font-weight: 500;
    cursor: help;
}

.ipam-util-aggregate-tag {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 0.65rem;
    font-family: var(--font-mono, ui-monospace, monospace);
    background: var(--c-bg-muted, #f7f7f8);
    color: var(--c-text-muted, #6a737d);
    border: 1px solid var(--c-border-subtle, #e5e7eb);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* =============================================================
   Inventory picker (port / device picker modal)

   Uses native <dialog> so it renders in the browser's top layer,
   above the Forms <dialog>. ::backdrop styles the overlay; <dialog>
   centers itself by default.
   ============================================================= */

.picker-dialog {
    /* Override default <dialog> styling — borderless, custom shadow. */
    border: none;
    padding: 0;
    background: var(--c-bg, #fff);
    border-radius: 8px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.25);
    width: 540px;
    max-width: calc(100vw - 32px);
    max-height: calc(100vh - 100px);
    overflow: hidden;
}
.picker-dialog[open] {
    display: flex;
    flex-direction: column;
}
.picker-dialog::backdrop {
    background: rgba(0, 0, 0, 0.5);
}

.picker-dialog header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--c-border, #e1e4e8);
    flex: 0 0 auto;
}
.picker-dialog header h3 {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}
.picker-close {
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--c-text-subtle, #8a929c);
    padding: 0 4px;
}
.picker-close:hover { color: var(--c-text, #1d2025); }

/* Body grows with content; scroll only if content exceeds the
   dialog's max-height. flex: 1 1 auto + min-height: 0 lets the
   body grow up to the dialog's max-height while still allowing
   inner overflow scroll if needed. The earlier "flex: 1" alone
   collapsed the body to zero in dialogs sized to content. */
.picker-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.picker-level {
    display: grid;
    grid-template-columns: 100px 1fr auto;
    gap: 10px;
    align-items: center;
}

.picker-level-label {
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--c-text-muted, #6a737d);
}

.picker-select {
    padding: 6px 8px;
    border: 1px solid var(--c-border, #d1d5db);
    border-radius: 4px;
    background: var(--c-bg, #fff);
    font-size: 0.85rem;
    font-family: var(--font-base, system-ui);
}
.picker-select:disabled {
    background: var(--c-bg-muted, #f7f7f8);
    color: var(--c-text-muted, #6a737d);
}

.picker-level-change {
    border: none;
    background: transparent;
    color: var(--c-accent, #ea580c);
    font-size: 0.75rem;
    cursor: pointer;
    padding: 4px 6px;
}
.picker-level-change:hover { text-decoration: underline; }

.picker-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 12px 18px;
    border-top: 1px solid var(--c-border, #e1e4e8);
    background: var(--c-bg-muted, #f7f7f8);
}

.picker-summary {
    flex: 1;
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.75rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.picker-footer-actions {
    display: flex;
    gap: 8px;
}

.picker-cancel, .picker-confirm {
    padding: 6px 14px;
    border-radius: 4px;
    font-size: 0.85rem;
    cursor: pointer;
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
}
.picker-cancel:hover { background: var(--c-bg-hover, #eef0f3); }

.picker-confirm {
    background: var(--c-accent, #ea580c);
    color: white;
    border-color: var(--c-accent, #ea580c);
    font-weight: 500;
}
.picker-confirm:hover { background: var(--c-accent-hover, #c2410c); }
.picker-confirm:disabled {
    background: var(--c-bg-muted, #f7f7f8);
    color: var(--c-text-muted, #6a737d);
    border-color: var(--c-border-subtle, #e5e7eb);
    cursor: not-allowed;
}

/* =============================================================
   Picker field (used inside a form)
   ============================================================= */

.field-picker-summary {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.85rem;
    color: var(--c-text-muted, #6a737d);
    background: var(--c-bg-muted, #f7f7f8);
    padding: 6px 10px;
    border-radius: 4px;
    margin-bottom: 6px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.field-picker-summary-filled {
    color: var(--c-text, #1d2025);
    background: rgba(234, 88, 12, 0.06);
}

.field-picker-btn {
    padding: 6px 14px;
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.85rem;
}
.field-picker-btn:hover {
    background: var(--c-bg-hover, #eef0f3);
    border-color: var(--c-accent, #ea580c);
}

.picker-origin-banner {
    padding: 10px 18px;
    background: rgba(234, 88, 12, 0.06);
    border-bottom: 1px solid var(--c-border-subtle, #e5e7eb);
    font-size: 0.8rem;
}
.picker-origin-crumb {
    font-family: var(--font-mono, ui-monospace, monospace);
    color: var(--c-text, #1d2025);
}

/* =============================================================
   IP addresses section on device/port detail cards
   ============================================================= */

.ip-section {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--c-border-subtle, #e5e7eb);
}

.ip-list-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8rem;
}
.ip-list-table th,
.ip-list-table td {
    padding: 6px 8px;
    text-align: left;
    border-bottom: 1px solid var(--c-border-subtle, #eef0f3);
    vertical-align: middle;
}
.ip-list-table tbody tr:last-child td { border-bottom: none; }
.ip-list-table th {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--c-text-subtle, #8a929c);
    font-weight: 600;
    background: var(--c-bg-muted, #f7f7f8);
}
.ip-list-table .mono {
    font-family: var(--font-mono, ui-monospace, monospace);
}
.ip-list-table .muted {
    color: var(--c-text-muted, #6a737d);
}

.ip-gw-badge {
    display: inline-block;
    margin-left: 4px;
    padding: 0 4px;
    border-radius: 3px;
    font-size: 0.6rem;
    font-weight: 600;
    background: rgba(217, 119, 6, 0.15);
    color: #b45309;
    letter-spacing: 0.05em;
}

.ip-status {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.7rem;
    font-family: var(--font-mono, ui-monospace, monospace);
}
.ip-status-active     { background: rgba(22, 163, 74, 0.10); color: #166534; }
.ip-status-reserved   { background: rgba(217, 119, 6, 0.10); color: #b45309; }
.ip-status-deprecated { background: rgba(107, 114, 128, 0.12); color: var(--c-text-muted, #6a737d); }

/* =============================================================
   Inline warning banner shown at the top of a form body
   ============================================================= */
.form-warning-banner {
    background: rgba(217, 119, 6, 0.10);
    border: 1px solid rgba(217, 119, 6, 0.35);
    border-radius: 4px;
    padding: 10px 12px;
    margin-bottom: 12px;
    font-size: 0.85rem;
    color: #7c2d12;
    line-height: 1.4;
}
.form-warning-banner strong {
    color: #b45309;
    font-weight: 600;
}

/* =============================================================
   Import catalogue dialog
   ============================================================= */
.import-dialog {
    border: none;
    padding: 0;
    background: var(--c-bg, #fff);
    border-radius: 8px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.25);
    width: 480px;
    max-width: calc(100vw - 32px);
    max-height: calc(100vh - 100px);
    overflow: hidden;
}
.import-dialog[open] {
    display: flex;
    flex-direction: column;
}
.import-dialog::backdrop {
    background: rgba(0, 0, 0, 0.5);
}
.import-dialog header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--c-border, #e1e4e8);
}
.import-dialog header h3 {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}
.import-close {
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--c-text-subtle, #8a929c);
    padding: 0 4px;
}
.import-close:hover { color: var(--c-text, #1d2025); }

.import-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: 16px 18px;
}
.import-body code {
    background: var(--c-bg-muted, #f7f7f8);
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 0.85em;
}

.import-report {
    margin: 14px 0;
    padding: 12px;
    background: var(--c-bg-muted, #f7f7f8);
    border-radius: 4px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.import-report-line {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 0.85rem;
}
.import-report-label {
    font-weight: 500;
    color: var(--c-text, #1d2025);
}
.import-report-counts {
    display: flex;
    gap: 8px;
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.75rem;
}
.import-count-create { color: #166534; }
.import-count-update { color: #b45309; }
.import-count-skip   { color: var(--c-text-muted, #6a737d); }

.import-errors {
    margin-top: 10px;
    padding: 8px 12px;
    background: rgba(217, 119, 6, 0.08);
    border-left: 3px solid #d97706;
    border-radius: 3px;
    font-size: 0.8rem;
}
.import-errors ul {
    margin: 4px 0 0 0;
    padding-left: 18px;
}

.import-overwrite {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 12px;
    font-size: 0.9rem;
    cursor: pointer;
}
#import-overwrite-hint {
    font-size: 0.75rem;
    margin: 4px 0 0 24px;
}

.import-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 18px;
    border-top: 1px solid var(--c-border, #e1e4e8);
    background: var(--c-bg-muted, #f7f7f8);
}
.import-cancel, .import-confirm {
    padding: 6px 14px;
    border-radius: 4px;
    font-size: 0.85rem;
    cursor: pointer;
    border: 1px solid var(--c-border, #d1d5db);
    background: var(--c-bg, #fff);
}
.import-cancel:hover { background: var(--c-bg-hover, #eef0f3); }
.import-confirm {
    background: var(--c-accent, #ea580c);
    color: white;
    border-color: var(--c-accent, #ea580c);
    font-weight: 500;
}
.import-confirm:hover { background: var(--c-accent-hover, #c2410c); }

/* =============================================================
   Rack view: device with an inlined model SVG
   ============================================================= */

/* When an SVG is present, dim the frame slightly so the drawing
   stands out. Fallback (no SVG) keeps the current strong background. */
.rack-device-bg-svg {
    fill: rgba(255,255,255,0.02);
    stroke: var(--c-border-subtle, #e5e7eb);
}

/* Hostname text is drawn over the SVG for identification — give it
   a subtle backdrop so it stays readable against colourful drawings. */
.rack-device-host-overlay {
    paint-order: stroke;
    stroke: rgba(255,255,255,0.9);
    stroke-width: 3px;
    stroke-linejoin: round;
}

/* File input styling — keep the native picker but match the form's
   spacing. Some browsers render this awkwardly by default. */
.field-input-file {
    padding: 4px 0;
    font-size: 0.85rem;
}

/* =============================================================
   Model SVG builder — full-screen overlay editor
   ============================================================= */

.svgb-overlay {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: var(--c-bg, #fafbfc);
    display: flex;
    flex-direction: column;
    font-family: system-ui, -apple-system, sans-serif;
}

.svgb-titlebar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 16px;
    border-bottom: 1px solid var(--c-border, #d0d7de);
    background: var(--c-bg-elev, #fff);
    flex: 0 0 auto;
}

.svgb-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--c-text, #24292f);
}

.svgb-titlebar-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}

.svgb-btn {
    padding: 6px 12px;
    border: 1px solid var(--c-border, #d0d7de);
    background: var(--c-bg-elev, #fff);
    color: var(--c-text, #24292f);
    border-radius: 6px;
    font-size: 13px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.svgb-btn:hover:not(:disabled) {
    background: var(--c-bg, #f6f8fa);
}
.svgb-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.svgb-btn-ghost {
    border: none;
    background: transparent;
    padding: 6px 8px;
}
.svgb-btn-primary {
    background: var(--c-accent, #0969da);
    color: white;
    border-color: var(--c-accent, #0969da);
}
.svgb-btn-primary:hover:not(:disabled) {
    background: var(--c-accent-hover, #0860c7);
}

.svgb-body {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
}

/* --- Left sidebar: port chip list --- */

.svgb-sidebar {
    flex: 0 0 260px;
    border-right: 1px solid var(--c-border, #d0d7de);
    background: var(--c-bg-elev, #fff);
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.svgb-sidebar-head {
    padding: 12px 14px 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--c-text, #24292f);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.svgb-sidebar-hint {
    padding: 0 14px 10px;
    font-size: 11px;
    color: var(--c-text-muted, #656d76);
    line-height: 1.4;
}

.svgb-chips {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 4px 8px 8px;
}

.svgb-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    margin-bottom: 3px;
    border: 1px solid var(--c-border, #d0d7de);
    border-radius: 4px;
    background: var(--c-bg-elev, #fff);
    cursor: grab;
    font-size: 12px;
    user-select: none;
}
.svgb-chip:hover {
    border-color: var(--c-accent, #0969da);
    background: var(--c-bg-accent-subtle, #ddf4ff);
}
.svgb-chip:active {
    cursor: grabbing;
}
.svgb-chip-placed {
    opacity: 0.5;
}
.svgb-chip-placed:hover {
    opacity: 0.8;
}

.svgb-chip-dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #6a737d;
}
.svgb-chip-dot[data-media="copper"]      { background: #3fb950; }
.svgb-chip-dot[data-media="fibre"]       { background: #e6a23c; }
.svgb-chip-dot[data-media="transceiver"] { background: #0969da; }

.svgb-chip-label {
    flex: 1 1 auto;
    font-family: monospace, monospace;
    font-size: 11px;
    color: var(--c-text, #24292f);
}
.svgb-chip-media {
    flex: 0 0 auto;
    font-size: 10px;
    color: var(--c-text-muted, #656d76);
    text-transform: uppercase;
}

/* --- Center: canvas + info + props panel --- */

.svgb-canvas-wrap {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--c-bg, #fafbfc);
}

.svgb-canvas-info {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 6px 12px;
    font-size: 11px;
    color: var(--c-text-muted, #656d76);
    border-bottom: 1px solid var(--c-border-subtle, #eaeef2);
    background: var(--c-bg-elev, #fff);
    flex: 0 0 auto;
    font-family: monospace, monospace;
}
.svgb-cursor-pos {
    font-variant-numeric: tabular-nums;
}

.svgb-canvas-scroll {
    flex: 1 1 auto;
    overflow: auto;
    padding: 24px;
    display: flex;
    align-items: flex-start;
    justify-content: center;
}

.svgb-canvas {
    width: 100%;
    max-width: 1200px;
    height: auto;
    background: transparent;
    border: 1px dashed var(--c-border, #d0d7de);
}

.svgb-grid circle {
    opacity: 0.5;
}

/* Port group on canvas — hover + selected states */
.svgb-port {
    cursor: move;
}
.svgb-port:hover rect {
    stroke: var(--c-accent, #0969da);
    stroke-width: 1.2 !important;
}
.svgb-port-selected rect {
    stroke: var(--c-accent, #0969da) !important;
    stroke-width: 1.5 !important;
}

.svgb-props {
    flex: 0 0 auto;
    padding: 12px 16px;
    border-top: 1px solid var(--c-border, #d0d7de);
    background: var(--c-bg-elev, #fff);
    min-height: 100px;
    max-height: 200px;
    overflow: auto;
}

.svgb-props-placeholder {
    color: var(--c-text-muted, #656d76);
    font-size: 12px;
    font-style: italic;
}

.svgb-props-grid {
    display: grid;
    grid-template-columns: 90px 1fr;
    gap: 4px 12px;
    font-size: 12px;
    margin: 0 0 10px;
}
.svgb-props-grid dt {
    color: var(--c-text-muted, #656d76);
    font-weight: 500;
}
.svgb-props-grid dd {
    margin: 0;
    font-family: monospace, monospace;
    color: var(--c-text, #24292f);
}

.svgb-props-actions {
    margin-bottom: 6px;
}
.svgb-props-hint {
    font-size: 11px;
    color: var(--c-text-muted, #656d76);
    margin: 0;
}

/* =============================================================
   SVG builder: chassis colour picker
   ============================================================= */

.svgb-chassis-picker {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--c-border-subtle, #e5e7eb);
}

.svgb-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
}

.svgb-swatch {
    width: 28px;
    height: 28px;
    border-radius: 4px;
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
    display: inline-block;
    box-shadow: 0 0 0 1px rgba(0,0,0,0.1) inset;
    transition: transform 0.08s;
}
.svgb-swatch:hover {
    transform: scale(1.08);
}
.svgb-swatch.active {
    border-color: #4a9eff;
    box-shadow: 0 0 0 1px #4a9eff, 0 0 0 1px rgba(0,0,0,0.1) inset;
}

/* The "custom colour" swatch is a label containing an <input type=color>.
   Style the label to match a regular swatch, and hide the input's native
   chrome so only our square shows. Native colour dialog opens on click. */
.svgb-swatch-custom {
    position: relative;
    overflow: hidden;
    background: conic-gradient(
        from 0deg,
        #ff0000, #ffff00, #00ff00, #00ffff,
        #0000ff, #ff00ff, #ff0000
    );
}
.svgb-swatch-custom input[type="color"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    border: 0;
    padding: 0;
    cursor: pointer;
}

/* =============================================================
   Cable detail: chain diagram
   ============================================================= */

.cable-chain {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--c-border-subtle, #e5e7eb);
}
.cable-chain-svg {
    display: block;
    width: 100%;
    max-width: 640px;
    margin: 8px auto 0;
    height: auto;
}

/* =============================================================
   Detail section: inline "add" action button next to the title.
   Used by VLAN detail's "Attach subnet" link and similar
   in-section CRUD entry points.
   ============================================================= */

.details-section-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.details-section-add {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    font-size: 0.8em;
    background: transparent;
    border: 1px solid var(--c-border-subtle, #e5e7eb);
    border-radius: 4px;
    color: var(--c-text-muted, #6b7280);
    cursor: pointer;
    transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.details-section-add:hover {
    background: var(--c-bg-subtle, #f9fafb);
    color: var(--c-text-strong, #111827);
    border-color: var(--c-border-strong, #9ca3af);
}

/* =============================================================
   VLAN detail: port members list (access + tagged groups).
   Spacious per-row layout to match the port-side "VLAN memberships"
   section on port detail cards.
   ============================================================= */

.vlan-members {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.vlan-member-group {
    /* No border/heavy chrome — heading + list is enough separation. */
}
.vlan-member-group-title {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 4px;
    font-size: 0.85em;
    font-weight: 600;
    color: var(--c-text-muted, #6b7280);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.vlan-member-count {
    display: inline-block;
    min-width: 20px;
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--c-bg-subtle, #f3f4f6);
    color: var(--c-text-muted, #6b7280);
    font-size: 0.85em;
    font-weight: 500;
    text-align: center;
    text-transform: none;
    letter-spacing: 0;
}
.vlan-member-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.vlan-member-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    border-radius: 4px;
    transition: background 0.1s;
}
.vlan-member-row:hover {
    background: var(--c-bg-subtle, #f9fafb);
}
.vlan-member-device {
    font-weight: 500;
}
.vlan-member-sep {
    color: var(--c-text-muted, #9ca3af);
}
.vlan-member-port {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.92em;
}
.vlan-member-media {
    font-size: 0.85em;
}
.vlan-member-container {
    font-size: 0.85em;
    margin-left: auto;   /* pushes container name + button to the right */
}
.vlan-member-remove {
    background: transparent;
    border: 0;
    padding: 2px 4px;
    border-radius: 3px;
    color: var(--c-text-muted, #9ca3af);
    cursor: pointer;
    transition: background 0.1s, color 0.1s;
}
.vlan-member-remove:hover {
    background: var(--c-danger-subtle, #fee2e2);
    color: var(--c-danger, #dc2626);
}
