/* Stringer developer dashboard.
 *
 * The brand is the public site (src/api/site.ts): a phosphor-CRT terminal --
 * green on near-black, monospace throughout, square boxes, "// " section
 * headings, bordered CTAs that invert on hover. This file wears that identity
 * but at operator density: no hero, no vignette, no glow on anything you have
 * to READ. Decoration is confined to the chrome (header, scanlines, meter).
 *
 * Palette values marked SITE are lifted verbatim from site.ts. The three
 * additions exist because an admin tool needs states a landing page does not:
 *   --mut   the site's --dim is 3.8:1 on --bg -- fine for rules and borders,
 *           below AA for text, and this page is mostly small text. --mut is
 *           6.3:1 on --bg / 5.9:1 on --panel, so secondary labels pass AA.
 *   --bad   the site has no failure colour; Revoke/Rotate and error text need
 *           one. 7.3:1 on --bg.
 *   --sunk  a recessed surface for inputs, <pre> and secrets.
 * Measured contrast on --bg: --fg 14.2:1, --hot 17.6:1, --amber 11.4:1.
 *
 * No external resources of any kind -- CSP here is `default-src 'self'`.
 */
:root {
  color-scheme: dark;                 /* fixed dark identity: native controls must follow */
  --bg:#050806;                       /* SITE */
  --fg:#4bf58a;                       /* SITE -- phosphor */
  /* 5.63:1 on --bg. Was #1f7a44 (3.76:1) until 2026-08-10 -- BELOW WCAG AA for
     body text, and measured on 31 elements at 15px including the claim-token
     warning and the "I'm a Human" tab. The comment here said "structure, never
     body text"; the markup used it for body text anyway, which is what a rule
     enforced only by a comment is worth.
     The APP fixed this exact colour on 2026-08-07 (provider-app/native/ui/theme.ts)
     and the web kept it for three more days -- same defect, diagnosed once,
     left standing on every other surface. */
  --dim:#2f9a56;
  --hot:#b6ffcf;                      /* SITE -- emphasis, values, headings */
  --amber:#ffb454;                    /* SITE -- caution */
  --line:#0f331f;                     /* SITE -- box rules */
  --glow:0 0 6px rgba(75,245,138,.45);/* SITE */
  --mut:#35a35e;                      /* added: AA-legible secondary text */
  --bad:#ff6b5b;                      /* added: destructive / failure */
  --panel:#08140d;                    /* SITE .box background, opaque */
  --sunk:#030604;
  --ink:#04120a;                      /* SITE: text on an inverted (filled) control */
}

* { box-sizing: border-box; }

html, body { margin:0; background:var(--bg); color:var(--fg); }

body {
  /* Monospace everywhere, as on the site -- and it is the right choice here
     anyway: every column on this page is a key, an id or an amount. */
  font:15px/1.55 ui-monospace,SFMono-Regular,Menlo,Consolas,"DejaVu Sans Mono",monospace;
  letter-spacing:.01em;
  font-variant-numeric:tabular-nums;  /* digits must not shift between rows */
  background-image:radial-gradient(120% 90% at 50% -10%, #0a140d 0%, #050806 60%);
  min-height:100vh;
}

/* Scanlines: the one purely atmospheric borrow. Kept faint (a 16% line every
   3px, no vignette) so a table of balances stays comfortable, and dropped
   entirely when the reader has asked for more contrast. */
body::before {
  content:""; position:fixed; inset:0; pointer-events:none; z-index:5;
  background:repeating-linear-gradient(to bottom, rgba(0,0,0,0) 0 2px, rgba(0,0,0,.16) 2px 3px);
}
@media (prefers-contrast: more) { body::before { display:none; } }

/* --- chrome --------------------------------------------------------------- */

header {
  position:sticky; top:0; z-index:6;
  padding:14px 24px; border-bottom:1px solid var(--dim);
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  background:var(--bg);
}
header h1 {
  font-size:15px; margin:0; font-weight:600; flex:1; min-width:0;
  color:var(--hot); letter-spacing:.18em; text-shadow:var(--glow);
  display:flex; align-items:baseline; gap:8px; flex-wrap:wrap;
}
header .sep { color:var(--dim); letter-spacing:0; text-shadow:none; }
header .sub {
  color:var(--mut); font-size:13px; font-weight:400;
  letter-spacing:.04em; text-shadow:none; text-transform:lowercase;
}
header .dot {
  width:9px; height:9px; flex:0 0 auto;
  background:var(--fg); box-shadow:var(--glow);
}
.cursor {
  display:inline-block; width:.6ch; height:1em; background:var(--fg);
  vertical-align:-1px; animation:blink 1.05s steps(1) infinite;
}
@keyframes blink { 50% { opacity:0; } }
@media (prefers-reduced-motion: reduce) { .cursor { animation:none; } }

main { max-width:960px; margin:0 auto; padding:20px 24px 96px; position:relative; z-index:1; }

/* --- boxes ---------------------------------------------------------------- */

.card {
  background:var(--panel); border:1px solid var(--line);
  padding:16px 18px; margin:16px 0;
  overflow-x:auto;                    /* a wide table scrolls in its box, never the page */
}
.card h2 {
  font-size:13px; text-transform:uppercase; letter-spacing:.12em;
  color:var(--hot); font-weight:600; margin:0 0 12px;
}
.card h2::before { content:"// "; color:var(--dim); }   /* SITE .box h2 */
.card.warn { border-color:var(--amber); }
.card.warn h2 { color:var(--amber); }
.card.warn h2::before { color:var(--amber); opacity:.6; }

/* --- controls ------------------------------------------------------------- */

input, select, textarea, button { font:inherit; letter-spacing:inherit; }

input, select, textarea {
  width:100%; padding:9px 11px; min-height:40px;
  background:var(--sunk); border:1px solid var(--dim); border-radius:0;
  color:var(--hot); caret-color:var(--fg);
}
textarea { resize:vertical; line-height:1.45; }
/* The agent pickers are <select>s; some platforms paint the popup from the
   option's own colours rather than the control's. */
option { background:var(--sunk); color:var(--hot); }
::placeholder { color:var(--mut); opacity:1; }
input:focus, select:focus, textarea:focus { border-color:var(--fg); }

/* SITE .cta: a bordered box that inverts on hover. */
button {
  padding:8px 14px; min-height:40px;
  background:transparent; color:var(--hot);
  border:1px solid var(--fg); border-radius:0;
  cursor:pointer; margin:0 8px 6px 0;
}
button:not(:disabled):hover { background:var(--fg); color:var(--ink); }
button.secondary { border-color:var(--dim); color:var(--fg); }
button.secondary:not(:disabled):hover { background:transparent; border-color:var(--fg); color:var(--hot); }
button.danger { border-color:var(--bad); color:var(--bad); }
button.danger:not(:disabled):hover { background:var(--bad); color:#120603; }
button:disabled { opacity:.45; cursor:default; }

/* One visible focus ring for everything, and it must not be the hover style:
   keyboard users need to see where they are on a page that revokes keys. */
:focus-visible { outline:2px solid var(--hot); outline-offset:2px; }

.row { display:flex; gap:10px; align-items:end; flex-wrap:wrap; margin-top:12px; }
.row > input, .row > select { flex:1; min-width:120px; }
.row > button { flex:0 0 auto; margin:0; }   /* the row's own gap does the spacing */

/* A labelled input. Money amounts are entered in MAJOR units, so the caption
   saying so has to travel with the box rather than sit somewhere else. */
.field { display:flex; flex-direction:column; gap:4px; }
.field > span { font-size:12px; line-height:1.35; }
.row > .field { flex:1; min-width:200px; }

/* --- tabs ----------------------------------------------------------------- */

.tabs { display:flex; gap:2px; border-bottom:1px solid var(--dim); margin-top:18px; flex-wrap:wrap; }
.tab {
  background:transparent; color:var(--mut);
  border:1px solid transparent; border-bottom:0; margin:0 0 -1px 0;
  padding:9px 14px; font-size:12px; text-transform:uppercase; letter-spacing:.12em;
}
/* :not(.active) -- otherwise hovering the selected tab strips its panel
   background and it reads as deselected while the pointer sits on it. */
.tab:not(.active):not(:disabled):hover { background:transparent; color:var(--fg); }
.tab.active {
  color:var(--hot); background:var(--panel);
  border-color:var(--dim); border-bottom:1px solid var(--panel);
  box-shadow:inset 0 2px 0 var(--fg);
}
.tab.active::before { content:"> "; color:var(--dim); }

/* --- tables --------------------------------------------------------------- */

table { width:100%; border-collapse:collapse; }
/* NARROW SCREENS: let the columns take their natural width and let the CARD
   scroll, rather than squeezing them.
   
   Measured on a 390px viewport (2026-08-10): the Keys table held an unbreakable
   40-character `agt_...` id, so `width:100%` could not shrink that column and
   took the space out of every other one instead. Rows became 238px tall, the
   red "! unusable -- nothing can be sealed to it" wrapped to FIVE lines in an
   81px column, and Rotate / Revoke / Replace sealing key were pushed out of
   sight -- on the one surface a person would reach for on a phone to repair a
   broken sealing key.
   
   `max-content` is deliberately not `overflow-wrap:anywhere` on the id: that id
   exists to be copied into a curl, and an id broken across lines is one a person
   transcribes wrongly. Better a table that scrolls than an identifier that lies.
   
   `.kv` tables are excluded -- they are label/value pairs with no long tokens
   and their 40% first column is doing real work. */
table:not(.kv) { width:max-content; min-width:100%; }
/* `width:max-content` with `min-width:100%`, NOT `min-width:max-content`, which
   was tried first and measured no different at all: on a border-collapse table
   already carrying `width:100%`, a min-width does not force the columns to open
   up -- the box stays put and the text wraps inside it. Verified against the
   deployed stylesheet at 390px: row height 237px before AND after. This pair
   sizes the table to its content and still fills the card on a wide screen. */
th, td {
  text-align:left; padding:8px 10px 8px 0; border-bottom:1px solid var(--line);
  font-variant-numeric:tabular-nums; vertical-align:top;
}
th {
  font-size:12px; color:var(--mut); font-weight:600;
  text-transform:uppercase; letter-spacing:.1em;
}
tbody tr:last-child td { border-bottom:0; }
tbody tr:hover td { background:rgba(75,245,138,.045); }
/* Amounts right-align under a right-aligned heading; with tabular figures the
   decimal points line up, which is the whole point of a balances column. */
th.num, td.num { text-align:right; padding-right:14px; color:var(--hot); }
/* The key/value tables (Limits): label dim, value bright. */
table.kv td:first-child { color:var(--mut); width:40%; }
table.kv td:last-child { color:var(--hot); }
td button { min-height:36px; padding:7px 11px; font-size:13px; margin:0 6px 4px 0; }

/* --- meter ---------------------------------------------------------------- */

.bar {
  height:12px; background:var(--sunk); border:1px solid var(--dim); overflow:hidden;
}
.bar-fill {
  height:100%; width:0; transition:width .3s;
  /* Segmented, like a console gauge, rather than a solid marketing bar. */
  background:repeating-linear-gradient(90deg, var(--fg) 0 7px, transparent 7px 10px);
}
.bar-fill.hot { background:repeating-linear-gradient(90deg, var(--bad) 0 7px, transparent 7px 10px); }

/* --- text ----------------------------------------------------------------- */

.mono { font-family:inherit; font-size:13px; }
.secret, .code {
  font-size:14px; word-break:break-all; color:var(--hot);
  background:var(--sunk); border:1px solid var(--dim);
  padding:12px; margin:10px 0; line-height:1.5;
}
.code { border-color:var(--amber); }        /* a live 15-minute capability */
.rekey-out td { background:var(--sunk); }
pre {
  background:var(--sunk); border:1px solid var(--line);
  padding:12px; overflow-x:auto; font-size:13px; margin:12px 0;
}
a { color:var(--hot); text-decoration:none; border-bottom:1px dotted var(--dim); }   /* SITE */
a:hover { background:var(--fg); color:var(--ink); border-bottom-color:transparent; }

.muted { color:var(--mut); }
.err { color:var(--bad); font-size:13px; }
.ok  { color:var(--fg); font-size:13px; }
.err::before { content:"! "; }
.ok::before  { content:"> "; color:var(--dim); }
/* Last, and !important: every screen switch on this page is a .hide toggle, so
   nothing added above may out-specify it. */
.hide { display:none !important; }

.toast {
  position:fixed; bottom:20px; left:50%; transform:translateX(-50%); z-index:20;
  background:var(--panel); border:1px solid var(--fg); color:var(--hot);
  padding:10px 16px; box-shadow:0 6px 24px rgba(0,0,0,.6); max-width:90vw;
  font-size:14px;
}

@media (max-width:640px) {
  main { padding:16px 14px 96px; }
  header { padding:12px 14px; }
  .card { padding:14px 12px; }
  .row > input, .row > select, .row > button, .row > .field { flex:1 1 100%; min-width:0; }
  .row > button { margin-bottom:0; }
  th, td { padding:8px 8px 8px 0; font-size:13px; }
  .tab { padding:9px 10px; letter-spacing:.08em; }
  /* The title wraps here; the "//" would be left stranded at the end of the
     first line, so drop it and let the subtitle sit on its own. */
  header .sep { display:none; }
  header h1 { gap:0 8px; }
}
