@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&display=swap');
/* getdowntonight flavour of the 2bqed app design system: the file below is cdn/www/css/base.css from the 2bqed repo, VERBATIM, followed by one override block that maps its tokens onto the getdowntonight CRT palette. Re-sync = copy the 2bqed file in again and keep the block at the end. */
/* 2bqed shared design system — base.css
 * One stylesheet for every internal app. Link it and you inherit the tokens,
 * typography, light/dark theming, and the component set below.
 *   <link rel="stylesheet" href="https://cdn.2bqed.com/css/base.css">
 * Theme: defaults to the OS setting via prefers-color-scheme; an explicit
 * choice is applied by <html data-theme="light|dark"> (see js/theme.js).
 */

/* ---- self-hosted fonts (latin, variable) ---- */
/* paths are relative to this stylesheet so they resolve whether served from
 * cdn.2bqed.com/css/ or home.2bqed.com/cdn/css/ (tunnel same-origin subpath). */
@font-face{
  font-family:"Inter";
  font-style:normal;font-weight:100 900;font-display:swap;
  src:url("../fonts/inter.woff2") format("woff2");
}
@font-face{
  font-family:"JetBrains Mono";
  font-style:normal;font-weight:100 800;font-display:swap;
  src:url("../fonts/jetbrains-mono.woff2") format("woff2");
}

/* ============================ TOKENS ============================ */
:root{
  /* typography */
  --font-sans:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,Menlo,Consolas,monospace;
  --fs-xs:12px; --fs-sm:13px; --fs-base:15px; --fs-lg:18px; --fs-xl:22px;
  --fs-2xl:28px; --fs-3xl:clamp(2rem,6vw,3.2rem);
  --lh:1.5; --tracking:-0.01em;

  /* spacing */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px;
  --sp-6:32px; --sp-7:48px; --sp-8:64px;

  /* radius & elevation */
  --r-1:6px; --r-2:10px; --r-3:14px; --r-pill:999px;
  --shadow-1:0 1px 2px rgba(11,11,11,.06),0 1px 3px rgba(11,11,11,.10);
  --shadow-2:0 4px 12px rgba(11,11,11,.10),0 2px 4px rgba(11,11,11,.06);

  /* light theme (default) */
  --plane:#f9f9f7;
  --surface:#fcfcfb;
  --surface-2:#f2f1ee;
  --ink:#0b0b0b;
  --ink-2:#52514e;
  --muted:#898781;
  --border:rgba(11,11,11,.10);
  --grid:#e1e0d9;
  --accent:#2a78d6;
  --accent-2:#1c5cab;
  --accent-ink:#ffffff;
  --accent-soft:rgba(42,120,214,.10);
  --good:#0ca30c; --warn:#fab219; --serious:#ec835a; --critical:#d03b3b;
  --good-ink:#065f06; --warn-ink:#7a5200; --serious-ink:#7c3a1c; --critical-ink:#8a1f1f;
  color-scheme:light;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){ color-scheme:dark;
    --plane:#0d0d0d; --surface:#1a1a19; --surface-2:#242422;
    --ink:#ffffff; --ink-2:#c3c2b7; --muted:#898781;
    --border:rgba(255,255,255,.12); --grid:#2c2c2a;
    --accent:#3987e5; --accent-2:#5598e7; --accent-ink:#ffffff;
    --accent-soft:rgba(57,135,229,.16);
    --shadow-1:0 1px 2px rgba(0,0,0,.4); --shadow-2:0 6px 18px rgba(0,0,0,.5);
    --good-ink:#0ca30c; --warn-ink:#fab219; --serious-ink:#ec835a; --critical-ink:#e66767;
  }
}
:root[data-theme="dark"]{ color-scheme:dark;
  --plane:#0d0d0d; --surface:#1a1a19; --surface-2:#242422;
  --ink:#ffffff; --ink-2:#c3c2b7; --muted:#898781;
  --border:rgba(255,255,255,.12); --grid:#2c2c2a;
  --accent:#3987e5; --accent-2:#5598e7; --accent-ink:#ffffff;
  --accent-soft:rgba(57,135,229,.16);
  --shadow-1:0 1px 2px rgba(0,0,0,.4); --shadow-2:0 6px 18px rgba(0,0,0,.5);
  --good-ink:#0ca30c; --warn-ink:#fab219; --serious-ink:#ec835a; --critical-ink:#e66767;
}

/* ============================ RESET ============================ */
*,*::before,*::after{box-sizing:border-box}
*{margin:0}
html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--font-sans);font-size:var(--fs-base);line-height:var(--lh);
  color:var(--ink);background:var(--plane);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  /* Never let a page scroll sideways on mobile. `clip` (not `hidden`) doesn't create a
     scroll container, so it leaves position:sticky nav bars working. Wide content should
     scroll inside its own box (see pre / table rules) rather than stretch the page. */
  overflow-x:clip;overflow-wrap:break-word;
}
img,svg,video{display:block;max-width:100%}
button,input,select,textarea{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}
::selection{background:var(--accent-soft)}

/* ============================ TYPOGRAPHY ============================ */
h1,h2,h3,h4{line-height:1.2;letter-spacing:var(--tracking);font-weight:650}
h1{font-size:var(--fs-2xl)} h2{font-size:var(--fs-xl)}
h3{font-size:var(--fs-lg)} h4{font-size:var(--fs-base)}
p{color:var(--ink-2)}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
small,.muted{color:var(--muted)}
code,kbd,pre,.mono{font-family:var(--font-mono)}
code{font-size:.9em;background:var(--surface-2);padding:.1em .4em;border-radius:var(--r-1)}
pre{background:var(--surface-2);padding:var(--sp-4);border-radius:var(--r-2);overflow:auto;font-size:var(--fs-sm)}
hr{border:0;border-top:1px solid var(--border);margin:var(--sp-5) 0}

/* ============================ LAYOUT ============================ */
/* .container is the standard page width for every app. Not every page needs a
 * max-width wrapper, but any page that has one must use .container — don't
 * invent per-app widths. Apps may override its padding locally (killswitch
 * does, for phone-tuned spacing); the width itself stays shared. */
.container{max-width:1000px;margin:0 auto;padding:var(--sp-6) var(--sp-5) var(--sp-8);
  /* body is a flex column, so as a flex item this would otherwise take its widest child's
     intrinsic width (a scrolling rail) and overflow any pane narrower than 1000px */
  min-width:0;width:100%}
.container-wide{max-width:1240px}
.stack>*+*{margin-top:var(--sp-4)}
.row{display:flex;gap:var(--sp-3);align-items:center;flex-wrap:wrap}
.grid{display:grid;gap:var(--sp-4)}
.grid-auto{grid-template-columns:repeat(auto-fit,minmax(min(160px,100%),1fr))}
.spacer{flex:1}

/* ---- mobile: keep every app within the viewport ---- */
@media (max-width:560px){
  .container,.container-wide{padding-left:var(--sp-4);padding-right:var(--sp-4)}
  /* a wide data table scrolls inside its own box instead of stretching the page wider
     than the screen (which would otherwise force a horizontal scroll / clipped layout). */
  table{display:block;overflow-x:auto}
}

/* ==================== APP BAR — the standard nav (use on every app) ====================
 * Canonical markup:
 *   <header class="appbar">
 *     <a class="brand" href="https://home.2bqed.com"><img src=".../logo.svg" height="22"></a>
 *     <span class="chip chip-accent app-name">app name</span>   (optional; .app-name = own row on mobile)
 *     <span class="spacer"></span>
 *     …optional app-specific status/actions…
 *     <span data-theme-toggle></span>                  (ALWAYS last → top-right)
 *   </header>
 * The .spacer pushes everything after it to the right, so the theme toggle is
 * always in the top-right corner. */
.appbar{display:flex;align-items:center;gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-5);border-bottom:1px solid var(--border);
  background:var(--surface);position:sticky;top:0;z-index:10}
.appbar .brand{display:flex;align-items:center;gap:var(--sp-2);font-weight:650;
  letter-spacing:var(--tracking);color:var(--ink);text-decoration:none}
.appbar .brand:hover{text-decoration:none;opacity:.85}
.appbar .brand svg,.appbar .brand img{width:auto;height:22px}
/* wordmark is HTML text (not baked into the SVG) so it follows the theme —
   an <img>-loaded SVG can't read the page's currentColor. */
.appbar .brand .wordmark{font-size:var(--fs-lg);color:var(--ink)}
.appbar nav{display:flex;gap:var(--sp-4);font-size:var(--fs-sm)}
.appbar nav a{color:var(--ink-2)} .appbar nav a:hover{color:var(--ink);text-decoration:none}
/* Narrow screens: the app-name chip drops onto its own full-width row so the brand +
   status + actions keep a row to themselves instead of everything squashing onto one
   line. It becomes a plain left-aligned accent title on that row. This targets the opt-in
   .app-name marker only — NOT every .chip-accent — so a nav that uses chip-accent for
   something else (e.g. webmail's folder title) is left alone. */
@media (max-width:560px){
  .appbar{flex-wrap:wrap;row-gap:var(--sp-2)}
  .appbar .app-name{order:10;flex-basis:100%;background:transparent;border:0;
    border-radius:0;padding:0;font-size:var(--fs-sm);letter-spacing:var(--tracking)}
}
/* small phones: the mark + app chip identify the site; the wordmark just
   forces a second row once a page adds any inline control (music's speaker) */
@media (max-width:430px){.appbar .brand .wordmark{display:none}}

/* ============================ CARD / SECTION ============================ */
.card,section.panel{background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-3);padding:var(--sp-5)}
.card+.card,section.panel+section.panel{margin-top:var(--sp-4)}
.panel-title{font-size:var(--fs-sm);text-transform:uppercase;letter-spacing:.04em;
  color:var(--muted);font-weight:600;margin-bottom:var(--sp-3)}

/* ============================ STAT TILE ============================ */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--sp-3)}
.tile{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-2);padding:14px 16px}
.tile-k{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
.tile-v{font-size:var(--fs-2xl);font-weight:650;margin:2px 0;letter-spacing:var(--tracking)}
.tile-d{font-size:var(--fs-xs);color:var(--ink-2)}

/* ============================ BUTTONS ============================ */
.btn{display:inline-flex;align-items:center;gap:var(--sp-2);cursor:pointer;
  font-size:var(--fs-sm);font-weight:550;line-height:1;padding:9px 14px;
  border-radius:var(--r-2);border:1px solid var(--border);background:var(--surface);
  color:var(--ink);transition:background .12s,border-color .12s,transform .04s}
.btn:hover{background:var(--surface-2);text-decoration:none}
.btn:active{transform:translateY(1px)}
.btn-primary{background:var(--accent);border-color:transparent;color:var(--accent-ink)}
.btn-primary:hover{background:var(--accent-2)}
.btn-ghost{background:transparent;border-color:transparent}
.btn-icon{padding:8px;border-radius:var(--r-2)}

/* ============================ CHIPS / BADGES ============================ */
.chip{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-xs);font-weight:700;
  padding:2px 9px;border-radius:var(--r-1);line-height:1.6}
.chip .dot{width:7px;height:7px;border-radius:50%;background:currentColor}
.chip-good{background:color-mix(in srgb,var(--good) 16%,transparent);color:var(--good-ink)}
.chip-warn{background:color-mix(in srgb,var(--warn) 20%,transparent);color:var(--warn-ink)}
.chip-serious{background:color-mix(in srgb,var(--serious) 20%,transparent);color:var(--serious-ink)}
.chip-critical{background:color-mix(in srgb,var(--critical) 18%,transparent);color:var(--critical-ink)}
.chip-accent{background:var(--accent-soft);color:var(--accent-2)}
.chip-solid.chip-good{background:var(--good)} .chip-solid.chip-warn{background:var(--warn)}
.chip-solid.chip-critical{background:var(--critical)} .chip-solid{color:#fff}
.chip-solid.chip-warn{color:#3a2a00}

/* ============================ STATUS DOT ============================ */
.status-dot{width:10px;height:10px;border-radius:50%;display:inline-block;vertical-align:middle}
.status-dot.is-good{background:var(--good);box-shadow:0 0 10px color-mix(in srgb,var(--good) 60%,transparent)}
.status-dot.is-warn{background:var(--warn)}
.status-dot.is-critical{background:var(--critical);box-shadow:0 0 10px color-mix(in srgb,var(--critical) 55%,transparent)}

/* ============================ TABLE ============================ */
table{width:100%;border-collapse:collapse;font-size:var(--fs-sm)}
th,td{text-align:left;padding:9px 10px;border-bottom:1px solid var(--border);vertical-align:top}
th{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.04em;color:var(--muted);font-weight:600}
tbody tr:hover{background:var(--surface-2)}
.tabular{font-variant-numeric:tabular-nums}

/* ============================ FORMS ============================ */
input[type=text],input[type=password],input[type=search],input[type=number],
input[type=email],input[type=tel],input[type=url],input[type=date],input[type=time],
input[type=datetime-local],input[type=month],input[type=week],input:not([type]),select,textarea{
  width:100%;padding:9px 12px;background:var(--surface);color:var(--ink);
  border:1px solid var(--border);border-radius:var(--r-2);min-height:38px}
/* keep native calendar/clock picker icons visible in dark mode */
input[type=date]::-webkit-calendar-picker-indicator,
input[type=time]::-webkit-calendar-picker-indicator{filter:var(--picker-invert,none);cursor:pointer}
:root[data-theme="dark"]{--picker-invert:invert(1)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--picker-invert:invert(1)}}
input::placeholder,textarea::placeholder{color:var(--muted)}
label{font-size:var(--fs-sm);color:var(--ink-2);font-weight:550}

/* ============================ THEME TOGGLE ============================ */
.theme-toggle{display:inline-flex;border:1px solid var(--border);border-radius:var(--r-pill);
  background:var(--surface);padding:2px;gap:2px}
.theme-toggle button{border:0;background:transparent;color:var(--muted);cursor:pointer;
  padding:5px 8px;border-radius:var(--r-pill);display:inline-flex;line-height:0}
.theme-toggle button[aria-pressed="true"]{background:var(--surface-2);color:var(--ink)}
.theme-toggle svg{width:15px;height:15px}

/* ======================== SHARED NAV (cdn/js/nav.js) ======================== */
/* One appbar + one dropdown menu across every app. The bar stays sticky (see
   .appbar above); the menu drops from under it, right-anchored on desktop and
   a near-full-width sheet on phones. Rows are 48px — real tap targets. */
.nav-burger{display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;flex:none;border:1px solid var(--border);
  border-radius:var(--r-2);background:var(--surface);color:var(--ink);cursor:pointer}
.nav-burger:hover{border-color:var(--accent)}
.nav-burger svg{width:22px;height:22px}
.nav-menu{position:fixed;right:var(--sp-4);z-index:60;min-width:260px;max-width:340px;
  max-height:calc(100dvh - 80px);overflow-y:auto;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);
  box-shadow:var(--shadow-2,0 16px 48px rgba(0,0,0,.25));padding:6px}
.nav-item{display:flex;align-items:center;gap:12px;width:100%;min-height:48px;
  padding:0 14px;border:0;border-radius:var(--r-2);background:none;cursor:pointer;
  color:var(--ink);font:inherit;font-size:16px;text-align:left;text-decoration:none}
a.nav-item:hover,button.nav-item:hover{background:var(--surface-2);text-decoration:none}
.nav-item .nav-ic{font-size:1.25rem;width:1.6em;text-align:center;flex:none}
.nav-item .nav-lb{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav-item .nav-badge{position:static;flex:none}
.nav-item.on{background:var(--accent-soft,var(--surface-2))}
.nav-item-raw{cursor:default}
.nav-sep{height:1px;background:var(--border);margin:6px 10px}
.nav-theme .theme-toggle{margin-left:auto}
@media (max-width:560px){.nav-menu{left:var(--sp-3);right:var(--sp-3);max-width:none}}

/* ========================= MOBILE SIZING (site-wide) ========================= */
/* Most of the family uses phones first. Two jobs here: (1) fields at ≥16px so
   iOS Safari stops auto-zooming into every input (THE mobile-zoom bug — the
   viewport tag alone doesn't prevent it); (2) slightly larger captions and
   44px-minimum tap targets, per Apple/Google guidance. */
@media (max-width:640px){
  :root{--fs-xs:13px;--fs-sm:15px;--fs-base:16px;--fs-lg:19px;--fs-xl:23px}
  input,select,textarea{font-size:16px}
  input[type=text],input[type=password],input[type=search],input[type=number],
  input[type=email],input[type=tel],input[type=url],input[type=date],input[type=time],
  input[type=datetime-local],input:not([type]),select,textarea{min-height:44px}
  .btn{min-height:44px;padding:11px 16px}
  .chip{min-height:32px}
  .theme-toggle button{padding:8px 10px}
  .theme-toggle svg{width:17px;height:17px}
}

/* ============================ FOOTER & MISC ============================ */
.appfooter{color:var(--muted);font-size:var(--fs-xs);text-align:center;padding:var(--sp-5) 0}
.empty{color:var(--muted);font-size:var(--fs-sm)}
[hidden]{display:none!important}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ===== getdowntonight override: same token names, the CRT amber palette ===== */
:root, :root[data-theme="dark"], :root:not([data-theme="light"]){
  --font-sans:"Fira Code","JetBrains Mono",ui-monospace,Menlo,Consolas,monospace;
  --font-mono:"Fira Code","JetBrains Mono",ui-monospace,Menlo,Consolas,monospace;
  --plane:#0c0c0c; --surface:#12100c; --surface-2:#1a1510;
  --ink:#e8943c; --ink-2:#c87830; --muted:#9a7e58;
  --border:#2a2015; --grid:#1e1710;
  --accent:#ffa854; --accent-2:#e8943c; --accent-ink:#0c0c0c; --accent-soft:rgba(200,120,48,.14);
  --good:#5a9a5a; --warn:#fab219; --serious:#ec835a; --critical:#c44;
  --good-ink:#7fbf7f; --warn-ink:#fab219; --serious-ink:#ec835a; --critical-ink:#e66767;
  --shadow-1:0 1px 2px rgba(0,0,0,.5); --shadow-2:0 6px 18px rgba(0,0,0,.6);
  color-scheme:dark;
}
:root[data-theme="light"]{
  --plane:#f5e6d0; --surface:#f0dfc8; --surface-2:#eddbc2;
  --ink:#1a0f05; --ink-2:#3a2010; --muted:#8b6b48;
  --border:#d4b896; --grid:#dcc5a8;
  --accent:#c87830; --accent-2:#a85f20; --accent-ink:#ffffff; --accent-soft:rgba(200,120,48,.16);
  --good:#2f7a2f; --warn:#8a5a00; --serious:#a0421c; --critical:#b33333;
  --good-ink:#2f7a2f; --warn-ink:#7a5200; --serious-ink:#7c3a1c; --critical-ink:#8a1f1f;
  --shadow-1:0 1px 2px rgba(58,32,16,.12); --shadow-2:0 6px 18px rgba(58,32,16,.18);
  color-scheme:light;
}
body{background:var(--plane);color:var(--ink)}
