/* Groundskeeper -- stylesheet */
/* Refined utilitarian dashboard aesthetic */

/* IBM Plex, served from this server (frontend/fonts, SIL Open Font License): never fetched from Google (FONTS-LOCAL-01). */
@font-face { font-family:'IBM Plex Sans'; font-style:normal; font-weight:300; font-display:swap; src:url('/static/fonts/ibm-plex-sans-300.woff2') format('woff2'); }
@font-face { font-family:'IBM Plex Sans'; font-style:normal; font-weight:400; font-display:swap; src:url('/static/fonts/ibm-plex-sans-400.woff2') format('woff2'); }
@font-face { font-family:'IBM Plex Sans'; font-style:normal; font-weight:500; font-display:swap; src:url('/static/fonts/ibm-plex-sans-500.woff2') format('woff2'); }
@font-face { font-family:'IBM Plex Sans'; font-style:normal; font-weight:600; font-display:swap; src:url('/static/fonts/ibm-plex-sans-600.woff2') format('woff2'); }
@font-face { font-family:'IBM Plex Mono'; font-style:normal; font-weight:400; font-display:swap; src:url('/static/fonts/ibm-plex-mono-400.woff2') format('woff2'); }
@font-face { font-family:'IBM Plex Mono'; font-style:normal; font-weight:500; font-display:swap; src:url('/static/fonts/ibm-plex-mono-500.woff2') format('woff2'); }

* { box-sizing: border-box; margin: 0; padding: 0; }

:root {
    --sidebar-width: 220px;
    --sidebar-collapsed: 56px;
    --navy: #1a365d;
    --navy-light: #1e3a6e;
    --navy-dark: #132a4a;
    --accent: #3b82f6;
    --accent-soft: #dbeafe;
    /* Translucent, so one value reads on both themes (the Central pages). */
    --accent-faint: rgba(59,130,246,0.10);
    --accent-border: rgba(59,130,246,0.25);
    --green: #22c55e;
    --amber: #f59e0b;
    --red: #ef4444;
    --slate: #64748b;
    --bg: #f1f5f9;
    --card: #ffffff;
    --border: #e2e8f0;
    --text: #1e293b;
    --text-soft: #64748b;
    --text-muted: #94a3b8;
    --sidebar-transition: 0.22s cubic-bezier(0.4,0,0.2,1);

    /* -----------------------------------------------------------------
       THEME-SOON-01: semantic variables promoted out of hardcoded
       [data-theme="dark"] overrides (see the "Dark mode theme" block
       below). Each one carries its light/default value here; a theme
       block overrides only the ones that actually need to differ.
       Aliased to an existing palette variable wherever the literal
       already matched one exactly, so there is exactly one place each
       colour is written rather than two that can drift apart.
    ----------------------------------------------------------------- */
    --heading-accent: var(--navy);
    --topbar-bg: var(--card);
    --input-bg: var(--card);
    --btn-secondary-bg: var(--bg);
    --btn-secondary-color: var(--text-soft);
    --btn-secondary-border: var(--border);
    --btn-secondary-hover-bg: var(--border);
    --control-border: var(--border);
    --row-divider: #f8fafc;
    --panel-bg: #f8fafc;
    --disabled-bg: #f8fafc;
    --muted-badge-bg: var(--bg);
    --menu-item-text: var(--text);
    --menu-item-hover-bg: var(--bg);
    --badge-bg: #eff6ff;
    --badge-text: #1d4ed8;
    --success-bg: #f0fdf4;
    --success-border: #bbf7d0;
    --success-text: #15803d;
    --danger-bg: #fef2f2;
    --danger-border: #fecaca;
    --danger-text: #dc2626;
    --warn-bg: #fffbeb;
    --warn-border: #fde68a;
    --warn-text: #b45309;
    --ack-hover-bg: #f0fdf4;
    --ack-hover-border: #86efac;
    --snooze-hover-bg: #fffbeb;
    --snooze-hover-border: #fde68a;
}

/* ---------------------------------------------------------------------------
   Dark mode theme
   Applied via [data-theme="dark"] on <html>, set before render from localStorage
--------------------------------------------------------------------------- */

[data-theme="dark"] {
    --navy: #0f172a;
    --navy-light: #1e293b;
    --navy-dark: #020617;
    --accent: #60a5fa;
    --accent-soft: #1e3a5f;
    --green: #4ade80;
    --amber: #fbbf24;
    --red: #f87171;
    --bg: #0f172a;
    --card: #1e293b;
    --border: #334155;
    --text: #f1f5f9;
    --text-soft: #94a3b8;
    --text-muted: #64748b;

    /* THEME-SOON-01: dark-specific values for the semantic variables
       declared in :root above. Every rule that used to hardcode one of
       these hex values directly under [data-theme="dark"] has been
       removed -- the base (unthemed) rule now reads var(--xxx) and picks
       up the correct colour purely from the cascade. See the base rules
       throughout this file (.settings-card h3, .topbar, .btn-secondary,
       .result-msg.ok, etc.) for where each variable is consumed. */
    --heading-accent: #93c5fd;
    --topbar-bg: #1e293b;
    --input-bg: var(--bg);
    --btn-secondary-bg: #334155;
    --btn-secondary-color: #cbd5e1;
    --btn-secondary-border: #475569;
    --btn-secondary-hover-bg: #475569;
    --control-border: #475569;
    --row-divider: #334155;
    --panel-bg: var(--bg);
    --disabled-bg: var(--card);
    --muted-badge-bg: #334155;
    --menu-item-text: #cbd5e1;
    --menu-item-hover-bg: #334155;
    --badge-bg: #1e3a5f;
    --badge-text: #93c5fd;
    --success-bg: #052e16;
    --success-border: #166534;
    --success-text: #4ade80;
    --danger-bg: #2d0a0a;
    --danger-border: #991b1b;
    --danger-text: #f87171;
    --warn-bg: #1c1408;
    --warn-border: #78350f;
    --warn-text: #fbbf24;
    --ack-hover-bg: #334155;
    --ack-hover-border: #64748b;
    --snooze-hover-bg: #334155;
    --snooze-hover-border: #64748b;
}

/* This one dark rule stays as its own override rather than folding into
   the variable mechanism above: it deliberately points .tab-btn's colour
   at a DIFFERENT existing variable (--text-muted) than the base rule uses
   (--text-soft), rather than at a new dark-only literal. Nothing to
   promote -- there was never a hardcoded hex here. */
[data-theme="dark"] .tab-btn { color: var(--text-muted); }

/* ---------------------------------------------------------------------------
   Slate theme
   Applied via [data-theme="slate"] on <html>. A cool neutral, light-mode-ish
   palette -- only the sidebar/heading/background/border identity changes;
   text, severity (green/amber/red) and status-tint colours (success/danger/
   warn/badge) are deliberately left at their :root (light) defaults, since
   this theme keeps a light main content area.
--------------------------------------------------------------------------- */

[data-theme="slate"] {
    --navy: #334155;
    --navy-light: #475569;
    --navy-dark: #1e293b;
    --bg: #f8fafc;
    --border: #cbd5e1;
}

/* ---------------------------------------------------------------------------
   Forest theme
   Applied via [data-theme="forest"] on <html>. A deep green, light-mode-ish
   palette -- same approach as Slate above.
--------------------------------------------------------------------------- */

[data-theme="forest"] {
    --navy: #14532d;
    --navy-light: #166534;
    --navy-dark: #052e16;
    --bg: #f0fdf4;
    --border: #bbf7d0;
}

body {
    font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    background: var(--bg);
    color: var(--text);
    min-height: 100vh;
    display: flex;
}

/* ---------------------------------------------------------------------------
   Sidebar
--------------------------------------------------------------------------- */

.sidebar {
    position: fixed;
    top: 0; left: 0;
    height: 100vh;
    width: var(--sidebar-width);
    background: var(--navy);
    display: flex;
    flex-direction: column;
    z-index: 100;
    transition: width var(--sidebar-transition);
    overflow: hidden;
}

.sidebar.collapsed { width: var(--sidebar-collapsed); }

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1.125rem 1rem;
    border-bottom: 1px solid rgba(255,255,255,0.08);
    min-height: 60px;
    text-decoration: none;
    flex-shrink: 0;
}

.sidebar-brand-icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    background-image: url('/static/favicon.svg');
    background-repeat: no-repeat;
    background-position: center;
    background-size: 26px 26px;
    font-size: 0;
    color: transparent;
}

.sidebar-brand-text {
    overflow: hidden;
    white-space: nowrap;
    transition: opacity var(--sidebar-transition);
}

.sidebar-brand-name { font-size: 0.95rem; font-weight: 600; color: white; letter-spacing: -0.01em; line-height: 1.2; }

.sidebar-brand-sub {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.6rem;
    color: rgba(255,255,255,0.4);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-top: 1px;
}

/* SIDEBAR-VERSION-01: the running version under the brand, injected by
   nav_gating.js from /api/mat/role. One notch quieter than the tagline
   above it -- a glance-check, not a headline. Lives inside
   .sidebar-brand-text, so the collapsed-sidebar fade below covers it too. */
.sidebar-brand-version {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.6rem;
    color: rgba(255,255,255,0.28);
    letter-spacing: 0.05em;
    margin-top: 2px;
}

.sidebar.collapsed .sidebar-brand-text { opacity: 0; pointer-events: none; }

.sidebar-nav { flex: 1; padding: 0.75rem 0; overflow-y: auto; overflow-x: hidden; }
.sidebar-nav::-webkit-scrollbar { width: 0; }

.nav-section-label {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.6rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(255,255,255,0.3);
    padding: 0.875rem 1rem 0.25rem;
    white-space: nowrap;
    overflow: hidden;
    transition: opacity var(--sidebar-transition);
}

.sidebar.collapsed .nav-section-label { opacity: 0; }

.nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 1rem;
    color: rgba(255,255,255,0.65);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 400;
    white-space: nowrap;
    transition: background 0.15s, color 0.15s;
    border-left: 3px solid transparent;
    position: relative;
}

.nav-item:hover { background: rgba(255,255,255,0.07); color: white; }

.nav-item.active {
    background: rgba(59,130,246,0.18);
    color: white;
    border-left-color: var(--accent);
    font-weight: 500;
}

.nav-icon { font-size: 1rem; width: 24px; text-align: center; flex-shrink: 0; }
.nav-label { overflow: hidden; white-space: nowrap; transition: opacity var(--sidebar-transition); }
.sidebar.collapsed .nav-label { opacity: 0; pointer-events: none; }

.sidebar.collapsed .nav-item:hover::after {
    content: attr(data-label);
    position: absolute;
    left: calc(var(--sidebar-collapsed) + 8px);
    top: 50%;
    transform: translateY(-50%);
    background: var(--navy-dark);
    color: white;
    font-size: 0.8rem;
    padding: 4px 10px;
    border-radius: 4px;
    white-space: nowrap;
    pointer-events: none;
    z-index: 200;
    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}

.sidebar-footer { padding: 0.75rem; border-top: 1px solid rgba(255,255,255,0.08); flex-shrink: 0; }

.sidebar-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: 0.5rem;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 6px;
    color: rgba(255,255,255,0.5);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    font-size: 0.85rem;
    gap: 0.5rem;
    white-space: nowrap;
    overflow: hidden;
}

.sidebar-toggle:hover { background: rgba(255,255,255,0.12); color: white; }
.toggle-icon { flex-shrink: 0; font-size: 1rem; transition: transform var(--sidebar-transition); }
.sidebar.collapsed .toggle-icon { transform: rotate(180deg); }
.toggle-label { transition: opacity var(--sidebar-transition); font-size: 0.78rem; }
.sidebar.collapsed .toggle-label { opacity: 0; width: 0; }

.nav-status-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--green);
    margin-left: auto;
    flex-shrink: 0;
    transition: opacity var(--sidebar-transition);
}
.sidebar.collapsed .nav-status-dot { opacity: 0; }

/* ---------------------------------------------------------------------------
   Main content
--------------------------------------------------------------------------- */

.main-wrap {
    margin-left: var(--sidebar-width);
    flex: 1;
    /* min-width: 0 is LOAD-BEARING, not tidiness (2026-08-27, found live by
       Richard on /devices: the whole page scrolled sideways). body is a flex
       container and a flex item's default min-width:auto refuses to shrink
       below its content's intrinsic width -- a wide table propagates its
       min-content width up THROUGH its own overflow-x:auto wrapper (scroll
       containers still contribute content width to intrinsic sizing), so
       one wide table forced .main-wrap to 2500px+ and every sibling row
       (filter chips, banners) stretched to match. With min-width:0 the
       wrapper is capped at the viewport and wide content scrolls inside its
       own container, which is what those containers are for. Same fix the
       admin panel's sidebar conversion needed on its .main (2026-08-21). */
    min-width: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    transition: margin-left var(--sidebar-transition);
}

.main-wrap.sidebar-collapsed { margin-left: var(--sidebar-collapsed); }

.topbar {
    background: var(--topbar-bg);
    border-bottom: 1px solid var(--border);
    padding: 0 1.5rem;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-shrink: 0;
    position: sticky;
    top: 0;
    z-index: 50;
}

.topbar-title { font-size: 0.925rem; font-weight: 600; color: var(--text); }
.topbar-subtitle { font-family: 'IBM Plex Mono', monospace; font-size: 0.7rem; color: var(--text-muted); letter-spacing: 0.04em; }
.topbar > :first-child { min-width: 0; margin-right: 1rem; }   /* TOPBAR-01: the title block gives way, never the buttons */
.topbar-subtitle { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-right { display: flex; align-items: center; gap: 0.75rem; flex-shrink: 0; white-space: nowrap; }
.topbar-status { display: flex; align-items: center; gap: 0.4rem; font-size: 0.75rem; color: var(--text-soft); font-family: 'IBM Plex Mono', monospace; }
/* BRANDING-01: the school's name and logo, first thing on the right of every top bar. */
.brand-chip { display: inline-flex; align-items: center; gap: 0.5rem; text-decoration: none; color: var(--text); font-size: 0.8rem; font-weight: 600; max-width: 280px; margin-left: 0.25rem; }
.brand-chip:hover { color: var(--accent); }
.brand-chip-logo { height: 28px; max-width: 120px; object-fit: contain; display: block; }
.brand-chip-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.present-logo { height: 48px; max-width: 200px; object-fit: contain; vertical-align: middle; margin-right: 0.75rem; }

.pulse-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--green);
    animation: pulse 2.5s infinite;
}

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

main { padding: 1.5rem; flex: 1; }

/* ---------------------------------------------------------------------------
   Cards
--------------------------------------------------------------------------- */

.card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; margin-bottom: 1rem; }
.card h2 { font-size: 0.875rem; font-weight: 600; color: var(--heading-accent); margin-bottom: 0.875rem; letter-spacing: -0.01em; }
.card h3 { font-size: 0.825rem; font-weight: 600; color: var(--heading-accent); margin-bottom: 0.75rem; }

.two-col { display: grid; grid-template-columns: 1fr 300px; gap: 1rem; margin-top: 1rem; }
@media (max-width: 900px) { .two-col { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
   AI
--------------------------------------------------------------------------- */

.summary-banner-wrap {
    background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 6px;
    padding: 0.6rem 1rem; margin-bottom: 1rem;
    font-size: 0.825rem; color: #1d4ed8; font-weight: 500;
    display: flex; align-items: center; gap: 0.5rem;
}
.summary-banner-wrap::before { content: '\2726'; font-size: 0.7rem; opacity: 0.6; flex-shrink: 0; }

.ai-panel { margin-bottom: 1rem; }
.ai-input-row { display: flex; gap: 0.5rem; }
.ai-input-row input {
    flex: 1; padding: 0.55rem 0.875rem;
    border: 1px solid var(--border); border-radius: 6px;
    font-size: 0.875rem; font-family: 'IBM Plex Sans', sans-serif;
    color: var(--text); background: white; transition: border-color 0.15s;
}
.ai-input-row input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(59,130,246,0.12); }
.ai-input-row button {
    padding: 0.55rem 1.25rem; background: var(--accent); color: white;
    border: none; border-radius: 6px; cursor: pointer;
    font-size: 0.875rem; font-family: 'IBM Plex Sans', sans-serif;
    font-weight: 500; transition: background 0.15s; white-space: nowrap;
}
.ai-input-row button:hover { background: #2563eb; }
.ai-response {
    margin-top: 0.75rem; padding: 0.875rem 1rem;
    background: #eff6ff; border-left: 3px solid var(--accent);
    border-radius: 0 6px 6px 0; font-size: 0.875rem;
    line-height: 1.65; white-space: pre-wrap; color: var(--text);
}
.hidden { display: none; }

/* ---------------------------------------------------------------------------
   Feed
--------------------------------------------------------------------------- */

.feed-panel { margin-bottom: 0; }
.feed-event {
    display: flex; align-items: flex-start; gap: 0.75rem;
    padding: 0.625rem 0; border-bottom: 1px solid var(--row-divider);
    transition: opacity 0.2s ease;
}
.feed-event:last-child { border-bottom: none; }
.feed-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex-shrink: 0; }
.severity-ok .feed-dot     { background: var(--green); }
.severity-warning .feed-dot { background: var(--amber); }
.severity-critical .feed-dot { background: var(--red); }
.severity-info .feed-dot   { background: var(--accent); }
/* A11Y-SEVERITY-01 (2026-09-02): severity is never colour ALONE. Each dot
   also has a SHAPE -- circle ok, diamond warning, triangle critical, square
   info -- so red/amber/green still separate for the ~8% of men with
   red-green colourblindness, on a projector, and on a monochrome printout.
   The colour stays: the shape is added, not swapped. Settings -> Appearance
   can turn the shapes off; that writes data-severity="colour-only" on
   <html> from localStorage, the same way the theme is applied. */
.severity-warning  .feed-dot { border-radius: 0; clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); width: 10px; height: 10px; margin-top: 4px; }
.severity-critical .feed-dot { border-radius: 0; clip-path: polygon(50% 0, 100% 100%, 0 100%); width: 10px; height: 10px; margin-top: 4px; }
.severity-info     .feed-dot { border-radius: 2px; }
[data-severity="colour-only"] .feed-dot { border-radius: 50%; clip-path: none; width: 8px; height: 8px; margin-top: 5px; }
.feed-content { flex: 1; min-width: 0; }
/* overflow-wrap on title + detail (2026-08-28, found live): a feed event
   carrying a long unbroken token -- the trigger was a Meraki 429 whose
   detail quoted a 150-char API URL -- otherwise refuses to wrap, pushes
   the feed card past the viewport and gives the WHOLE Dashboard a
   horizontal scrollbar. `anywhere` over `break-word`: it also lets the
   flex sizing shrink the box, which break-word does not. */
.feed-title { font-size: 0.825rem; font-weight: 500; line-height: 1.4; color: var(--text); display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem; overflow-wrap: anywhere; }
.feed-detail { font-size: 0.75rem; color: var(--text-soft); margin-top: 2px; line-height: 1.4; overflow-wrap: anywhere; }
.feed-right { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
.feed-meta { font-family: 'IBM Plex Mono', monospace; font-size: 0.65rem; color: var(--text-muted); text-align: right; white-space: nowrap; line-height: 1.5; }

.feed-connector-tag {
    cursor: pointer;
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.65rem;
    color: var(--text-muted);
    transition: color 0.12s;
    display: inline-block;
}
.feed-connector-tag:hover { color: var(--accent); }

.feed-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }

.explain-btn {
    font-size: 0.68rem; padding: 2px 7px;
    background: transparent; border: 1px solid var(--border); border-radius: 4px;
    cursor: pointer; color: var(--text-soft); white-space: nowrap;
    font-family: 'IBM Plex Mono', monospace; transition: background 0.12s, border-color 0.12s;
}
.explain-btn:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

.draft-comms-btn {
    font-size: 0.68rem; padding: 2px 7px;
    background: transparent; border: 1px solid #fca5a5; border-radius: 4px;
    cursor: pointer; color: #dc2626; white-space: nowrap;
    font-family: 'IBM Plex Mono', monospace; transition: background 0.12s, border-color 0.12s;
}
.draft-comms-btn:hover { background: #fef2f2; border-color: var(--red); }

/* Acknowledge button */
.ack-btn {
    font-size: 0.68rem; padding: 2px 7px;
    background: transparent; border: 1px solid var(--control-border); border-radius: 4px;
    cursor: pointer; color: var(--text-soft); white-space: nowrap;
    font-family: 'IBM Plex Mono', monospace; transition: background 0.12s, border-color 0.12s;
}
.ack-btn:hover { background: var(--ack-hover-bg); border-color: var(--ack-hover-border); color: #15803d; }

/* Snooze button + dropdown */
.snooze-wrap { position: relative; }
.snooze-btn {
    font-size: 0.68rem; padding: 2px 7px;
    background: transparent; border: 1px solid var(--control-border); border-radius: 4px;
    cursor: pointer; color: var(--text-soft); white-space: nowrap;
    font-family: 'IBM Plex Mono', monospace; transition: background 0.12s, border-color 0.12s;
}
.snooze-btn:hover { background: var(--snooze-hover-bg); border-color: var(--snooze-hover-border); color: #b45309; }
.snooze-menu {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.12);
    z-index: 200;
    min-width: 140px;
    overflow: hidden;
}
.snooze-menu button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.45rem 0.875rem;
    font-size: 0.8rem;
    font-family: 'IBM Plex Sans', sans-serif;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--menu-item-text);
    transition: background 0.1s;
}
.snooze-menu button:hover { background: var(--menu-item-hover-bg); }
.snooze-menu .snooze-clear {
    border-top: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 0.75rem;
}
.snooze-menu .snooze-clear:hover { background: #fef2f2; color: var(--red); }

/* Acknowledge / Snooze state badges */
.ack-badge {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.6rem;
    font-weight: 600;
    padding: 1px 6px;
    border-radius: 3px;
    letter-spacing: 0.04em;
    flex-shrink: 0;
}
.ack-badge-acked   { background: #f0fdf4; color: #15803d; }
.ack-badge-snoozed { background: #fffbeb; color: #b45309; }
/* FEED-RESOLVED-01: an incident a later recovery resolved. Struck through on
   the title only (the detail stays readable), dimmed less than acknowledged --
   acknowledged means "I know", resolved means "it is over" -- and the badge
   jumps to the recovery. A condition whose state merely moved on (a warning
   that became a critical) is tagged, never struck. Badges are inline-block
   so the title's line does not run through them. */
.feed-event.resolved { opacity: 0.72; }
.feed-title-resolved { text-decoration: line-through; text-decoration-thickness: 1px; }
.feed-title-resolved .ack-badge, .feed-title-resolved .maint-badge,
.feed-title-resolved .resolved-badge, .feed-title-resolved .superseded-badge,
.feed-title-resolved .recur-badge { display: inline-block; text-decoration: none; }
.resolved-badge, .superseded-badge, .recur-badge {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.6rem;
    font-weight: 600;
    padding: 1px 6px;
    border-radius: 3px;
    letter-spacing: 0.04em;
    flex-shrink: 0;
    margin-left: 0.4rem;
}
.resolved-badge { background: #f0fdf4; color: #15803d; }
.resolved-badge-link { cursor: pointer; text-decoration: underline dotted; }
.superseded-badge { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); }
/* FEED-RECURRENCE-01: "3rd time in 30 days" beside a row whose condition keeps
   coming back -- struck or live. Quiet, like the Superseded tag: it is context,
   not a state. */
.recur-badge { background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); font-weight: 500; letter-spacing: 0; }
.feed-event.feed-flash { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* An outage inside a maintenance window (MAINT-WINDOWS-01): expected, not a fault. */
.maint-badge {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.6rem;
    font-weight: 600;
    padding: 1px 6px;
    border-radius: 3px;
    letter-spacing: 0.04em;
    flex-shrink: 0;
    margin-left: 0.4rem;
    background: #eff6ff;
    color: #1d4ed8;
}

.explain-panel {
    margin: 0 0 6px 1.25rem; padding: 0.75rem 0.875rem;
    background: #fffbeb; border-left: 2px solid var(--amber);
    border-radius: 0 4px 4px 0; font-size: 0.8rem; line-height: 1.6; color: var(--text);
}
.explain-loading { color: var(--text-muted); font-style: italic; }

.draft-comms-panel { background: #fef2f2; border-left-color: var(--red); }

.draft-comms-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.5rem;
}

.draft-comms-label {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.68rem;
    font-weight: 600;
    color: #b91c1c;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.draft-copy-btn {
    font-size: 0.68rem; padding: 2px 8px;
    background: white; border: 1px solid #fca5a5; border-radius: 4px;
    cursor: pointer; color: #dc2626;
    font-family: 'IBM Plex Mono', monospace; transition: background 0.12s;
}
.draft-copy-btn:hover { background: #fee2e2; }

.draft-comms-text { white-space: pre-wrap; line-height: 1.65; font-size: 0.825rem; color: var(--text); }

.feed-filters {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.875rem;
    flex-wrap: wrap;
}
.feed-filter-btn {
    padding: 0.25rem 0.75rem;
    border-radius: 4px;
    border: 1px solid var(--border);
    background: transparent;
    font-size: 0.75rem;
    font-family: 'IBM Plex Mono', monospace;
    cursor: pointer;
    color: var(--text-soft);
    transition: background 0.12s, color 0.12s, border-color 0.12s;
    white-space: nowrap;
}
.feed-filter-btn:hover { background: var(--bg); }
.feed-filter-btn.active { background: var(--navy); color: white; border-color: var(--navy); }
.feed-filter-btn.sev-critical.active { background: var(--red); border-color: var(--red); }
.feed-filter-btn.sev-warning.active  { background: var(--amber); border-color: var(--amber); color: white; }
.feed-filter-btn.sev-ok.active       { background: var(--green); border-color: var(--green); }
.feed-filter-btn.sev-info.active     { background: var(--accent); border-color: var(--accent); }
.feed-filter-sep { width: 1px; height: 18px; background: var(--border); flex-shrink: 0; }
.feed-count { font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; color: var(--text-muted); margin-left: auto; }
.load-more-btn {
    display: none;
    width: 100%;
    margin-top: 0.75rem;
    padding: 0.5rem;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.8rem;
    font-family: 'IBM Plex Sans', sans-serif;
    color: var(--text-soft);
    cursor: pointer;
    transition: background 0.12s;
}
.load-more-btn:hover { background: var(--border); }

/* ---------------------------------------------------------------------------
   Connector status panel
--------------------------------------------------------------------------- */

.connector-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.75rem;
    margin-bottom: 5px;
    background: var(--bg);   /* was #f8fafc: in dark mode the name (var(--text), light) vanished on it -- SITE-SCREENS-01 */
    border-radius: 6px;
    border: 1px solid var(--border);
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
.connector-item:hover { background: color-mix(in srgb, var(--accent) 8%, var(--card)); border-color: color-mix(in srgb, var(--accent) 35%, var(--border)); }
.connector-item-active { background: color-mix(in srgb, var(--accent) 12%, var(--card)) !important; border-color: var(--accent) !important; }
.connector-left { display: flex; align-items: center; gap: 8px; }
.connector-name { font-size: 0.8rem; font-weight: 500; color: var(--text); }
.connector-last { font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; color: var(--text-muted); }
.connector-status { font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; font-weight: 500; padding: 2px 8px; border-radius: 4px; }
.cs-ok       { background: var(--success-bg); color: var(--success-text); }
.cs-err      { background: var(--danger-bg); color: var(--danger-text); }
.cs-stale    { background: var(--warn-bg); color: var(--warn-text); }
.cs-enabled  { background: var(--success-bg); color: var(--success-text); }
.cs-disabled { background: var(--disabled-bg); color: var(--text-muted); }
.dot-sm { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }

/* ---------------------------------------------------------------------------
   SLT view
--------------------------------------------------------------------------- */

.status-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.status-card { background: var(--card); border-radius: 8px; padding: 1.25rem; border: 1px solid var(--border); border-top: 3px solid #cbd5e0; }
.status-card.ok      { border-top-color: var(--green); }
.status-card.warning  { border-top-color: var(--amber); }
.status-card.critical { border-top-color: var(--red); }
.status-card.unknown  { border-top-color: #cbd5e0; }
.card-top { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; }
.status-icon { font-size: 1.4rem; flex-shrink: 0; }
.status-label { font-size: 0.875rem; font-weight: 500; color: var(--text); }
.status-value { font-family: 'IBM Plex Mono', monospace; font-size: 0.72rem; font-weight: 500; padding: 2px 8px; border-radius: 4px; display: inline-block; margin-top: 2px; }
.status-value.ok       { background: #f0fdf4; color: #15803d; }
.status-value.warning  { background: #fffbeb; color: #b45309; }
.status-value.critical { background: #fef2f2; color: #dc2626; }
.status-value.unknown  { background: #f8fafc; color: #94a3b8; }
.card-events { margin-top: 0.75rem; border-top: 1px solid #f1f5f9; padding-top: 0.75rem; }
.card-event { font-size: 0.775rem; color: var(--text-soft); padding: 0.25rem 0; border-bottom: 1px solid #f8fafc; line-height: 1.4; }
.card-event:last-child { border-bottom: none; }
.card-hint { font-size: 0.72rem; color: var(--text-muted); margin-top: 0.75rem; font-style: italic; line-height: 1.5; }
.card-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
.card-ticket-btn { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0.65rem; font-family: 'IBM Plex Mono', monospace; font-size: 0.7rem; font-weight: 500; color: var(--accent); background: transparent; border: 1px solid var(--accent); border-radius: 5px; cursor: pointer; }
.card-ticket-btn:hover { background: var(--accent); color: white; }
.card-ticket-btn.copied { color: #15803d; border-color: #15803d; background: #f0fdf4; }
.overall-banner { border-radius: 8px; padding: 1rem 1.25rem; margin-bottom: 1.5rem; font-size: 0.95rem; font-weight: 500; display: flex; align-items: center; justify-content: space-between; }
.overall-banner.ok       { background: #f0fdf4; border: 1px solid #bbf7d0; color: #15803d; }
.overall-banner.warning  { background: #fffbeb; border: 1px solid #fde68a; color: #b45309; }
.overall-banner.critical { background: #fef2f2; border: 1px solid #fecaca; color: #dc2626; }
.overall-banner.unknown  { background: #f8fafc; border: 1px solid var(--border); color: #94a3b8; }
.last-updated { font-family: 'IBM Plex Mono', monospace; font-size: 0.7rem; font-weight: 400; opacity: 0.75; }
.slt-note { font-size: 0.75rem; color: var(--text-muted); text-align: center; margin-top: 1rem; }
.info-note { background: #eff6ff; border: 1px solid #bfdbfe; color: #1e40af; border-radius: 8px; padding: 0.85rem 1.1rem; margin-top: 1rem; font-size: 0.825rem; line-height: 1.5; display: flex; align-items: flex-start; gap: 0.6rem; }
.info-note .info-note-icon { flex-shrink: 0; font-size: 1rem; }
.info-note .info-note-title { font-weight: 500; margin-bottom: 0.2rem; }

/* ---------------------------------------------------------------------------
   Settings
--------------------------------------------------------------------------- */

.tabs { display: flex; gap: 0; border-bottom: 1px solid var(--border); margin-bottom: 1.5rem; overflow-x: auto; }
.tab-btn { padding: 0.7rem 1.25rem; font-size: 0.825rem; border: none; background: none; cursor: pointer; color: var(--text-soft); border-bottom: 2px solid transparent; white-space: nowrap; font-weight: 500; font-family: 'IBM Plex Sans', sans-serif; transition: color 0.15s; }
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }
.tab-btn:hover { color: var(--text); }
.tab-pane { display: none; }
.tab-pane.active { display: block; }

.settings-card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; margin-bottom: 1rem; }
.settings-card h3 { font-size: 0.875rem; font-weight: 600; color: var(--heading-accent); margin-bottom: 0.875rem; }

label { display: flex; align-items: center; gap: 0.35rem; font-size: 0.8rem; font-weight: 500; color: var(--text-soft); margin-bottom: 0.3rem; }

input[type="text"], input[type="password"], input[type="number"], select, textarea {
    width: 100%; padding: 0.5rem 0.875rem;
    border: 1px solid var(--border); border-radius: 6px;
    font-size: 0.875rem; margin-bottom: 0.875rem;
    color: var(--text); background: var(--input-bg);
    font-family: 'IBM Plex Sans', sans-serif; transition: border-color 0.15s;
}
textarea { resize: vertical; min-height: 80px; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(59,130,246,0.1); }

.btn { padding: 0.5rem 1.25rem; border-radius: 6px; border: none; cursor: pointer; font-size: 0.875rem; font-weight: 500; font-family: 'IBM Plex Sans', sans-serif; transition: background 0.15s; }
.btn-primary { background: var(--accent); color: white; }
/* A disabled button must LOOK disabled. Until 2026-09-02 nothing styled
   the disabled state, so the restore dialog's typed gate held (the click
   did nothing) while the button looked clickable -- Richard: "It's not grey
   but it doesn't do anything if I click it." The guard was invisible, which
   reads as broken. Applies to every .btn in the product. */
.btn:disabled, .btn[disabled] { opacity: 0.45; cursor: not-allowed; }
.btn-primary:hover { background: #2563eb; }
.btn-secondary { background: var(--btn-secondary-bg); color: var(--btn-secondary-color); border: 1px solid var(--btn-secondary-border); }
.btn-secondary:hover { background: var(--btn-secondary-hover-bg); }
.btn-sm { padding: 0.35rem 0.875rem; font-size: 0.8rem; }
.btn-row { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; margin-top: 0.5rem; }

.result-msg { font-size: 0.8rem; padding: 0.5rem 0.875rem; border-radius: 6px; display: none; }
.result-msg.ok   { background: var(--success-bg); border: 1px solid var(--success-border); color: var(--success-text); }
.result-msg.fail { background: var(--danger-bg); border: 1px solid var(--danger-border); color: var(--danger-text); }

.connector-row { display: flex; align-items: center; justify-content: space-between; padding: 0.875rem 0; border-bottom: 1px solid var(--row-divider); cursor: pointer; }
.connector-row:last-child { border-bottom: none; }
.catalog-row { cursor: default; }
.connector-row-left { display: flex; align-items: center; gap: 0.75rem; }
.connector-icon { font-size: 1.2rem; }
.connector-name { font-size: 0.875rem; font-weight: 500; }
.connector-desc { font-size: 0.775rem; color: var(--text-soft); }
.connector-fields { display: none; padding: 1rem; background: var(--panel-bg); border-radius: 6px; margin-top: 0.5rem; margin-bottom: 0.5rem; }
.connector-fields.open { display: block; }

/* CONN-TABS-01 (2026-09-06): Connector Settings uses the shared .tabs bar
   above (it had its own pill-style strip inside the card until now, the
   "different design language" Richard noticed). These add the two
   things its Active/Catalogue tabs need: a count pill inside a tab, and a
   search box at the bar's right end. */
.tabs .tab-count {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.65rem;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: 600;
    margin-left: 0.3rem;
    vertical-align: middle;
}
.tab-count-muted {
    background: var(--muted-badge-bg);
    color: var(--text-muted);
}
.tabs .tab-spacer { flex: 1; }
.tabs .tab-search {
    width: auto;
    min-width: 14rem;
    margin: 0.25rem 0;
    padding: 0.35rem 0.75rem;
    font-size: 0.8rem;
    font-family: 'IBM Plex Mono', monospace;
}

/* Connector modal */
.connector-modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(15,23,42,0.45);
    z-index: 300;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}
.connector-modal-overlay.open {
    display: flex;
}
.connector-modal-box {
    background: var(--card);
    border-radius: 10px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.2);
    width: 100%;
    max-width: 560px;
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.connector-modal-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    padding: 1.125rem 1.25rem 1rem;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.connector-modal-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--heading-accent);
    line-height: 1.3;
}
.connector-modal-desc {
    font-size: 0.775rem;
    color: var(--text-muted);
    margin-top: 2px;
}
.connector-modal-close {
    font-size: 1.25rem;
    line-height: 1;
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 4px;
    flex-shrink: 0;
    margin-left: 0.75rem;
    transition: background 0.12s, color 0.12s;
}
.connector-modal-close:hover { background: var(--bg); color: var(--text); }
.connector-modal-body {
    padding: 1.125rem 1.25rem;
    overflow-y: auto;
    flex: 1;
}
.connector-modal-footer {
    padding: 0.875rem 1.25rem;
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
    background: var(--panel-bg);
    border-radius: 0 0 10px 10px;
}

/* Theme swatches */
.theme-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 0.75rem;
    margin-top: 0.75rem;
}
.theme-swatch {
    border: 2px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
    transition: border-color 0.15s, transform 0.12s;
    position: relative;
}
.theme-swatch:hover { border-color: var(--accent); transform: translateY(-1px); }
.theme-swatch.active { border-color: var(--accent); }
.theme-swatch.coming-soon { cursor: default; opacity: 0.6; }
.theme-swatch.coming-soon:hover { border-color: var(--border); transform: none; }
.theme-preview {
    height: 52px;
    display: flex;
}
.theme-preview-sidebar { width: 28%; }
.theme-preview-main { flex: 1; padding: 5px; display: flex; flex-direction: column; gap: 3px; }
.theme-preview-bar { height: 7px; border-radius: 2px; }
.theme-preview-card { height: 10px; border-radius: 2px; }
.theme-label {
    padding: 0.3rem 0.5rem;
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--text-soft);
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.theme-cs-badge {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 0.6rem;
    padding: 1px 5px;
    border-radius: 3px;
    background: #f1f5f9;
    color: var(--text-muted);
}

.toggle { position: relative; width: 40px; height: 22px; flex-shrink: 0; }
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle-slider { position: absolute; cursor: pointer; inset: 0; background: #cbd5e0; border-radius: 22px; transition: 0.2s; }
.toggle-slider::before { content: ''; position: absolute; height: 16px; width: 16px; left: 3px; bottom: 3px; background: white; border-radius: 50%; transition: 0.2s; }
.toggle input:checked + .toggle-slider { background: var(--green); }
.toggle input:checked + .toggle-slider::before { transform: translateX(18px); }

.version-badge { display: inline-block; font-family: 'IBM Plex Mono', monospace; font-size: 0.78rem; padding: 0.2rem 0.75rem; border-radius: 4px; background: var(--badge-bg); color: var(--badge-text); }
.update-banner { background: var(--warn-bg); border: 1px solid var(--warn-border); border-radius: 6px; padding: 0.875rem 1rem; margin-bottom: 1rem; font-size: 0.875rem; color: var(--warn-text); display: none; }

.domain-list { list-style: none; margin-bottom: 0.875rem; min-height: 10px; }
.domain-item { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 0.75rem; background: var(--panel-bg); border-radius: 4px; margin-bottom: 4px; font-size: 0.825rem; font-family: 'IBM Plex Mono', monospace; }
.domain-remove { cursor: pointer; color: #dc2626; font-size: 1rem; line-height: 1; background: none; border: none; padding: 0 4px; }
.domain-add-row { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
.domain-add-row input { margin-bottom: 0; flex: 1; font-family: 'IBM Plex Mono', monospace; }

.org-list { list-style: none; margin-bottom: 0.75rem; }
.org-item { display: grid; grid-template-columns: 1fr 1fr auto; gap: 0.5rem; align-items: center; margin-bottom: 6px; }
.org-item input { margin-bottom: 0; }
.org-remove { cursor: pointer; color: #dc2626; font-size: 1rem; background: none; border: none; padding: 2px 6px; flex-shrink: 0; }
.org-header { display: grid; grid-template-columns: 1fr 1fr auto; gap: 0.5rem; margin-bottom: 4px; }
.org-header span { font-size: 0.72rem; font-weight: 500; color: var(--text-muted); }

/* ---------------------------------------------------------------------------
   Help tooltips
--------------------------------------------------------------------------- */

.help-tip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: var(--border);
    color: var(--text-soft);
    font-size: 0.65rem;
    font-weight: 600;
    cursor: help;
    position: relative;
    flex-shrink: 0;
    font-style: normal;
    line-height: 1;
    transition: background 0.15s;
}

.help-tip:hover { background: var(--accent); color: white; }

.help-tip::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--navy-dark);
    color: white;
    font-size: 0.75rem;
    font-weight: 400;
    line-height: 1.5;
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
    white-space: pre-wrap;
    width: 260px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.2);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 500;
    text-align: left;
}

.help-tip::before {
    content: '';
    position: absolute;
    bottom: calc(100% + 2px);
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--navy-dark);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 500;
}

.help-tip:hover::after,
.help-tip:hover::before { opacity: 1; }

.help-tip.tip-below::after { bottom: auto; top: calc(100% + 8px); }
.help-tip.tip-below::before { bottom: auto; top: calc(100% + 2px); border-top-color: transparent; border-bottom-color: var(--navy-dark); }

/* UX-TOOLTIP-01: while help-tips.js is managing this element's tooltip (see
   frontend/js/help-tips.js), suppress the native ::after/::before bubble so
   the two mechanisms never show two overlapping tooltips at once. !important
   is deliberate here -- it must win over the plain :hover rule above,
   regardless of selector order. This is pure progressive enhancement: if
   help-tips.js fails to load for any reason, js-hover is never added and the
   original CSS-only tooltip (with its known modal-clipping limitation)
   still works exactly as before. */
.help-tip.js-hover::after,
.help-tip.js-hover::before { opacity: 0 !important; }

/* JS-positioned tooltip popup (help-tips.js). Rendered as a single shared
   element appended directly to <body> with position:fixed, computed from
   the anchor's real getBoundingClientRect() -- this is what actually fixes
   the modal-clipping/z-index issue above, since a fixed-position element is
   only affected by an ancestor with its own transform/filter/perspective
   (none of which exist anywhere in the connector modal's markup), so it can
   never be cropped by .connector-modal-body's overflow-y:auto and always
   renders above the modal regardless of the modal's own z-index. */
.gk-tooltip-popup {
    position: fixed;
    z-index: 9999;
    background: var(--navy-dark);
    color: white;
    font-size: 0.75rem;
    font-weight: 400;
    line-height: 1.5;
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
    white-space: pre-wrap;
    box-shadow: 0 4px 12px rgba(0,0,0,0.2);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.12s;
    text-align: left;
}
.gk-tooltip-popup.visible { opacity: 1; }
.gk-tooltip-popup::after {
    content: '';
    position: absolute;
    left: var(--gk-tip-arrow-x, 50%);
    transform: translateX(-50%);
    border: 5px solid transparent;
}
.gk-tooltip-popup.arrow-top::after { top: 100%; border-top-color: var(--navy-dark); }
.gk-tooltip-popup.arrow-bottom::after { bottom: 100%; border-bottom-color: var(--navy-dark); }

/* Central drawer (CENTRAL-DRAWER-01, 2026-09-06): the slide-in panel the hub
   pages share -- frontend/js/central-drawer.js injects the markup. The Devices
   page drawer's shape, prefixed so the two never collide. */
.cdrawer-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.18); z-index: 200; }
.cdrawer-overlay.open { display: block; }
.cdrawer { position: fixed; top: 0; right: 0; bottom: 0; width: 440px; max-width: 100vw; background: var(--card); border-left: 1px solid var(--border); z-index: 201; overflow-y: auto; transform: translateX(100%); transition: transform 0.22s cubic-bezier(0.4,0,0.2,1); padding: 1.5rem 1.5rem 2rem; }
.cdrawer.open { transform: translateX(0); }
@media (prefers-reduced-motion: reduce) { .cdrawer { transition: none; } }
.cdrawer-close { position: absolute; top: 1rem; right: 1rem; background: none; border: none; font-size: 1.25rem; cursor: pointer; color: var(--text-muted); line-height: 1; padding: 0.25rem; }
.cdrawer-title { font-size: 1.05rem; font-weight: 700; color: var(--text); margin-bottom: 0.25rem; padding-right: 2rem; }
.cdrawer-sub { font-size: 0.78rem; color: var(--text-muted); margin-bottom: 1.1rem; font-family: 'IBM Plex Mono', monospace; }
.cdrawer-pill { color: #fff; font-size: 0.68rem; padding: 2px 8px; border-radius: 3px; font-weight: 600; font-family: 'IBM Plex Sans', sans-serif; }
.cdrawer-section { margin-bottom: 1.1rem; }
.cdrawer-section-title { font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 0.45rem; }
.cdrawer-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.35rem 0; border-bottom: 1px solid var(--border); font-size: 0.825rem; }
.cdrawer-row:last-child { border-bottom: none; }
.cdrawer-subrow { font-size: 0.74rem; padding: 0 0 0.35rem 1.1rem; border-bottom: 1px solid var(--border); }
.cdrawer-label { color: var(--text-soft); display: inline-flex; align-items: center; gap: 0.4rem; }
.cdrawer-val { font-family: 'IBM Plex Mono', monospace; font-size: 0.76rem; color: var(--text); text-align: right; }
.cdrawer-mono { font-family: 'IBM Plex Mono', monospace; }
.cdrawer-bad { color: #dc2626; }
.cdrawer-muted { font-size: 0.76rem; color: var(--text-muted); line-height: 1.45; }
.cdrawer-own { margin-bottom: 0.9rem; }
.cdrawer-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.cdrawer-issue { display: flex; gap: 0.6rem; align-items: flex-start; padding: 0.4rem 0; border-bottom: 1px solid var(--border); }
.cdrawer-issue:last-child { border-bottom: none; }
.cdrawer-issue .cdrawer-dot { margin-top: 5px; }
.cdrawer-issue-main { min-width: 0; }
.cdrawer-issue-title { font-size: 0.8rem; color: var(--text); font-weight: 600; line-height: 1.35; }
.cdrawer-issue-resolved .cdrawer-issue-title { text-decoration: line-through; color: var(--text-muted); font-weight: 500; }
.cdrawer-issue-meta { font-size: 0.7rem; color: var(--text-muted); margin-top: 2px; font-family: 'IBM Plex Mono', monospace; }
.cdrawer-badge { display: inline-block; margin-left: 0.4rem; font-size: 0.6rem; font-weight: 600; padding: 1px 6px; border-radius: 3px; letter-spacing: 0.04em; background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); }
.cdrawer-badge-ok { background: #f0fdf4; color: #15803d; border-color: transparent; }
.cdrawer-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.cdrawer-chip { font-size: 0.68rem; padding: 2px 8px; border-radius: 3px; background: var(--bg); border: 1px solid var(--border); color: var(--text-soft); }
.cdrawer-links { display: flex; flex-direction: column; gap: 0.4rem; margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.cdrawer-link { font-size: 0.8rem; color: var(--accent); text-decoration: none; font-weight: 500; }
.cdrawer-link:hover { text-decoration: underline; }
.cdrawer-rag-green { color: #16a34a; } .cdrawer-rag-amber { color: #d97706; } .cdrawer-rag-red { color: #dc2626; } .cdrawer-rag-unknown { color: var(--text-muted); }
.cdrawer-resolved-note { margin-top: 0.4rem; }
/* Central Alerts (CENTRAL-DRAWER-01): a forwarded alert the school has since
   resolved is struck, as on the school's own feed; a row is clickable. */
.alert-row-click { cursor: pointer; }
.alert-row-click:hover { background: var(--bg); }
.alert-row-resolved .alert-title { text-decoration: line-through; color: var(--text-muted); font-weight: 500; }
.alert-badge { display: inline-block; font-size: 0.6rem; font-weight: 600; padding: 1px 6px; border-radius: 3px; letter-spacing: 0.04em; background: var(--bg); color: var(--text-muted); border: 1px solid var(--border); }
.alert-badge-ok { background: #f0fdf4; color: #15803d; border-color: transparent; }
.alerts-check { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.8rem; color: var(--text-soft); cursor: pointer; white-space: nowrap; }
.rollup-none { color: var(--text-muted); }

/* ---------------------------------------------------------------------------
   Phone layout (MOBILE-01, 2026-09-03) -- parity sweep item 7.
   Below 768px the sidebar is the 56px icon rail whatever the stored collapse
   preference says. nav_gating.js adds the two things CSS cannot: a tap on the
   rail's toggle opens the full-width menu OVER the page (.gk-open, with a
   scrim on body; tap anywhere else to close), and on the first page of a
   browser session the menu slides out with its labels for a moment and
   retracts (.gk-peek) so the icons have been seen with their names once.
   Feed rows put connector, time and the action buttons on a line UNDER the
   title instead of in a column beside it, sized for a thumb. Every rule is
   inside the media query; laptops and desktops are untouched.
--------------------------------------------------------------------------- */
@media (max-width: 767px) {
    .sidebar, .sidebar.collapsed { width: var(--sidebar-collapsed); }
    .sidebar.gk-open, .sidebar.gk-peek { width: var(--sidebar-width); box-shadow: 4px 0 24px rgba(0,0,0,0.35); }
    .sidebar .sidebar-brand-text, .sidebar .nav-label, .sidebar .nav-section-label,
    .sidebar .toggle-label, .sidebar .nav-status-dot { opacity: 0; pointer-events: none; }
    .sidebar .toggle-label { width: 0; }   /* or the chevron is centred out of the 40px button */
    .sidebar.gk-open .sidebar-brand-text, .sidebar.gk-open .nav-label, .sidebar.gk-open .nav-section-label,
    .sidebar.gk-open .toggle-label, .sidebar.gk-open .nav-status-dot,
    .sidebar.gk-peek .sidebar-brand-text, .sidebar.gk-peek .nav-label, .sidebar.gk-peek .nav-section-label,
    .sidebar.gk-peek .toggle-label, .sidebar.gk-peek .nav-status-dot { opacity: 1; pointer-events: auto; }
    .sidebar.gk-open .toggle-label, .sidebar.gk-peek .toggle-label { width: auto; }
    /* The hover tooltip belongs to a mouse; a thumb never hovers. */
    .sidebar .nav-item:hover::after { display: none; }
    /* On the rail the chevrons point right ("open"); open, they point back. */
    .sidebar .toggle-icon { transform: rotate(180deg); }
    .sidebar.gk-open .toggle-icon, .sidebar.gk-peek .toggle-icon { transform: none; }
    body.gk-nav-open::after { content: ''; position: fixed; inset: 0; background: rgba(0,0,0,0.35); z-index: 90; }

    .main-wrap, .main-wrap.sidebar-collapsed { margin-left: var(--sidebar-collapsed); }
    .topbar { padding: 0 0.875rem; height: 48px; }
    .topbar-subtitle { display: none; }
    .brand-chip-name { display: none; }   /* BRANDING-01: the logo alone on a phone */
    main { padding: 0.75rem; }
    .card { padding: 0.875rem; }
    .two-col { gap: 0.75rem; margin-top: 0.75rem; }

    .feed-event { flex-wrap: wrap; row-gap: 0.4rem; }
    .feed-title { font-size: 0.875rem; }
    .feed-detail { font-size: 0.8rem; }
    .feed-right {
        flex-direction: column; align-items: stretch;
        width: 100%; gap: 0.4rem;
        padding-left: calc(10px + 0.75rem);
    }
    .feed-meta { text-align: left; white-space: normal; }
    .feed-meta br { display: none; }
    .feed-meta .rel-time::before { content: ' \00b7 '; }
    .feed-actions { flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: flex-start; gap: 6px; }
    .explain-btn, .draft-comms-btn, .ack-btn, .snooze-btn { padding: 6px 10px; font-size: 0.72rem; }
    .explain-panel { margin-left: 0; }
    .feed-search { flex: 1; min-width: 0; }
}

/* ACTION1-PATCHWEEK-01: the dashboard's Patch status card */
.patch-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.75rem; margin-bottom: 0.75rem; }
.patch-fig { border: 1px solid var(--border); border-radius: 6px; padding: 0.75rem; background: var(--bg); }
.patch-num { font-family: 'IBM Plex Mono', monospace; font-size: 1.6rem; font-weight: 500; color: var(--text); }
.patch-lbl { font-size: 0.75rem; color: var(--text-soft); margin-top: 2px; }
.patch-cmp { font-size: 0.85rem; color: var(--text); }
.patch-note, .patch-source { font-size: 0.72rem; color: var(--text-muted); font-weight: 400; }
.patch-note { margin-top: 0.4rem; }
@media (max-width: 560px) { .patch-grid { grid-template-columns: 1fr; } }

/* DEMO-MODE-01: the strip shown on every page while the server is in demo mode (frontend/js/demo_banner.js) */
/* A thin strip fixed to the bottom edge: out of the page flow (the body is a flex row, so an inserted block became a
   narrow column), above the sidebar, full width at any size. body.demo-on leaves room so it never covers content. */
.demo-banner { position: fixed; left: 0; right: 0; bottom: 0; z-index: 2000; box-sizing: border-box;
    background: var(--warn-bg); color: var(--warn-text); border-top: 1px solid var(--warn-border);
    padding: 0.3rem 0.75rem; text-align: center; font-size: 0.75rem; line-height: 1.2; font-weight: 600; }
.demo-banner-link { color: inherit; text-decoration: underline; margin-left: 0.75rem; }
body.demo-on { padding-bottom: 1.9rem; }
.demo-login-hint { color: var(--warn-text); background: var(--warn-bg); border: 1px solid var(--warn-border);
    border-radius: 6px; padding: 0.5rem 0.75rem; margin: 0.75rem 0; text-align: center; font-size: 0.85rem; }
