/*
 * DDoS Gameboard styles.
 *
 * Version history:
 *   1.0.0 / 2026-07-08 / Initial Python conversion of the WinterCMS DDoS Gameboard.
 *   1.1.0 / 2026-07-12 / Fluid root font size: every panel (all text/spacing use
 *                        rem/em) scales with the window width, clamped for
 *                        legibility on small and very large screens.
 *   1.2.0 / 2026-07-12 / Enlarge and unify the Attack Timeline and Log Timeline
 *                        panels (matching, ~2pt-larger fonts).
 *   1.3.0 / 2026-07-12 / Compact the admin Plan of Attack table (many columns):
 *                        smaller viewport-capped font, tight padding, wrapping
 *                        cells, so all columns fit without the font being huge.
 *   1.4.0 / 2026-07-12 / Disclaimer matrix styles (date inputs, green done-row).
 *
 * This file is part of the DDoS Gameboard project. Supports DDoS Exercises
 *
 * @link https://github.com/Cyb0rg42/ddosgameboard
 * @copyright 2026 Karl Lovink a.k.a Cyb0rg42 (karl@lovink.net)
 * @license GNU General Public License v3.0 (GPL-3.0)
 */

html {
    /* Fluid typography: all panels use rem/em, so scaling this root size scales
       every panel's fonts (and rem-based spacing) with the window. ~16px at a
       1280px-wide window, shrinking on smaller windows and growing on wide ones,
       clamped to [13px, 24px] so it never gets illegible or oversized. */
    font-size: clamp(13px, 0.5vw + 10px, 24px);
}

:root {
    /* Anti-DDoS Coalitie brand palette (from the 'no more ddos' logo) */
    --brand-navy: #09344f;
    --brand-teal: #00d4c0;

    --bg: #062133;
    --panel: #0b3350;
    --panel-2: #124460;
    --border: #1c577a;
    --text: #eaf5f8;
    --muted: #8fb2c4;
    --primary: #00d4c0;
    --blue: #4a9eff;
    --red: #ff5d5d;
    --purple: #b98bff;
    --green: #46c37b;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
}

/* --- Login --- */
.login-body {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background:
        radial-gradient(1200px 600px at 50% -10%, rgba(0, 212, 192, 0.12), transparent 60%),
        linear-gradient(160deg, #062133 0%, #041826 100%);
}
.login-card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-top: 3px solid var(--brand-teal);
    border-radius: 14px;
    padding: 2.5rem;
    width: 380px;
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5);
}
.brand-logo {
    display: block;
    background: #ffffff;
    border-radius: 10px;
    padding: 1.1rem 1.3rem;
    margin: 0 0 1.6rem;
}
.brand-logo img { display: block; width: 100%; height: auto; }
.login-title { color: var(--text); margin: 0 0 .25rem; font-size: 1.4rem; font-weight: 400; text-align: center; }
.login-sub { color: var(--brand-teal); margin: 0 0 1.5rem; font-size: .85rem; letter-spacing: .04em; text-transform: uppercase; text-align: center; }
.login-form { display: flex; flex-direction: column; gap: .35rem; }
.login-form label { font-size: .8rem; color: var(--muted); margin-top: .6rem; }
.login-form input {
    padding: .6rem .7rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
}
.login-error { color: var(--red); font-size: .85rem; margin: .5rem 0 0; }
.login-hint { color: var(--muted); font-size: .8rem; margin-top: 1.2rem; }
.login-hint code { color: var(--primary); }

/* --- Buttons --- */
.btn {
    background: var(--panel-2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: .5rem .9rem;
    cursor: pointer;
    font-size: .85rem;
}
.btn:hover { border-color: var(--primary); }
.btn-primary { background: var(--primary); color: var(--brand-navy); border-color: var(--primary); font-weight: 700; margin-top: 1rem; }
.btn-ghost { background: transparent; }

/* --- Dropdown menu (hamburger) --- */
.menu { position: relative; display: inline-block; }
.menu-toggle { font-size: 1.15rem; line-height: 1; padding: .4rem .6rem; }
.menu-dropdown {
    position: absolute;
    right: 0;
    top: calc(100% + .35rem);
    min-width: 160px;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
    z-index: 50;
}
.menu-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    color: var(--text);
    padding: .6rem .9rem;
    font-size: .88rem;
    cursor: pointer;
}
.menu-item:hover { background: rgba(255, 255, 255, 0.08); }
/* The `display: block` above beats the UA `[hidden]` rule at equal specificity,
   so a hidden menu item (e.g. API keys for non-red / non-admin roles) would
   still show. Re-hide it explicitly. */
.menu-item[hidden] { display: none; }

/* --- Header --- */
#game-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: .8rem 1.2rem;
    background: var(--panel);
    border-bottom: 1px solid var(--border);
}
.header-left { display: flex; align-items: center; gap: .7rem; }
.header-logo {
    display: inline-flex;
    background: #ffffff;
    border-radius: 6px;
    padding: .3rem .5rem;
}
.header-logo img { height: 22px; width: auto; display: block; }
#board-title { margin: 0; color: var(--primary); font-weight: 300; font-size: 1.5rem; }
.version { color: var(--muted); font-size: .75rem; }
.header-center { text-align: center; }
.countdown { font-size: 1.4rem; font-variant-numeric: tabular-nums; letter-spacing: 1px; }
.phase { font-size: .75rem; color: var(--muted); text-transform: uppercase; }
.header-right { display: flex; align-items: center; gap: .5rem; }
#username-label { color: var(--muted); margin-right: .5rem; }

/* --- Board --- */
/* The Attack timeline takes two-thirds of the width, the log timeline one-third. */
#board { display: flex; height: calc(100vh - 64px); }
#parties-board { flex: 2; overflow: auto; padding: 1rem; min-width: 0; }
#timeline-panel {
    flex: 1;
    min-width: 0;
    border-left: 1px solid var(--border);
    background: var(--panel);
    padding: 1rem;
    overflow: auto;
}
/* Log Timeline title uses the same style/size as the Attack Timeline title. */
#timeline-panel h2 { font-size: 1.45rem; margin: 0 0 .8rem; color: var(--primary); font-weight: 300; }

/* Attack Timeline board (gameboard home left panel) — fills its two-thirds. The
   panel's fonts are ~2pt larger than the admin tables; the Log Timeline below
   matches these sizes so the two panels read identically. */
.plan-board { width: 100%; }
.plan-board-title { margin: 0 0 .8rem; color: var(--primary); font-weight: 300; font-size: 1.45rem; }
.plan-board-table { width: 100%; font-size: 1.05rem; }
.plan-board-table th { font-size: .9rem; }
/* The attack active right now uses the primary button's colours. */
.plan-active td, .plan-active:hover td {
    background: var(--primary);
    color: var(--brand-navy);
    font-weight: 700;
}

.party {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 10px;
    margin-bottom: 1rem;
    overflow: hidden;
}
.party-header {
    padding: .6rem 1rem;
    background: var(--panel-2);
    font-weight: 600;
    display: flex;
    justify-content: space-between;
}
.party-actions { padding: .6rem 1rem; display: flex; flex-wrap: wrap; gap: .6rem; }
.action-card {
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-left: 4px solid var(--primary);
    border-radius: 8px;
    padding: .55rem .7rem;
    min-width: 190px;
}
.action-card.cancelled { opacity: .5; text-decoration: line-through; }
.action-card.issues { border-left-color: var(--red); }
.action-name { font-weight: 600; }
.action-meta { color: var(--muted); font-size: .78rem; margin-top: .25rem; }
.action-tag {
    display: inline-block;
    font-size: .7rem;
    background: var(--border);
    border-radius: 4px;
    padding: .1rem .4rem;
    margin-top: .3rem;
}

/* --- Logs --- */
#log-list { list-style: none; margin: 0; padding: 0; }
.log-item {
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: .5rem .7rem;
    margin-bottom: .5rem;
}
.log-item.role-red { border-left: 3px solid var(--red); }
.log-item.role-blue { border-left: 3px solid var(--blue); }
.log-item.role-purple { border-left: 3px solid var(--purple); }
.log-item.role-system { border-left: 3px solid var(--green); }
/* Log Timeline entry fonts match the Attack Timeline table (body 1.05rem, meta .9rem). */
.log-time { color: var(--muted); font-size: .9rem; white-space: nowrap; }
.log-author { font-size: .9rem; color: var(--muted); }
.log-text { margin-top: .2rem; font-size: 1.05rem; white-space: pre-wrap; word-break: break-word; }
.log-attachments { margin-top: .3rem; font-size: .9rem; color: var(--blue); }
.log-attachment { color: var(--blue); text-decoration: none; cursor: pointer; }
.log-attachment:hover { text-decoration: underline; }
.log-edit { float: right; cursor: pointer; color: var(--muted); font-size: .85rem; }

/* --- Modals --- */
.modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    z-index: 50;
}
.modal[hidden] { display: none; }
.modal-card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 1.6rem;
    width: 420px;
    max-width: 100%;
    max-height: 90vh;
    overflow-y: auto;
    box-sizing: border-box;
}
.modal-card h3 { margin: 0 0 1rem; color: var(--primary); }
.modal-card label { display: block; font-size: .8rem; color: var(--muted); margin: .6rem 0 .25rem; }
.modal-card input, .modal-card textarea, .modal-card select {
    width: 100%;
    padding: .55rem .7rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
    box-sizing: border-box;
}
.modal-actions { display: flex; justify-content: flex-end; align-items: center; gap: .6rem; margin-top: 1rem; }
/* The primary button's default margin-top would drop it below the others in the
   row; the row already provides its own top margin, so cancel it here. */
.modal-actions .btn-primary { margin-top: 0; }
.modal-actions .btn-danger { margin-right: auto; }

/* --- Log attachment dropzone --- */
.dropzone {
    border: 2px dashed var(--border);
    border-radius: 8px;
    padding: 1.1rem;
    text-align: center;
    color: var(--muted);
    cursor: pointer;
    transition: border-color .15s, background .15s;
}
.dropzone:hover { border-color: var(--primary); }
.dropzone.dragover {
    border-color: var(--brand-teal);
    background: rgba(0, 212, 192, 0.08);
    color: var(--text);
}
.dropzone-hint { margin: 0; font-size: .85rem; }
.link-btn {
    background: none;
    border: none;
    color: var(--brand-teal);
    cursor: pointer;
    text-decoration: underline;
    font: inherit;
    padding: 0;
}
.filelist { list-style: none; padding: 0; margin: .6rem 0 0; }
.file-item {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .35rem .55rem;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 6px;
    margin-bottom: .35rem;
    font-size: .82rem;
}
.file-item .file-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-item .file-size { color: var(--muted); font-size: .75rem; }
.file-remove {
    background: none;
    border: none;
    color: var(--red);
    cursor: pointer;
    font-size: 1.1rem;
    line-height: 1;
    padding: 0 .2rem;
}
#parties-filter { list-style: none; padding: 0; margin: 0; }
#parties-filter li { padding: .4rem 0; display: flex; gap: .5rem; align-items: center; }

/* Organisations dialog rows: <name> <edit> <hide> <delete> */
.org-list { list-style: none; padding: 0; margin: 0 0 .5rem; }
.org-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .5rem .2rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.org-name { font-weight: 600; }
.org-actions { display: flex; gap: .4rem; white-space: nowrap; }

/* --- Admin dashboard --- */
.admin-main {
    /* Fill the full browser width so the wide panels (e.g. the Plan-of-Attack
       tables with their many columns) use all available space. The horizontal
       padding scales with the window rather than being fixed. */
    width: 100%;
    max-width: none;
    margin: 0;
    padding: 1.5rem clamp(1rem, 2.5vw, 3rem) 3rem;
}
.admin-tabs {
    display: flex;
    /* The tab row grows with every new panel, so it must never run off the
       window: tabs shrink with the viewport first (clamp below) and wrap to a
       second row once they genuinely no longer fit. */
    flex-wrap: wrap;
    gap: clamp(.2rem, .45vw, .5rem);
    margin-bottom: 0;
}
.admin-tab {
    background: var(--primary);
    border: 1px solid var(--primary);
    border-radius: 8px;
    color: var(--brand-navy);
    /* Fluid padding/type, same approach as the root font: full size on a wide
       window, tightening on narrow ones so more tabs stay on one row. */
    padding: .5rem clamp(.4rem, 1.05vw, 1.1rem);
    font-size: clamp(.68rem, .78vw + .12rem, .9rem);
    font-weight: 700;
    /* Keep each label on one line — without this "Plan of Attack" breaks into
       three lines and drags the whole row's height with it. */
    white-space: nowrap;
    cursor: pointer;
}
.admin-tab:hover { filter: brightness(1.08); }
/* A tab that is really a link to another page (Monitor Graphs). */
.admin-tab-link { text-decoration: none; display: inline-flex; align-items: center; }
.admin-tab-link:visited { color: var(--brand-navy); }
.admin-tab.active {
    box-shadow: 0 0 0 2px var(--text) inset;
}
.admin-section {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 1.2rem 1.4rem;
    margin-bottom: 1.6rem;
}
.admin-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: .8rem;
}
.admin-section-head h2 { margin: 0; font-size: 1.15rem; color: var(--text); }
.admin-section-head .btn-primary { margin-top: 0; }
.admin-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.admin-table th {
    text-align: left;
    color: var(--muted);
    font-weight: 500;
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    padding: .4rem .6rem;
    border-bottom: 1px solid var(--border);
}
.admin-table td { padding: .55rem .6rem; border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
.admin-table tr:hover td { background: rgba(255, 255, 255, 0.03); }
.admin-table th.sortable { cursor: pointer; user-select: none; }
.admin-table th.sortable:hover { color: var(--primary); }
.admin-table th[data-sort-dir="asc"]::after { content: " \25B2"; font-size: .7em; }
.admin-table th[data-sort-dir="desc"]::after { content: " \25BC"; font-size: .7em; }
.row-actions { text-align: right; white-space: nowrap; }
.btn-sm { padding: .3rem .6rem; font-size: .78rem; }
.btn-danger { color: var(--red); border-color: rgba(255, 93, 93, 0.4); }
.btn-danger:hover { border-color: var(--red); background: rgba(255, 93, 93, 0.1); }
.badge {
    font-size: .65rem;
    background: var(--brand-teal);
    color: var(--brand-navy);
    border-radius: 4px;
    padding: .05rem .35rem;
    font-weight: 700;
    vertical-align: middle;
}
.badge-warn { background: #f0a63c; color: #2a1a04; }
.form-note { color: var(--brand-teal); font-size: .85rem; margin: .6rem 0 0; }
.role-pill {
    display: inline-block;
    font-size: .7rem;
    font-weight: 600;
    border-radius: 4px;
    padding: .1rem .45rem;
    color: #fff;
    background: var(--muted);
}
.role-pill.role-red { background: var(--red); }
.role-pill.role-blue { background: var(--blue); }
.role-pill.role-observer { background: #6b7a88; }
.role-pill.role-gameleader { background: var(--purple); }

.logs-hint { color: var(--muted); font-size: .85rem; margin: 0 0 .8rem; }
.logs-hint code { color: var(--brand-teal); }
.logs-controls { display: flex; align-items: flex-end; gap: 1rem; flex-wrap: wrap; }
.logs-controls label { display: flex; flex-direction: column; gap: .3rem; font-size: .8rem; color: var(--muted); }
.logs-controls select {
    padding: .5rem .6rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
    min-width: 220px;
}
.logs-controls .btn-primary { margin-top: 0; }

/* --- Plan of Attack builder --- */
.pva-builder {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .8rem;
    margin-bottom: 1rem;
}
.pva-builder label {
    display: flex;
    flex-direction: column;
    font-size: .8rem;
    color: var(--muted);
    gap: .25rem;
}
.pva-builder select {
    padding: .5rem .6rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
    min-width: 150px;
}
.pva-builder .btn-primary { margin-top: 0; }

/* --- Plan of Attack per-organisation sub-panels --- */
.pva-org {
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1rem 1.1rem;
    margin-bottom: 1.2rem;
    background: rgba(255, 255, 255, 0.02);
    /* The plan table is wide (per-target columns); scroll it rather than
       overflow the page. */
    overflow-x: auto;
}
.pva-org > h3 {
    margin: 0 0 .8rem;
    color: var(--primary);
    font-size: 1.02rem;
}
/* The Plan of Attack table has ~17 columns; keep it compact and independent of
   the fluid root size (viewport-based clamp, tight padding, wrapping cells) so
   all columns fit on screen. Horizontal scroll (above) stays as a last resort on
   very narrow windows. */
.pva-org .admin-table { font-size: clamp(9.5px, 0.6vw + 2px, 12.5px); }
.pva-org .admin-table th {
    font-size: clamp(8.5px, 0.5vw + 2px, 11px);
    padding: .35em .45em;
    letter-spacing: 0;
}
.pva-org .admin-table td {
    padding: .35em .45em;
    word-break: break-word;
}
.pva-org .attack-id, .pva-org .plan-duration { font-size: .95em; }

/* Participant Plan-of-Attack controls (red team: view toggle + org filter). */
.plan-controls {
    display: flex;
    flex-direction: column;
    gap: .6rem;
    margin-bottom: 1.1rem;
}
.plan-views, .plan-filter {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.plan-views label, .plan-filter label {
    display: flex;
    align-items: center;
    gap: .35rem;
    color: var(--text);
    font-size: .85rem;
}
.plan-label { color: var(--muted); font-size: .8rem; min-width: 6.5rem; }
.plan-empty { color: var(--muted); font-style: italic; }
.plan-pause td { color: var(--muted); }

/* The exercise window shown atop the participant plan. */
.plan-window { font-weight: 600; color: var(--text); }

/* Exercise/pause event popup (blue & red): logo, message and an alarm. */
.event-card { text-align: center; max-width: 420px; }
.event-logo {
    display: block;
    margin: 0 auto 1.2rem;
    max-width: 200px;
    width: 60%;
    height: auto;
}
.event-card h3 { font-size: 1.4rem; margin: 0 0 .6rem; color: var(--primary); }
.event-message { color: var(--text); margin: 0 0 1rem; font-size: 1rem; }
.event-card .modal-actions { justify-content: center; }

/* Unique per-attack identifier ("<Org>-RED-001"): monospaced so the numbers
   line up, and a "Pause" tag for idle quarters. */
.attack-id {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .85em;
    color: var(--brand-teal);
    white-space: nowrap;
}
.plan-pause-tag { color: var(--muted); font-style: italic; }

/* Disclaimer (indemnification) matrix. */
.disclaimer-date {
    padding: .3rem .4rem;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
    font: inherit;
}
.disclaimer-need { color: var(--red); font-weight: 600; }
/* A row turns green once the signed disclaimer has been sent to the red-teamer. */
.disclaimer-done td { background: rgba(70, 195, 123, 0.18); }
.disclaimer-done .disclaimer-date { border-color: var(--green); }

/* Red-teamer API-key modal. */
.apikey-create { display: flex; gap: .6rem; margin: .6rem 0 1rem; }
.apikey-create input {
    flex: 1;
    padding: .5rem .6rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
}
.apikey-new { word-break: break-all; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* Input paired with an inline action button (e.g. hostname + Resolve DNS) */
.input-with-btn { display: flex; gap: .4rem; align-items: center; }
.input-with-btn input { flex: 1; }
.input-with-btn .btn { white-space: nowrap; }

/* SMTP settings modal */
.check-inline { display: flex; align-items: center; gap: .5rem; margin: .6rem 0; font-weight: normal; }
.check-inline input { width: auto; }
.smtp-test-row { display: flex; gap: .6rem; margin: 1rem 0 .2rem; }
.smtp-test-row input { flex: 1; }

/* Monitoring status: the confirmed up/down state per probe and target address.
   Colour carries the state at a glance, but the cell also spells it out (UP /
   DOWN / UNKNOWN) so it does not rely on colour alone. */
.mon-state-up { color: var(--green); font-weight: 600; }
.mon-state-down { color: var(--red); font-weight: 600; }
.mon-state-unknown { color: var(--muted); font-weight: 600; }
/* Heartbeat badge in the monitoring-clients table: a boxed UP/DOWN so a probe
   that has stopped reporting is impossible to miss. */
.mon-hb {
    display: inline-block;
    min-width: 4.6em;
    padding: .1rem .45rem;
    border-radius: 4px;
    font-weight: 700;
    font-size: .8rem;
    text-align: center;
    color: var(--muted);
}
.mon-hb-up { color: #fff; background: var(--green); }
.mon-hb-down { color: #fff; background: var(--red); }
#monitoring-section h3 { margin: 1.6rem 0 .3rem; }
#mon-status-body small { color: var(--muted); word-break: break-word; }
/* Admin-only danger zone: clearing all monitoring data board-wide. */
.mon-danger { margin-top: 1.8rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.mon-danger h3 { color: var(--red); }

/* Hide the Organisation column for game leaders / blue team (one org). */
.mon-hide-org .mon-org-col { display: none; }

/* The monitoring tables must always fit their panel — long addresses and plugin
   output must never push columns off-screen. A fixed layout with proportional
   widths shares the available width; content wraps (and long tokens break)
   instead of forcing the table wider. */
#mon-status-table { table-layout: fixed; width: 100%; }
#mon-status-table th, #mon-status-table td,
#mon-clients-table th, #mon-clients-table td {
    overflow-wrap: anywhere;
    /* Tighter column spacing than the default .admin-table padding. */
    padding-left: .3rem;
    padding-right: .3rem;
}
#mon-status-table td small { word-break: break-word; }
/* Column widths for Current status (order: Organisation, Target, Address, Probe,
   Type, State, Since, Last check, Plugin output). The output column is left
   unsized so it takes the remaining space; when Organisation is hidden its share
   frees up automatically. */
#mon-status-table th:nth-child(1) { width: 9%; }
#mon-status-table th:nth-child(2) { width: 15%; }
#mon-status-table th:nth-child(3) { width: 12%; }
#mon-status-table th:nth-child(4) { width: 12%; }
#mon-status-table th:nth-child(5) { width: 9%; }
#mon-status-table th:nth-child(6) { width: 6%; }
#mon-status-table th:nth-child(7) { width: 11%; }
#mon-status-table th:nth-child(8) { width: 8%; }

/* Participants summary: meal counts + aggregated diet wishes. */
.part-summary { display: flex; flex-wrap: wrap; align-items: stretch; gap: 1.6rem;
    background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
    padding: .9rem 1.3rem; margin: .6rem 0 1rem; }
.part-summary[hidden] { display: none; }
.part-stat { display: flex; flex-direction: column; justify-content: center; min-width: 7rem; }
.part-stat-v { font-size: 1.9rem; font-weight: 700; color: var(--primary); line-height: 1.1;
    font-variant-numeric: tabular-nums; }
.part-stat-l { font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.part-diet { border-left: 1px solid var(--border); padding-left: 1.6rem; flex: 1; min-width: 12rem; }
.part-diet-h { font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em;
    margin-bottom: .35rem; }
#part-diet-list { margin: 0; padding-left: 1.1rem; columns: 2; column-gap: 1.6rem; }
#part-diet-list li { font-size: .85rem; margin-bottom: .15rem; break-inside: avoid; }
.part-diet-empty { list-style: none; color: var(--muted); margin-left: -1.1rem; }

/* Pagination + page-size controls under a monitoring table. */
.mon-page-controls { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
    gap: 1rem; margin: .5rem 0 .2rem; font-size: .82rem; color: var(--muted); }
.mon-page-controls[hidden] { display: none; }
.mon-page-size { display: inline-flex; align-items: center; gap: .4rem; }
.mon-page-size select { padding: .25rem .45rem; border-radius: 6px; border: 1px solid var(--border);
    background: var(--panel-2); color: var(--text); }
.mon-pager { display: inline-flex; align-items: center; gap: .5rem; }
.mon-page-num { min-width: 3.5em; text-align: center; font-variant-numeric: tabular-nums; }

/* --- Monitor Graphs page --- */
.mg-controls { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end; margin-bottom: .6rem; }
.mg-control { display: flex; flex-direction: column; gap: .25rem; }
/* Without this the flex display above beats the [hidden] attribute, leaking the
   empty Organisations filter to game leaders / blue team (who have one org). */
.mg-control[hidden] { display: none; }
.mg-control label { font-size: .8rem; color: var(--muted); }
.mg-control select { padding: .45rem .6rem; border-radius: 8px; border: 1px solid var(--border);
    background: var(--panel-2); color: var(--text); }
.mg-control-note { margin-left: auto; align-self: flex-end; }

/* Checkbox-dropdown multi-select (organisations / targets). */
.mg-ms { position: relative; }
.mg-ms-btn { min-width: 12rem; max-width: 20rem; text-align: left; padding: .45rem .6rem;
    border-radius: 8px; border: 1px solid var(--border); background: var(--panel-2);
    color: var(--text); cursor: pointer; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; }
.mg-ms-btn::after { content: " \25BE"; color: var(--muted); }
.mg-ms-panel { position: absolute; z-index: 60; top: calc(100% + 4px); left: 0; min-width: 100%;
    max-height: 16rem; overflow-y: auto; background: var(--panel); border: 1px solid var(--border);
    border-radius: 8px; padding: .3rem; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35); }
.mg-ms-panel[hidden] { display: none; }
.mg-ms-row { display: flex; align-items: center; gap: .5rem; padding: .3rem .45rem; border-radius: 6px;
    white-space: nowrap; cursor: pointer; color: var(--text); font-size: .85rem; }
.mg-ms-row:hover { background: var(--panel-2); }
.mg-ms-row input { width: auto; margin: 0; }

.mg-card { background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    padding: 1rem 1.2rem 1.2rem; margin-bottom: 1.1rem; }
.mg-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.mg-card-title h3 { margin: 0; color: var(--primary); font-size: 1.05rem; }
.mg-card-meta { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .3rem; }
.mg-tag { font-size: .72rem; color: var(--muted); background: var(--panel-2);
    border: 1px solid var(--border); border-radius: 4px; padding: .05rem .4rem; }
.mg-tag-plugin { font-family: ui-monospace, monospace; }
.mg-state { display: inline-block; min-width: 4.4em; text-align: center; padding: .12rem .5rem;
    border-radius: 4px; font-weight: 700; font-size: .78rem; color: #fff; background: var(--muted);
    white-space: nowrap; }
.mg-state-up { background: var(--green); }
.mg-state-down { background: var(--red); }
/* One or more (but not all) addresses down — partially reachable. */
.mg-state-partial { background: #e8892b; }
.mg-state-unknown { background: var(--muted); }

.mg-stats { display: flex; flex-wrap: wrap; gap: 1.4rem; margin: .7rem 0 .2rem; }
.mg-stat { display: flex; flex-direction: column; }
.mg-stat-v { font-weight: 700; font-variant-numeric: tabular-nums; }
.mg-stat-l { font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

.mg-chart { margin-top: .5rem; }
.mg-svg { width: 100%; height: auto; display: block; }
.mg-grid { stroke: var(--border); stroke-width: 1; }
.mg-axis { fill: var(--muted); font-size: 13px; }
.mg-line { stroke-width: 1.6; fill: none; }
.mg-dot { opacity: .8; }

.mg-legend { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: .5rem; font-size: .78rem;
    color: var(--muted); }
.mg-legend-item { display: flex; align-items: center; gap: .35rem; font-weight: 600; }
.mg-swatch { width: .8rem; height: .8rem; border-radius: 2px; display: inline-block; }
/* Legend label colour = the address's current state across all probes. */
.mg-leg-up { color: var(--green); }
.mg-leg-down { color: var(--red); }
.mg-leg-partial { color: #e8892b; }
.mg-leg-unknown { color: var(--muted); }

/* Live attack-duration countdown: tabular figures so it does not jitter. */
.plan-duration {
    font-variant-numeric: tabular-nums;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    white-space: nowrap;
}
.plan-active .attack-id { color: inherit; }

/* Attacks scheduled past the (re)scheduled stop time: kept but flagged. */
.plan-flag { color: var(--red); cursor: help; }
.plan-out-of-range td, .pva-out-of-range td { color: var(--red); }

/* --- Exercise schedule form --- */
.schedule-form { max-width: 720px; }
.schedule-form label { font-size: .8rem; color: var(--muted); }
.schedule-form input {
    padding: .5rem .6rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--panel-2);
    color: var(--text);
    width: 100%;
}

/* Plan-of-Attack edit overlay: read-only (derived) fields and the Bps value+unit. */
.pe-readonly {
    padding: .5rem .55rem;
    color: var(--muted);
    background: rgba(255, 255, 255, 0.03);
    border-radius: 6px;
    min-height: 1.2rem;
}
.pe-bps { display: flex; gap: .4rem; }
.pe-bps[hidden] { display: none; }  /* [hidden] must beat the flex rule above */
.pe-bps input { flex: 1; min-width: 0; }
.pe-bps select { flex: 0 0 auto; width: auto; }

.modal-wide { width: 560px; max-width: 92vw; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .3rem 1rem; }
.form-grid > div { display: flex; flex-direction: column; min-width: 0; }
/* The rule above sets `display` on grid children, which would otherwise beat the
   UA `[hidden]` rule and leak fields meant to be hidden (e.g. the Organisation
   selector, which is hidden and server-locked for game leaders). */
.form-grid > div[hidden] { display: none; }
.form-error { color: var(--red); font-size: .85rem; margin: .6rem 0 0; }
.checkbox-row { display: flex; align-items: center; gap: .5rem; margin-top: .8rem; }
.checkbox-inline { display: flex; gap: 1.2rem; margin: .3rem 0 .6rem; }
.checkbox-inline label { display: flex; align-items: center; gap: .4rem; color: var(--text); }
.hint { color: var(--muted); font-weight: 400; font-size: .75rem; }
.logistics {
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: .6rem .9rem 1rem;
    margin-top: 1rem;
}
.logistics legend { color: var(--muted); font-size: .8rem; padding: 0 .4rem; }

/* Log role colour for game leader (formerly purple) */
.log-item.role-gameleader { border-left: 3px solid var(--purple); }

/* --- Role-specific Help --- */
#btn-help {
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1;
    padding: .35rem .65rem;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--primary);
}
.help-card { width: 640px; max-width: 92vw; }
.help-body { text-align: left; }
.help-intro { color: var(--muted); margin: 0 0 1rem; }
.help-section { margin-bottom: 1rem; }
.help-section h4 {
    margin: 0 0 .4rem;
    color: var(--primary);
    font-size: .95rem;
    font-weight: 600;
}
.help-section ul { margin: 0; padding-left: 1.2rem; }
.help-section li { margin: .3rem 0; line-height: 1.4; }
.help-section code {
    background: var(--panel-2);
    padding: .05rem .3rem;
    border-radius: 4px;
    font-size: .85em;
}

/* --- Inline field validation status (e.g. username availability) --- */
.field-status { display: block; margin-top: .25rem; font-size: .78rem; }
.field-status.field-ok { color: var(--green); }
.field-status.field-bad { color: var(--red); }
.field-status.field-checking { color: var(--muted); }
