/* ==========================================================================
   Zabbix MCP Server — Admin Portal Design System
   initMAX branded, dark/light mode, Rubik font
   ========================================================================== */

/* ---------- Font Faces ---------- */
@font-face {
    font-family: 'Rubik';
    src: url('/static/rubik-regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Rubik';
    src: url('/static/rubik-semibold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

/* ---------- CSS Custom Properties (Dark Mode Default) ---------- */
:root {
    /* Background */
    --bg-primary: #1a1a2e;
    --bg-secondary: #16213e;
    --bg-card: #1e293b;
    --bg-input: #0f172a;
    --bg-sidebar: #0f172a;
    --bg-header: #1e293b;
    --bg-overlay: rgba(0, 0, 0, 0.6);
    --bg-hover: rgba(255, 255, 255, 0.05);
    --bg-code: #0f172a;

    /* Text */
    --text-primary: #f1f5f9;
    --text-secondary: #94a3b8;
    --text-muted: #64748b;
    --text-inverse: #1e293b;

    /* Borders */
    --border-color: #334155;
    --border-hover: #475569;
    --border-focus: #1f65f4;

    /* Brand / Accent */
    --color-primary: #1f65f4;
    --color-primary-hover: #1a56d6;
    --color-primary-light: rgba(31, 101, 244, 0.15);
    --color-danger: #ef4444;
    --color-danger-hover: #dc2626;
    --color-danger-light: rgba(239, 68, 68, 0.15);
    --color-success: #22c55e;
    --color-success-hover: #16a34a;
    --color-success-light: rgba(34, 197, 94, 0.15);
    --color-warning: #f59e0b;
    --color-warning-hover: #d97706;
    --color-warning-light: rgba(245, 158, 11, 0.15);

    /* Shadows */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);
    --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2);

    /* Layout */
    --sidebar-width: 240px;
    --header-height: 56px;
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-full: 9999px;

    /* Scrollbar */
    --scrollbar-bg: #1e293b;
    --scrollbar-thumb: #475569;

    /* Transitions */
    --transition-fast: 0.15s ease;
    --transition-base: 0.2s ease;
    --transition-slow: 0.3s ease;

    /* Font */
    --font-sans: 'Rubik', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --font-mono: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', 'Consolas', 'Liberation Mono', monospace;
}

/* ---------- Light Mode Override ---------- */
[data-theme="light"] {
    --bg-primary: #f8fafc;
    --bg-secondary: #f1f5f9;
    --bg-card: #ffffff;
    --bg-input: #ffffff;
    --bg-sidebar: #1e293b;
    --bg-header: #ffffff;
    --bg-overlay: rgba(0, 0, 0, 0.4);
    --bg-hover: rgba(0, 0, 0, 0.04);
    --bg-code: #f1f5f9;

    --text-primary: #1e293b;
    --text-secondary: #64748b;
    --text-muted: #94a3b8;
    --text-inverse: #f1f5f9;

    --border-color: #e2e8f0;
    --border-hover: #cbd5e1;
    --border-focus: #1f65f4;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
    --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);

    --scrollbar-bg: #f1f5f9;
    --scrollbar-thumb: #cbd5e1;
}

/* ---------- Reset & Base ---------- */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    font-size: 14px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    font-family: var(--font-sans);
    color: var(--text-primary);
    background: var(--bg-primary);
    min-height: 100vh;
    line-height: 1.5;
}

a {
    color: var(--color-primary);
    text-decoration: none;
    transition: color var(--transition-fast);
}

a:hover {
    color: var(--color-primary-hover);
}

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

::-webkit-scrollbar-track {
    background: var(--scrollbar-bg);
}

::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border-radius: var(--radius-full);
}

::-webkit-scrollbar-thumb:hover {
    background: var(--border-hover);
}

/* Firefox */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-bg);
}

/* ---------- Layout ---------- */
.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: var(--sidebar-width);
    height: 100vh;
    background: var(--bg-sidebar);
    border-right: 1px solid var(--border-color);
    display: flex;
    flex-direction: column;
    z-index: 100;
    transition: transform var(--transition-base), width var(--transition-base);
    overflow-y: auto;
    overflow-x: hidden;
}

.sidebar.collapsed {
    transform: translateX(calc(-1 * var(--sidebar-width)));
}

.sidebar-header {
    height: var(--header-height);
    padding: 0 20px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    flex-shrink: 0;
    display: flex;
    align-items: center;
}

.logo {
    display: flex;
    align-items: center;
    gap: 10px;
}

.logo img,
.logo svg {
    height: 28px;
    width: auto;
}

.logo-text {
    font-weight: 600;
    font-size: 1.1rem;
    color: #f1f5f9;
    white-space: nowrap;
}

/* Sidebar always has dark text for logo */
[data-theme="light"] .logo-text {
    color: #f1f5f9;
}

.nav-menu {
    list-style: none;
    padding: 0;
    margin: 0;
    flex: 1;
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 20px;
    color: #94a3b8;
    font-size: 0.93rem;
    transition: all var(--transition-fast);
    border-left: 3px solid transparent;
    cursor: pointer;
}

.nav-item:hover {
    background: rgba(255, 255, 255, 0.05);
    color: #f1f5f9;
}

.nav-item.active {
    background: rgba(31, 101, 244, 0.12);
    color: #f1f5f9;
    border-left-color: var(--color-primary);
}

.nav-icon {
    font-size: 1.1rem;
    width: 24px;
    text-align: center;
    flex-shrink: 0;
}

.sidebar-footer {
    padding: 12px 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    flex-shrink: 0;
}

.version {
    font-size: 0.8rem;
    color: #64748b;
}

/* ---------- Header ---------- */
.header {
    position: fixed;
    top: 0;
    left: var(--sidebar-width);
    right: 0;
    height: var(--header-height);
    background: var(--bg-header);
    border-bottom: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    padding: 0 20px;
    z-index: 90;
    transition: left var(--transition-base);
    gap: 16px;
}

.sidebar.collapsed ~ .header {
    left: 0;
}

.hamburger {
    display: none;
    background: none;
    border: none;
    color: var(--text-primary);
    font-size: 1.4rem;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    transition: background var(--transition-fast);
}

.hamburger:hover {
    background: var(--bg-hover);
}

.header-center {
    flex: 1;
    text-align: center;
}

.server-name {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text-secondary);
}

.restart-badge {
    display: inline-block;
    margin-left: 12px;
    padding: 3px 10px;
    font-size: 0.78rem;
    font-weight: 600;
    color: #fff;
    background: var(--color-danger, #ef4444);
    border-radius: 12px;
    animation: restartBlink 1.2s ease-in-out infinite;
}

@keyframes restartBlink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

.mcp-status-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 8px;
    flex-shrink: 0;
}
.mcp-status-dot.checking {
    background: #f59e0b;
    animation: statusPulse 1s ease-in-out infinite;
}
.mcp-status-dot.ok {
    background: #22c55e;
}
.mcp-status-dot.error {
    background: #ef4444;
    animation: statusPulse 1.5s ease-in-out infinite;
}

@keyframes statusPulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.4; transform: scale(0.85); }
}

.header-right {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 1;
    min-width: 0;
}

.theme-toggle {
    background: none;
    border: 1px solid var(--border-color);
    color: var(--text-primary);
    font-size: 1.1rem;
    cursor: pointer;
    padding: 6px 10px;
    border-radius: var(--radius-md);
    transition: all var(--transition-fast);
    line-height: 1;
}

.theme-toggle:hover {
    background: var(--bg-hover);
    border-color: var(--border-hover);
}

.user-menu {
    display: flex;
    align-items: center;
    gap: 10px;
}

.user-name {
    font-size: 0.9rem;
    color: var(--text-secondary);
    font-weight: 500;
}

/* ---------- Main Content ---------- */
.content {
    margin-left: var(--sidebar-width);
    margin-top: var(--header-height);
    padding: 24px;
    min-height: calc(100vh - var(--header-height));
    background: var(--bg-primary);
    transition: margin-left var(--transition-base);
}

.sidebar.collapsed ~ .content,
.sidebar.collapsed ~ .header ~ .content {
    margin-left: 0;
}

/* ---------- Cards ---------- */
.card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 20px;
    box-shadow: var(--shadow-card);
    transition: box-shadow var(--transition-base), border-color var(--transition-base);
}

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

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border-color);
}

.card-title {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--text-primary);
    /* Truncate when the title carries user-controlled text (token name,
       template name, server name) so a 5000-character paste cannot
       blow the card layout out across the whole viewport. Reported
       2026-04-27 with a video of a long token name forcing horizontal
       overflow. The full string lives in the `title` attribute the
       templates already set. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    max-width: 100%;
}

/* Card titles that host an explanatory tooltip-icon need overflow
   visible, otherwise the tooltip popup (absolute-positioned ::after
   on the icon) gets clipped to the card-title rect and the operator
   sees a hover-active icon with no popup. The user-controlled-name
   truncation guard above does not apply to dashboard panels with
   tooltip icons (Active Tasks, ...), where the title is operator-set
   prose, so the trade-off is fine. Reported 2026-05-04 - tooltip-icon
   on Active Tasks lit up on hover but no popup ever appeared because
   the H2 overflow:hidden was clipping the absolutely-positioned
   tooltip body. */
.card-title:has(.tooltip-icon) {
    overflow: visible;
}

.card-body {
    color: var(--text-secondary);
}

/* Stat Cards */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 24px;
}

.stat-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 20px;
    box-shadow: var(--shadow-card);
    display: flex;
    align-items: flex-start;
    gap: 16px;
}

.stat-icon {
    font-size: 2rem;
    line-height: 1;
    flex-shrink: 0;
}

.stat-content {
    flex: 1;
    min-width: 0;
}

.stat-value {
    font-size: 1.8rem;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.2;
}

.stat-label {
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin-top: 2px;
}

/* ---------- Tables ---------- */
.table-container {
    /* overflow-x: auto on its own implicitly turns overflow-y from
       visible into auto (CSS spec - one-axis overflow demands the
       other be at least auto), which clipped tooltip popups that
       float above the first row of the table to "invisible".
       Reported 2026-05-04 - the legacy-token row's warning tooltip
       did not render. Explicit overflow-y: visible decouples the
       two axes so x can still scroll on a too-wide table while y
       lets popups escape the container box. */
    overflow-x: auto;
    overflow-y: visible;
    border-radius: var(--radius-lg);
    border: 1px solid var(--border-color);
    background: var(--bg-card);
}

table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

thead {
    background: var(--bg-input);
}

th {
    text-align: left;
    padding: 12px 16px;
    font-weight: 600;
    color: var(--text-secondary);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border-bottom: 1px solid var(--border-color);
    white-space: nowrap;
    user-select: none;
}

/* Sortable column header - inline ↑ + ↓ pair sitting immediately
   after the header text. Operator-friendly: both arrows always
   visible so the column reads as toggleable, the active direction
   lights up in the primary accent color at full opacity + bold,
   the inactive arrow fades to 0.15. Hover lifts both to ~0.7
   when no direction is active.
   Two iterations ago this was a single ↕ glyph (U+2195) that
   rendered differently from the ↑/↓ active state across DejaVu /
   Noto / SF Pro - the active vs inactive baselines did not match.
   One iteration ago it was an absolute-positioned stacked ▲▼ pair
   on the right edge of the column - cleaner glyphs but visually
   detached from the text label. Reported 2026-05-04: sort buttons
   should sit directly next to the text, not on the far right. */
th.sortable {
    cursor: pointer;
}

.sort-arrows {
    display: inline-block;
    margin-left: 6px;
    font-size: 0.85em;
    line-height: 1;
    letter-spacing: 1px;
    user-select: none;
    pointer-events: none;
    white-space: nowrap;
}
.sort-arrows .sort-arrow {
    color: currentColor;
    opacity: 0.3;
    font-weight: 400;
    transition: opacity 0.12s ease, color 0.12s ease, font-weight 0.12s ease;
}
th.sortable.sort-asc .sort-arrows .sort-arrow-up {
    opacity: 1;
    color: var(--color-primary, var(--text-primary));
    font-weight: 700;
}
th.sortable.sort-asc .sort-arrows .sort-arrow-down {
    opacity: 0.15;
}
th.sortable.sort-desc .sort-arrows .sort-arrow-down {
    opacity: 1;
    color: var(--color-primary, var(--text-primary));
    font-weight: 700;
}
th.sortable.sort-desc .sort-arrows .sort-arrow-up {
    opacity: 0.15;
}
th.sortable:hover .sort-arrows .sort-arrow {
    opacity: 0.7;
}
th.sortable.sort-asc:hover .sort-arrows .sort-arrow-down,
th.sortable.sort-desc:hover .sort-arrows .sort-arrow-up {
    opacity: 0.4;
}

/* BC fallback: any th.sortable WITHOUT explicit .sort-arrows spans
   gets a ::after pseudo with the same dual-arrow content. Active
   direction collapses to the single highlighted arrow. Used by any
   template that has not yet been migrated. */
th.sortable:not(:has(.sort-arrows))::after {
    content: '\2191\2009\2193';
    display: inline-block;
    margin-left: 6px;
    font-size: 0.85em;
    line-height: 1;
    color: currentColor;
    opacity: 0.3;
    letter-spacing: 1px;
}
th.sortable:not(:has(.sort-arrows)):hover::after {
    opacity: 0.7;
}
th.sortable:not(:has(.sort-arrows)).sort-asc::after {
    content: '\2191';
    opacity: 1;
    color: var(--color-primary, var(--text-primary));
    font-weight: 700;
}
th.sortable:not(:has(.sort-arrows)).sort-desc::after {
    content: '\2193';
    opacity: 1;
    color: var(--color-primary, var(--text-primary));
    font-weight: 700;
}

td {
    padding: 12px 16px;
    border-bottom: 1px solid var(--border-color);
    color: var(--text-primary);
    vertical-align: middle;
}

tbody tr {
    transition: background var(--transition-fast);
}

tbody tr:nth-child(even) {
    background: var(--bg-hover);
}

/* Only highlight rows that have actual data. The "No entries" empty
   state row uses [data-empty] (or has just a colspan placeholder)
   and should not pretend it's clickable. */
tbody tr:hover:not([data-empty]) {
    background: var(--color-primary-light);
}
tbody tr[data-empty]:hover {
    background: inherit;
    cursor: default;
}

/* Truncate user-controlled text columns to a fixed width with
   ellipsis. Without this, a 200-character token name pushes the
   Delete button off-screen and breaks the entire row layout. The
   full text remains accessible via the title attribute (browser
   tooltip on hover). Apply via class="cell-truncate" on <td>. */
td.cell-truncate {
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
td.cell-truncate-wide {
    max-width: 480px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Form invalid state - red border around the input so the operator
   sees which field is missing without reading the inline message. */
.input-invalid,
input.input-invalid,
select.input-invalid,
textarea.input-invalid {
    border-color: var(--color-danger) !important;
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.15);
}

/* Status labels are informational only - they look like inline tags
   (flat fill, no shadow, no hover) so the operator never thinks
   they are clickable. Badges with btn-like styling were reported
   2026-04-17 as "looks clickable but isn't, confusing". */
.status-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 8px;
    margin-left: 4px;
    border-radius: 4px;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    cursor: default;
    pointer-events: none;
    border: 1px solid;
}
.status-label-info    { background: rgba(59,130,246,0.10); border-color: rgba(59,130,246,0.45); color: #3b82f6; }
.status-label-success { background: rgba(34,197,94,0.10);  border-color: rgba(34,197,94,0.45);  color: #22c55e; }
.status-label-warn    { background: rgba(245,158,11,0.10); border-color: rgba(245,158,11,0.45); color: #f59e0b; }
.status-label-danger  { background: rgba(239,68,68,0.10);  border-color: rgba(239,68,68,0.45);  color: #ef4444; }

/* Tooltip helper icon next to labeled fields - a ? in a circle,
   centered, drawn as inline SVG so layout never depends on font
   metrics or emoji rendering. The icon hides on hover so it does
   not visually compete with the tooltip popover that overlaps it. */
.tooltip-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    vertical-align: middle;
    margin-left: 2px;
    /* Hide any inner text the template might still pass (legacy
       Unicode 🛈 we used pre-1.25). The SVG replaces it. */
    font-size: 0;
    line-height: 0;
    color: transparent;
    user-select: none;
    cursor: help;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2394a3b8' stroke-width='1.5'%3E%3Ccircle cx='8' cy='8' r='6.5'/%3E%3Cpath d='M5.8 6.2c0-1.2 1-2.2 2.2-2.2s2.2 1 2.2 2.2c0 .9-.5 1.4-1.2 1.8-.7.4-1 .7-1 1.4v.4'/%3E%3Ccircle cx='8' cy='12' r='.6' fill='%2394a3b8' stroke='none'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    /* The pseudo-element tooltip needs a non-static parent. */
    position: relative;
}
.tooltip-icon:hover,
.tooltip-icon:focus {
    /* Slightly darken on hover so the user gets a "this is
       interactive" cue, but keep the ?-circle visible while the
       tooltip popover is showing - reported as "po najeti zmizi
       ten otaznicek" (the question mark vanishes on hover, looks
       like a glitch). The popover floats above with z-index, no
       overlap. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23475569' stroke-width='1.5'%3E%3Ccircle cx='8' cy='8' r='6.5'/%3E%3Cpath d='M5.8 6.2c0-1.2 1-2.2 2.2-2.2s2.2 1 2.2 2.2c0 .9-.5 1.4-1.2 1.8-.7.4-1 .7-1 1.4v.4'/%3E%3Ccircle cx='8' cy='12' r='.6' fill='%23475569' stroke='none'/%3E%3C/svg%3E");
}

/* Warning sibling of .tooltip-icon - same 16x16 circle, same hover /
   focus / data-tooltip plumbing, but draws an "!" inside in the
   warning color so it scans as "this is a warning" instead of
   "this is informational". Used on the legacy-token row in the
   /tokens list. Reported 2026-05-04 - the previous "Legacy" badge
   and the bare "!" character both stuck out next to the rest of
   the portal's circular help bubbles; a circle-with-! matches
   the visual weight of the help icons exactly. */
.warning-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    vertical-align: middle;
    margin-left: 2px;
    font-size: 0;
    line-height: 0;
    color: transparent;
    user-select: none;
    cursor: help;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23d97706' stroke-width='1.5'%3E%3Ccircle cx='8' cy='8' r='6.5'/%3E%3Cpath d='M8 4.5v4'/%3E%3Ccircle cx='8' cy='11.3' r='.6' fill='%23d97706' stroke='none'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    position: relative;
}
.warning-icon:hover,
.warning-icon:focus {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23b45309' stroke-width='1.5'%3E%3Ccircle cx='8' cy='8' r='6.5'/%3E%3Cpath d='M8 4.5v4'/%3E%3Ccircle cx='8' cy='11.3' r='.6' fill='%23b45309' stroke='none'/%3E%3C/svg%3E");
}

/* Bulk-delete sticky action bar - appears once 1+ rows on a list
   page are checked. Floats above the table on scroll so the user
   does not lose the Delete button mid-table. */
.bulk-bar {
    position: sticky;
    top: var(--header-height, 60px);
    z-index: 90;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 16px;
    margin-bottom: 12px;
    border-radius: var(--radius-md, 6px);
    background: var(--bg-card, #1e293b);
    border: 1px solid var(--color-primary, #3b82f6);
    box-shadow: 0 4px 14px rgba(59, 130, 246, 0.15);
    font-size: 0.95rem;
}
.bulk-bar[hidden] { display: none; }
.bulk-bar .bulk-bar-count {
    font-weight: 600;
    color: var(--color-primary, #3b82f6);
}

/* Per-row select checkbox - keep small, vertically centered. */
td.bulk-select-cell, th.bulk-select-cell {
    width: 30px;
    padding-left: 12px;
    padding-right: 4px;
}

/* Defensive overflow guard - any user-controlled text rendered as a
   page heading (token name, server name, user name, ...) must not
   blow out the layout. Long names truncate visually with an ellipsis
   while the full string lives in a title= tooltip. */
.page-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 80vw;
}

/* Inputs that approach the maxlength get a subtle warning border so
   the operator sees the limit before they hit Submit. */
.input-near-limit {
    border-color: var(--color-warning) !important;
    box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.15);
}

tbody tr:last-child td {
    border-bottom: none;
}

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 16px;
    font-size: 0.9rem;
    font-weight: 500;
    font-family: var(--font-sans);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all var(--transition-fast);
    text-decoration: none;
    line-height: 1.4;
    white-space: nowrap;
}

.btn:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.btn-primary {
    background: var(--color-primary);
    color: #ffffff;
    border-color: var(--color-primary);
}

.btn-primary:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
    color: #ffffff;
}

.btn-danger {
    background: var(--color-danger);
    color: #ffffff;
    border-color: var(--color-danger);
}

.btn-danger:hover {
    background: var(--color-danger-hover);
    border-color: var(--color-danger-hover);
    color: #ffffff;
}

.btn-success {
    background: var(--color-success);
    color: #ffffff;
    border-color: var(--color-success);
}

.btn-success:hover {
    background: var(--color-success-hover);
    border-color: var(--color-success-hover);
    color: #ffffff;
}

.btn-ghost {
    background: transparent;
    color: var(--text-secondary);
    border-color: var(--border-hover);
}

.btn-ghost:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
    border-color: var(--border-hover);
}

.btn-sm {
    padding: 4px 10px;
    font-size: 0.82rem;
}

.btn-lg {
    padding: 12px 24px;
    font-size: 1rem;
}

.btn-icon {
    padding: 6px;
    min-width: 32px;
    min-height: 32px;
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* ---------- Badges / Tags ---------- */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    font-size: 0.75rem;
    font-weight: 600;
    border-radius: var(--radius-full);
    white-space: nowrap;
    line-height: 1.6;
}

/* Per-badge spacing using right + bottom margins (NOT left margins).
   Adjacent-sibling left margins create a visible indent on the
   second and third badges when the chip row wraps onto a new line:
   the wrapped badge keeps its margin-left even though there is no
   sibling to the left of it any more, so the new row appears
   shifted to the right by the gap value. Reported 2026-05-04 on
   /tokens scopes column. Right + bottom margin is the standard
   "trailing gap" pattern - the wrap happens cleanly because the
   next chip starts at column 0 with no left margin to push it.
   The very last badge in a row has a stray margin-right but the
   td padding eats it; visually invisible. */
.badge {
    margin-right: 4px;
    margin-bottom: 4px;
}

/* btn-sm-sized icon button. Stack with btn-sm + btn-icon on the
   same element. Override the base .btn-icon defaults (32x32
   square). Reported 2026-05-04 - icon buttons next to a text
   Delete in /tokens looked oversized. */
.btn.btn-sm.btn-icon {
    padding: 0 8px;
    line-height: 0;
    min-width: 0;
    min-height: 0;
    height: 26px;
}
.btn.btn-sm.btn-icon svg {
    display: block;
    width: 13px;
    height: 13px;
}

/* Wide-table polish for the tokens list: compact Actions column +
   Name column ellipsis on an inner span. Reported 2026-05-04 -
   the table needs to fit a ~960px content area on a 1200px laptop
   screen without horizontal scroll, AND a long-name link inside
   the cell needs to show its full text on hover via the styled
   data-tooltip popover. Putting the ellipsis on the <td> itself
   forced overflow:hidden on the cell, which clipped the tooltip
   popover on the link inside it. The inner .name-trunc span
   handles ellipsis without changing the cell's overflow, so the
   tooltip absolute-positioned ::after escapes the cell box and
   shows above the table. */
/* Outer wrapper: holds the tooltip; no overflow guard so the popover
   can escape the cell. Inner .name-trunc handles the actual ellipsis. */
table.tokens-list .name-cell {
    display: inline-block;
    vertical-align: middle;
    /* position:relative comes from [data-tooltip]; no need to repeat. */
}
table.tokens-list .name-trunc {
    display: inline-block;
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}
table.tokens-list td.col-actions {
    white-space: nowrap;
}
table.tokens-list td.col-actions .btn-sm {
    padding-left: 8px;
    padding-right: 8px;
    min-width: auto;
}

.badge-primary {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.badge-danger {
    background: var(--color-danger-light);
    color: var(--color-danger);
}

.badge-success {
    background: var(--color-success-light);
    color: var(--color-success);
}

.badge-warning {
    background: var(--color-warning-light);
    color: var(--color-warning);
}

.badge-muted {
    background: var(--bg-hover);
    color: var(--text-muted);
}

/* Scope-specific badges */
.badge-monitoring {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.badge-data_collection {
    background: rgba(139, 92, 246, 0.15);
    color: #a78bfa;
}

.badge-alerts {
    background: var(--color-warning-light);
    color: var(--color-warning);
}

.badge-users {
    background: rgba(6, 182, 212, 0.15);
    color: #22d3ee;
}

.badge-administration {
    background: var(--color-danger-light);
    color: var(--color-danger);
}

.badge-extensions {
    background: rgba(251, 146, 60, 0.15);
    color: #fb923c;
}

.badge-\* {
    background: var(--color-success-light);
    color: var(--color-success);
}

/* ---------- Forms ---------- */
.form-group {
    margin-bottom: 16px;
}

.form-label {
    display: block;
    margin-bottom: 6px;
    font-weight: 500;
    font-size: 0.9rem;
    color: var(--text-primary);
}

.form-hint {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-top: 4px;
}

.form-input,
.form-select,
.form-textarea {
    width: 100%;
    padding: 8px 12px;
    font-size: 0.9rem;
    font-family: var(--font-sans);
    color: var(--text-primary);
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
    outline: none;
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

.form-input::placeholder,
.form-textarea::placeholder {
    color: var(--text-muted);
}

.form-textarea {
    resize: vertical;
    min-height: 80px;
}

.form-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%2394a3b8' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    padding-right: 32px;
    cursor: pointer;
}

/* Validation States */
.form-input.is-error,
.form-select.is-error,
.form-textarea.is-error {
    border-color: var(--color-danger);
    box-shadow: 0 0 0 3px var(--color-danger-light);
}

.form-input.is-valid,
.form-select.is-valid,
.form-textarea.is-valid {
    border-color: var(--color-success);
    box-shadow: 0 0 0 3px var(--color-success-light);
}

.form-error {
    font-size: 0.8rem;
    color: var(--color-danger);
    margin-top: 4px;
}

/* Checkbox group styled as badge tags */
.scope-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.scope-tag {
    position: relative;
}

.scope-tag input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.scope-tag label {
    display: inline-flex;
    align-items: center;
    padding: 6px 14px;
    font-size: 0.85rem;
    font-weight: 500;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: all var(--transition-fast);
    color: var(--text-secondary);
    background: var(--bg-input);
}

.scope-tag input[type="checkbox"]:checked + label {
    background: var(--color-primary-light);
    color: var(--color-primary);
    border-color: var(--color-primary);
}

.scope-tag label:hover {
    border-color: var(--border-hover);
    background: var(--bg-hover);
}

/* ---------- Toggle Switch ---------- */
.toggle {
    position: relative;
    display: inline-block;
    width: 44px;
    height: 24px;
    flex-shrink: 0;
}

.toggle input {
    opacity: 0;
    width: 0;
    height: 0;
    position: absolute;
}

.toggle-slider {
    position: absolute;
    inset: 0;
    background: var(--border-color);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background var(--transition-base);
}

.toggle-slider::before {
    content: '';
    position: absolute;
    width: 18px;
    height: 18px;
    left: 3px;
    bottom: 3px;
    background: #ffffff;
    border-radius: 50%;
    transition: transform var(--transition-base);
}

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

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

.toggle input:focus-visible + .toggle-slider {
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

/* Disabled toggle - replace the brand-primary "on" track with the
   muted text colour so the operator immediately reads it as
   "inactive / read-only" instead of mistaking it for an editable
   on switch. cursor: not-allowed reinforces the same signal on
   hover. Used for things that would foot-gun the operator if
   changed from inside the portal, e.g. [admin].enabled. */
.toggle input:disabled + .toggle-slider {
    background: var(--text-muted);
    cursor: not-allowed;
}

.toggle-label {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
}
.toggle-label:has(input:disabled) {
    cursor: not-allowed;
}

/* ---------- Toast Notifications ---------- */
.toast {
    position: fixed;
    top: 16px;
    right: 16px;
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-radius: var(--radius-md);
    font-size: 0.9rem;
    font-weight: 500;
    box-shadow: var(--shadow-lg);
    animation: slideInRight var(--transition-slow) ease-out;
    max-width: 400px;
}

.toast button {
    background: none;
    border: none;
    color: inherit;
    font-size: 1.2rem;
    cursor: pointer;
    opacity: 0.7;
    padding: 0 0 0 8px;
    line-height: 1;
}

.toast button:hover {
    opacity: 1;
}

.toast-success {
    background: var(--color-success);
    color: #ffffff;
}

.toast-error {
    background: var(--color-danger);
    color: #ffffff;
}

.toast-warning {
    background: var(--color-warning);
    color: #1e293b;
}

.toast-info {
    background: var(--color-primary);
    color: #ffffff;
}

@keyframes slideInRight {
    from {
        transform: translateX(100%);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

/* ---------- Modal Dialogs ---------- */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: var(--bg-overlay);
    backdrop-filter: blur(4px);
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: fadeIn var(--transition-base) ease-out;
}

.modal-overlay[hidden] {
    display: none;
}

.modal {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 24px;
    max-width: 480px;
    width: calc(100% - 32px);
    box-shadow: var(--shadow-lg);
    animation: slideUp var(--transition-slow) ease-out;
}

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}

.modal-title {
    font-size: 1.1rem;
    font-weight: 600;
}

.modal-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.4rem;
    cursor: pointer;
    padding: 4px;
    line-height: 1;
    border-radius: var(--radius-sm);
    transition: color var(--transition-fast);
}

.modal-close:hover {
    color: var(--text-primary);
}

.modal-body {
    color: var(--text-secondary);
    margin-bottom: 20px;
    line-height: 1.6;
}

.modal-footer {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes slideUp {
    from {
        transform: translateY(20px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

/* ---------- Status Indicators ---------- */
.status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 6px;
    flex-shrink: 0;
}

.status-dot-green {
    background: var(--color-success);
    box-shadow: 0 0 6px rgba(34, 197, 94, 0.4);
}

.status-dot-red {
    background: var(--color-danger);
    box-shadow: 0 0 6px rgba(239, 68, 68, 0.4);
}

.status-dot-yellow {
    background: var(--color-warning);
    box-shadow: 0 0 6px rgba(245, 158, 11, 0.4);
}

.status-inline {
    display: inline-flex;
    align-items: center;
    font-size: 0.85rem;
}

/* While the Test Connection request is in flight, the inline JS in
   servers.html adds the `is-testing` class to the triggering button.
   We can't rely on htmx's own `htmx-request` class because the body
   element sets `hx-indicator="#loader"` which directs all indicators
   to the top progress bar, never decorating the trigger.
   Reported 2026-04-27 by a viewer who waited several seconds and
   gave up because the only visible cue was the existing pulse dot. */
.btn.is-testing {
    opacity: 0.65;
    pointer-events: none;
    position: relative;
}
.btn.is-testing::after {
    content: ' (testing...)';
    color: var(--text-muted);
    font-style: italic;
}
/* Also re-render the success checkmark larger and stay visible
   longer (was animation: fadeOut 2s forwards - too fast to register
   on a slow page). */
.test-ok {
    display: inline-block;
    font-weight: 700;
    font-size: 1rem;
    animation: fadeOut 4s forwards;
}

/* ---------- Copy Button ---------- */
.copy-group {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.btn-copy {
    background: none;
    border: 1px solid var(--border-color);
    color: var(--text-muted);
    font-size: 0.85rem;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    transition: all var(--transition-fast);
    line-height: 1;
}

.btn-copy:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
    border-color: var(--border-hover);
}

/* ---------- Token Reveal ---------- */
.token-reveal {
    filter: blur(4px);
    transition: filter var(--transition-base);
    user-select: none;
}

.token-reveal:hover {
    filter: none;
    user-select: auto;
}

/* Token display box (shown once after creation) */
.token-display {
    background: var(--bg-code);
    border: 2px solid var(--color-warning);
    border-radius: var(--radius-md);
    padding: 16px;
    margin: 16px 0;
}

.token-display .token-value {
    font-family: var(--font-mono);
    font-size: 0.95rem;
    word-break: break-all;
    color: var(--text-primary);
    margin-bottom: 8px;
}

.token-display .token-warning {
    font-size: 0.85rem;
    color: var(--color-warning);
    font-weight: 500;
}

/* ---------- Monospace ---------- */
.monospace {
    font-family: var(--font-mono);
    font-size: 0.85rem;
}

/* ---------- Page Header ---------- */
.page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 24px;
    flex-wrap: wrap;
    gap: 12px;
}

.page-title {
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--text-primary);
}

.page-subtitle {
    font-size: 0.9rem;
    color: var(--text-secondary);
    margin-top: 2px;
}

/* ---------- HTMX Indicator / Spinner ---------- */
.htmx-indicator {
    display: none;
    position: fixed;
    top: var(--header-height);
    left: var(--sidebar-width);
    right: 0;
    z-index: 80;
    height: 3px;
    background: linear-gradient(90deg, var(--color-primary), var(--color-primary-hover), var(--color-primary));
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
    display: block;
}

@keyframes shimmer {
    0% { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

.spinner {
    width: 32px;
    height: 32px;
    border: 3px solid var(--border-color);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    margin: 40px auto;
}

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

/* Inline spinner (small) */
.spinner-sm {
    width: 16px;
    height: 16px;
    border-width: 2px;
    display: inline-block;
    vertical-align: middle;
    margin: 0;
}

/* ---------- Filters Bar ---------- */
.filters {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.filters .form-input,
.filters .form-select {
    width: auto;
    min-width: 160px;
}

.filters .search-input {
    min-width: 240px;
}

/* ---------- Section ---------- */
.section {
    margin-bottom: 32px;
}

.section-title {
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 16px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border-color);
}

/* ---------- Grid Layouts ---------- */
.grid-2 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 16px;
}

.grid-3 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 16px;
}

/* ---------- Server Card ---------- */
.server-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 20px;
    box-shadow: var(--shadow-card);
    display: flex;
    flex-direction: column;
    gap: 12px;
}

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

.server-card-name {
    font-weight: 600;
    font-size: 1.05rem;
    /* Same truncation guard as .card-title - user can name a server
       with arbitrary text, do not let one absurd value distort the
       whole grid. Full string lives in the `title` attribute. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    max-width: 100%;
    flex: 1 1 auto;
}

.server-card-badges {
    display: flex;
    gap: 6px;
}

.server-card-url {
    font-family: var(--font-mono);
    font-size: 0.82rem;
    color: var(--text-muted);
    word-break: break-all;
}

.server-card-meta {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.server-card-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-top: 12px;
    border-top: 1px solid var(--border-color);
}

/* ---------- Template Editor (Split View) ---------- */
.editor-container {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    overflow: hidden;
    height: calc(100vh - var(--header-height) - 160px);
    min-height: 400px;
}

.editor-pane {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.editor-pane + .editor-pane {
    border-left: 1px solid var(--border-color);
}

.editor-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: var(--bg-input);
    border-bottom: 1px solid var(--border-color);
    flex-shrink: 0;
}

.editor-textarea {
    flex: 1;
    width: 100%;
    padding: 12px;
    font-family: var(--font-mono);
    font-size: 0.85rem;
    color: var(--text-primary);
    background: var(--bg-card);
    border: none;
    outline: none;
    resize: none;
    line-height: 1.6;
}

.editor-preview {
    flex: 1;
    border: none;
    background: #ffffff;
}

/* Variables sidebar panel */
.variables-panel {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 16px;
    margin-top: 16px;
}

.variables-panel.collapsed .variables-body {
    display: none;
}

.variables-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.95rem;
}

.variables-body {
    margin-top: 12px;
}

.variable-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 0;
    border-bottom: 1px solid var(--border-color);
    font-size: 0.85rem;
}

.variable-item:last-child {
    border-bottom: none;
}

.variable-name {
    font-family: var(--font-mono);
    color: var(--color-primary);
}

.variable-desc {
    color: var(--text-muted);
    font-size: 0.8rem;
}

/* ---------- Settings Sections ---------- */
.settings-section {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 20px;
    margin-bottom: 20px;
}

.settings-section-title {
    font-size: 1.1rem;
    font-weight: 600;
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.settings-row {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: 16px;
    align-items: start;
    padding: 12px 0;
    border-bottom: 1px solid var(--border-color);
}

.settings-row:last-child {
    border-bottom: none;
}

.settings-label {
    font-weight: 500;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 6px;
    padding-top: 6px;
}

.restart-icon {
    color: var(--color-warning);
    font-size: 0.9rem;
}

.restart-banner {
    background: var(--color-warning-light);
    border: 1px solid var(--color-warning);
    color: var(--color-warning);
    padding: 12px 16px;
    border-radius: var(--radius-md);
    font-weight: 500;
    font-size: 0.9rem;
    margin-bottom: 20px;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* ---------- Password Strength Indicator ---------- */
.password-strength {
    height: 4px;
    border-radius: var(--radius-full);
    background: var(--border-color);
    margin-top: 6px;
    overflow: hidden;
}

.password-strength-bar {
    height: 100%;
    border-radius: var(--radius-full);
    transition: width var(--transition-base), background var(--transition-base);
}

.strength-weak { width: 33%; background: var(--color-danger); }
.strength-medium { width: 66%; background: var(--color-warning); }
.strength-strong { width: 100%; background: var(--color-success); }

/* ---------- Empty State ---------- */
.empty-state {
    text-align: center;
    padding: 48px 24px;
    color: var(--text-muted);
}

.empty-state-icon {
    font-size: 3rem;
    margin-bottom: 12px;
    opacity: 0.5;
}

.empty-state-text {
    font-size: 1rem;
    margin-bottom: 16px;
}

/* ---------- Action Buttons Row ---------- */
.actions {
    display: flex;
    gap: 6px;
    align-items: center;
}

/* ---------- Login Page ---------- */
.login-page {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary));
    padding: 16px;
}

.login-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 32px;
    width: 100%;
    max-width: 400px;
    box-shadow: var(--shadow-lg);
}

.login-logo {
    text-align: center;
    margin-bottom: 24px;
}

.login-logo img,
.login-logo svg {
    height: 40px;
    margin-bottom: 12px;
}

.login-title {
    font-size: 1.3rem;
    font-weight: 600;
    text-align: center;
    margin-bottom: 24px;
    color: var(--text-primary);
}

.login-error {
    background: var(--color-danger-light);
    color: var(--color-danger);
    padding: 10px 14px;
    border-radius: var(--radius-md);
    font-size: 0.85rem;
    font-weight: 500;
    margin-bottom: 16px;
    text-align: center;
}

/* ---------- Load More ---------- */
.load-more {
    text-align: center;
    padding: 16px;
}

/* ---------- Quick Actions ---------- */
.quick-actions {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 24px;
}

/* ---------- Utility Classes ---------- */
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-muted { color: var(--text-muted); }
.text-sm { font-size: 0.82rem; }
.text-danger { color: var(--color-danger); }
.text-success { color: var(--color-success); }
.text-warning { color: var(--color-warning); }

.mt-0 { margin-top: 0; }
.mt-4 { margin-top: 16px; }
.mt-6 { margin-top: 24px; }
.mb-0 { margin-bottom: 0; }
.mb-4 { margin-bottom: 16px; }
.mb-6 { margin-bottom: 24px; }

.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.gap-4 { gap: 16px; }

.w-full { width: 100%; }
.inline { display: inline; }
.hidden { display: none; }

/* ---------- Responsive ---------- */
@media (max-width: 768px) {
    .sidebar {
        transform: translateX(calc(-1 * var(--sidebar-width)));
    }

    .sidebar.open {
        transform: translateX(0);
    }

    .sidebar.collapsed {
        transform: translateX(calc(-1 * var(--sidebar-width)));
    }

    .header {
        left: 0;
    }

    .content {
        margin-left: 0;
    }

    .hamburger {
        display: block;
    }

    .header-right {
        flex-wrap: wrap;
        justify-content: flex-end;
        gap: 8px;
    }

    .header-right .btn {
        font-size: 0.8rem;
        padding: 4px 8px;
    }

    .stat-grid {
        grid-template-columns: 1fr 1fr;
    }

    .editor-container {
        grid-template-columns: 1fr;
        height: auto;
    }

    .settings-row {
        grid-template-columns: 1fr;
        gap: 6px;
    }

    .page-header {
        flex-direction: column;
        align-items: flex-start;
    }

    .filters {
        flex-direction: column;
        align-items: stretch;
    }

    .filters .form-input,
    .filters .form-select,
    .filters .search-input {
        width: 100%;
        min-width: 0;
    }

    .editor-tabs {
        flex-wrap: wrap;
        gap: 6px;
    }

    .editor-tabs .form-select {
        min-width: 0;
        width: 100%;
        order: 10;
    }

    .tool-zones {
        flex-direction: column;
    }

    /* Make wide tables horizontally scrollable instead of letting
       them overflow the viewport. The table-container already has
       overflow-x:auto but on small screens we also relax the
       cell-truncate caps so common columns stay readable. */
    .table-container {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    td.cell-truncate { max-width: 140px; }
    td.cell-truncate-wide { max-width: 200px; }

    /* MCP-available banner can wrap on phone */
    .header-center {
        flex-wrap: wrap;
        gap: 4px;
    }
    .update-badge {
        margin-left: 0 !important;
    }
}

@media (max-width: 480px) {
    .stat-grid {
        grid-template-columns: 1fr;
    }

    .grid-2,
    .grid-3 {
        grid-template-columns: 1fr;
    }

    .login-card {
        padding: 24px 20px;
    }
}

/* ---------- Logo theme switching ---------- */
/* Dark mode: show light logo, hide dark logo */
:root .logo-dark-theme { display: inline; }
:root .logo-light-theme { display: none; }

/* Light mode: show dark logo, hide light logo */
[data-theme="light"] .logo-dark-theme { display: none; }
[data-theme="light"] .logo-light-theme { display: inline; }

/* ---------- Login footer ---------- */
.login-footer {
    text-align: center;
    margin-top: 32px;
    font-size: 12px;
    color: var(--text-muted);
}

/* duplicate removed — .login-page defined above */

/* ---------- Sidebar copyright ---------- */
.sidebar-footer .copyright {
    display: block;
    font-size: 10px;
    color: var(--text-muted);
    margin-top: 4px;
    opacity: 0.6;
}
.sidebar-footer a {
    color: inherit;
    text-decoration: none;
}
.sidebar-footer a:hover {
    opacity: 0.8;
}

/* ---------- Theme Switcher (3 buttons: light/auto/dark) ---------- */
.theme-switcher,
.theme-switcher-login {
    display: inline-flex;
    gap: 2px;
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 2px;
}
.theme-btn {
    background: none;
    border: none;
    padding: 4px 8px;
    font-size: 14px;
    cursor: pointer;
    border-radius: var(--radius-sm);
    opacity: 0.5;
    transition: opacity 0.2s, background 0.2s;
    line-height: 1;
}
.theme-btn:hover { opacity: 0.8; }
.theme-btn.active {
    opacity: 1;
    background: var(--color-primary);
    color: white;
    border-radius: var(--radius-sm);
}
.theme-switcher-login {
    position: absolute;
    top: 20px;
    right: 20px;
}

/* ---------- Test connection success fade ---------- */
@keyframes fadeOut {
    0% { opacity: 1; }
    70% { opacity: 1; }
    100% { opacity: 0; }
}

/* ---------- Custom Modal ---------- */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: var(--bg-overlay);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 200;
}
.modal-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 0;
    width: 90%;
    max-width: 440px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
.modal-header {
    padding: 20px 24px 0;
}
.modal-header h3 { margin: 0; font-size: 1.15rem; }
.modal-body {
    padding: 16px 24px;
    color: var(--text-secondary);
    font-size: 0.95rem;
}
.modal-footer {
    padding: 12px 24px 20px;
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

/* ---------- Progress bar ---------- */
.progress-bar {
    height: 6px;
    background: var(--bg-input);
    border-radius: 3px;
    overflow: hidden;
    margin: 12px 0 8px;
}
.progress-fill {
    height: 100%;
    background: var(--color-primary);
    border-radius: 3px;
    width: 0%;
    transition: width 0.3s ease;
}

/* ---------- Custom number input with +/- buttons ---------- */
.number-input-group {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--bg-card);
}
.number-input-group input[type="number"] {
    border: none;
    border-left: 1px solid var(--border-color);
    border-right: 1px solid var(--border-color);
    text-align: center;
    width: 80px;
    padding: 10px 4px;
    background: var(--bg-card);
    color: var(--text-primary);
    font-family: var(--font-sans);
    font-size: 0.95rem;
    font-weight: 500;
    -moz-appearance: textfield;
    outline: none;
}
.number-input-group input[type="number"]::-webkit-inner-spin-button,
.number-input-group input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.number-input-group .num-btn {
    background: transparent;
    border: none;
    color: var(--text-secondary);
    width: 42px;
    padding: 10px 0;
    cursor: pointer;
    font-size: 1.2rem;
    font-weight: 300;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
    user-select: none;
}
.number-input-group .num-btn:hover {
    background: var(--color-primary);
    color: white;
}
.number-input-group .num-btn:active {
    transform: scale(0.92);
}

/* ---------- Flatpickr dark mode ---------- */
:root .flatpickr-calendar {
    background: var(--bg-card);
    border-color: var(--border-color);
    box-shadow: 0 4px 20px rgba(0,0,0,0.3);
    font-family: var(--font-sans);
}
:root .flatpickr-day {
    color: var(--text-primary);
}
:root .flatpickr-day.selected {
    background: var(--color-primary);
    border-color: var(--color-primary);
}
:root .flatpickr-day:hover {
    background: var(--bg-input);
}
:root .flatpickr-months .flatpickr-month,
:root .flatpickr-current-month .flatpickr-monthDropdown-months,
:root .flatpickr-weekdays,
:root span.flatpickr-weekday {
    background: var(--bg-card);
    color: var(--text-primary);
}
:root .flatpickr-months .flatpickr-prev-month,
:root .flatpickr-months .flatpickr-next-month {
    color: var(--text-primary);
    fill: var(--text-primary);
}
[data-theme="light"] .flatpickr-calendar {
    background: #fff;
    border-color: #e2e8f0;
}
[data-theme="light"] .flatpickr-day { color: #1e293b; }
[data-theme="light"] .flatpickr-months .flatpickr-month,
[data-theme="light"] .flatpickr-weekdays,
[data-theme="light"] span.flatpickr-weekday { background: #fff; color: #1e293b; }

/* ---------- Select dropdown arrow (dark mode) ---------- */
.form-select {
    color-scheme: dark;
}
[data-theme="light"] .form-select {
    color-scheme: light;
}

/* nav-menu spacing handled in main definition */

/* ---------- Editor Tabs ---------- */
.editor-tabs {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-bottom: 0;
    padding: 8px 12px;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-bottom: none;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.editor-tab {
    padding: 8px 16px;
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    border-radius: var(--radius-md);
    font-family: var(--font-sans);
    font-size: 0.9rem;
    transition: all 0.15s;
}
.editor-tab.active {
    background: var(--color-primary);
    color: white;
}
.editor-tab:hover:not(.active) {
    background: var(--bg-input);
}
.editor-panel {
    border: 1px solid var(--border-color);
    border-top: none;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    overflow: hidden;
}

/* ---------- GrapesJS dark mode ---------- */
:root .gjs-one-bg { background: var(--bg-card) !important; }
:root .gjs-two-color { color: var(--text-primary) !important; }
:root .gjs-three-bg { background: var(--bg-input) !important; }
:root .gjs-four-color, :root .gjs-four-color-h:hover { color: var(--color-primary) !important; }
:root .gjs-pn-panel { background: var(--bg-card) !important; border-color: var(--border-color) !important; overflow-x: auto !important; }
:root .gjs-pn-commands, :root .gjs-pn-views { flex-wrap: wrap !important; }
:root .gjs-block { background: var(--bg-input) !important; color: var(--text-primary) !important; border-color: var(--border-color) !important; }
:root .gjs-category-title { background: var(--bg-card) !important; color: var(--text-primary) !important; }

/* ---------- Tool Exposure — Zones + Bubbles ---------- */
.tool-zones {
    display: flex;
    flex-direction: row;
    gap: 16px;
}
.tool-zones > .tool-zone {
    flex: 1;
    min-width: 0;
}
.tool-zone {
    border: 2px dashed var(--border-color);
    border-radius: var(--radius-lg);
    padding: 12px;
    min-height: 80px;
    transition: border-color 0.2s, background 0.2s;
}
.tool-zone.drag-over {
    border-color: var(--color-primary);
    background: rgba(31, 101, 244, 0.05);
}
.tool-zone-allowed { border-color: rgba(34,197,94,0.3); }
.tool-zone-disabled { border-color: rgba(239,68,68,0.3); }
.tool-zone-header {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 8px;
    opacity: 0.7;
}
.tool-zone-bubbles {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.tool-bubble {
    display: inline-flex;
    align-items: center;
    padding: 6px 14px;
    border-radius: 20px;
    font-size: 0.82rem;
    cursor: grab;
    user-select: none;
    transition: all 0.15s;
    font-family: var(--font-sans);
}
.tool-bubble:active { cursor: grabbing; }
.tool-bubble.dragging { opacity: 0.4; }
.tool-bubble-group {
    background: var(--color-primary);
    color: white;
    font-weight: 600;
}
.tool-zone-bubbles .tool-bubble-group {
    margin-top: 8px;
}
.tool-zone-bubbles .tool-bubble-group:first-child {
    margin-top: 0;
}
.tool-bubble-group[data-group="extensions"] {
    background: #fb923c;
    color: #fff;
}
.tool-bubble-group.disabled {
    background: var(--bg-input);
    color: var(--text-muted);
    border: 1px solid var(--border-color);
}
.tool-bubble-tool {
    background: rgba(34, 197, 94, 0.15);
    color: var(--color-success);
}
.tool-bubble-tool.disabled {
    background: rgba(239, 68, 68, 0.1);
    color: var(--text-muted);
}
.tool-bubble-global-disabled {
    background: var(--bg-input);
    color: var(--text-muted);
    border: 1px dashed var(--border-color);
    opacity: 0.6;
}
.tool-bubble-global-disabled:hover {
    transform: none;
    box-shadow: none;
}
.tool-bubble:hover {
    transform: scale(1.05);
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

/* ---------- Pulsing status dot (checking/pending) ---------- */
.status-dot-pulse {
    animation: dotPulse 1.2s ease-in-out infinite;
}
.status-dot-yellow.status-dot-pulse {
    animation: dotPulseYellow 1.2s ease-in-out infinite;
}
@keyframes dotPulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.4; transform: scale(0.85); }
}
@keyframes dotPulseYellow {
    0%, 100% { background: var(--color-warning); box-shadow: 0 0 6px rgba(245, 158, 11, 0.4); opacity: 1; }
    50% { background: var(--color-warning); box-shadow: 0 0 12px rgba(245, 158, 11, 0.6); opacity: 0.5; }
}

/* ---------- Instant CSS Tooltips ---------- */
[data-tooltip] {
    position: relative;
    cursor: default;
}
[data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    padding: 10px 14px;
    border-radius: var(--radius-md, 6px);
    background: var(--bg-card, #1e293b);
    color: var(--text-primary, #e2e8f0);
    font-size: 1rem;
    line-height: 1.5;
    font-weight: 400;
    white-space: normal;
    max-width: 380px;
    width: max-content;
    box-shadow: 0 6px 18px rgba(0,0,0,0.30);
    border: 1px solid var(--border-color, #334155);
    z-index: 1000;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.1s;
}
[data-tooltip]:hover::after,
[data-tooltip]:focus::after {
    opacity: 1;
}
[data-tooltip].tooltip-right::after {
    bottom: auto;
    left: calc(100% + 8px);
    top: 50%;
    transform: translateY(-50%);
}
