/* The station's design tokens, and the shell the account pages are built from.
 *
 * Two layers, and the split matters:
 *
 *   :root     tokens. Loaded by every page including index.html, which is why
 *             nothing here may assume the account pages' markup.
 *   .page     components for login, profile and admin only. index.html has its
 *             own component layer inline; scoping keeps the two from fighting
 *             when both stylesheets are on the same document.
 *
 * The previous version of this file kept a *copy* of index.html's tokens with
 * a comment saying they could not drift. They had: --pred, --lift and --med
 * were never copied across, so the account pages had no way to express
 * "predicted, not yet true" and reached for a confirmed-green instead. One
 * definition, linked by all four pages, is the only version of that promise
 * that stays true.
 */
:root{
  --bg:#0a0c10; --s1:#11141a; --s2:#171b23; --s3:#1e2430;
  --line:#232936; --line2:#2e3644;

  /* Text. --tx3 was #6b7688, which measures 4.26:1 on --bg and 3.39:1 on
     --s3 - under the 4.5:1 floor, and it carries the sidebar helper text,
     every table header and every stat label at 11-12px. #8792a4 is 6.22:1
     on --bg and 4.95:1 on --s3, so it passes on the lightest surface it is
     ever painted on and still reads as clearly tertiary. */
  --tx:#e9edf4; --tx2:#adb7c7; --tx3:#8792a4;

  /* Colour carries one meaning each, and they are never mixed:
       ac  something is happening now      ok  verified fact
       wn  needs a decision                dg  blocked or destructive
     A prediction ("eligible") is deliberately not green - green is reserved
     for things that have actually been confirmed. This is not decoration:
     the operator reads these colours to decide what is safe to erase, and
     erasing a session that exists nowhere else is unrecoverable. */
  --ac:#4c8dff; --ac2:#1a2740;
  --ok:#34d399; --ok2:#12301f;
  --wn:#f6b73c; --wn2:#332612;
  --dg:#f2686a; --dg2:#3a1a1c;
  --pred:#8fb0e8;           /* predicted / expected, not yet true */

  --r:8px; --r2:6px;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace;
  --sans:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",sans-serif;
  --dock:52px;
  --sbw:264px;              /* sidebar width; dragged, persisted in localStorage */

  /* Spacing scale. Every gap in the page is one of these six numbers - the
     previous ad-hoc 9px/11px/14px margins are most of why it read as assembled
     rather than designed. */
  --s1x:4px; --s2x:8px; --s3x:12px; --s4x:16px; --s5x:24px; --s6x:32px;

  /* Type scale. Five sizes, no more. Each is a step up from where it started:
     this is a screen someone reads for a whole shift, and the old 10.5px
     tertiary text was being asked to carry table headers and helper copy. */
  --fs-xs:11.5px; --fs-sm:12.5px; --fs-md:13.5px; --fs-lg:15px; --fs-xl:22px;

  /* How wide content is allowed to get. Without a cap, four counters on a
     1600px display sat in 310px cells with 250px of dead air beside each -
     stretched, not designed. */
  --maxw:1280px;

  --hair:rgba(255,255,255,.06);
  --lift:0 1px 0 rgba(255,255,255,.03) inset;
  --shadow:0 8px 24px rgba(0,0,0,.45);
  --fast:.12s; --med:.18s;
}

/* ===================================================================
   Account pages: login, profile, admin.
   Scoped to .page so index.html can link this file for the tokens
   without inheriting a second, conflicting set of components.
   =================================================================== */
*{box-sizing:border-box;margin:0;padding:0}

.page{background:var(--bg);color:var(--tx);font:14px/1.5 var(--sans);
  -webkit-font-smoothing:antialiased;min-height:100vh}
.page a{color:var(--ac);text-decoration:none}
.page a:hover{text-decoration:underline}
/* Not scoped, deliberately. As `.page button` this reset scored higher than
   the pages' own single-class rules (.tab, .x) and stripped the background and
   border straight back off them - the tabs rendered as bare text. index.html
   declares this identical rule itself, so leaving it global costs nothing. */
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
.page :focus-visible{outline:2px solid var(--ac);outline-offset:2px;border-radius:4px}

.page input,.page select{font:inherit;color:var(--tx);background:var(--bg);
  border:1px solid var(--line2);border-radius:var(--r2);padding:9px 11px;width:100%;
  transition:border-color var(--fast),box-shadow var(--fast)}
.page input:focus,.page select:focus{outline:none;border-color:var(--ac);
  box-shadow:0 0 0 3px var(--ac2)}
.page input::placeholder{color:var(--tx3)}
.page label{display:block;font-size:var(--fs-xs);color:var(--tx2);
  margin-bottom:var(--s2x);text-transform:uppercase;letter-spacing:.06em;
  font-weight:600}
.page .field{margin-bottom:var(--s4x)}

/* Buttons carry the dashboard's shapes: a filled accent for the one action a
   screen is for, a surface button for everything else. The markup already
   said which was which (.btn vs .btn.ghost), it just did not look like the
   dashboard while saying it. */
.page .btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  background:var(--ac);color:#04101f;border:1px solid var(--ac);
  border-radius:var(--r2);padding:8px 14px;font-weight:640;
  font-size:var(--fs-md);white-space:nowrap;
  transition:background var(--fast),border-color var(--fast)}
.page .btn:hover:not(:disabled){background:#5d99ff;border-color:#5d99ff;
  text-decoration:none}
.page .btn:disabled{opacity:.38;cursor:not-allowed}
.page .btn.ghost{background:var(--s2);border-color:var(--line2);color:var(--tx);
  font-weight:520}
.page .btn.ghost:hover:not(:disabled){background:var(--s3);border-color:#3b4658}
.page .btn.danger{background:transparent;border-color:#4a2528;color:#ff9a9c;
  font-weight:520}
.page .btn.danger:hover:not(:disabled){background:var(--dg2);border-color:#63343a}
.page .btn.sm{padding:5px 10px;font-size:var(--fs-sm)}

.page .card{background:var(--s1);border:1px solid var(--line);
  border-radius:var(--r);padding:var(--s5x);box-shadow:var(--lift)}
.page .msg{border-radius:var(--r2);padding:10px 12px;font-size:var(--fs-md);
  margin-bottom:var(--s4x);display:none}
.page .msg.bad{background:var(--dg2);border:1px solid #4a2528;color:#ff9a9c;display:block}
.page .msg.good{background:var(--ok2);border:1px solid #1c4a33;color:var(--ok);display:block}
.page .muted{color:var(--tx2);font-size:var(--fs-md)}
.page .mono{font-family:var(--mono);font-size:var(--fs-sm)}

.page .pill{display:inline-block;padding:2px 8px;border-radius:99px;
  font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.06em;
  font-weight:600;white-space:nowrap}
.page .pill.admin{background:var(--ac2);color:var(--ac)}
.page .pill.operator{background:var(--s3);color:var(--tx2)}
.page .pill.ok{background:var(--ok2);color:var(--ok)}
.page .pill.bad{background:var(--dg2);color:var(--dg)}
.page .pill.run{background:var(--ac2);color:var(--ac)}

/* Figures line up down a column instead of jittering as they change - the
   same reason index.html sets this on its own numbers. */
.page table{width:100%;border-collapse:collapse;font-size:var(--fs-md)}
.page th{text-align:left;font-size:var(--fs-xs);text-transform:uppercase;
  letter-spacing:.06em;color:var(--tx3);font-weight:680;
  padding:var(--s2x) var(--s3x);border-bottom:1px solid var(--line)}
.page td{padding:var(--s2x) var(--s3x);border-bottom:1px solid var(--hair);
  font-variant-numeric:tabular-nums}
.page tr:last-child td{border-bottom:none}

/* The header, matched to the dashboard's: same 52px, same surface, same
   wordmark treatment, same logo. Landing on /profile from the dashboard used
   to look like landing in a different application. */
.page .topbar{display:flex;align-items:center;gap:var(--s4x);height:52px;
  padding:0 var(--s4x);border-bottom:1px solid var(--line);
  background:var(--s1);position:sticky;top:0;z-index:5}
.page .topbar .grow{flex:1}
.page .brand{display:flex;align-items:center;gap:9px;font-weight:650;
  font-size:13px;letter-spacing:.24px;color:var(--tx)}
.page .brand:hover{text-decoration:none}
/* 30px, not smaller: two of the four circles are dark navy and stop reading
   against the dark header below roughly this size. */
.page .brand img{height:30px;width:auto;max-width:170px;object-fit:contain;
  display:block}

/* Top-level navigation is a row of quiet links, not three filled boxes
   competing with whatever the page's actual primary action is. */
.page .nav{display:flex;align-items:center;gap:var(--s1x)}
.page .nav a{display:flex;align-items:center;gap:7px;padding:6px 11px;
  border-radius:var(--r2);font-size:var(--fs-sm);color:var(--tx2);
  transition:background var(--fast),color var(--fast)}
.page .nav a:hover{background:var(--s2);color:var(--tx);text-decoration:none}
.page .nav a.danger:hover{background:var(--dg2);color:var(--dg)}

.page .wrap{max-width:var(--maxw);margin:0 auto;padding:var(--s6x) var(--s5x) 64px}
.page h1{font-size:var(--fs-xl);font-weight:660;letter-spacing:-.3px;
  margin-bottom:var(--s2x)}
.page h2{font-size:var(--fs-lg);font-weight:620;margin-bottom:var(--s3x)}

/* An empty table is a normal state here - a fresh station has no accounts
   beyond the first and no jobs yet. Give it the presence the dashboard gives
   its own empty states instead of one grey line under a header. */
.page .empty-row td{color:var(--tx3);text-align:center;padding:var(--s6x) var(--s3x)}
