/* N13: a deliberately small, dependency-free stylesheet -- no framework,
   no build step, matching this service's "thin front end" scope. */
:root {
  --bg: #0f1420;
  --panel: #171d2b;
  --border: #2a3346;
  --text: #e6e9f0;
  --muted: #93a0b8;
  --accent: #5b8cff;
  --ok: #38c793;
  --warn: #e0a93a;
  --err: #e2596b;
  --input-bg: #0b0f18;
  /* U7 (gap §10): text painted directly onto --accent/--err button
     backgrounds -- --text (#e6e9f0, near-white) only reaches ~2.6-2.9:1 on
     those backgrounds, well under WCAG AA's 4.5:1 for normal-size text.
     Dark, near-black text clears it comfortably (~5.2-5.8:1) against THIS
     theme's --accent/--err, which are both light/vivid enough for that to
     read correctly -- the light-theme override below uses white instead,
     since that theme's --accent/--err are comparatively darker. */
  --button-text: #0f1420;
}

/* U4 (docs/user-friendly-roadmap.md): this console was dark-only until now
   (no media query at all) -- dark stays the default identity/branding, this
   just adds a light palette for an operator whose OS is set to light, so
   the console is legible either way rather than assuming everyone's on
   dark. Every color an element uses comes from one of these tokens (chart
   grid/axis included, since U4 -- see app.js's renderLineChart), so this
   one block is the only place the light palette needs to be defined. */
@media (prefers-color-scheme: light) {
  :root {
    --bg: #f5f6fa;
    --panel: #ffffff;
    --border: #d9dce6;
    --text: #1a2233;
    --muted: #5b6478;
    --accent: #3f6fe0;
    /* U7: darkened from the original #1f9d6c/#a86a08 -- those only hit
       ~3.2:1 / ~4.1:1 against this theme's --bg/--panel, under WCAG AA's
       4.5:1 for the normal-size text they're used as (.banner.success,
       .alert-banner.warning). These reach ~4.9-5.8:1, comfortably clear,
       while staying recognizably green/amber. */
    --ok: #157a51;
    --warn: #8f5906;
    --err: #c73652;
    --input-bg: #ffffff;
    /* U7: see the dark-theme --button-text comment above -- this theme's
       --accent/--err are darker, so white text is what clears 4.5:1 here
       (~4.6/5.2:1), the opposite choice from the dark theme. */
    --button-text: #ffffff;
  }
}

* { box-sizing: border-box; }

/* C2 (docs/commercial-polish-roadmap.md), found live via headless-browser
   verification: [hidden] and a class that itself sets `display` (e.g.
   .form-row's `display: flex`) have equal CSS specificity, so source order
   alone decided the winner -- an author rule always beats the [hidden]
   UA-stylesheet default regardless of where it's declared. This made
   #activation-continue-row visible immediately instead of staying hidden
   until the password step actually completes. Reset once, globally, so
   `hidden` always means hidden no matter what other classes an element
   also carries -- toggle visibility with element.hidden in app.js, never
   inline style.display, and it will always work. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
}

#login-screen {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

/* C2 (docs/commercial-polish-roadmap.md): hidden by default, like #app --
   only shown by app.js right after a token login that reports no password
   set yet, never on initial load (checkSession's own default assumption is
   "logged out", handled by #login-screen having no such rule at all). */
#activation-screen { display: none; }
#activation-screen.visible {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.login-box {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 32px;
  width: 360px;
}

.login-box h1 { font-size: 18px; margin: 0 0 4px; }
.login-box p.hint { color: var(--muted); font-size: 12px; margin: 0 0 20px; }

/* U5: token/password login toggle */
.login-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
.login-tab {
  flex: 1;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--muted);
  padding: 8px 4px;
  font-weight: 600;
  font-size: 13px;
}
.login-tab.active { color: var(--text); border-bottom-color: var(--accent); }
.login-panel { display: none; }
.login-panel.active { display: block; }

input, textarea, select, button {
  font: inherit;
  color: inherit;
}

input, textarea, select {
  background: var(--input-bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  width: 100%;
}

textarea { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }

button {
  background: var(--accent);
  color: var(--button-text);
  border: none;
  border-radius: 6px;
  padding: 8px 14px;
  cursor: pointer;
  font-weight: 600;
}
button.secondary { background: transparent; border: 1px solid var(--border); color: var(--text); }
button.danger { background: var(--err); }
button:disabled { opacity: 0.5; cursor: default; }

/* U7 (gap §10): a visible focus indicator for every keyboard-operable
   control, including the nav links now that they're focusable (index.html/
   app.js) -- :focus-visible so a mouse click doesn't show the ring, only
   real keyboard focus does. */
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

#app { display: none; height: 100vh; grid-template-columns: 200px 1fr; }
#app.visible { display: grid; }

nav {
  background: var(--panel);
  border-right: 1px solid var(--border);
  padding: 16px 0;
  display: flex;
  flex-direction: column;
}

nav .brand { padding: 0 16px 16px; font-weight: 700; border-bottom: 1px solid var(--border); margin-bottom: 8px; }
nav .brand small { display: block; color: var(--muted); font-weight: 400; font-size: 11px; }

nav a {
  color: var(--muted);
  text-decoration: none;
  padding: 10px 16px;
  cursor: pointer;
  border-left: 3px solid transparent;
}
nav a:hover { color: var(--text); }
nav a.active { color: var(--text); border-left-color: var(--accent); background: rgba(91,140,255,0.08); }
nav .spacer { flex: 1; }
nav .logout { color: var(--muted); font-size: 12px; padding: 10px 16px; }
/* U5: "logged in as X (role)" -- display-only, see session.go's own doc comment */
nav .nav-identity { color: var(--muted); font-size: 11px; padding: 0 16px 8px; }
nav .nav-identity strong { color: var(--text); font-weight: 600; }

main { padding: 24px 32px; overflow-y: auto; }
main section { display: none; }
main section.active { display: block; }

h2 { margin: 0 0 4px; font-size: 20px; }
p.subtitle { color: var(--muted); margin: 0 0 20px; font-size: 13px; }

.stat-row { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 20px; }
.stat {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 20px;
  min-width: 160px;
}
.stat .label { color: var(--muted); font-size: 12px; margin-bottom: 6px; }
.stat .value { font-size: 26px; font-weight: 700; }
.stat .value.err { color: var(--err); }
.stat .value.ok { color: var(--ok); }

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 20px;
  margin-bottom: 20px;
  /* U7 (gap §10): a many-column table (Consumer Keys, Operators) must
     scroll within its own panel at a narrow width, never force the whole
     page to scroll horizontally. */
  overflow-x: auto;
}
.panel h3 { margin: 0 0 12px; font-size: 14px; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }

.chart-row { display: flex; gap: 16px; margin-bottom: 20px; }
.chart-row .panel { flex: 1; margin-bottom: 0; }

/* C4 (docs/commercial-polish-roadmap.md): deep-links out to Perses/
   Prometheus/Jaeger from within the Dashboard tab -- three cards, not a
   raw list of bare URLs, so each reads as "a tool, with a purpose" rather
   than an unexplained link dump. */
.obs-links { display: flex; gap: 12px; flex-wrap: wrap; }
/* obs-card supersedes the old single-link obs-link card (2026-09-07): each
   tool's whole card used to just be one <a>; now it also holds a live,
   fetched-not-hardcoded list of that tool's real dashboards/rules/services,
   which can't nest inside an anchor -- so the card itself is a plain div,
   with its own small "Open" link in the header for the old whole-card-click
   behavior. */
.obs-card {
  flex: 1;
  min-width: 220px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
}
.obs-card-header { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.obs-card-header strong { font-size: 13px; }
.obs-card-header a { font-size: 12px; color: var(--accent); text-decoration: none; white-space: nowrap; }
.obs-card-header a:hover { text-decoration: underline; }
.obs-card > span.muted { display: block; font-size: 12px; line-height: 1.4; margin-top: 4px; }
.obs-sublist { list-style: none; margin: 10px 0 0; padding: 0; border-top: 1px solid var(--border); }
.obs-sublist li {
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.obs-sublist li:last-child { border-bottom: none; }
.obs-sublist a { color: var(--text); text-decoration: none; }
.obs-sublist a:hover { color: var(--accent); text-decoration: underline; }
/* Prometheus rule state -- same red/amber/green vocabulary
   activity-badge's ok/err already established, extended with a third
   "pending" state (a firing alert mid-for-window, not yet confirmed). */
.rule-state { font-size: 10px; text-transform: uppercase; letter-spacing: 0.03em; padding: 1px 6px; border-radius: 3px; flex-shrink: 0; }
.rule-state.firing { background: rgba(226,89,107,0.15); color: var(--err); }
.rule-state.pending { background: rgba(217,162,75,0.18); color: #d9a24b; }
.rule-state.inactive { background: rgba(148,163,184,0.15); color: var(--muted); }

/* C5 (docs/commercial-polish-roadmap.md): Recent Activity feed row outcome
   badge -- green/red, matching the same "green=allow, red=deny" convention
   named in the roadmap's own research citation (Cloudflare Security
   Events, Agent Wall's live event feed). */
.activity-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.activity-badge.ok { background: rgba(56,199,147,0.15); color: var(--ok); }
.activity-badge.err { background: rgba(226,89,107,0.15); color: var(--err); }

svg.chart { width: 100%; height: 160px; overflow: visible; }
svg.chart .legend text { fill: var(--muted); font-size: 11px; }
svg.chart .grid-line { stroke: var(--border); }
svg.chart .axis-label { fill: var(--muted); }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }
tr.revoked { opacity: 0.5; }
tr.suspended { color: var(--warn); }

.form-row { display: flex; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.form-row > * { flex: 1; min-width: 140px; }
.form-row.actions { justify-content: flex-end; }

.banner { padding: 10px 14px; border-radius: 6px; margin-bottom: 14px; font-size: 13px; }
.banner.error { background: rgba(226,89,107,0.15); border: 1px solid var(--err); color: var(--err); }
.banner.success { background: rgba(56,199,147,0.15); border: 1px solid var(--ok); color: var(--ok); }

code.mono, td.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
.muted { color: var(--muted); }
.refresh-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }

/* Consumer Portal branding logo preview */
#branding-preview { max-height: 48px; max-width: 160px; border: 1px solid var(--border); border-radius: 4px; padding: 4px; background: #fff; }

/* U3: per-policy History panel (routing/guardrail) */
.history-panel { margin-top: 14px; }
.history-panel td.actions-cell { text-align: right; white-space: nowrap; }
.history-panel pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px;
  max-height: 300px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-all;
}

/* C3 (docs/commercial-polish-roadmap.md): the guided-form / JSON-fallback
   toggle -- same visual language as .login-tabs above, reused rather than
   inventing a second tab style. */
.editor-mode-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--border); max-width: 420px; }
.mode-tab {
  flex: 1;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--muted);
  padding: 8px 4px;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
}
.mode-tab.active { color: var(--text); border-bottom-color: var(--accent); }

/* C3: the routing policy's guided candidate-chain table (default chain +
   each named route) -- inputs sized to their field, not stretched full
   width like .form-row's inputs, since several sit side by side in one row. */
.candidate-table input { width: 100%; min-width: 0; }
.candidate-table td { vertical-align: top; padding: 6px 8px; }
.candidate-table td.actions-cell { white-space: nowrap; text-align: right; }
.candidate-table td.actions-cell button { padding: 6px 8px; font-size: 12px; }
.route-panel { margin-top: 14px; border: 1px solid var(--border); border-radius: 8px; padding: 14px 16px; background: var(--bg); }

/* C3: the guardrail policy's guided rule cards. */
.rule-card {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  margin-bottom: 12px;
  background: var(--bg);
}
.rule-card .form-row { margin-bottom: 8px; }
.rule-card .form-row:last-child { margin-bottom: 0; }
.rule-card-actions { display: flex; justify-content: flex-end; }
.rule-card-actions button { padding: 6px 12px; font-size: 12px; }

/* C3: a field/row a PUT rejected -- the form's own equivalent of the JSON
   textarea's locateValidationError selection-and-scroll. */
.field-error-msg { color: var(--err); font-size: 12px; margin: 4px 0 0; }
.field-invalid { border-color: var(--err) !important; }
.row-invalid { outline: 2px solid var(--err); outline-offset: -1px; }

/* U4: dashboard tenant/model/range filter row -- same .form-row shape as
   every other form on this page, just without the "actions" right-align. */
.dashboard-filters { margin-bottom: 20px; }
.dashboard-filters select { flex: 1; min-width: 140px; }
.dashboard-filters button { flex: 0 0 auto; min-width: auto; }

/* U4: Alertmanager firing-alert badge -- a small banner per active alert,
   not a full alert-management UI (no ack/silence control here). Severity
   colors reuse --warn/--err so a "critical" alert reads at the same
   urgency as an error banner elsewhere in the console. */
.alert-banner {
  padding: 10px 14px;
  border-radius: 6px;
  margin-bottom: 10px;
  font-size: 13px;
}
.alert-banner.warning { background: rgba(224,169,58,0.15); border: 1px solid var(--warn); color: var(--warn); }
.alert-banner.critical { background: rgba(226,89,107,0.15); border: 1px solid var(--err); color: var(--err); }

/* U4: toast-style confirmations (app.js's toast()), replacing plain banner
   divs for successful mutations -- fixed bottom-right stack, auto-dismiss.
   Error banners are unaffected; they stay inline (see toast()'s own doc
   comment for why). */
#toast-container {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.toast {
  background: var(--panel);
  border: 1px solid var(--ok);
  color: var(--text);
  border-left: 4px solid var(--ok);
  border-radius: 6px;
  padding: 10px 16px;
  font-size: 13px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.25);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  max-width: 340px;
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast.error { border-color: var(--err); border-left-color: var(--err); }

/* U7 (gap §10): no width breakpoint existed at all before this -- the
   fixed 200px sidebar (#app's grid-template-columns) ate a large fraction
   of a narrow window (e.g. a split-screen laptop) with no room left for
   .panel's now-scrollable tables to be usable. Below this width the nav
   becomes a horizontal, wrapping top bar instead of a sidebar, and main
   regains the full window width. */
@media (max-width: 760px) {
  #app.visible { display: flex; flex-direction: column; height: auto; min-height: 100vh; }
  nav { flex-direction: row; flex-wrap: wrap; border-right: none; border-bottom: 1px solid var(--border); }
  nav .spacer { display: none; }
  main { padding: 16px; }
  .chart-row { flex-wrap: wrap; }
  .chart-row .panel { flex: 1 1 100%; }
  .login-box { width: min(360px, 90vw); }
}
