/* GRT Rate Maintenance — stylesheet.

   The colour values in the first `:root` block are the Magellan house palette
   carried from archive/prototype/grt-prototype.html, and are not ours to
   re-pick. The prototype wrote spacing, radius, font size, z-index and a few
   colours as literals at every use; those are tokens now (second `:root`
   block), so a value changes in one place. Rules below use the tokens.

   The prototype pulled Ubuntu from fonts.googleapis.com on every load. The
   faces are now served from web/fonts/ — same family, same weights, latin
   subset, no third-party request and nothing that fails when the network does.
   Licence: web/fonts/UBUNTU-FONT-LICENCE.txt (UFL 1.0). */

@font-face {
  font-family: "Ubuntu"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/ubuntu-400.woff2") format("woff2");
}
@font-face {
  font-family: "Ubuntu"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("fonts/ubuntu-500.woff2") format("woff2");
}
@font-face {
  font-family: "Ubuntu"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("fonts/ubuntu-700.woff2") format("woff2");
}
@font-face {
  font-family: "Ubuntu Mono"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/ubuntu-mono-400.woff2") format("woff2");
}
@font-face {
  font-family: "Ubuntu Mono"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("fonts/ubuntu-mono-700.woff2") format("woff2");
}

/* Magellan house tokens, carried from the McFee rate-lookup app and the
   GRT discovery artifact. This system is light-only by design; the page
   paints every colour explicitly so it holds on any host ground. */
:root {
  --blue:#0071bf; --dark-blue:#003c7a; --sky:#00a9e0; --sky-soft:#e5f6fc;
  --magenta:#bb0e83; --orange:#f99d2a;
  --ink:#1f1f1f; --muted:#5d6872; --line:#d7dee5; --control-border:#7a8794; --line-soft:#e7edf2;
  --panel:#fff; --wash:#f5f8fa; --wash-deep:#eaf0f5; --on-accent:#fff;
  --danger:#c8102e; --danger-bg:#fdecef;
  --success:#247a3d; --success-bg:#eaf5ee;
  --warning:#8a5a00; --warning-bg:#fdf7dc;
  --shadow:0 12px 30px rgba(0,60,122,.08); --shadow-sm:0 2px 8px rgba(0,60,122,.06);
  color-scheme:light;
  font-family:Ubuntu,"Trebuchet MS",Arial,sans-serif;

  /* Derived colours the prototype wrote as literals. `--blue-hover` is 6.7:1
     against white; `--focus` is the brand blue (5.1:1 on the panel and 4.8:1 on
     the wash) because the sky blue the ring used to be is 2.7:1, under the 3:1
     a focus indicator needs. */
  --blue-hover:#005fa0; --focus:var(--blue); --danger-hover:#a30d25;
  --warning-border:#e6d9a8; --danger-border:#f3c9d1;
  --info-border:#bfe6f5; --success-border:#c5e3d0;
  --scrim:rgba(31,31,31,.42); --divider-faint:rgba(0,0,0,.08);

  /* Spacing: a 4px scale. */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px;

  /* Radius: controls, surfaces, and the pill. */
  --r-sm:4px; --r-md:8px; --r-lg:12px; --r-pill:999px;

  /* Type scale. Seven sizes where the prototype had fourteen (half pixels
     included): xs for uppercase labels, sm for supporting text, md for
     controls, tables and notes, body for running text, then lg, xl and the
     tile figure. */
  --fs-xs:11px; --fs-sm:12px; --fs-md:14px; --fs-body:15px; --fs-lg:16px; --fs-xl:22px; --fs-num:28px;

  /* Heading roles. An h2 is the page; an h3 is a panel title, a dialog title
     or a subhead, each with its own class (`panel-title`, `dialog-title`,
     `subhead`) and one size apiece. */
  --h-page:var(--fs-xl); --h-dialog:var(--fs-lg); --h-panel:var(--fs-md); --h-sub:var(--fs-sm);

  /* Stacking: sticky bar < modal scrim < menu < toast < skip link. */
  --z-raised:1; --z-sticky:5; --z-scrim:40; --z-menu:45; --z-toast:50; --z-skip:60;
}
*{box-sizing:border-box}
body{margin:0;background:var(--wash);color:var(--ink);font-size:var(--fs-body);line-height:1.5}
h1,h2,h3{text-wrap:balance;margin:0}
button,input,select{font:inherit;color:inherit}
:focus-visible{outline:3px solid var(--focus);outline-offset:2px;border-radius:var(--r-sm)}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ---------- signed-out page (signed-out.html) ---------- */
.signedout{display:grid;justify-items:center;padding:var(--sp-6) var(--sp-4);padding-top:calc(var(--sp-6) * 3)}
.signedout-card{width:100%;max-width:440px;padding:var(--sp-6) calc(var(--sp-6) + var(--sp-2));
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow);text-align:left}
.signedout-mark{display:block;margin-bottom:var(--sp-4);color:var(--success)}
.signedout-card h2{margin:0 0 var(--sp-2);font-size:var(--h-page);font-weight:500;line-height:1.25}
.signedout-card p{margin:0 0 var(--sp-5);color:var(--muted)}
.signedout-card .note{margin-bottom:var(--sp-5)}
.signedout-card .note[hidden]{display:none}
.signedout-card .signedout-fine{margin:var(--sp-5) 0 0;padding-top:var(--sp-4);border-top:1px solid var(--line-soft);
  font-size:var(--fs-md)}

/* ---------- top bar ---------- */
.topbar{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-5);
  padding:var(--sp-3) var(--sp-6);background:var(--panel);border-bottom:1px solid var(--line);
  box-shadow:var(--shadow-sm)}
.brand{display:flex;align-items:center;gap:var(--sp-3);min-width:0}
.brand-mark{display:grid;place-items:center;width:40px;height:40px;flex:0 0 auto;
  border-radius:var(--r-md);background:var(--dark-blue);color:var(--on-accent);font-weight:700;font-size:var(--fs-md)}
.brand h1{font-size:var(--fs-lg);font-weight:500;line-height:1.2}
.topright{display:flex;align-items:center;gap:var(--sp-4);font-size:var(--fs-md);color:var(--muted)}
.env{display:inline-flex;align-items:center;gap:var(--sp-2);padding:var(--sp-1) var(--sp-2);border-radius:var(--r-pill);
  background:var(--sky-soft);color:var(--dark-blue);font-size:var(--fs-sm);font-weight:500;
  letter-spacing:.02em}
.env::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--sky)}

.identity-menu{position:relative}
.identity-menu summary{display:flex;align-items:center;gap:var(--sp-1);cursor:pointer;
  list-style:none;color:var(--muted)}
.identity-menu summary::-webkit-details-marker{display:none}
.identity-menu summary::after{content:"";width:5px;height:5px;margin-top:-3px;
  border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);
  transform:rotate(45deg);transition:transform .12s}
.identity-menu[open] summary::after{transform:rotate(225deg);margin-top:2px}
.identity-menu-body{position:absolute;right:0;top:calc(100% + 8px);z-index:var(--z-menu);
  min-width:130px;padding:var(--sp-2);background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-md);box-shadow:var(--shadow)}
.identity-menu-body .btn{width:100%;height:32px;padding:0 var(--sp-3);font-size:var(--fs-md);
  justify-content:center}

/* ---------- shell ---------- */
.shell{display:grid;grid-template-columns:216px minmax(0,1fr);min-height:calc(100vh - 110px)}
.rail{border-right:1px solid var(--line);background:var(--panel);padding:var(--sp-4) var(--sp-3);display:flex;flex-direction:column;gap:2px}
.rail .grp{margin:var(--sp-4) var(--sp-3) var(--sp-1);font-size:var(--fs-sm);font-weight:500;color:var(--muted)}
.navbtn{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);width:100%;
  padding:var(--sp-2) var(--sp-3);border:0;border-radius:var(--r-md);background:transparent;cursor:pointer;
  text-align:left;font-size:var(--fs-md);color:var(--ink);transition:background .12s}
.navbtn:hover{background:var(--wash)}
.navbtn .count{font-size:var(--fs-sm);font-weight:700;color:var(--on-accent);background:var(--magenta);
  border-radius:var(--r-pill);padding:1px var(--sp-2);font-variant-numeric:tabular-nums}
main{padding:var(--sp-6) var(--sp-6) 64px;min-width:0}

/* ---------- page furniture ---------- */
.pagehead{margin-bottom:var(--sp-5)}
.pagehead h2{font-size:var(--h-page);font-weight:500;color:var(--dark-blue)}
.pagehead p{margin:var(--sp-1) 0 0;color:var(--muted);max-width:66ch}
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-sm);margin-bottom:var(--sp-5);overflow:hidden}
.panel-title{padding:var(--sp-3) var(--sp-5);border-bottom:1px solid var(--line-soft);font-size:var(--h-panel);
  font-weight:500;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3)}
.panel .body{padding:var(--sp-4) var(--sp-5)}
.label{font-size:var(--fs-sm);font-weight:500;color:var(--muted);display:block;margin-bottom:var(--sp-1)}

/* ---------- view tabs (e.g. the rate schedule's tabs) ---------- */
.tabs{display:flex;gap:var(--sp-6);border-bottom:1px solid var(--line);margin-bottom:var(--sp-5)}
.tab{display:inline-flex;align-items:center;padding:var(--sp-3) 2px;border:0;border-bottom:2px solid transparent;
  margin-bottom:-1px;background:none;color:var(--muted);font-size:var(--fs-md);font-weight:500;
  text-decoration:none;cursor:pointer;transition:color .12s,border-color .12s}
.tab:hover{color:var(--ink)}
.tab[aria-selected="true"]{color:var(--dark-blue);border-bottom-color:var(--blue)}

/* ---------- summary tiles ---------- */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));gap:var(--sp-3);margin-bottom:var(--sp-5)}
.tile{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);padding:var(--sp-4);box-shadow:var(--shadow-sm)}
.tile .n{font-size:var(--fs-num);font-weight:700;color:var(--dark-blue);font-variant-numeric:tabular-nums;line-height:1.1}
.tile .n.warn{color:var(--warning)} .tile .n.bad{color:var(--danger)} .tile .n.ok{color:var(--success)}
.tile .cap{font-size:var(--fs-sm);color:var(--muted);margin-top:var(--sp-1)}

/* ---------- queue ---------- */
.qitem{display:flex;gap:var(--sp-4);align-items:flex-start;padding:var(--sp-4) var(--sp-5);border-bottom:1px solid var(--line-soft);
  cursor:pointer;background:none;border-left:0;border-right:0;border-top:0;width:100%;text-align:left;transition:background .12s}
.qitem:last-child{border-bottom:0}
.qitem:hover{background:var(--wash)}
.qitem-static{cursor:default}
.qitem-static:hover{background:none}
.stripe{width:4px;align-self:stretch;border-radius:var(--r-sm);flex:0 0 auto;background:var(--blue)}
.stripe.warn{background:var(--orange)} .stripe.bad{background:var(--danger)} .stripe.ok{background:var(--success)}
.qbody{min-width:0;flex:1}
.qbody .t{display:block;font-weight:500;margin-bottom:2px}
.qbody .d{font-size:var(--fs-md);color:var(--muted)}
.chev{color:var(--muted);flex:0 0 auto;align-self:center}

/* Home: the search is the page, the jobs sit under it. */
.home-jobs{display:flex;flex-wrap:wrap;gap:var(--sp-3);margin-top:var(--sp-4)}
.home-warn-text{color:var(--warning);font-weight:500}
.home-find ~ .panel p a, .aside-link{color:var(--blue);text-underline-offset:2px}
.home-find ~ .panel p a:hover, .aside-link:hover{color:var(--blue-hover)}
.home-find ~ .panel p a.home-warn{color:var(--warning);font-weight:500}
.panel-title .aside-link{font-size:var(--fs-md);font-weight:400}
.panel .body > p + p{margin-top:var(--sp-2)}

/* ---------- pills ---------- */
.pill{display:inline-block;padding:2px var(--sp-2);border-radius:var(--r-pill);font-size:var(--fs-sm);font-weight:500;
  letter-spacing:.03em;white-space:nowrap}
.pill.active{background:var(--success-bg);color:var(--success)}
.pill.ended{background:var(--wash-deep);color:var(--muted)}
.pill.future{background:var(--sky-soft);color:var(--dark-blue)}
.pill.derived{background:var(--wash-deep);color:var(--muted);font-family:Ubuntu,sans-serif}
.pill.bad{background:var(--danger-bg);color:var(--danger)}
.pill.warn{background:var(--warning-bg);color:var(--warning)}

/* A pill that is a button (e.g. "calculated — show") rather than a static
   label -- .pill.derived's muted gray reads as inert, which is right for a
   fact like "from schedule" beside it but wrong for something a maintainer
   is meant to click, so this gets its own tone plus the hover/focus/cursor
   affordances a <button> needs and a plain <span> pill never did. */
.pill.action{background:var(--sky-soft);color:var(--dark-blue);font-family:Ubuntu,sans-serif;
  border:1px solid transparent;cursor:pointer;transition:background .12s,border-color .12s}
.pill.action:hover{background:var(--wash-deep);border-color:var(--blue);text-decoration:underline}

/* A problem message, which can run much longer than a pill's short verb --
   wraps rather than forcing the row (and the table's horizontal scrollbar)
   wide enough to hold it on one line. */
.result-text{white-space:normal;word-break:break-word}
.result-text.bad{color:var(--danger)}

/* A cell whose marked value differs from what's on file right now. */
td.changed{background:var(--sky-soft);font-weight:600}

/* ---------- tables ---------- */
.tablewrap{overflow-x:auto}
table{border-collapse:collapse;width:100%;font-size:var(--fs-md)}
th{text-align:left;font-size:var(--fs-sm);color:var(--muted);
  font-weight:500;padding:var(--sp-2) var(--sp-4);border-bottom:1px solid var(--line);white-space:nowrap;background:var(--wash)}
td{padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line-soft);vertical-align:top}
tr:last-child td{border-bottom:0}
.num{font-family:"Ubuntu Mono",ui-monospace,monospace;font-variant-numeric:tabular-nums;white-space:nowrap}
.dim{color:var(--muted)}
.rowbtn{cursor:pointer}
.rowbtn:hover td{background:var(--wash)}
/* The row's one link covers the whole row, so clicking the address works too. */
.rowfull{position:relative}
.rowfull .rowlink::after{content:"";position:absolute;inset:0}
.rowfull .rowraise,.rowfull .btn{position:relative;z-index:var(--z-raised)}

/* ---------- controls ---------- */
/* Buttons and text inputs otherwise reach slightly different heights (native
   date/search-input chrome, differing padding), so a shared height keeps a
   button level with the input beside it instead of looking offset by a few
   px. Everything here is box-sizing:border-box, so height already accounts
   for padding and border. */
.btn{display:inline-flex;align-items:center;gap:var(--sp-2);height:40px;padding:0 var(--sp-4);border-radius:var(--r-md);border:1px solid var(--blue);
  background:var(--blue);color:var(--on-accent);font-size:var(--fs-md);font-weight:500;cursor:pointer;transition:background .12s}
.btn:hover{background:var(--blue-hover)}
.btn.ghost{background:var(--panel);color:var(--blue)}
.btn.ghost:hover{background:var(--sky-soft)}
.btn.quiet{background:var(--panel);color:var(--muted);border-color:var(--control-border)}
.btn.quiet:hover{background:var(--wash)}
.btn.danger{background:var(--danger);border-color:var(--danger)}
.btn.danger:hover{background:var(--danger-hover);border-color:var(--danger-hover)}
a.btn{text-decoration:none}
.btn:disabled,.btn[aria-disabled="true"]{opacity:.5;cursor:not-allowed}
.field{display:block;margin-bottom:var(--sp-3)}
.field input,.field select{width:100%;height:40px;padding:var(--sp-2) var(--sp-3);border:1px solid var(--control-border);border-radius:var(--r-md);background:var(--panel)}
.field input[readonly]{background:var(--wash);color:var(--muted)}

/* ---------- file input: styled and a drop target, not the OS's own button ---------- */
/* The real <input type=file> covers the whole zone (opacity 0, not display:none, so it
   stays focusable and a native drop still lands on it) -- .filedrop-body is what's actually
   seen, and pointer-events:none on it lets clicks and drops both pass straight to the input
   underneath rather than landing on the decoration. */
.filedrop{position:relative;display:block;border:1px dashed var(--control-border);border-radius:var(--r-md);
  padding:var(--sp-5);text-align:center;cursor:pointer;background:var(--wash);
  transition:border-color .12s,background .12s}
.filedrop:hover{border-color:var(--sky)}
.filedrop.drag{border-color:var(--blue);background:var(--sky-soft)}
.filedrop input[type="file"]{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}
.filedrop-body{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:center;gap:var(--sp-2);
  pointer-events:none;font-size:var(--fs-md)}
.filedrop-body strong{color:var(--blue);font-weight:500}
.filedrop-name{flex-basis:100%;font-size:var(--fs-sm);color:var(--muted)}
.searchbar{display:flex;gap:var(--sp-3);align-items:center;flex-wrap:wrap}
.searchbar input{flex:1;min-width:240px;height:40px;padding:var(--sp-2) var(--sp-3);border:1px solid var(--control-border);border-radius:var(--r-md)}
/* A .field stacks a label above its input, so it is taller than a bare .btn;
   centering the row centers the button against that whole stack instead of
   against the input itself. Bottom-align so a button sits level with the
   input row, not with the label above it. */
.searchbar > .btn, .searchbar > a.btn { align-self: flex-end; }
/* The date field is a fixed-width control, and the checkbox sits level with its input, not its label. */
.searchbar.asof{gap:var(--sp-4)}
.searchbar.asof .field{flex:0 0 auto}
.searchbar.asof input[type=date]{flex:none;min-width:0;width:180px}
.searchbar.asof .check input{flex:none;min-width:0;width:18px;height:18px;padding:0;margin:0}
.searchbar.asof .check{margin:0;align-self:flex-end;height:40px;display:flex;align-items:center}

/* ---------- callouts ---------- */
.note{border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);font-size:var(--fs-md);margin-bottom:var(--sp-4);border:1px solid transparent}
.note.warn{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning)}
.note.bad{background:var(--danger-bg);border-color:var(--danger-border);color:var(--danger)}
.note.info{background:var(--sky-soft);border-color:var(--info-border);color:var(--dark-blue)}
.note b{display:block;margin-bottom:2px}
/* How many times the same finding was raised; sits at the right end of the title line. */
.note .count{float:right;margin-left:var(--sp-3);padding:0 var(--sp-2);border-radius:var(--r-pill);
  color:var(--on-accent);font-size:var(--fs-sm);font-weight:600;font-variant-numeric:tabular-nums;line-height:1.5}
.note.warn .count{background:var(--warning)}
.note.bad .count{background:var(--danger)}
.note.info .count{background:var(--dark-blue)}

/* ---------- derivation strip ---------- */
.derive{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;background:var(--wash);
  border:1px dashed var(--line);border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);margin:var(--sp-3) 0}
.derive .op{color:var(--muted)}
.derive .val{font-family:"Ubuntu Mono",monospace;font-weight:700;font-variant-numeric:tabular-nums}
.derive .out{color:var(--dark-blue);font-size:var(--fs-lg)}

/* ---------- choice cards (correction) ---------- */
p + .choices{margin-top:var(--sp-3)}
.choices{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:var(--sp-4)}
.choice{display:block;border:2px solid var(--control-border);border-radius:var(--r-lg);padding:var(--sp-4);cursor:pointer;background:var(--panel);transition:border-color .12s,background .12s}
.choice:hover{border-color:var(--sky)}
.choice input{width:auto;height:auto;margin-right:var(--sp-2)}
.choice[data-on="1"]{border-color:var(--blue);background:var(--sky-soft)}
.choice .ct{font-weight:500;margin-bottom:var(--sp-2)}
.choice .cd{font-size:var(--fs-md);color:var(--muted)}
.choice .cw{font-size:var(--fs-sm);margin-top:var(--sp-2);padding-top:var(--sp-2);border-top:1px solid var(--line-soft);color:var(--muted)}

/* ---------- dialog ---------- */
.scrim{position:fixed;inset:0;background:var(--scrim);display:grid;place-items:center;padding:var(--sp-6);z-index:var(--z-scrim)}
.dialog{background:var(--panel);border-radius:var(--r-lg);box-shadow:var(--shadow);width:min(760px,100%);
  max-height:86vh;display:flex;flex-direction:column;overflow:hidden}
.dialog form{display:flex;flex-direction:column;min-height:0;overflow:hidden}
.dialog header{padding:var(--sp-4) var(--sp-5);border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3)}
.dialog-title{font-size:var(--h-dialog);font-weight:500;color:var(--dark-blue)}
.dialog .dbody{padding:var(--sp-5) var(--sp-5);overflow:auto}
.dialog footer{padding:var(--sp-4) var(--sp-5);border-top:1px solid var(--line);display:flex;justify-content:flex-end;gap:var(--sp-3);background:var(--wash)}
.x{border:0;background:none;cursor:pointer;color:var(--muted);font-size:var(--fs-xl);line-height:1;padding:var(--sp-1) var(--sp-2)}

/* ---------- review page ---------- */
.review-bar{position:sticky;bottom:0;z-index:var(--z-sticky);display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-4);margin-top:var(--sp-4);background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow)}
dl.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--sp-3) var(--sp-5);margin:0}
dl.summary dt{font-size:var(--fs-sm);color:var(--muted)}
dl.summary dd{margin:2px 0 0;overflow-wrap:anywhere}
.review-headline{margin:0 0 var(--sp-4);font-size:var(--fs-lg);line-height:1.45;max-width:72ch}
.note ul{margin:var(--sp-1) 0 0;padding-left:var(--sp-5)}
.note ul li+li{margin-top:var(--sp-1)}
.arrow{color:var(--muted)}
dl.techlist{display:grid;gap:var(--sp-2);margin:0 0 var(--sp-3)}
dl.techlist dt{font-size:var(--fs-sm);color:var(--muted)}
dl.techlist dd{margin:2px 0 0;display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;color:var(--ink)}
.wrapall{white-space:normal;overflow-wrap:anywhere}
.btn.copybtn{height:auto;padding:1px var(--sp-2);font-size:var(--fs-sm);font-weight:400;border-color:var(--line);vertical-align:baseline}

/* ---------- inline detail under a row ---------- */
.detail{border-top:1px solid var(--line);background:var(--wash)}
.detail tr.now td{background:var(--sky-soft)}
.ratewhen{font-size:var(--fs-sm,.85em);margin-top:2px}

/* ---------- toast ---------- */
/* A stack, newest at the bottom: two confirmations in a row both stay readable. */
.toasts{position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:var(--z-toast);
  display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);pointer-events:none}
.toast{pointer-events:auto;display:flex;align-items:center;gap:var(--sp-3);
  background:var(--dark-blue);color:var(--on-accent);padding:var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-5);border-radius:var(--r-md);box-shadow:var(--shadow);font-size:var(--fs-md)}
.toast .x{color:inherit;opacity:.8}
.toast .x:hover{opacity:1}

.stack{display:flex;flex-direction:column;gap:var(--sp-2)}
.row2{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--sp-4)}
.foot{color:var(--muted);font-size:var(--fs-sm);padding:var(--sp-3) var(--sp-5);border-top:1px solid var(--line-soft);background:var(--wash)}
@media (max-width:820px){.shell{grid-template-columns:minmax(0,1fr)}.rail{flex-direction:row;flex-wrap:nowrap;overflow-x:auto;border-right:0;border-bottom:1px solid var(--line);padding:var(--sp-2) var(--sp-3)}.rail .grp{display:none}.rail .navbtn{width:auto;flex:none;white-space:nowrap}}

/* ================================================================
   Routing, feedback and state rules.
   ================================================================ */

/* ---------- hash routing: the rail and the queue are links now ---------- */
/* A route that can be pasted into a ticket has to be an <a href="#/...">, so
   these two carry the anchor reset a button never needed. */
a.navbtn, a.qitem { text-decoration: none; color: var(--ink); }
a.navbtn:hover, a.qitem:hover { background: var(--wash); }
.navbtn[aria-current="page"] {
  background: var(--sky-soft); color: var(--dark-blue); font-weight: 500;
  box-shadow: inset 3px 0 0 var(--blue);
}
.rowlink { color: var(--dark-blue); font-weight: 500; text-decoration: none; }
.rowlink:hover { text-decoration: underline; }
.crumbs { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin-bottom: var(--sp-4); font-size:var(--fs-md); }
.crumbs a { color: var(--blue); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }
.pagehead p a { color: var(--blue); text-decoration: none; }
.pagehead p a:hover { text-decoration: underline; }

/* ---------- skip link and the route announcer ---------- */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: var(--z-skip);
  background: var(--dark-blue); color: var(--on-accent); padding: var(--sp-3) var(--sp-4);
  border-radius: 0 0 var(--r-md) 0; text-decoration: none;
}
.skip:focus { left: 0; }
/* main only takes focus from script (route change, dialog close), never as a control,
   so it gets no ring: :focus-visible matches a scripted focus on load and drew a box
   around the whole page. */
main:focus, main:focus-visible { outline: none; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- server paging ---------- */
.pager { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-5); border-top: 1px solid var(--line-soft); background: var(--wash);
  font-size:var(--fs-sm); color: var(--muted); }
.pager .btn { padding: var(--sp-1) var(--sp-3); font-size:var(--fs-sm); }

/* ---------- the success note ---------- */
.note.ok { background: var(--success-bg); border-color: var(--success-border); color: var(--success); }
.note .why { display: block; font-family: "Ubuntu Mono", ui-monospace, monospace;
  margin-top: var(--sp-1); white-space: pre-wrap; }
.note.none { background: var(--wash); border-color: var(--line); color: var(--muted); }

/* ---------- background worth keeping, not worth showing by default ---------- */
.moreinfo { margin-bottom: var(--sp-4); font-size:var(--fs-md); color: var(--muted); }
.moreinfo summary { cursor: pointer; color: var(--blue); font-weight: 500; }
.moreinfo summary::marker { color: var(--muted); }
.moreinfo[open] summary { margin-bottom: var(--sp-2); color: var(--ink); font-weight: 400; }

/* ---------- one review checkbox per code-state category, not per code ---------- */
.ackgroup-head { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); margin-bottom: var(--sp-1); }
.ack-toggle { display: flex; align-items: center; gap: var(--sp-2); font-weight: 400;
  font-size:var(--fs-md); white-space: nowrap; cursor: pointer; }
.subnote { padding-top: var(--sp-2); margin-top: var(--sp-2); border-top: 1px solid var(--divider-faint); }
.subnote:first-child { padding-top: 0; margin-top: 0; border-top: 0; }

/* ---------- the uppercase section label the dialogs wrote inline ---------- */
.subhead { font-size: var(--h-sub); font-weight: 500;
  color: var(--muted); margin: var(--sp-4) 0 var(--sp-2); }
.subhead:first-child { margin-top: 0; }

/* ---------- small utilities, so no render function writes a style attribute --- */
.m0 { margin: 0; }
.mb0 { margin-bottom: 0; }
.mt12 { margin-top: var(--sp-3); }
.grow { flex: 1; min-width: 200px; }
.narrow { max-width: 300px; }
.actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: center; }
.actions.tight { gap: var(--sp-2); }
.up { color: var(--success); }
.down { color: var(--danger); }
.big { font-size:var(--fs-lg); color: var(--dark-blue); }
.moved { color: var(--dark-blue); }

/* ---------- loading and failure ---------- */
.state { padding: var(--sp-6) var(--sp-5); text-align: center; color: var(--muted); }
.state.bad { color: var(--danger); }
.state.warn { color: var(--warning); }
.state.loading { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); }
.spinner {
  width: 24px; height: 24px; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--blue);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* A link jumps a maintainer to a row that could be thousands of rows away on
   a large sheet -- this is what says which one, once the scroll lands. */
.flash-row { animation: rowflash 1.6s ease-out; }
@keyframes rowflash {
  from { background: var(--sky-soft); }
  to { background: transparent; }
}

/* ---------- fill the viewport without guessing the header's height ----------
   A hardcoded min-height:calc(100vh - 110px) stood in for the topbar's height.
   The topbar isn't 110px tall, so on a page
   short enough for min-height to be what decides .shell's height, the rail
   and main both come up short and the body's wash color shows through as a
   gap at the bottom of the viewport. Flexing the body column lets .shell
   claim exactly what the topbar doesn't use, however tall the topbar turns
   out to be, and still grow past the viewport on a long page. */
body { min-height: 100vh; display: flex; flex-direction: column; }
.shell { min-height: 0; flex: 1 0 auto; }

/* Form primitives: inline field errors, the error summary, a checkbox row, and
   the in-flight state `inflight.js` puts on a button while its request runs. */
/* Hints sit under their control like the error does, at the supporting-text size. */
.field > .dim, .check > .dim { display: block; margin-top: var(--sp-1); font-size: var(--fs-sm); }
.field-error { display: block; margin-top: var(--sp-1); font-size:var(--fs-sm); color: var(--danger); }
.field input[aria-invalid="true"], .field select[aria-invalid="true"] { border-color: var(--danger); }
.form-errors ul { margin: var(--sp-2) 0 0; padding-left: var(--sp-5); }
.form-errors a { color: inherit; text-decoration: underline; }
.row-problems { margin: 0; padding-left: var(--sp-4); }
td.cell-error { box-shadow: inset 0 0 0 2px var(--danger); }
.check { margin-bottom: var(--sp-3); }
.check label { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; }
.btn[aria-busy="true"] { cursor: progress; }
/* Reduced motion switches the spinner's animation off, which would leave a frozen
   ring; the button says "Working…" (or its own busy label) in words instead. */
@media (prefers-reduced-motion:reduce){.btn[aria-busy="true"]::before{display:none}}
.btn[aria-busy="true"]::before {
  content: ""; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: spin .7s linear infinite;
}

/* A unit that belongs to the number typed beside it, inside the input's own box. */
.inputwrap{position:relative;display:block}
.inputwrap input{padding-right:var(--sp-6)}
.inputwrap .suffix{position:absolute;right:var(--sp-3);top:50%;transform:translateY(-50%);color:var(--muted);pointer-events:none}
/* The rate strip's "in force today" line: the number being replaced, beside the new one. */
.derive-was{flex-basis:100%;font-size:var(--fs-md);color:var(--muted)}
.derive-was .num{color:var(--ink);font-weight:700;font-size:var(--fs-md)}

/* A panel that folds: the fields a maintainer rarely touches, one line until they ask. */
details.fold > summary{padding:var(--sp-3) var(--sp-5);cursor:pointer;font-weight:500;font-size:var(--fs-md);color:var(--dark-blue)}
details.fold > summary .dim{font-weight:400}
details.fold[open] > summary{border-bottom:1px solid var(--line-soft)}

/* A control that is really a link: the "how is this worked out" disclosures under a rate. */
.linkbtn{font-family:Ubuntu,"Trebuchet MS",Arial,sans-serif;padding:0;border:0;background:none;color:var(--blue);cursor:pointer;font-size:var(--fs-sm);text-decoration:underline;text-underline-offset:2px}
.linkbtn:hover{color:var(--blue-hover)}
/* The rate is the answer on this screen, so it is the biggest thing in the row. */
td.finalrate strong{font-size:var(--fs-xl);color:var(--dark-blue);line-height:1.2}
td.finalrate .ratewhen{margin-top:2px}
/* Controls that sit on the page background rather than in a card. */
.toolbar{margin-bottom:var(--sp-5)}
.crumbs + h2{margin-top:0}
.actions .push{margin-left:auto}
.btn.destructive{color:var(--danger);border-color:var(--danger-border)}
.btn.destructive:hover{background:var(--danger-bg)}

/* Grids of many like rows: tighter, with numbers right-aligned under right-aligned headings. */
table.compact td{padding-top:var(--sp-2);padding-bottom:var(--sp-2)}
th.r,td.r{text-align:right}

/* A shortened id: reads like a commit hash, copies whole. Sits above a row-wide link overlay. */
.shortid{position:relative;z-index:var(--z-raised);padding:0;border:0;border-bottom:1px dotted var(--muted);background:none;
  font-family:"Ubuntu Mono",ui-monospace,monospace;font-size:inherit;color:var(--muted);cursor:copy}
.shortid:hover{color:var(--ink);border-bottom-color:var(--ink)}

/* Running text inside a card stays a readable measure however wide the card is. */
.panel .body > p, .panel .body > .dim{max-width:70ch}

/* A sentence under the tab strip that says what this tab is for. */
.tablead{margin:0 0 var(--sp-4);color:var(--muted);max-width:70ch}

/* A real sequence: numbered steps, each a heading and a sentence or two. */
ol.steps{list-style:none;counter-reset:step;margin:0 0 var(--sp-5);padding:0;display:flex;flex-direction:column;gap:var(--sp-3);max-width:70ch}
ol.steps > li{counter-increment:step;position:relative;padding-left:calc(var(--sp-6) + var(--sp-2))}
ol.steps > li::before{content:counter(step);position:absolute;left:0;top:0;width:var(--sp-6);height:var(--sp-6);border-radius:var(--r-pill);background:var(--sky-soft);color:var(--dark-blue);font-weight:700;display:flex;align-items:center;justify-content:center;font-size:var(--fs-md)}
ol.steps > li > b{display:block}
ol.steps ul{margin:var(--sp-1) 0 0;padding-left:var(--sp-5)}

/* A read-only value in a form: said plainly rather than as a greyed-out box. */
.readout{margin-bottom:var(--sp-4)}
.readout .val{font-family:"Ubuntu Mono",monospace;font-weight:700;font-size:var(--fs-lg);display:block}
.dlg-sub{margin:0 0 var(--sp-4)}
.choices + .field{margin-top:var(--sp-4)}

/* Notes, footnotes and disclosures keep a readable measure, left-aligned, however wide the card is. */
.note, .moreinfo{max-width:70ch}
.foot{padding-right:max(var(--sp-5), calc(100% - 70ch))}
.searchbar .field input{min-width:0}
@media (max-width:820px){.shell{grid-template-rows:auto 1fr;align-content:start}}

/* A row of narrow controls (codes, rates, dates): each at most 300px, wrapping, never stretched to halves. */
.row-narrow{display:flex;flex-wrap:wrap;gap:var(--sp-4);align-items:flex-start}
.row-narrow > .field{flex:0 1 300px;min-width:0;width:300px;max-width:100%}
.row-narrow > .readout{flex:0 0 300px;margin-bottom:var(--sp-3)}
/* A sentence and the one button that acts on it; pairs are spaced evenly. */
.pair{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp-3)}
.pair p{margin:0}
.pair + .pair{margin-top:var(--sp-5)}
ol.steps > li > .panel{margin:var(--sp-3) 0 var(--sp-2)}
ol.steps > li > ul{margin-bottom:var(--sp-2)}

/* The reason a change was made: the most useful line in a change-set row, so it reads as text, not metadata. */
.reason{color:var(--ink)}
