
:root{
 --navy-900:#030f24; --navy-700:#0a1c3d; --navy-500:#1e345a;
 --gold:#BEA34D; --gold-soft:#d8c98a; --white:#fff;
 --ink:#e8edf6; --ink-muted:#9fb0cc;
 --hairline:rgba(190,163,77,0.22);
 --surface:#0a1c3d; --surface-2:#102444; --radius:14px;
 --font-body:'Theinhardt',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
 --font-display:'Bodoni',Georgia,serif;
}
*,*::before,*::after{box-sizing:border-box}
body{margin:0;font:14px/1.55 var(--font-body);color:var(--ink);
 background:var(--navy-900);-webkit-font-smoothing:antialiased}
a{color:var(--gold);text-decoration:none} a:hover{color:var(--gold-soft)}
h1,h2,h3{font-family:var(--font-display);font-weight:400;line-height:1.15;margin:0 0 .5rem}
h1{font-size:1.5rem} h2{font-size:1.15rem;margin-top:1.6rem} h3{font-size:1rem}
:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:3px}

header{background:var(--navy-900);border-bottom:1px solid var(--hairline);
 color:var(--ink);padding:.55rem 1rem;display:flex;gap:1.1rem;align-items:center;flex-wrap:wrap}
header a{color:var(--ink-muted)} header a:hover{color:var(--white)}
header .sp{flex:1}
.brand{display:inline-flex;align-items:center;gap:.55rem}
.brand__mark{width:26px;height:auto;display:block}
.brand__word{font-weight:700;font-size:1.1rem;letter-spacing:-.01em;color:var(--white)}
.brand__word b{color:var(--gold);font-weight:700}
/* §1.1/§2.2 — the app name ("console" / "client portal") is a static sub-label
   stacked *under* the wordmark, not an item in the nav row. Sitting in the row
   it read as a broken link: same type as the links beside it, but not clickable.
   The left padding lines it up with the wordmark (26px mark + .55rem gap). */
.brand-block{display:inline-flex;flex-direction:column;gap:.05rem;margin-right:.4rem}
.app-name{color:var(--ink-muted);font-size:.78rem;letter-spacing:.06em;
 padding-left:2.3rem}

/* §1.2 — the portal's account controls (email, change password, log out) collapse
   into one dropdown triggered by the email. Pure CSS + <details>: neither app
   loads any script (R1 — same-origin and dependency-free, since the UIs are
   reached over SSH tunnels), so the native disclosure widget is the mechanism. */
details.account{position:relative}
details.account>summary{list-style:none;cursor:pointer;color:var(--ink-muted);
 padding:.15rem .6rem;border:1px solid var(--hairline);border-radius:999px}
details.account>summary::-webkit-details-marker{display:none}
details.account>summary::after{content:"\25BE";margin-left:.4rem;font-size:.8em}
details.account[open]>summary,details.account>summary:hover{color:var(--white);
 border-color:var(--gold)}
.account__menu{position:absolute;right:0;top:calc(100% + .35rem);z-index:20;
 min-width:12rem;display:flex;flex-direction:column;background:var(--surface);
 border:1px solid var(--hairline);border-radius:8px;padding:.3rem;
 box-shadow:0 8px 24px rgba(0,0,0,.45)}
.account__menu a{padding:.35rem .5rem;border-radius:6px;white-space:nowrap}
.account__menu a:hover{background:var(--surface-2);color:var(--white)}

main{max-width:1040px;margin:1.3rem auto;padding:0 1rem}

table{border-collapse:collapse;width:100%;background:var(--surface);
 margin:.5rem 0;border:1px solid var(--hairline);border-radius:8px;overflow:hidden}
th,td{text-align:left;padding:.45rem .65rem;border-bottom:1px solid var(--hairline);
 vertical-align:top}
th{background:var(--surface-2);font-weight:700;color:var(--ink)}
tr:last-child td{border-bottom:0}
/* One fixed column grid for the portal Controls tab (§1.5): each pillar renders its
   own <table>, so without a shared layout the columns drift between pillar blocks.
   table-layout:fixed + these widths make every pillar's rows line up vertically. */
table.pillar-grid{table-layout:fixed}
table.pillar-grid th:nth-child(1),table.pillar-grid td:nth-child(1){width:16%}
table.pillar-grid th:nth-child(2),table.pillar-grid td:nth-child(2){width:46%}
table.pillar-grid th:nth-child(3),table.pillar-grid td:nth-child(3){width:22%}
table.pillar-grid th:nth-child(4),table.pillar-grid td:nth-child(4){width:16%}
td .tag{overflow-wrap:anywhere}

.pill{display:inline-block;padding:.05rem .55rem;border-radius:999px;
 font-size:.78rem;font-weight:700;letter-spacing:.01em}
.pass{background:rgba(74,222,128,.14);color:#4ade80}
.fail,.critical{background:rgba(248,113,113,.15);color:#f87171}
.exception,.high{background:rgba(251,146,60,.15);color:#fb923c}
.medium{background:rgba(251,191,36,.14);color:#fbbf24}
.low{background:rgba(147,197,253,.13);color:#93c5fd}

.muted{color:var(--ink-muted)}
.tag{font-family:ui-monospace,'SFMono-Regular',Menlo,monospace;font-size:.85rem}
.card{background:var(--surface);padding:1rem;border-radius:var(--radius);
 border:1px solid var(--hairline)}
.notice{background:rgba(25,120,192,.16);color:#bcdcff;
 padding:.6rem .8rem;border-radius:8px;border:1px solid rgba(25,120,192,.3)}
/* Block banners for the client console's resolve report (P7-D2). `.notice` above
   already served that app; these complete the set on the navy surface.
   Contrast measured against the tint-over-navy each one actually composites to,
   not against the raw background: .error/.partial 8.39:1, .complete 10.52:1,
   .warn 9.45:1 — all past AAA, let alone the AA floor.

   `.partial` and `.error` are ONE rule on purpose, and it must stay that way. A
   partial resolution is the failure mode of that console — a document that looks
   finished while some pseudonyms silently did not resolve, which is why D21 makes
   the CLI exit 3 for it. Styling it as a gentler cousin of `.error` (amber, or a
   plain note) would make the quiet failure quieter, which is fail-open dressed as
   polish. `test_client_console_branding.py` asserts the two resolve identically. */
.error,.partial{background:rgba(248,113,113,.15);color:#fca5a5;
 padding:.6rem .8rem;border-radius:8px;border:1px solid rgba(248,113,113,.35)}
.complete{background:rgba(74,222,128,.14);color:#86efac;
 padding:.6rem .8rem;border-radius:8px;border:1px solid rgba(74,222,128,.32)}
/* A WARNING, distinct from `.notice`, which is information (AR-539-001).
   `--gold-soft` on a gold tint with a gold left rule: 9.45:1 against the
   tint-over-navy it composites to, past AAA. No new colour is invented — both
   values are palette tokens.

   Why it exists as its own class rather than by restyling `.notice` gold, which is
   what Programme 7's P7-D2 line literally asked for: `.notice` is used by the
   operator console and the client portal too (`console/templates.py:991`, `:1227`,
   `:1321`, `:1547`, `portal_templates.py:209`, `:652`, `:726`), and P7-D5 rules
   that those two apps change in the wordmark and nothing else. Recolouring a class
   they share would have been exactly the silent visual change that ruling forbids.

   What it is for: the client console's "this copy carries no provenance line inside
   the file" banner. The owner's ruling of 2026-08-12 accepted "stated on the page,
   absent from the file" only on the condition that the statement is not a footnote
   and carries the same visual weight as the resolution verdict. Rendering it in the
   same blue as the page's reassurance paragraph ("everything stays on this machine")
   made the warning the quietest thing in the report — the direction the ruling was
   written to prevent. `.warn` is deliberately NOT `.notice`, and
   `test_webkit_branding.py::test_a_warning_is_not_styled_like_an_information_notice`
   fails if the two are ever merged back together. */
.warn{background:rgba(190,163,77,.14);color:var(--gold-soft);
 padding:.6rem .8rem;border-radius:8px;border:1px solid rgba(190,163,77,.5);
 border-left:4px solid var(--gold)}
/* The unresolved-token list: monospace and breakable, because these are long
   `anon_…` strings with no spaces and they must not force the page to scroll. */
.tokens{font-family:ui-monospace,'SFMono-Regular',Menlo,monospace;
 font-size:.85rem;word-break:break-all}

.deg{background:rgba(248,113,113,.15);color:#f87171;padding:.05rem .45rem;
 border-radius:4px;font-size:.8rem;font-weight:600}
.ok{background:rgba(74,222,128,.14);color:#4ade80;padding:.05rem .45rem;
 border-radius:4px;font-size:.8rem;font-weight:600}

form.inline{display:inline}
label{display:inline-block}
/* §2.1/§2.5 — stacked form fields on one column width. Without this each input
   sat immediately after its label, so the left edges drifted row to row with the
   length of the label text (console sign-in, notification channels). */
form.stack{max-width:24rem}
form.stack label{display:block;margin:0 0 .75rem}
form.stack input,form.stack select,form.stack textarea{display:block;width:100%;
 margin:.2rem 0 0}
form.stack .hint{display:block;color:var(--ink-muted);font-size:.82rem;margin-top:.15rem}
input,select,textarea{font:inherit;padding:.35rem .5rem;margin:.2rem 0;
 background:var(--surface-2);color:var(--ink);
 border:1px solid var(--hairline);border-radius:6px}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--gold)}
button{cursor:pointer;font:inherit;font-weight:700;padding:.4rem .85rem;border-radius:999px;
 border:1.5px solid var(--gold);background:var(--gold);color:var(--navy-900);
 transition:background .15s ease,color .15s ease}
button:hover{background:var(--gold-soft)}
button.ghost{background:transparent;color:var(--ink);border-color:var(--hairline)}
button.ghost:hover{border-color:var(--gold);color:var(--white)}
button.danger{background:#b91c1c;border-color:#b91c1c;color:var(--white)}
button.danger:hover{background:#dc2626}

pre{background:#00081a;color:var(--ink);padding:.8rem;border-radius:8px;
 overflow-x:auto;font-size:.82rem;border:1px solid var(--hairline)}
