/* Light is the complete palette. The dark block redefines only what changes, and every
   colour has its definition here — nothing is defined solely inside a theme block, so no
   state can end up with a missing value. */
:root{
  --paper:#eef1f5; --surface:#ffffff; --ink:#131c27; --rule:#c7d0da;
  /* The accent is the logo's lit blue, stepped down for contrast on white; --bar is its
     shadowed navy. Taking both from the mark rather than inventing a second blue is what
     makes the chrome read as the same family as the logo. */
  --pen:#0a4fb8; --fail:#a8322a; --warn:#a9761a; --ok:#256b4e; --muted:#63717f;
  --pen-lit:#2f8ae8; --navy:#0d2138;
  --grid:#e6ebf0;                /* chart gridlines */
  --tip-bg:#131c27; --tip-ink:#ffffff;
  --cell-edge:transparent;       /* see the dark block */
  --paper-lines:var(--rule);     /* the ruled-paper background */
  /* Deliberately inverted surfaces: the view bar, a selected tab, a ticked chip. In light
     these are ink-on-white inverted to white-on-ink. They cannot be written as
     "background:var(--ink); color:#fff", because in dark --ink IS near-white and that
     renders white on white — invisible. */
  --bar:#0d2138; --bar-ink:#eaf2fb;
  --raise:#f5f8fb;               /* row hover, faintly raised surface */
  --track:#e6ebf0;               /* the unfilled part of a bar */
  --callout:#fdf6f5; --callout-warn:#fdfaf3;
  --mono:ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  color-scheme:light;
}

/* Dark is selected, not an inverted light: these are chosen steps. The ruled-paper
   background goes transparent rather than being recoloured, because a grid of hairlines
   that reads as paper in light reads as noise on dark.

   The tape's defect fills are deliberately NOT redefined. They are a categorical palette
   validated all-pairs — any two cells can end up adjacent in that grid — and the six hues
   cannot be re-stepped into the dark lightness band without collapsing into one another:
   the red has to stay dark to stay distinct from the pink, and a dark red cannot clear
   3:1 on a dark surface. Keeping the validated fills keeps every cell distinguishable
   from every other, which is what actually identifies a defect. Two of them then sit
   below 3:1 against the dark panel, so relief is provided as the method requires: the
   legend names every colour, the per-cell tooltip names every defect in words, and the
   Explorer panel is the table view of the same rows. --cell-edge gives every cell a
   hairline as well, so its boundary is visible whatever the fill. */
:root[data-theme="dark"]{
  --paper:#14171a; --surface:#1b1f24; --ink:#e7ecf2; --rule:#2f3945;
  --pen:#4aa4f7; --fail:#ef8079; --warn:#d9a54a; --ok:#5cba8e; --muted:#9aa8b8;
  --pen-lit:#7cc0fb; --navy:#0b1a2c;
  --grid:#2a323c;
  --tip-bg:#0b0e12; --tip-ink:#f2f5f8;
  --cell-edge:rgba(255,255,255,.22);
  --paper-lines:transparent;
  --bar:#16304f; --bar-ink:#eaf2fb;
  --raise:#212832;
  --track:#2a323c;
  --callout:#2a1e1e; --callout-warn:#2b2417;
  color-scheme:dark;
}
*{box-sizing:border-box}
/* The UA rule for [hidden] is display:none, but any author rule that sets display
   outranks it — .view.on and .fresh both do. Without this, hiding an element by
   attribute silently fails and the fault panel appears on top of a live report. */
[hidden]{display:none!important}
html,body{margin:0;padding:0}
body{
  background:var(--paper); color:var(--ink); font-family:var(--mono);
  font-size:13px; line-height:1.45;
  background-image:linear-gradient(var(--paper-lines) 1px,transparent 1px);
  background-size:100% 28px; background-position:0 -1px;
}
.wrap{max-width:1280px;margin:0 auto;padding:0 20px 80px}

/* ---------- masthead ---------- */
/* flow-root so the floated stamp is contained. The stamp grew — identity, sign-out,
   freshness stamps and the refresh button — and once it was taller than the title block
   it spilled past the border and collided with the navigation underneath it. */
/* Flex rather than a float: with the per-report title gone the left column is just the
   brand, and the freshness stamp on the right is far taller. Centring the two against each
   other closes the dead space that a float left under the logo. */
header{padding:22px 0 18px;border-bottom:2px solid var(--ink);margin-bottom:0;
  display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap}
.eyebrow{font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}
/* Brand lockup. The wordmark echoes the mark: "Mirror Mirror" in the weight of the M, and
   "on The Wall" set light beneath it, so the pair reads as one object rather than a logo
   with a caption. */
.brand{display:inline-flex;align-items:center;gap:14px;text-decoration:none;color:inherit}
.brand-logo{display:block;width:52px;height:52px;flex:0 0 auto}
.brand-name{display:flex;flex-direction:column;font-family:var(--mono);font-size:22px;
  font-weight:600;letter-spacing:-.01em;line-height:1.05;color:var(--ink)}
.brand-thin{font-size:11.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);margin-top:5px}
.brand:hover .brand-thin{color:var(--pen)}
.gate .brand-logo{width:64px;height:64px}
.gate .brand-name{font-size:26px}
h1{font-family:var(--mono);font-size:26px;font-weight:600;letter-spacing:-.01em;margin:6px 0 4px}
.sub{font-family:var(--sans);color:var(--muted);font-size:13px;max-width:60ch}
.stamp{order:2;text-align:right;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);line-height:1.9}
/* Who is signed in. Kept in the masthead rather than a corner widget, because on a page
   whose contents depend on your grants, "which account am I?" is load-bearing. */
.ident{padding-bottom:5px;margin-bottom:5px;border-bottom:1px solid var(--rule)}
.ident span{text-transform:none;letter-spacing:0;font-size:11px;color:var(--ink)}
.ident .act{margin-left:9px}
/* Theme toggle. A two-state segmented control rather than one icon that flips: the label
   names the mode you are IN, so nobody has to work out whether a moon means "currently
   dark" or "click for dark". */
.theme{display:inline-flex;border:1px solid var(--rule);margin-left:10px;vertical-align:-2px}
.theme button{appearance:none;background:none;border:none;cursor:pointer;padding:2px 7px;
  font-family:var(--mono);font-size:9px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);line-height:1.7}
.theme button[aria-pressed=true]{background:var(--bar);color:var(--bar-ink)}
.theme button:focus-visible{outline:2px solid var(--pen);outline-offset:-2px}

/* ---------- admin tab ---------- */
.grp{background:var(--surface);border:1px solid var(--rule);margin:12px 0;padding:14px 16px}
.grp.reserved{border-left:3px solid var(--pen)}
.grp-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.grp-head h3{margin:0;font-size:15px}
.grp-tag{font-size:9px;letter-spacing:.12em;text-transform:uppercase;border:1px solid var(--pen);
  color:var(--pen);padding:1px 5px}
.grp-meta{margin-left:auto;font-size:10px;color:var(--muted)}
.grp-reports{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}
.mem{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0 4px}
.mem-chip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--rule);
  background:var(--paper);padding:3px 5px 3px 8px;font-size:11px}
.mem-chip.dom{border-style:dashed}
.mem-chip b{font-weight:600}
.mem-chip button{appearance:none;background:none;border:none;cursor:pointer;color:var(--muted);
  font-family:var(--mono);font-size:13px;line-height:1;padding:0 2px}
.mem-chip button:hover{color:var(--fail)}
.mem-chip.root button{visibility:hidden}
.mem-add{position:relative;display:flex;gap:6px;align-items:flex-start;margin-top:8px}
.mem-add textarea{flex:1 1 auto;min-height:30px;font-family:var(--mono);font-size:12px;
  padding:5px 7px;border:1px solid var(--rule);background:var(--surface);color:var(--ink);
  resize:vertical}
/* Suggestions are positioned against the field, not the page, so they follow it when the
   panel scrolls. */
.sugg{position:absolute;z-index:40;top:100%;left:0;right:120px;background:var(--surface);
  border:1px solid var(--ink);max-height:210px;overflow-y:auto;box-shadow:0 6px 18px rgba(0,0,0,.18)}
.sugg button{display:block;width:100%;text-align:left;appearance:none;background:none;
  border:none;border-bottom:1px solid var(--rule);cursor:pointer;padding:6px 9px;
  font-family:var(--mono);font-size:11.5px;color:var(--ink)}
.sugg button:hover,.sugg button.on{background:var(--raise)}
.sugg .sn{color:var(--muted);margin-left:6px}
.sugg-note{padding:6px 9px;font-family:var(--sans);font-size:10.5px;color:var(--muted)}
.stamp b{display:block;font-size:14px;letter-spacing:0;text-transform:none;color:var(--ink)}
.mode{display:inline-block;border:1px solid var(--rule);padding:1px 6px;margin-top:4px}
.mode.live{border-color:var(--ok);color:var(--ok)}
.mode.bad{border-color:var(--fail);color:var(--fail)}
/* Shown only once a newer pull has landed on the server. Reloading is the
   reader's call: re-rendering underneath them would discard their filters. */
.fresh{display:block;margin-top:5px;margin-left:auto;font-family:var(--mono);font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;cursor:pointer;
  background:var(--pen);color:#fff;border:1px solid var(--pen);padding:2px 7px}
.fresh:hover{background:var(--navy)}
/* Refresh state and control. Right-aligned to sit under the stamp without
   disturbing the masthead it hangs off. */
.pull{margin-top:7px;padding-top:6px;border-top:1px solid var(--rule);text-align:right}
.pull-row{display:block;font-size:9px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);line-height:1.7}
.pull-k{margin-right:6px}
.pull-row b{display:inline;font-size:10.5px;letter-spacing:0;text-transform:none;color:var(--ink)}
.pull-row b.overdue{color:var(--warn)}
/* The sheet's default .act is a text-link style — right for "Export CSV" sitting in a
   row of controls, wrong here, where this is the one thing on the masthead a reader is
   meant to press. It gets a filled box so it reads as a button, and a clearly drawn
   disabled state so a running cooldown looks deliberate rather than broken. */
.pull .act{margin-top:5px;padding:4px 9px;letter-spacing:.1em;
  border:1px solid var(--pen);background:var(--pen);color:#fff}
.pull .act:hover:not(:disabled){background:var(--navy);border-color:var(--navy);color:#fff}
.pull .act:disabled{background:var(--paper);border-color:var(--rule);
  color:var(--muted);opacity:1;cursor:not-allowed}
/* The wrapper carries the hover tip. A disabled button fires no mouse events, so the
   tip has to hang off something that is never disabled — and it must still be a hover
   target, hence inline-block rather than a bare span. */
.pull-btn-wrap{display:inline-block;cursor:help}
.pull-msg{display:block;margin-top:4px;font-size:10px;letter-spacing:0;text-transform:none;
  font-family:var(--sans);color:var(--muted);max-width:220px;margin-left:auto}
.pull-msg.err{color:var(--fail)}
.pull-msg.ok{color:var(--ok)}

/* ---------- explanation tooltips ---------- */
/* A real button, not a bare glyph: it takes focus so the explanation is reachable
   from the keyboard, and text-transform/letter-spacing are reset because the KPI
   label above it is uppercased and would otherwise deform the "i". */
.info{display:inline-flex;align-items:center;justify-content:center;
  width:13px;height:13px;margin-left:5px;padding:0;vertical-align:1px;
  border:1px solid var(--rule);border-radius:50%;background:var(--surface);
  color:var(--muted);font-family:var(--mono);font-size:9px;font-weight:600;
  line-height:1;letter-spacing:0;text-transform:none;cursor:help}
.info:hover,.info:focus-visible{border-color:var(--pen);color:var(--pen);
  background:var(--raise);outline:none}
#help{position:fixed;z-index:60;max-width:320px;background:var(--tip-bg);color:var(--tip-ink);
  padding:10px 12px;font-family:var(--sans);font-size:11.5px;line-height:1.55;
  border-radius:2px;opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .1s ease;box-shadow:0 6px 18px rgba(0,0,0,.3)}
/* The honest empty state: no data means no report, not an empty report. */
.fault{border:1px solid var(--fail);border-left:3px solid var(--fail);background:var(--surface);
  padding:18px 20px;margin:24px 0}
.fault h2{margin:0 0 8px;font-size:16px;color:var(--fail)}
.fault p{font-family:var(--sans);margin:8px 0;max-width:70ch}
.fault .detail{font-family:var(--mono);font-size:12px;color:var(--fail)}
.fault pre{background:var(--paper);border:1px solid var(--rule);padding:9px 11px;
  font-size:12px;overflow-x:auto}
.filters{border:1px solid var(--ink);border-top:none;background:var(--paper);padding:11px 14px}
.frow{display:flex;gap:10px;align-items:center;flex-wrap:wrap;padding:4px 0}
.frow+.frow{border-top:1px solid #dfe5ec}
.flabel{flex:0 0 84px;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.fnote{font-family:var(--sans);font-size:12px;color:var(--muted)}
.checks{display:flex;gap:2px;flex-wrap:wrap}
.checks label{display:inline-flex;align-items:center;gap:5px;font-size:11px;letter-spacing:0;
  text-transform:none;color:var(--ink);border:1px solid var(--rule);background:var(--surface);
  padding:4px 8px;cursor:pointer}
.checks label:has(input:checked){border-color:var(--bar);background:var(--bar);color:var(--bar-ink)}
.checks label .sw{display:inline-block;width:9px;height:9px;border-radius:1px}
.checks label:has(input:focus-visible){outline:2px solid var(--pen);outline-offset:1px}
.checks input{accent-color:var(--pen);margin:0}
.checks .n{color:var(--muted);font-variant-numeric:tabular-nums}
.checks label:has(input:checked) .n{color:#9dc0f0}
button.act.tiny{font-size:9.5px}

/* ---------- verdict ---------- */
.verdict{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:0;
  border:1px solid var(--ink);border-top:none;background:var(--surface)}
.kpi{padding:14px 16px;border-right:1px solid var(--rule)}
.kpi:last-child{border-right:none}
.kpi .lbl{font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.kpi .num{font-size:30px;font-weight:600;letter-spacing:-.02em;line-height:1.15;margin-top:5px}
.kpi .den{font-size:12px;color:var(--muted);font-weight:400}
.kpi .note{font-size:10.5px;color:var(--muted);margin-top:3px}
.kpi.caption{background:var(--paper);display:flex;align-items:center}
.kpi.caption span{font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);line-height:1.6}
.kpi.bad .num{color:var(--fail)} .kpi.mid .num{color:var(--warn)} .kpi.good .num{color:var(--ok)}

/* ---------- signature: certification tape ---------- */

.tape-block{background:var(--surface);border:1px solid var(--ink);border-top:none;padding:16px}
.tape-block.bare{border:none;padding:0}
.tape-head{display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:8px;margin-bottom:10px}
.tape-title{font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.tape{display:flex;flex-wrap:wrap;gap:2px}
.cell{width:14px;height:24px;cursor:pointer;position:relative;border-radius:1px;
  box-shadow:inset 0 0 0 1px var(--cell-edge)}
.cell:hover{outline:2px solid var(--ink);outline-offset:1px;z-index:2}
/* Tape fills — a categorical set, validated rather than eyeballed.
   All six defect hues were checked all-pairs (any two cells can end up adjacent in
   the grid, so adjacent-only validation would not be enough) against the white panel
   at OKLab ΔE×100: worst normal-vision pair 16.3, clear of the 15 floor. The previous
   pale set scored 4.0 on its worst pair, which is why nothing was tellable apart.
   Deutan separation is 6.1, inside the band that is only legal with a secondary
   channel — here the legend plus the per-cell hover tooltip, which names every defect
   in words, so colour is never the sole carrier of identity.
   Ordered worst-first, matching DEFECT_ORDER in app.js. */
.c-link{background:#a8322a}        /* no portfolio link — invisible work */
.c-type{background:#eda100}        /* link not carried by a Story */
.c-desc{background:#4a3aa7}        /* no description */
.c-res{background:#2a78d6}         /* resolution field never set */
.c-stale{background:#1baf7a}       /* idle over 30 days */
.c-unassigned{background:#e87ba4}  /* open and active but nobody owns it */
/* Clean is the majority state and deliberately sits outside the categorical set: a
   near-grey that recedes toward the surface, so the eye lands on defects instead of
   having to subtract the good cells first. */
.c-ok{background:#dde3e9}
/* More than one defect: the fill still shows the leading one, and this foot bar says
   there are others. A flat "multiple" colour would hide which defect to act on. */
/* White, not a dark red as before: the leading-defect fill is now a saturated hue, and
   the old bar was almost invisible against the dark red one. A bright bar reads on all
   six fills, and it can never land on the pale clean fill — a second defect implies a
   first, so the fill underneath is always coloured. */
.cell.multi::after{content:"";position:absolute;left:2px;right:2px;bottom:2px;height:4px;
  background:#ffffff;border-radius:1px}
.cell.out.multi::after{left:3px;right:3px;bottom:3px}
.legend i.multi{position:relative}
.legend i.multi::after{content:"";position:absolute;left:1px;right:1px;bottom:1px;height:3px;
  background:#ffffff;border-radius:1px}
/* Outside MT is a property of where the ticket lives, not what is wrong with it, so it
   rides as a ring and leaves the fill free to show the actual defect. Formerly purple,
   which now collides with the violet "no description" fill — a ring must not be
   mistakable for a hue, so it moved off the colour scale entirely.
   A double ring, white outside and ink inside, because a single one cannot win against
   every fill: ink disappears into the dark red "no portfolio link" cells that make up
   most of the MPL/MIN block, and white disappears into both the pale clean fill and the
   white panel behind it. One of the two always contrasts, whatever sits underneath. */
.cell.out{box-shadow:inset 0 0 0 1px #ffffff, inset 0 0 0 2.5px var(--ink)}
.legend i.out{box-shadow:inset 0 0 0 1px #ffffff, inset 0 0 0 2px var(--ink)}
.legend{display:flex;gap:14px;flex-wrap:wrap;font-size:10.5px;color:var(--muted);margin-top:10px}
.legend i{display:inline-block;width:11px;height:11px;margin-right:5px;vertical-align:-1px;border-radius:1px}
#tip{position:fixed;z-index:50;background:var(--tip-bg);color:var(--tip-ink);padding:0;font-size:11px;
  width:320px;pointer-events:none;opacity:0;transition:opacity .08s;line-height:1.45;
  box-shadow:0 6px 20px rgba(19,28,39,.28)}
#tip .th{padding:9px 11px 8px;border-bottom:1px solid rgba(255,255,255,.16)}
#tip .tk{font-weight:600;color:#9dc0f0}
#tip .tsp{float:right;font-size:9px;letter-spacing:.1em;text-transform:uppercase;
  color:#d9c2f0;border:1px solid rgba(217,194,240,.5);padding:0 4px;line-height:1.5}
#tip .ts{display:block;margin-top:3px;color:#fff}
#tip .tm{display:block;margin-top:3px;font-size:10.5px;color:rgba(255,255,255,.6)}
#tip .tp{display:block;margin-top:7px;padding-top:6px;border-top:1px solid rgba(255,255,255,.12)}
#tip .tp b{display:block;color:rgba(255,255,255,.45);font-weight:400;font-size:9px;
  letter-spacing:.16em;text-transform:uppercase;margin-bottom:2px}
#tip .tp .pk{color:#9dc0f0;font-weight:600;font-size:12px;letter-spacing:.03em}
#tip .tp .pt{margin-left:6px;font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(255,255,255,.55);border:1px solid rgba(255,255,255,.25);padding:0 4px}
#tip .tp .ptitle{display:block;color:#fff;font-size:11.5px;margin-top:1px}
#tip .tp .via{display:block;color:rgba(255,255,255,.5);font-size:10px;margin-top:3px}
#tip .tp .nolink{color:#e8a89f;font-weight:600;font-size:11.5px}
#tip .tc{padding:8px 11px 10px}
#tip .tclbl{font-size:9px;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(255,255,255,.5);margin-bottom:5px}
#tip .tcrow{display:flex;gap:7px;align-items:baseline;padding:1.5px 0}
#tip .tcn{flex:0 0 13px;text-align:right;color:rgba(255,255,255,.45);font-size:10px}
#tip .tcf{flex:1 1 auto}
#tip .tcfirst{font-size:9px;letter-spacing:.1em;text-transform:uppercase;color:#e8a89f}
#tip .tcok{color:#a9d2bd}

/* ---------- tabs ---------- */
/* Level 1 — two ways of looking at the same data. Ticket work is filterable and
   drill-down; team and portfolio views are aggregates that must never be filtered. */
/* Reporting groups — the outermost level, above the views. Drawn as a tab strip on the
   paper rather than on the dark bar, so the hierarchy reads group → view → panel from
   lightest to darkest instead of competing with the view tabs for the same emphasis. */
nav.l0{display:flex;gap:2px;border-bottom:2px solid var(--ink)}
nav.l0 button{appearance:none;background:var(--paper);border:1px solid var(--rule);
  border-bottom:none;cursor:pointer;font-family:var(--mono);font-size:11px;font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted);padding:8px 20px 7px;
  margin-bottom:-1px;transition:color .1s,background .1s}
nav.l0 button:hover{color:var(--ink)}
nav.l0 button[aria-selected=true]{background:var(--bar);border-color:var(--bar);color:var(--bar-ink)}
nav.l0 button:focus-visible{outline:2px solid var(--pen);outline-offset:-2px}

nav.l1{position:sticky;top:0;z-index:30;display:flex;background:var(--bar);
  border:1px solid var(--bar);border-top:none}
nav.l1 button{appearance:none;flex:0 0 auto;background:none;border:none;cursor:pointer;
  text-align:left;padding:12px 22px;color:rgba(255,255,255,.55);
  border-right:1px solid rgba(255,255,255,.14);transition:color .1s,background .1s}
nav.l1 button:last-of-type{border-right:none}
nav.l1 button b{display:block;font-family:var(--mono);font-size:13px;font-weight:600;
  letter-spacing:.06em;text-transform:uppercase}
nav.l1 button em{display:block;font-family:var(--sans);font-style:normal;font-size:11px;
  letter-spacing:0;text-transform:none;margin-top:2px;opacity:.85}
nav.l1 button:hover{color:rgba(255,255,255,.85)}
nav.l1 button[aria-selected=true]{background:var(--surface);color:var(--ink)}
nav.l1 button[aria-selected=true] em{color:var(--muted)}
nav.l1 button:focus-visible{outline:2px solid #9dc0f0;outline-offset:-3px}

/* Level 2 — which report inside the chosen view. */
nav.l2{display:flex;align-items:stretch;flex-wrap:wrap;background:var(--paper);
  border:1px solid var(--ink);border-top:none}
nav.l2 button{appearance:none;background:none;border:none;border-bottom:2px solid transparent;
  font-family:var(--mono);font-size:11px;letter-spacing:.11em;text-transform:uppercase;
  padding:11px 15px 9px;cursor:pointer;color:var(--muted);white-space:nowrap;
  transition:color .1s,border-color .1s}
nav.l2 button:hover{color:var(--ink);border-bottom-color:var(--rule)}
nav.l2 button[aria-selected=true]{color:var(--ink);border-bottom-color:var(--ink);font-weight:600}
nav.l2 button:focus-visible{outline:2px solid var(--pen);outline-offset:-3px}

section.view{display:none}
section.view.on{display:block}
@media(max-width:900px){nav.l1{position:static;flex-wrap:wrap}
  nav.l1 button{flex:1 1 100%;border-right:none;border-bottom:1px solid rgba(255,255,255,.14)}}

section.panel{display:none;background:var(--surface);border:1px solid var(--ink);border-top:none;padding:20px}
section.panel.on{display:block}
h2{font-size:12px;letter-spacing:.16em;text-transform:uppercase;margin:0 0 4px;font-weight:600}
h2+.hint{font-family:var(--sans);color:var(--muted);font-size:12.5px;margin:0 0 14px;max-width:78ch}
h3{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);margin:26px 0 8px;font-weight:600}
.rule-hr{border:none;border-top:1px solid var(--rule);margin:24px 0}

/* ---------- tables ---------- */
table{width:100%;border-collapse:collapse;font-size:12px}
th{text-align:left;font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);
  border-bottom:1px solid var(--ink);padding:6px 8px 6px 0;white-space:nowrap}
th.s{cursor:pointer;user-select:none} th.s:hover{color:var(--ink)}
td{padding:5px 8px 5px 0;border-bottom:1px solid #e6ebf0;vertical-align:top}
tbody tr:hover{background:var(--raise)}
.num-col{text-align:right;font-variant-numeric:tabular-nums}
a.jk{color:var(--pen);text-decoration:none;border-bottom:1px solid #b9c9e2}
a.jk:hover{border-bottom-color:var(--pen)}
.tag{display:inline-block;font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;
  padding:1px 5px;border:1px solid var(--rule);margin:0 3px 2px 0;white-space:nowrap}
.tag.f{border-color:var(--fail);color:var(--fail)}
.tag.w{border-color:var(--warn);color:var(--warn)}
.tag.o{border-color:var(--ok);color:var(--ok)}
.bar{display:inline-block;height:8px;background:var(--pen);vertical-align:0}
.bar.f{background:var(--fail)} .bar.o{background:var(--ok)}
.trk{display:block;background:var(--track);height:8px;width:100%;position:relative}
.trk>i{display:block;height:8px;background:var(--ok)}
.trk.low>i{background:var(--fail)} .trk.mid>i{background:var(--warn)}

/* ---------- controls ---------- */
.controls{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:0 0 14px;
  padding:10px;background:var(--paper);border:1px solid var(--rule)}
.controls label{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);display:block;margin-bottom:3px}
select,input[type=search],input[type=date]{font-family:var(--mono);font-size:12px;padding:5px 7px;border:1px solid var(--rule);
  background:var(--surface);color:var(--ink);min-width:130px}
input[type=search]{min-width:200px}
input[type=date]{min-width:140px}
button.act{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  padding:3px 1px;border:none;border-bottom:1px solid var(--rule);background:none;cursor:pointer;
  color:var(--muted);transition:color .1s,border-color .1s}
button.act:hover{color:var(--pen);border-bottom-color:var(--pen)}
button.act:focus-visible{outline:2px solid var(--pen);outline-offset:2px}
.count{font-size:11px;color:var(--muted);margin-left:auto}

/* ---------- charts ---------- */
/* ---------- sign-in and no-access pages ---------- */
.gate{max-width:640px}
.gate header{border-bottom:2px solid var(--ink)}
.gate-card{background:var(--surface);border:1px solid var(--ink);border-top:none;
  padding:24px 26px 26px}
.gate-card h2{margin:0 0 10px;font-size:17px}
.gate-card p{font-family:var(--sans);color:var(--muted);max-width:56ch;margin:9px 0}
.gate-who{font-family:var(--mono)!important;color:var(--ink)!important;font-size:14px;
  background:var(--paper);border:1px solid var(--rule);padding:8px 11px;display:inline-block}
.gate-note{font-size:11.5px}
/* Google asks that its sign-in button stay recognisably its own: white, its wordmark
   colours, not restyled into the surrounding palette. */
.gbtn{display:inline-flex;align-items:center;gap:10px;margin:14px 0 4px;
  background:#fff;border:1px solid #747775;border-radius:4px;padding:10px 18px;
  font-family:var(--sans);font-size:14px;font-weight:500;color:#1f1f1f;text-decoration:none}
.gbtn:hover{background:#f7f8f8;border-color:#5f6368}
.gbtn:focus-visible{outline:2px solid var(--pen);outline-offset:2px}

/* ---------- KPI small multiples ---------- */
/* Six measures in three different units, so each gets its own panel and its own scale.
   One chart with a second y-axis would be the wrong answer twice over. */
/* Wider minimum so each panel is readable: three across on a full-width sheet, and
   fewer per row as it narrows rather than shrinking past legibility. */
.spark-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(330px,1fr));gap:14px}
.spark{margin:0;background:var(--surface);border:1px solid var(--rule);padding:9px 10px 4px}
.spark figcaption{font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);display:flex;align-items:baseline;gap:6px}
.spark figcaption b{margin-left:auto;font-size:15px;letter-spacing:0;text-transform:none;
  color:var(--ink)}
/* Marks the four series that are today's values projected backwards rather than
   recorded history. The page says so at length above; this keeps it visible per panel. */
.spark .est{font-size:8px;letter-spacing:.08em;border:1px solid var(--warn);color:var(--warn);
  padding:0 3px;cursor:help}

svg text{font-family:var(--mono);font-size:9.5px;fill:var(--muted)}
.grid-line{stroke:var(--grid);stroke-width:1}
.axis{stroke:var(--ink);stroke-width:1}

.two{display:grid;grid-template-columns:1fr 1fr;gap:28px}
.callout{border-left:3px solid var(--fail);background:var(--callout);padding:11px 13px;font-family:var(--sans);font-size:12.5px;margin:14px 0}
.callout b{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;display:block;margin-bottom:3px;color:var(--fail)}
.callout.warn{border-left-color:var(--warn);background:var(--callout-warn)}
.callout.warn b{color:var(--warn)}
/* load ladder */
.ladder{margin:4px 0 0}
.rung{display:grid;grid-template-columns:210px 1fr 58px;gap:10px;align-items:center;padding:2px 0}
.rung .nm{font-size:11.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rung .nm em{font-style:normal;color:var(--muted);font-size:10px}
.rung .track{position:relative;height:14px;background:var(--track)}
.rung .track>i{display:block;height:14px;background:var(--pen)}
.rung.hot .track>i{background:var(--fail)}
.rung.cold .track>i{background:#9aa8b6}
.rung .v{font-size:11px;text-align:right;font-variant-numeric:tabular-nums;color:var(--muted)}
.medline{position:relative;height:16px;margin-left:220px;margin-right:68px;border-top:1px dashed var(--ink);margin-top:6px}
.medline span{position:absolute;top:2px;font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
footer{margin-top:20px;font-size:10.5px;color:var(--muted);font-family:var(--sans)}
@media(max-width:860px){.two{grid-template-columns:1fr}
  header{align-items:flex-start}.stamp{order:1;text-align:left;margin-bottom:10px}}
@media(prefers-reduced-motion:reduce){*{transition:none!important}}


/* ---------- drill-down modal ---------- */
/* Opened by clicking a segment of a stacked bar. The point is verification: a reader who
   doubts a number should be able to see the rows behind it and follow them into Jira. */
.modal{position:fixed;inset:0;z-index:80;display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.55);padding:24px}
.modal-box{background:var(--surface);border:1px solid var(--ink);max-width:900px;width:100%;
  max-height:82vh;display:flex;flex-direction:column;box-shadow:0 18px 50px rgba(0,0,0,.4)}
.modal-head{display:flex;align-items:baseline;gap:12px;padding:14px 18px 8px;
  border-bottom:1px solid var(--rule)}
.modal-head h3{margin:0;font-size:15px}
.modal-x{margin-left:auto;appearance:none;background:none;border:none;cursor:pointer;
  color:var(--muted);font-family:var(--mono);font-size:20px;line-height:1;padding:0 4px}
.modal-x:hover{color:var(--fail)}
.modal .hint{padding:8px 18px 0;margin:0}
.modal-body{overflow:auto;padding:10px 18px 18px}
.modal-body table{margin:6px 0 0}
.modal-body td.sum{font-family:var(--sans);white-space:normal;max-width:420px}

/* ---------- sparkline hover ---------- */
.spark svg{display:block;cursor:crosshair}
.spark-guide{stroke:var(--muted);stroke-width:1;stroke-dasharray:2 2}
.spark-hit{fill:transparent}

/* A rung that opens a drill-down says so on hover, rather than leaving the reader to
   discover that some rows are clickable and others are not. */
.rung.clickable{cursor:pointer}
.rung.clickable:hover .nm{color:var(--pen)}
.rung.clickable:hover .track{outline:1px solid var(--pen)}
.modal-body .act.tiny{padding:0;border:none;background:none;color:var(--pen);
  text-transform:none;letter-spacing:0;font-size:12px;text-decoration:underline}

/* Any table row that opens a drill-down. Discoverability matters: without a hover cue the
   reader has no way to know which rows are live. */
tbody tr.clickable{cursor:pointer}
tbody tr.clickable:hover{background:var(--raise);outline:1px solid var(--pen)}

/* ---------- table sort and filter ---------- */
.tbl-tools{display:flex;align-items:center;gap:10px;margin:10px 0 0}
.tbl-filter{flex:0 1 260px;font-family:var(--mono);font-size:11.5px;padding:4px 7px;
  border:1px solid var(--rule);background:var(--surface);color:var(--ink)}
.tbl-filter:focus{outline:none;border-color:var(--pen)}
.tbl-count{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
/* The arrow appears on hover and stays once a column is sorted, so the header does not carry
   six permanent glyphs competing with the labels. */
th.th-sort{cursor:pointer;user-select:none;position:relative}
th.th-sort:hover{color:var(--pen)}
th.th-sort:hover::after{content:" ↕";opacity:.5}
th.th-sort[aria-sort=ascending]::after{content:" ↑";color:var(--pen)}
th.th-sort[aria-sort=descending]::after{content:" ↓";color:var(--pen)}

/* An inline control inside a KPI note. Sized to the note rather than the form controls
   elsewhere, so it reads as part of the sentence it sits in. */
.kpi-pick{margin-left:5px;font-family:var(--mono);font-size:10px;padding:0 2px;
  border:1px solid var(--rule);background:var(--surface);color:var(--ink);cursor:pointer}
.kpi-pick:focus{outline:1px solid var(--pen)}
