/* Nightwire panel — Cyber/Terminal Theme */

[x-cloak] {
    display: none !important;
}

html {
    scroll-behavior: smooth;
}

/* ── Font stacks (system, no network deps).
     --font-sans is the UI/body face; --font-mono is reserved for data
     surfaces (tables, code, badges, metric values, brand, modal titles)
     where the fixed-width rhythm signals "machine output". */
:root {
    --font-sans:
        -apple-system, BlinkMacSystemFont, "Segoe UI Variable", "Segoe UI",
        "Inter", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono:
        "SF Mono", "Cascadia Code", "JetBrains Mono", "Fira Code", "Menlo",
        "Consolas", monospace;
}

/* ── Cyber/terminal palette (only theme)
     Duplicated to [data-bs-theme="dark"] so Bootstrap's own dark-theme
     overrides (also scoped under that selector) lose the specificity tie. */
:root,
[data-bs-theme="dark"] {
    --mf-accent: #22d3ee;
    --mf-accent-rgb: 34, 211, 238;
    --mf-bg-surface: #0d141b;
    --mf-text: #b0bec5;
    --mf-text-bright: #cfd8dc;
    --mf-text-dim: #78909c;
    --mf-text-muted-rgb: 176, 190, 197;
    --mf-warning: #ffb700;
    --mf-warning-rgb: 255, 183, 0;
    --mf-danger: #ff6b6b;
    --mf-danger-rgb: 255, 107, 107;
    --mf-success: #2dd4bf;
    --mf-success-rgb: 45, 212, 191;
    --mf-info: #4d9fff;
    --mf-info-rgb: 77, 159, 255;
    --mf-violet-rgb: 167, 139, 250;
    /* Presence green — reserved ONLY for live/online status (sub/device/user),
       deliberately distinct from teal success and cyan accent. Green = online
       is universal; this is the one place green is intentional in the theme. */
    --mf-online: #22c55e;
    --mf-online-rgb: 34, 197, 94;
    --mf-shadow: rgba(0, 0, 0, 0.4);
    --mf-shadow-heavy: rgba(0, 0, 0, 0.6);
    --mf-shadow-drop: rgba(0, 0, 0, 0.5);
    --mf-scanline: rgba(34, 211, 238, 0.008);
    --mf-glow-text: 0 0 8px rgba(34, 211, 238, 0.4);
    --mf-glow-sm: 0 0 6px rgba(34, 211, 238, 0.3);
    /* Gold contact pins on the brand RJ45 plug — the one warm note in an
       otherwise cyan mark; reads as real connector contacts. */
    --mf-brand-pin: #ffd24a;
    /* close (×) is a black SVG recoloured to the accent via filter; recipe
       approximates black → #22d3ee (cyan). Re-derive if --mf-accent changes hue. */
    --mf-close-filter: invert(69%) sepia(54%) saturate(1300%) hue-rotate(154deg)
        brightness(96%) contrast(92%);
    --mf-chart-grid: rgba(255, 255, 255, 0.08);
    --mf-chart-axis: #6c757d;
    /* Chart RX/TX stay contrasting green/blue, NOT theme success/accent —
       both of those read greenish and merge on adjacent bars. */
    --mf-chart-rx: #198754;
    --mf-chart-tx: #0d6efd;
    --mf-chart-rx-fill: rgba(25, 135, 84, 0.15);
    --mf-chart-tx-fill: rgba(13, 110, 253, 0.15);
    --mf-code-bg: #0d141b;
    --mf-footer-border: rgba(255, 255, 255, 0.05);

    --bs-body-bg: #0a0f16;
    --bs-body-bg-rgb: 10, 15, 22;
    --bs-body-color: #b0bec5;
    --bs-body-color-rgb: 176, 190, 197;
    --bs-border-color: rgba(34, 211, 238, 0.08);
    --bs-primary: #22d3ee;
    --bs-primary-rgb: 34, 211, 238;
    --bs-secondary-bg: #0d141b;
    --bs-secondary-bg-rgb: 13, 20, 27;
    --bs-tertiary-bg: #111b24;
    --bs-tertiary-bg-rgb: 17, 27, 36;
    --bs-warning: #ffb700;
    --bs-warning-rgb: 255, 183, 0;
    --bs-danger: #ff6b6b;
    --bs-danger-rgb: 255, 107, 107;
    --bs-info: #4d9fff;
    --bs-info-rgb: 77, 159, 255;
    --bs-secondary: #78909c;
    --bs-secondary-rgb: 120, 144, 156;
    --bs-success: #2dd4bf;
    --bs-success-rgb: 45, 212, 191;
    --bs-link-color: #22d3ee;
    --bs-link-hover-color: #5ce0f5;
    --bs-link-color-rgb: 34, 211, 238;

    /* Muted text — drives .text-body-secondary / .text-body-tertiary so the
       standard Bootstrap 5.3 utilities render the theme's dim tones. */
    --bs-secondary-color: rgba(176, 190, 197, 0.45);
    --bs-secondary-color-rgb: 176, 190, 197;
    --bs-tertiary-color: rgba(176, 190, 197, 0.3);
    --bs-tertiary-color-rgb: 176, 190, 197;

    /* Subtle background / border / emphasis tokens — bg-*-subtle,
       border-*-subtle and text-*-emphasis utilities pick these up, so the
       5.3 subtle-color system follows the mf palette instead of stock colors. */
    --bs-primary-bg-subtle: rgba(var(--mf-accent-rgb), 0.1);
    --bs-primary-border-subtle: rgba(var(--mf-accent-rgb), 0.25);
    --bs-primary-text-emphasis: var(--mf-accent);
    --bs-success-bg-subtle: rgba(var(--mf-success-rgb), 0.1);
    --bs-success-border-subtle: rgba(var(--mf-success-rgb), 0.25);
    --bs-success-text-emphasis: var(--mf-success);
    --bs-danger-bg-subtle: rgba(var(--mf-danger-rgb), 0.1);
    --bs-danger-border-subtle: rgba(var(--mf-danger-rgb), 0.25);
    --bs-danger-text-emphasis: var(--mf-danger);
    --bs-warning-bg-subtle: rgba(var(--mf-warning-rgb), 0.1);
    --bs-warning-border-subtle: rgba(var(--mf-warning-rgb), 0.25);
    --bs-warning-text-emphasis: var(--mf-warning);
    --bs-info-bg-subtle: rgba(var(--mf-info-rgb), 0.1);
    --bs-info-border-subtle: rgba(var(--mf-info-rgb), 0.25);
    --bs-info-text-emphasis: var(--mf-info);
    --bs-secondary-bg-subtle: rgba(var(--mf-text-muted-rgb), 0.1);
    --bs-secondary-border-subtle: rgba(var(--mf-text-muted-rgb), 0.25);
    --bs-secondary-text-emphasis: var(--mf-text-dim);

    /* Sharp tactical edges. Pill remains pill. */
    --bs-border-radius: 0;
    --bs-border-radius-sm: 0;
    --bs-border-radius-lg: 0;
    --bs-border-radius-xl: 0;
    --bs-border-radius-2xl: 0;

    /* Accent-tinted focus ring across non-button surfaces (links, custom
       focusables) — Bootstrap 5.3 picks these up via --bs-focus-ring-*. */
    --bs-focus-ring-rgb: var(--mf-accent-rgb);
    --bs-focus-ring-color: rgba(var(--mf-accent-rgb), 0.25);
}

body {
    background-color: var(--bs-body-bg);
    font-family: var(--font-sans);
    /* Subtle scanline texture only — no glows, no vignette. The dark base
       carries the cyber-feel; ambient effects were too decorative. */
    background-image: repeating-linear-gradient(
        0deg,
        transparent,
        transparent 2px,
        var(--mf-scanline) 2px,
        var(--mf-scanline) 4px
    );
}


/* ── Sidebar ──
     A sticky, viewport-height column at lg+. Inner scroll keeps the brand,
     nav and profile independent of the page's main scroll so the profile
     stays docked to the bottom of the viewport. On <lg bootstrap's offcanvas
     classes take over and it slides as an overlay. Palette + accent-tinted
     border / glow hover carry over from the first sidebar iteration. */
.mf-sidebar {
    --bs-offcanvas-width: 260px;
    --bs-offcanvas-border-color: rgba(var(--mf-accent-rgb), 0.12);
    width: 260px;
    /* offcanvas-lg forces a transparent background at lg+. */
    background-color: var(--mf-bg-surface) !important;
    border-right: 1px solid var(--bs-offcanvas-border-color); /* bootstrap draws it only below lg */
    color: var(--mf-text);
}
@media (min-width: 992px) {
    .mf-sidebar {
        position: sticky;
        top: 0;
        height: 100vh;
        max-height: 100vh;
        overflow: hidden;
    }
}

/* Brand link at the top of the sidebar (terminal-glow accent with a
   blinking cursor after the wordmark — the original mikrotik-admin vibe). */
.mf-brand {
    font-family: var(--font-mono);
    letter-spacing: 0.06em;
    color: var(--mf-accent);
    text-shadow: var(--mf-glow-text);
}

/* Top shell strip height — the sidebar brand head and the main topbar share
   one min-height so their bottom borders line up across the top of the shell.
   The head stacks the wordmark over the RJ45 wire and carries the single
   divider, so the wire (not a separate border) splits brand from nav. */
.navbar.sticky-top,
.mf-sidebar .offcanvas-body > .mf-brand-head {
    min-height: 4rem;
}
/* The strip is the query container for its own contents: the breadcrumb reacts
   to the space it actually has, not to the viewport the sidebar shares. */
.mf-topbar {
    container: topbar / inline-size;
}
.mf-brand-head {
    gap: 0.1rem;
    padding-bottom: 0.1rem;
}
.mf-brand-head .mf-brand {
    font-size: 1.2rem;
}
.mf-brand::after {
    content: "_";
    color: var(--mf-accent);
    margin-left: 1px;
    animation: mf-blink-cursor 1s step-end infinite;
}

/* Two-tone wordmark: "night" inherits the accent from .mf-brand, "wire" is
   brightened to split-read the name without adding a second hue. */
.brand-wire {
    color: var(--mf-text-bright);
    text-shadow: none;
}
@keyframes mf-blink-cursor {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0;
    }
}

/* Brand wire: a fading patch cable to an RJ45 plug, picking up the "wire" in
   the wordmark — stacked under the name in the sidebar, centred on auth pages. */
.mf-wire-line {
    flex: 1 1 auto;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(
        90deg,
        rgba(var(--mf-accent-rgb), 0),
        rgba(var(--mf-accent-rgb), 0.3) 35%,
        var(--mf-accent)
    );
    box-shadow: var(--mf-glow-sm);
}
.mf-wire-jack {
    flex: 0 0 auto;
    width: 38px;
    height: 21px;
    color: var(--mf-accent);
    filter: drop-shadow(0 0 4px rgba(var(--mf-accent-rgb), 0.45));
}
.mf-wire-jack svg {
    width: 100%;
    height: 100%;
    display: block;
}
.mf-brand-wire-auth {
    margin-top: 0.55rem;
    max-width: 220px;
}

/* Group label — small-caps, mono, dim. */
.mf-sidebar h6 {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: rgba(var(--mf-text-muted-rgb), 0.45);
    margin-bottom: 0.25rem;
    padding: 0.75rem 1rem 0.25rem;
}

/* Nav pills: full-width, muted text, accent-glow on hover/active with a
   2px inset accent bar flush to the sidebar's left edge. */
.mf-sidebar .nav-pills .nav-link {
    border-radius: 0;
    padding: 0.55rem 1rem;
    color: var(--mf-text);
    font-size: 0.95rem;
    letter-spacing: 0.01em;
    transition:
        background-color 0.15s ease,
        color 0.2s ease,
        text-shadow 0.2s ease;
}
.mf-sidebar .nav-pills .nav-link i {
    width: 1rem;
    text-align: center;
    opacity: 0.75;
}
.mf-sidebar .nav-pills .nav-link:hover {
    background-color: rgba(var(--mf-accent-rgb), 0.06);
    color: var(--mf-accent);
    text-shadow: var(--mf-glow-sm);
}
.mf-sidebar .nav-pills .nav-link:hover i {
    opacity: 1;
}
.mf-sidebar .nav-pills .nav-link.active,
.mf-sidebar .nav-pills .show > .nav-link {
    background-color: rgba(var(--mf-accent-rgb), 0.1);
    color: var(--mf-accent);
    text-shadow: var(--mf-glow-sm);
    box-shadow: inset 2px 0 0 var(--mf-accent);
}

/* ── Cards — restrained dark surface, shared with the address-list accordion items.
     A faint border that brightens on hover. No top accent, no corners. */
.card,
.mf-addr-accordion .accordion-item {
    border: 1px solid rgba(var(--mf-accent-rgb), 0.08);
    box-shadow: 0 1px 4px var(--mf-shadow);
    transition:
        border-color 0.2s ease,
        box-shadow 0.2s ease;
}

.card:hover,
.mf-addr-accordion .accordion-item:hover {
    border-color: rgba(var(--mf-accent-rgb), 0.16);
}

.card-header {
    background-color: rgba(var(--mf-accent-rgb), 0.03);
    border-bottom: 1px solid rgba(var(--mf-accent-rgb), 0.08);
}

/* Alarm-state card (.border-danger, e.g. DNS cache full): soften the stock
   full-strength red border to the theme's dimmed style + glow + header wash. */
.card.border-danger {
    --bs-border-opacity: 0.4;
    box-shadow: 0 0 12px rgba(var(--mf-danger-rgb), 0.15);
}

.card.border-danger:hover {
    --bs-border-opacity: 0.6;
}

.card.border-danger .card-header {
    background-color: rgba(var(--mf-danger-rgb), 0.06);
    border-bottom-color: rgba(var(--mf-danger-rgb), 0.2);
}

/* ── Metric cards ── */
.metric-icon {
    width: 48px;
    height: 48px;
}
/* Icon glyph size owned here (not via an fs-* utility on the markup) so the
   phone media query can scale it down without an !important utility fight. */
.metric-icon i {
    font-size: 1.75rem;
}

.metric-value {
    font-family: var(--font-mono);
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.02em;
    /* Remnawave-style: value stays neutral-bright, the colour lives in the
       icon bubble (MetricCard Tone). Keeps metric rows from going all-cyan. */
    color: var(--mf-text-bright);
    font-variant-numeric: tabular-nums;
    /* One line, never a mid-word break — narrow tiles ellipsize gracefully
       instead of shredding "Running" into "Run/nin/g". */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.metric-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    opacity: 0.5;
    color: var(--mf-text);
}

/* ── Tables ── */
.table {
    --bs-table-bg: transparent;
    --bs-table-hover-bg: rgba(var(--mf-accent-rgb), 0.03);
}

.table > thead > tr > th {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgba(var(--mf-accent-rgb), 0.5);
    font-weight: 600;
    border-bottom-width: 1px;
    border-bottom-color: rgba(var(--mf-accent-rgb), 0.12);
}

.table > tbody > tr > td {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    border-bottom-color: rgba(var(--mf-accent-rgb), 0.05);
    vertical-align: middle;
    font-variant-numeric: tabular-nums;
}

.table > tbody > tr {
    transition: background-color 0.15s ease;
}

.table > tbody > tr:hover {
    background-color: rgba(var(--mf-accent-rgb), 0.03) !important;
}

/* Protocol glyph in the first /wg row — sized to breathe in the tall row
   without dominating the name column. */
.wg-row-icon svg {
    width: 28px;
    height: 28px;
}

/* Smaller variant for the WG/AWG type switcher in the create-modal header. */
.wg-type-icon svg {
    width: 20px;
    height: 20px;
}

/* ── Badges ── */
.badge {
    font-family: var(--font-mono);
    font-weight: 500;
    letter-spacing: 0.03em;
    font-variant-numeric: tabular-nums;
}

/* Tinted pills: each text-bg-* sets its tone (an r,g,b triple). Disabled
   (secondary) is a neutral blue-slate with no green channel, so it reads apart
   from the teal success; online is the presence green. */
.badge.text-bg-primary { --mf-tone: var(--mf-accent-rgb); }
.badge.text-bg-success { --mf-tone: var(--mf-success-rgb); }
.badge.text-bg-warning { --mf-tone: var(--mf-warning-rgb); }
.badge.text-bg-danger { --mf-tone: var(--mf-danger-rgb); }
.badge.text-bg-info { --mf-tone: var(--mf-info-rgb); }
.badge.text-bg-violet { --mf-tone: var(--mf-violet-rgb); }
.badge.text-bg-online { --mf-tone: var(--mf-online-rgb); }
.badge.text-bg-secondary { --mf-tone: 139, 147, 168; }
.badge[class*="text-bg-"] {
    background-color: rgba(var(--mf-tone), 0.15) !important;
    color: rgb(var(--mf-tone)) !important;
    border: 1px solid rgba(var(--mf-tone), 0.25);
}

/* Presence dot — small leading indicator before a name: green (glowing) when
   online, muted grey when offline. The dot carries state so the name text
   stays neutral and readable; replaces tinting the name itself. */
.status-dot {
    flex-shrink: 0;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background-color: rgba(var(--mf-text-muted-rgb), 0.35);
}
.status-dot.is-online {
    background-color: var(--mf-online);
    box-shadow: 0 0 6px rgba(var(--mf-online-rgb), 0.7);
}

/* .mf-toggle — a bare <button> used as a card/row collapse toggle: native
   keyboard support (Enter/Space) without the default button chrome. */
.mf-toggle {
    border: 0;
    background: transparent;
    padding: 0;
    color: inherit;
    text-align: start;
}

/* .mf-device-grid — a subscription's device cards packed responsively: as many
   per row as the width allows, collapsing to one column on phones. white-space
   reset shields the cards from the desktop table's text-nowrap. */
.mf-device-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
    gap: 0.5rem;
    white-space: normal;
}

/* ── Buttons — restrained, sharp-edged. */
.btn {
    font-family: var(--font-sans);
    font-weight: 500;
    transition: all 0.2s ease;
}

/* Every coloured button is transparent and tone-outlined: each colour class
   sets --mf-tone (an r,g,b triple), one rule draws the family from it. */
.btn-primary,
.btn-outline-primary { --mf-tone: var(--mf-accent-rgb); }
.btn-outline-success { --mf-tone: var(--mf-success-rgb); }
.btn-outline-danger { --mf-tone: var(--mf-danger-rgb); }
.btn-outline-warning { --mf-tone: var(--mf-warning-rgb); }
.btn-outline-info { --mf-tone: var(--mf-info-rgb); }
.btn-secondary { --mf-tone: var(--bs-secondary-rgb); }
.btn-outline-secondary { --mf-tone: var(--mf-text-muted-rgb); }

.btn-primary,
.btn-secondary,
.btn[class*="btn-outline-"] {
    --bs-btn-color: rgb(var(--mf-tone));
    --bs-btn-bg: transparent;
    --bs-btn-border-color: rgba(var(--mf-tone), 0.4);
    --bs-btn-hover-color: rgb(var(--mf-tone));
    --bs-btn-hover-bg: rgba(var(--mf-tone), 0.1);
    --bs-btn-hover-border-color: rgb(var(--mf-tone));
    --bs-btn-active-color: rgb(var(--mf-tone));
    --bs-btn-active-bg: rgba(var(--mf-tone), 0.15);
    --bs-btn-active-border-color: rgb(var(--mf-tone));
    --bs-btn-disabled-color: rgba(var(--mf-tone), 0.4);
    --bs-btn-disabled-bg: transparent;
    --bs-btn-disabled-border-color: rgba(var(--mf-tone), 0.2);
    --bs-btn-focus-shadow-rgb: var(--mf-tone);
    border-width: 1px;
}
.btn-primary:hover,
.btn-secondary:hover,
.btn[class*="btn-outline-"]:hover {
    box-shadow: 0 0 10px rgba(var(--mf-tone), 0.2);
}

/* The primary action carries a full-strength border and a resting glow. */
.btn-primary {
    --bs-btn-border-color: var(--mf-accent);
    --bs-btn-active-shadow: 0 0 16px rgba(var(--mf-accent-rgb), 0.35);
    box-shadow: 0 0 4px rgba(var(--mf-accent-rgb), 0.15);
}
.btn-primary:hover {
    box-shadow: 0 0 12px rgba(var(--mf-accent-rgb), 0.3);
    text-shadow: 0 0 4px rgba(var(--mf-accent-rgb), 0.4);
}

/* Secondary buttons keep body-coloured text that brightens on hover, and the
   outline a fainter border. */
.btn-secondary,
.btn-outline-secondary {
    --bs-btn-color: var(--mf-text);
    --bs-btn-hover-color: var(--mf-text-bright);
    --bs-btn-active-color: var(--mf-text-bright);
}
.btn-secondary {
    --bs-btn-border-color: var(--bs-secondary);
}
.btn-outline-secondary {
    --bs-btn-border-color: rgba(var(--mf-tone), 0.25);
    --bs-btn-hover-border-color: rgba(var(--mf-tone), 0.4);
}

/* ── Forms ── */
.form-control,
.form-select {
    background-color: rgba(var(--mf-accent-rgb), 0.03);
    border: 1px solid rgba(var(--mf-accent-rgb), 0.12);
    color: var(--mf-text);
    /* Cursor uses the accent — small detail, only shows while typing. */
    caret-color: var(--mf-accent);
    transition:
        border-color 0.2s ease,
        box-shadow 0.2s ease;
}

.form-control:focus,
.form-select:focus {
    background-color: rgba(var(--mf-accent-rgb), 0.04);
    border-color: rgba(var(--mf-accent-rgb), 0.35);
    color: var(--mf-text-bright);
    box-shadow: 0 0 0 3px rgba(var(--mf-accent-rgb), 0.08);
}

.form-control::placeholder {
    color: rgba(var(--mf-text-muted-rgb), 0.35);
}

.form-label {
    font-size: 0.85rem;
    letter-spacing: 0.02em;
    color: rgba(var(--mf-text-muted-rgb), 0.7);
}

.form-text {
    color: rgba(var(--mf-text-muted-rgb), 0.45);
}

/* ── Checks & switches ── */
.form-switch .form-check-input:checked {
    box-shadow: 0 0 6px rgba(var(--mf-accent-rgb), 0.3);
}

.form-check-input {
    border-color: rgba(var(--mf-accent-rgb), 0.2);
    background-color: rgba(var(--mf-accent-rgb), 0.03);
}

.form-check-input:checked {
    background-color: var(--mf-accent);
    border-color: var(--mf-accent);
}

.form-check-input:focus {
    box-shadow: 0 0 0 3px rgba(var(--mf-accent-rgb), 0.1);
    border-color: rgba(var(--mf-accent-rgb), 0.4);
}

/* ── Modals ── */
.modal-content {
    background-color: var(--mf-bg-surface);
    border: 1px solid rgba(var(--mf-accent-rgb), 0.15);
    box-shadow:
        0 0 30px var(--mf-shadow-heavy),
        0 0 15px rgba(var(--mf-accent-rgb), 0.05);
}

.modal-header {
    border-bottom: 1px solid rgba(var(--mf-accent-rgb), 0.1);
}

.modal-footer {
    border-top: 1px solid rgba(var(--mf-accent-rgb), 0.1);
}

.modal-title {
    font-family: var(--font-mono);
    letter-spacing: 0.03em;
    color: var(--mf-accent);
}

/* ── Alerts ── */
.alert {
    font-family: var(--font-mono);
    font-size: 0.875rem;
}

/* ── Dropdowns ── */
.dropdown-menu {
    background-color: var(--mf-bg-surface);
    border: 1px solid rgba(var(--mf-accent-rgb), 0.12);
    box-shadow:
        0 4px 20px var(--mf-shadow-drop),
        0 0 8px rgba(var(--mf-accent-rgb), 0.04);
}

.dropdown-item {
    transition:
        background-color 0.15s ease,
        color 0.15s ease;
    color: var(--mf-text);
}

.dropdown-item:hover,
.dropdown-item:focus {
    background-color: rgba(var(--mf-accent-rgb), 0.08);
    color: var(--mf-accent);
}

.dropdown-item.active,
.dropdown-item:active {
    background-color: rgba(var(--mf-accent-rgb), 0.12);
    color: var(--mf-accent);
}

.dropdown-divider {
    border-color: rgba(var(--mf-accent-rgb), 0.08);
}

/* ── Progress bars ── */
.progress {
    background-color: rgba(var(--mf-accent-rgb), 0.06);
}

/* The fill of a quota/load bar comes from its bg-* utility (!important); the
   glow follows the same tone. */
.progress-bar {
    --mf-tone: var(--mf-accent-rgb);
    background-color: var(--mf-accent);
    box-shadow: 0 0 6px rgba(var(--mf-tone), 0.3);
}
.progress-bar.bg-success { --mf-tone: var(--mf-success-rgb); }
.progress-bar.bg-warning { --mf-tone: var(--mf-warning-rgb); }
.progress-bar.bg-danger { --mf-tone: var(--mf-danger-rgb); }

.progress-sm {
    height: 8px;
}

.progress-xs {
    height: 6px;
}

/* Per-member traffic bars speak the charts' RX/TX colours, not the accent. */
.progress-bar.mf-bar-rx { background-color: var(--mf-chart-rx); box-shadow: none; }
.progress-bar.mf-bar-tx { background-color: var(--mf-chart-tx); box-shadow: none; }

/* A long member list scrolls inside the chart card instead of stretching it. */
.mf-member-traffic {
    max-height: 22rem;
    overflow-y: auto;
}

/* ── Pagination ── */
.page-link {
    background-color: transparent;
    border-color: rgba(var(--mf-accent-rgb), 0.1);
    color: var(--mf-text);
}

.page-link:hover {
    background-color: rgba(var(--mf-accent-rgb), 0.08);
    border-color: rgba(var(--mf-accent-rgb), 0.2);
    color: var(--mf-accent);
}

.page-item.active .page-link {
    background-color: rgba(var(--mf-accent-rgb), 0.12);
    border-color: var(--mf-accent);
    color: var(--mf-accent);
}

/* ── Code elements ── */
code {
    font-family: var(--font-mono);
    color: var(--mf-accent);
    background-color: rgba(var(--mf-accent-rgb), 0.06);
    padding: 0.15em 0.4em;
    font-size: 0.875em;
}

pre {
    font-family: var(--font-mono);
    background-color: rgba(var(--mf-accent-rgb), 0.03);
    border: 1px solid rgba(var(--mf-accent-rgb), 0.1);
    padding: 1rem;
    color: var(--mf-text);
}

.code-block {
    background-color: var(--mf-code-bg);
    color: var(--mf-text);
    white-space: pre-wrap;
    word-break: break-all;
}

/* The router console: xterm fits itself to this box, and takes its colors. */
.mf-console {
    height: 60vh;
    min-height: 20rem;
    background-color: var(--mf-code-bg);
    color: var(--mf-text);
    font-family: var(--font-mono);
}

.mf-console .xterm {
    height: 100%;
    padding: 0.5rem;
}

/* xterm.css paints its viewport black, and the viewport spans the padding. */
.mf-console .xterm .xterm-viewport {
    background-color: transparent;
}

/* Room on the right for an absolute-positioned copy button — pe-5 (3rem) is
   too narrow for a "copy + Copy" btn-sm, causing the first wrapped line of a
   long URL to overlap the button. */
.code-block-copyable {
    padding-right: 5.5rem;
}

/* ── Scrollbar - themed ── */
::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: rgba(var(--mf-accent-rgb), 0.15);
    border-radius: 0;
}

::-webkit-scrollbar-thumb:hover {
    background: rgba(var(--mf-accent-rgb), 0.3);
}

/* ── Selection ── */
::selection {
    background-color: rgba(var(--mf-accent-rgb), 0.2);
    color: var(--mf-text-bright);
}

/* ── HTMX loading indicator ──
   Display only: htmx's own indicator CSS is off (htmx-config meta). The child
   combinator keeps a polling container from lighting every spinner below it —
   each spinner sits directly under its hx-indicator target. A dropdown action
   lights the spinner on its always-visible split toggle, which drops its caret. */
.htmx-indicator,
.htmx-request > .htmx-hide,
.htmx-request.htmx-hide,
.htmx-request > .dropdown-toggle-split::after {
    display: none;
}
.htmx-request > .htmx-indicator,
.htmx-request.htmx-indicator,
.htmx-request > .dropdown-toggle-split > .htmx-indicator {
    display: inline-block;
}

/* Chart panel reload: hide the current content and center a spinner while the
   panel refetches (first load or period switch) — only the spinner shows, like
   the first load. Bound to the panel's own htmx-request, which htmx clears on
   every swap, so it can't get stuck. Spinner is a CSS pseudo: no DOM element,
   no .translate-middle to freeze the spin. */
.mf-chart-panel {
    position: relative;
}
.mf-chart-panel.htmx-request {
    min-height: 220px;
}
.mf-chart-panel.htmx-request > * {
    opacity: 0;
}
.mf-chart-panel.htmx-request::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 1.5rem;
    height: 1.5rem;
    margin: -0.75rem 0 0 -0.75rem;
    border: 0.2em solid var(--bs-secondary-color);
    border-right-color: transparent;
    border-radius: 50%;
    animation: spinner-border 0.75s linear infinite;
}

/* Breadcrumbs: subtle chevron separator, muted links, emphasized leaf.
   Section labels are short and fixed, so the trail holds one line by letting
   the leaf — the only crumb carrying a name — truncate. */
.breadcrumb {
    --bs-breadcrumb-divider: "\203A"; /* › */
    --bs-breadcrumb-divider-color: rgba(var(--mf-text-muted-rgb), 0.3);
}
.breadcrumb-item {
    flex-shrink: 0;
}
.breadcrumb-item:last-child {
    flex-shrink: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.breadcrumb-item a {
    color: rgba(var(--mf-text-muted-rgb), 0.7);
    transition: color 0.15s ease;
}
.breadcrumb-item a:hover {
    color: var(--mf-accent);
}
.breadcrumb-item.active {
    color: var(--mf-text-bright);
}
/* Narrow topbar: intermediate labels collapse to a bare "…", link and tap
   target intact. The query measures the strip's content box, so 34rem trips at
   roughly a 576px phone viewport. */
@container topbar (width < 34rem) {
    .breadcrumb-item:not(:first-child, :last-child) a {
        font-size: 0;
    }
    .breadcrumb-item:not(:first-child, :last-child) a::before {
        content: "…";
        content: "…" / ""; /* decorative: the label stays in the a11y tree */
        font-size: 1rem;
    }
}

/* "View as" chip: eye + username, never shrinks — the breadcrumb yields space
   instead. The whole chip is the click target, so the ✕ is pure affordance and
   drops out once the topbar gets tight. */
.mf-viewas {
    cursor: pointer;
    white-space: nowrap;
}
.mf-viewas-name {
    max-width: 10ch;
    overflow: hidden;
    text-overflow: ellipsis;
}
@container topbar (width < 34rem) {
    .mf-viewas-close {
        display: none;
    }
}

/* ── Close button adjust ── */
.btn-close {
    filter: var(--mf-close-filter);
}

/* ── Input group ── */
.input-group-text {
    background-color: rgba(var(--mf-accent-rgb), 0.05);
    border-color: rgba(var(--mf-accent-rgb), 0.12);
    color: rgba(var(--mf-text-muted-rgb), 0.6);
}

/* ── Nav tabs & pills ── */
.nav-tabs {
    border-bottom-color: rgba(var(--mf-accent-rgb), 0.1);
}

.nav-tabs .nav-link.active {
    background-color: var(--mf-bg-surface);
    border-color: rgba(var(--mf-accent-rgb), 0.1);
    border-bottom-color: transparent;
    color: var(--mf-accent);
}

/* Page-level nav-pills (e.g. router detail tabs) — accent-tinted active pill.
   Scoped sidebar selectors keep higher specificity, so this does not touch
   the sidebar's own active-pill styling. */
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
    background-color: rgba(var(--mf-accent-rgb), 0.1);
    color: var(--mf-accent);
}

/* ── Spinner ── */
.spinner-border {
    color: var(--mf-accent);
}

/* ── Footer ──
   The site footer and the sidebar profile block share one padding + min-
   height so they line up visually as "one strip" along the bottom of the
   shell. The avatar sets the lower bound, so min-height matches that. */
.site-footer,
.mf-sidebar-footer {
    padding: 1rem;
    min-height: 4.5rem;
    border-top: 1px solid var(--mf-footer-border);
}

.footer-logo {
    width: 16px;
    height: 16px;
    color: rgba(var(--mf-text-muted-rgb), 0.3);
}

.footer-brand {
    font-family: var(--font-mono);
    font-size: 0.8rem;
    letter-spacing: 0.04em;
    color: rgba(var(--mf-text-muted-rgb), 0.35);
}

.footer-sep {
    color: rgba(var(--mf-text-muted-rgb), 0.15);
    font-size: 0.8rem;
}

.footer-tagline {
    font-size: 0.75rem;
    color: rgba(var(--mf-text-muted-rgb), 0.25);
    letter-spacing: 0.01em;
}

.footer-build {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    color: rgba(var(--mf-text-muted-rgb), 0.22);
    font-variant-numeric: tabular-nums;
}

/* ── Focus visible outlines (accessibility) ── */
:focus-visible {
    outline: 2px solid rgba(var(--mf-accent-rgb), 0.4);
    outline-offset: 2px;
}

/* ── QR code images ── */
.qr-code {
    width: 350px;
    max-width: 100%;
    height: auto;
}

/* ── Chart containers ── */
.chart-container {
    min-height: 200px;
}

/* ── Country flag icons ── */
.flag-icon {
    width: 1.33em;
    height: 1em;
    border-radius: 1px;
    vertical-align: middle;
}

/* ── Collapse toggles: rotate chevron to match expanded state. Keyed on
   aria-expanded so it works for both Bootstrap collapse and Alpine toggles
   (subs rows bind :aria-expanded). ── */
[aria-expanded] .bi-chevron-down {
    transition: transform 0.2s ease;
}
[aria-expanded="true"] .bi-chevron-down {
    transform: rotate(180deg);
}

/* ── Bootstrap tooltip — match the dark panel palette ── */
/* Overrides Bootstrap 5.2+ tooltip CSS variables rather than hard-coding
 * colours so any future theme changes to --bs-* values propagate here.
 */
.tooltip {
    --bs-tooltip-bg: var(--bs-tertiary-bg);
    --bs-tooltip-color: var(--bs-body-color);
    --bs-tooltip-opacity: 1;
    --bs-tooltip-max-width: 340px;
    --bs-tooltip-padding-x: 0.65rem;
    --bs-tooltip-padding-y: 0.5rem;
    --bs-tooltip-border-radius: 0.35rem;
}
.tooltip .tooltip-inner {
    border: 1px solid var(--bs-border-color);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
    text-align: left;
}
.tooltip code {
    color: var(--bs-primary);
    background: transparent;
    padding: 0;
}

/* Flex/grid truncation helper Bootstrap doesn't ship — lets text-truncate
   work inside flex children. */
.min-w-0 {
    min-width: 0 !important;
}

/* Inline htmx status slot — collapses while empty so it doesn't spend a flex
   gap and push the neighbouring buttons off their row alignment. */
.mf-status-slot:empty {
    display: none;
}

/* Key column of detail-page config rows (ui.ConfigRow) — fixed key width
   keeps values aligned across rows. */
.mf-config-label {
    min-width: 7rem;
    letter-spacing: 0.06em;
}

/* Horizontal rule — gradient hairline that fades into ambient on both
   ends, so it doesn't visually butt up against neighbours. */
hr {
    border: 0;
    height: 1px;
    margin: 1.5rem 0;
    opacity: 1;
    background: linear-gradient(
        90deg,
        transparent,
        rgba(var(--mf-accent-rgb), 0.18),
        transparent
    );
}

/* Source-row in the address-list modal: type badge + value input. Badge
   has fixed width and stretches to input height so heterogeneous rows align. */
.mf-source-kind {
    flex: 0 0 5.5rem;
    align-self: stretch;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    letter-spacing: 0.04em;
}

/* URL-source entry-kind selector (Auto / Domains / IPs). Compact width keeps
   the URL input dominant; only rendered for url-typed rows via x-show. */
.mf-source-entry-kind {
    flex: 0 0 6.25rem;
    width: auto;
}

/* Geosite suggestions panel + clickable badges in the address-list modal. */
.mf-geosite-suggestions {
    max-height: 180px;
    overflow-y: auto;
    padding: 0.25rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.375rem;
}
.mf-geosite-suggestions:empty {
    display: none !important;
}
.mf-geosite-badge {
    cursor: pointer;
    border: 0;
}
.mf-geosite-badge:hover {
    background-color: var(--mf-accent) !important;
}

/* Address lists render as a spaced stack of card-like accordion items; their
   border shares the .card rule. */
.mf-addr-accordion {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* ── Mobile responsiveness ──
   Phone tier (Bootstrap `sm` and below): address-list modal source-row shrink. */
@media (max-width: 575.98px) {
    /* Address-list source rows: shrink the fixed kind/entry selectors so the
       value/URL input keeps usable width inside the narrow modal. */
    .mf-source-kind {
        flex-basis: 4rem;
    }
    .mf-source-entry-kind {
        flex-basis: 5rem;
    }
}

/* Metric tiles stay two-up (col-6) until xl, so scale value + icon down across
   the whole sub-xl range — not just below lg — else large numbers ellipsize in
   the narrow 992–1199 tiles. (nowrap/ellipsis live on the base rule.) */
@media (max-width: 1199.98px) {
    .metric-value {
        font-size: 1.25rem;
    }
    .metric-icon {
        width: 40px;
        height: 40px;
    }
    .metric-icon i {
        font-size: 1.25rem;
    }
}
