
/* == Tokens: dark on :root, light on [data-theme="light"], shared in both == */
:root{--font-ui:"Public Sans Variable", "Public Sans", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--font-mono:"JetBrains Mono Variable", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;--r-ctl:6px;--r-card:6px;--r-pill:999px;--pad:16px;--gutter:32px;--side-w:224px;--content-max:1200px;--ctl:32px;--ctl-sm:28px;--row-h:40px;--ease:cubic-bezier(0.22, 1, 0.36, 1);--motion-fast:120ms;--motion:180ms}
:root{--t-label:11px;--t-small:12px;--t-mono:12px;--t-body:13px;--t-section:15px;--t-title:20px;--t-display:28px}
:root{--bg-0:#0E1013;--bg-1:#131619;--bg-2:#191D22;--bg-3:#1F242A;--line-1:#24292F;--line-2:#303740;--fg-1:#E6EAEE;--fg-2:#9AA4B0;--fg-3:#808C9A;--accent:#2FBF7F;--accent-fg:#062015;--ok:#3AA876;--red:#F0716C;--red-soft:rgba(240,113,108,.12);--red-fg:#1A0A0A;--amber:#E3A83A;--amber-soft:rgba(227,168,58,.12);--blue:#6AA3F8;--blue-soft:rgba(106,163,248,.12);--shadow-float:0 16px 48px rgba(0,0,0,.5);--group:#2A5D7A;color-scheme:dark}
:root[data-theme="light"]{--bg-0:#F6F7F9;--bg-1:#FFFFFF;--bg-2:#F0F2F5;--bg-3:#E7EAEF;--line-1:#E3E7EC;--line-2:#CFD6DE;--fg-1:#14181E;--fg-2:#4C5663;--fg-3:#5F6B78;--accent:#158252;--accent-fg:#FFFFFF;--ok:#2E8A5F;--red:#B93832;--red-soft:#FBEAE9;--red-fg:#FFFFFF;--amber:#8A5A00;--amber-soft:#FBF1DC;--blue:#2A62C9;--blue-soft:#E6EEFC;--shadow-float:0 16px 48px rgba(20,24,30,.16);--group:#2A5D7A;color-scheme:light}
@font-face{font-family:'Public Sans Variable';font-style:normal;font-display:swap;font-weight:400 600;src:url(/assets/fonts/public-sans-latin-wght-normal.woff2) format('woff2-variations');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Public Sans Variable';font-style:normal;font-display:swap;font-weight:400 600;src:url(/assets/fonts/public-sans-latin-ext-wght-normal.woff2) format('woff2-variations');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'JetBrains Mono Variable';font-style:normal;font-display:swap;font-weight:400 600;src:url(/assets/fonts/jetbrains-mono-latin-wght-normal.woff2) format('woff2-variations');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'JetBrains Mono Variable';font-style:normal;font-display:swap;font-weight:400 600;src:url(/assets/fonts/jetbrains-mono-latin-ext-wght-normal.woff2) format('woff2-variations');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

/* == Reset and base ====================================================== */
*{box-sizing:border-box}
html,body{margin:0;background:var(--bg-0);color:var(--fg-1);font:var(--t-body)/1.5 var(--font-ui);-webkit-font-smoothing:antialiased}
body{min-height:100vh;display:flex;flex-direction:column}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit}
b,strong{font-weight:600}
h1,h2,h3,p,ul,ol,dl,figure{margin:0}
img{display:block;max-width:100%}
/* Machine truth: addresses, versions, keys, fingerprints, codes. Always this face. */
.mono{font-family:var(--font-mono);font-size:var(--t-mono)}
.tnum{font-variant-numeric:tabular-nums}
.muted{color:var(--fg-2)}
.faint{color:var(--fg-3)}
.hidden{display:none !important}
.caption{font-size:var(--t-label)}
.mt10{margin-top:8px}
.rowline{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
/* A control and the button that saves it are one thing and never wrap apart. */
form.act.rowline{flex-wrap:nowrap}
/* An icon reference, sized and coloured by its context. */
svg.i{width:1em;height:1em;stroke:currentColor;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;flex:none}
/* Focus: a 2px accent ring, 2px offset, on every element. One of the three places the accent may appear. */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* == Motion: one voice, nothing bounces =================================== */
@keyframes fade-up{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.fade-up{animation:fade-up var(--motion) var(--ease) both}
/* POLISH-2 (ADR-M228): a person who asked their system for less motion gets
   none. Every transition and animation the script can trigger by a class
   change (the drawer, the fade-up) is a rule here, so this one block covers
   them all; the script itself moves nothing except by instant assignment
   (test/a11y.test.ts pins both halves). */
@media (prefers-reduced-motion: reduce){.fade-up{animation-name:none}*,*::before,*::after{animation-duration:0.001ms !important;animation-iteration-count:1 !important;transition-duration:0.001ms !important;scroll-behavior:auto !important}}
/* The skip link: the first thing the keyboard reaches, seen only when it is. */
.skip{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.skip:focus{position:fixed;left:16px;top:16px;width:auto;height:auto;padding:8px 12px;margin:0;overflow:visible;clip:auto;z-index:20;background:var(--bg-2);border:1px solid var(--line-2);border-radius:var(--r-ctl);color:var(--fg-1);font-size:var(--t-body);font-weight:500}

/* == Shell: the sidebar, the header, the content well ==================== */
.shell{display:grid;grid-template-columns:var(--side-w) minmax(0,1fr);min-height:100vh}
.side{background:var(--bg-1);border-right:1px solid var(--line-1);padding:14px 12px;position:sticky;top:0;height:100vh;overflow:auto;display:flex;flex-direction:column}
/* The wordmark: an 18px accent square with a dot in it, then the name. The console wears the same square in fg-1. */
.brand{display:flex;align-items:center;gap:8px;padding:0 8px 16px;color:var(--fg-1);font-weight:600}
.brand .mark{width:18px;height:18px;border-radius:5px;background:var(--accent);position:relative;flex:none}
.brand .mark::after{content:"";position:absolute;left:6px;top:6px;width:6px;height:6px;border-radius:50%;background:var(--accent-fg)}
.brand b,.brand .wordmark{font-size:var(--t-body);font-weight:600}
.brand b span{color:var(--fg-3);font-weight:400}
.side.console-shell .brand .mark{background:var(--fg-1)}
.side.console-shell .brand .mark::after{background:var(--bg-0)}
/* One sidebar section: an 11px caps label, then its links. */
.group{display:flex;flex-direction:column;gap:1px}
.group h4{margin:0;padding:16px 8px 6px;font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3)}
/* One nav link: 30px tall, the words, an optional trailing count. */
.nav{display:flex;flex-direction:column;gap:1px}
.nav a{display:flex;align-items:center;gap:8px;height:30px;padding:0 8px;border-radius:var(--r-ctl);color:var(--fg-2);font-weight:400;font-size:var(--t-body);white-space:nowrap;overflow:hidden}
.nav a:hover{background:var(--bg-2);color:var(--fg-1)}
/* The active item: one background level up and a 2px accent bar. The second of the three places the accent may appear. */
.nav a.here{background:var(--bg-3);color:var(--fg-1);font-weight:500;box-shadow:inset 2px 0 0 var(--accent)}
.nav a svg{display:none}
.nav a .n{margin-left:auto;font-size:var(--t-small);color:var(--fg-3);font-variant-numeric:tabular-nums;flex:none}
/* A count is only coloured where the number is a call to look. */
.nav a .n.hot{color:var(--amber);font-weight:500}
.nav a .n.busy{color:var(--blue);font-weight:500}
/* A small word after an item: the Staff mark on the console door. */
.nav a .tail{margin-left:auto;font-size:var(--t-label);color:var(--fg-3);flex:none}
/* The foot of the sidebar: the door to the console, or the console's version line. */
.side .foot{margin-top:auto;padding-top:12px;border-top:1px solid var(--line-1);font-size:var(--t-small);color:var(--fg-3);line-height:1.5}
.side .foot .nav{margin-bottom:4px}
.side .version{padding:6px 8px 0}
/* The collapse toggle, at the foot of the rail. */
.side-collapse{display:flex;align-items:center;gap:8px;width:100%;margin-top:8px;height:30px;padding:0 8px;border-radius:var(--r-ctl);border:1px solid transparent;background:transparent;color:var(--fg-3);font-size:var(--t-small);cursor:pointer}
.side-collapse:hover{background:var(--bg-2);color:var(--fg-1)}
/* Collapsed: an icon rail. Labels hide; the items keep their height. */
.side.collapsed{width:56px;padding:14px 8px}
.side.collapsed .brand b,.side.collapsed .group h4,.side.collapsed .nav a span.label,.side.collapsed .nav a .n,.side.collapsed .nav a .tail,.side.collapsed .foot .version,.side.collapsed .side-collapse span{display:none}
.side.collapsed .nav a svg{display:block}
.shell:has(.side.collapsed){grid-template-columns:56px minmax(0,1fr)}
.side.collapsed .nav a{justify-content:center}

.main{min-width:0;display:flex;flex-direction:column}
/* The header: 48px, the workspace switcher, search, notifications, account. */
.top{height:48px;display:flex;align-items:center;gap:12px;padding:0 var(--gutter);border-bottom:1px solid var(--line-1);background:var(--bg-0);position:sticky;top:0;z-index:5}
.menu-btn{display:none;width:44px;height:44px;border-radius:var(--r-ctl);border:0;background:transparent;align-items:center;justify-content:center;color:var(--fg-2);cursor:pointer}
/* A visually hidden label: the select already says what it is. */
.ws-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* The legacy header's inner row (Shell.legacy, the one fallback a page takes when it cannot wear the shell). */
.top-in{display:flex;align-items:center;gap:12px;padding:0 24px;height:100%}
.top-in .right{margin-left:auto;display:flex;align-items:center;gap:12px}
/* The brand alone, on a page with no nav (sign-in, consent, an edge page). */
.brand-only{padding:0 24px}
/* The workspace switcher: 30px, one level up, the workspace's own square and its name. */
.ws{display:flex;align-items:center;gap:8px;height:30px;padding:0 10px;border:1px solid var(--line-2);border-radius:var(--r-ctl);background:var(--bg-2);font-weight:500;font-size:var(--t-body);flex:none;min-width:0}
.ws small{display:none}
.ws .initials{width:16px;height:16px;border-radius:4px;background:var(--group);color:#fff;display:inline-grid;place-items:center;font-size:var(--t-label);letter-spacing:-.04em;font-weight:600;flex:none}
.ws svg{stroke:var(--fg-3);width:11px;height:11px}
.ws select{border:0;background:none;color:var(--fg-1);font:inherit;font-weight:500;max-width:180px;padding:0;cursor:pointer}
.ws select:focus-visible{outline:none}
.ws:focus-within{outline:2px solid var(--accent);outline-offset:2px}
.ws-go{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}
/* Search: a plain GET form; Cmd/Ctrl+K focuses it (design/script.ts). */
.jump{flex:1;max-width:360px;height:30px;display:flex;align-items:center;gap:8px;padding:0 10px;border:1px solid var(--line-1);border-radius:var(--r-ctl);background:var(--bg-1);color:var(--fg-3);font-size:var(--t-body);white-space:nowrap;overflow:hidden}
.jump svg{display:none}
.jump input{flex:1;min-width:0;background:none;border:0;color:var(--fg-1);font:inherit;padding:0}
.jump input:focus-visible{outline:none}
.jump:focus-within{outline:2px solid var(--accent);outline-offset:2px}
.jump input::placeholder{color:var(--fg-3)}
.jump kbd{margin-left:auto;font:var(--t-label) var(--font-mono);padding:0 4px;border:1px solid var(--line-2);border-radius:4px;background:transparent;flex:none;line-height:16px}
/* The search icon that stands in for the box on a phone. */
.search-btn{display:none;width:44px;height:44px;border-radius:var(--r-ctl);align-items:center;justify-content:center;color:var(--fg-2)}
.top .right{margin-left:auto;display:flex;align-items:center;gap:16px}
/* Notifications: a 30px ghost square; the count is a 7px amber dot with a ring of the page behind it. */
.bell{position:relative;width:30px;height:30px;border-radius:var(--r-ctl);border:1px solid transparent;background:transparent;display:inline-flex;align-items:center;justify-content:center;color:var(--fg-2);cursor:pointer}
.bell:hover{background:var(--bg-3);color:var(--fg-1)}
.bell .n{position:absolute;top:5px;right:6px;width:7px;height:7px;padding:0;border-radius:50%;background:var(--amber);border:2px solid var(--bg-0);box-sizing:content-box;font-size:0;line-height:0;color:transparent;overflow:hidden}
/* The account: a 28px circle of initials, one level up. */
.avatar{width:28px;height:28px;border-radius:50%;background:var(--bg-3);display:grid;place-items:center;font-size:var(--t-label);font-weight:600;color:var(--fg-1)}
/* The account menu, a details disclosure. It floats, so it is one of the two things that may carry the shadow. */
.account{position:relative}
.account > summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:8px;border-radius:50%}
.account > summary::-webkit-details-marker{display:none}
.account .menu{position:absolute;right:0;top:calc(100% + 8px);min-width:240px;background:var(--bg-2);border:1px solid var(--line-2);border-radius:var(--r-card);box-shadow:var(--shadow-float);padding:6px;z-index:8}
.account .menu .who{padding:8px 8px 10px;border-bottom:1px solid var(--line-1);margin-bottom:4px;font-size:var(--t-mono);color:var(--fg-2)}
.account .menu a,.account .menu button{display:flex;width:100%;align-items:center;gap:8px;height:30px;padding:0 8px;border-radius:var(--r-ctl);border:0;background:none;text-align:left;color:var(--fg-1);font:inherit;font-size:var(--t-body);cursor:pointer}
.account .menu a:hover,.account .menu button:hover{background:var(--bg-3)}
.account .menu svg{display:none}
/* The lines under the actions: the plan, the version, the clock. Version and status live here, not in a footer. */
.account .menu .plan,.account .menu .about{padding:8px 8px 4px;border-top:1px solid var(--line-1);margin-top:4px;font-size:var(--t-small);color:var(--fg-3);line-height:1.5}
.account .menu .plan + .about{border-top:0;margin-top:0;padding-top:0}
/* The staff mark in the console header. */
.staff{height:22px;padding:0 8px;border-radius:4px;background:var(--bg-3);border:1px solid var(--line-2);display:inline-flex;align-items:center;font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-2);flex:none}
/* The content well. main.page below carries the padding and the measure. */
.content{flex:1;display:flex;flex-direction:column;min-width:0}

/* == Page head: breadcrumb, title, sub, actions =========================== */
.crumb{font-size:var(--t-small);color:var(--fg-3);margin-bottom:6px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.crumb a{color:var(--fg-3)}
.crumb a:hover{color:var(--fg-1)}
.crumb b{color:var(--fg-3);font-weight:400}
.head{display:flex;align-items:flex-end;gap:16px;margin-bottom:24px;flex-wrap:wrap}
.head > div:first-child{flex:1 1 360px;min-width:0}
.head h1{margin:0;font-size:var(--t-title);line-height:1.3;font-weight:600;overflow-wrap:anywhere}
.head .sub{color:var(--fg-2);margin-top:2px;font-size:var(--t-small)}
.head .acts{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}

/* == Buttons: one primary per view; every other class stands alone ======= */
.btn,.btn-primary,.btn-outline,.btn-ghost,.btn-danger{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:var(--ctl);padding:0 12px;border-radius:var(--r-ctl);border:1px solid var(--line-2);background:var(--bg-2);color:var(--fg-1);font-weight:500;font-size:var(--t-body);cursor:pointer;white-space:nowrap;text-decoration:none;-webkit-appearance:none;appearance:none;transition:background var(--motion-fast) var(--ease)}
.btn:hover,.btn-outline:hover{background:var(--bg-3)}
/* The one accent on a view. The third of the three places the accent may appear. */
.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--accent-fg)}
.btn-primary:hover{filter:brightness(1.05)}
/* Ghost: navigation-like actions inside tables and headers. */
.btn-ghost{background:transparent;border-color:transparent;color:var(--fg-2)}
.btn-ghost:hover{background:var(--bg-3);color:var(--fg-1)}
/* Danger is outlined until it sits inside a confirm dialog. */
.btn-danger{color:var(--red);border-color:color-mix(in srgb,var(--red) 40%,transparent);background:transparent}
.btn-danger:hover{background:var(--red-soft)}
dialog .btn-danger,.dialog .btn-danger,.confirm-card .btn-danger{background:var(--red);border-color:var(--red);color:var(--red-fg)}
.btn-sm{height:var(--ctl-sm);padding:0 10px;font-size:var(--t-small)}
.btn-icon{width:var(--ctl);padding:0;justify-content:center}
.btn-sm.btn-icon{width:var(--ctl-sm)}
/* A disabled control is a 1px line-1 border and fg-3 words. Its reason is text to its right, never a tooltip alone (.with-reason). */
.btn[disabled],.btn-primary[disabled],.btn-outline[disabled],.btn-ghost[disabled],.btn-danger[disabled]{background:transparent;border-color:var(--line-1);color:var(--fg-3);cursor:not-allowed;filter:none}
.with-reason{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}
.reason{font-size:var(--t-small);color:var(--fg-3)}
/* A button that runs a tool: lays out inline, never a block form's margin. */
form.act{display:inline-flex;margin:0}
/* A plain text-styled action, never a button pretending to be a sentence. */
.linkish{background:none;border:0;padding:0;color:var(--fg-1);cursor:pointer;font-weight:500;text-decoration:underline;text-decoration-color:var(--line-2);text-underline-offset:3px;font:inherit}
.linkish:hover{text-decoration-color:var(--fg-1)}

/* == Cards and grids: one panel level up, a 1px line, 16px padding ======= */
.card{background:var(--bg-1);border:1px solid var(--line-1);border-radius:var(--r-card)}
.card-head{display:flex;align-items:center;gap:8px;padding:14px var(--pad);border-bottom:1px solid var(--line-1);flex-wrap:wrap}
.card-head h2{margin:0;font-size:var(--t-section);font-weight:600}
.card-head .more{margin-left:auto;font-size:var(--t-small);color:var(--fg-2);font-weight:400}
.card-head .more:hover{color:var(--fg-1)}
.card-head .count{margin-left:auto;color:var(--fg-3);font-size:var(--t-body);font-weight:400;font-variant-numeric:tabular-nums}
.card-body{padding:var(--pad)}
.card-body.tight{padding-top:8px}
/* A quieter block inside a card: an aside, a manifest's frame. One level up again. */
.inset{background:var(--bg-2);border:1px solid var(--line-1);border-radius:var(--r-ctl);padding:12px 14px;margin-bottom:16px}
.inset > * + *{margin-top:8px}
.inset:last-child{margin-bottom:0}
.grid{display:grid;gap:24px}
/* The figures strip: one panel divided by lines, never four floating tiles. */
.g-kpi{grid-template-columns:repeat(4,minmax(0,1fr));gap:0;background:var(--bg-1);border:1px solid var(--line-1);border-radius:var(--r-card);overflow:hidden}
.g-kpi > .kpi{border:0;border-right:1px solid var(--line-1);border-radius:0}
.g-kpi > .kpi:last-child{border-right:0}
.g-main{grid-template-columns:minmax(0,1fr) 340px;margin-top:24px;align-items:start}
.col{display:grid;gap:24px;align-content:start}
.stack{display:flex;flex-direction:column;gap:24px}
/* A section heading between cards: the 11px caps label. */
h2.section,h3.section{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);margin:28px 0 8px}

/* == The figure tile: one number, one phrase, one line under ============= */
.kpi{padding:16px 20px}
.kpi .l{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3)}
.kpi .v{font-size:var(--t-display);font-weight:600;letter-spacing:-.01em;line-height:1.2;margin-top:6px}
.kpi .v small{font-size:var(--t-body);font-weight:400;color:var(--fg-2);letter-spacing:0}
.kpi .d{font-size:var(--t-small);color:var(--fg-2);margin-top:4px}
.kpi .d b{color:var(--amber);font-weight:500}

/* == Start here: the onboarding steps, until all are done ================ */
.start{display:grid;grid-template-columns:auto 1fr 1fr 1fr auto;gap:16px;align-items:center;padding:16px 20px;margin-bottom:24px}
.start .t{font-size:var(--t-section);font-weight:600}
.start .t small{display:block;font-size:var(--t-small);color:var(--fg-2);font-weight:400}
.start .step{display:flex;gap:12px;align-items:center}
.start .step .c{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;font-size:var(--t-body);font-weight:600;border:1px solid var(--line-2);color:var(--fg-2);flex:none}
.start .step.done .c{background:var(--bg-3);border-color:var(--bg-3);color:var(--fg-2)}
.start .step.now .c{background:var(--accent);border-color:var(--accent);color:var(--accent-fg)}
.start .step .s{font-weight:500}
.start .step .s small{display:block;color:var(--fg-2);font-weight:400;font-size:var(--t-small)}
.start .step.done .s{color:var(--fg-2)}

/* == Rows: one anatomy, a dot, an identity, facts, actions =============== */
.rows{list-style:none;margin:0;padding:0}
.row{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:12px;align-items:center;padding:10px 0;border-top:1px solid var(--line-1)}
.row:first-child{border-top:0}
.row.simple{grid-template-columns:minmax(0,1fr) auto}
.row.bare{border:0;padding:0}
.row .name{font-weight:500;font-size:var(--t-body);overflow-wrap:anywhere}
.row .name .fav{display:inline-grid;place-items:center;width:18px;height:18px;border-radius:4px;background:var(--bg-3);font-size:var(--t-label);color:var(--fg-3);margin-right:6px;vertical-align:-3px}
.row .why{font-size:var(--t-small);color:var(--fg-2);margin-top:2px;line-height:1.5}
.row .acts{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.row-detail{padding:0 0 12px 32px;border-top:0}

/* == Status: a 6px dot and a word. Colour is severity; green is the dot only == */
.light{width:6px;height:6px;border-radius:50%;justify-self:center;flex:none;display:inline-block;position:relative;box-sizing:border-box}
.light-ok,.light.ok{background:var(--ok)}
.light-busy,.light.busy{background:var(--blue)}
.light-warn,.light.warn{background:var(--amber)}
.light-error,.light.error{background:var(--red)}
.light-stopped,.light.stopped{border:1.5px solid var(--fg-3);background:transparent}
/* A pill: 22px, 999 radius, 12/500, the dot and the word. Fine is quiet; only what needs a person is coloured. */
.pill,.pill-ok,.pill-busy,.pill-warn,.pill-error,.pill-stopped{display:inline-flex;align-items:center;gap:6px;height:22px;padding:0 8px;border-radius:var(--r-pill);font-size:var(--t-small);font-weight:500;white-space:nowrap;border:1px solid transparent;color:var(--fg-2);background:none}
.pill-busy,.pill.busy{background:var(--blue-soft);color:var(--blue)}
.pill-warn,.pill.warn{background:var(--amber-soft);color:var(--amber)}
.pill-error,.pill.error{background:var(--red-soft);color:var(--red)}
.pill-stopped,.pill.stopped{border-color:var(--line-2);color:var(--fg-2)}
/* Machine truth in a chip: a version, a hash, a kind. Quiet mono, no hue. */
.tag{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:4px;background:var(--bg-2);border:1px solid var(--line-1);font:var(--t-mono) var(--font-mono);color:var(--fg-2);white-space:nowrap}
/* A machine code. Shown only on the Debug log (harbor.ts::refusal draws it nowhere else). */
.code{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:4px;background:var(--bg-2);border:1px solid var(--line-2);font:var(--t-mono) var(--font-mono);color:var(--fg-1);white-space:nowrap;letter-spacing:.02em}
/* An update count: counted, never coloured. Text, not a pill. */
.upd{color:var(--fg-1);font-variant-numeric:tabular-nums;font-weight:500}
/* A count chip: a role, a fact, the number beside it. */
.chips{display:flex;flex-wrap:wrap;gap:6px}
.swatch{display:inline-block;width:14px;height:14px;border-radius:4px;border:1px solid var(--line-2);vertical-align:-2px;margin-right:6px}
.chip{display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 10px;border-radius:var(--r-pill);background:transparent;border:1px solid var(--line-2);font-size:var(--t-small);font-weight:500;color:var(--fg-2)}
.chip b{font-family:var(--font-mono);font-weight:500;color:var(--fg-1);font-variant-numeric:tabular-nums}
.chip.on{background:var(--bg-3);border-color:var(--bg-3);color:var(--fg-1)}

/* == Tables: 40px rows, 11px caps headers, the table scrolls inside its card == */
/* The box is POSITIONED so that an absolutely placed descendant (the hidden
   "Actions" heading, .sr) is clipped by it: an absolute element escapes an
   unpositioned scroll box, and eight pages scrolled sideways at 375 by the
   width of their own table before a picture said so (POLISH-2). */
.scroll-x{overflow-x:auto;position:relative}
table{width:100%;border-collapse:collapse;font-size:var(--t-body)}
/* Headings are one or two words and never wrap. Widths are fixed where a column has a kind. */
th{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);text-align:left;padding:10px var(--pad);border-bottom:1px solid var(--line-1);white-space:nowrap}
td{padding:8px var(--pad);border-bottom:1px solid var(--line-1);vertical-align:middle;height:var(--row-h)}
tr:last-child td{border-bottom:0}
td.r,th.r{text-align:right;font-variant-numeric:tabular-nums}
tbody tr:hover td{background:var(--bg-2)}
/* The dense variant: tighter cells, the machine face for machine values. */
table.grid2{font-size:var(--t-body)}
table.grid2 th{padding:8px 12px 8px 0}
table.grid2 td{padding:8px 12px 8px 0}
table.grid2 th:last-child,table.grid2 td:last-child{padding-right:0}
table.grid2 td.m{font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-2);white-space:nowrap;font-variant-numeric:tabular-nums}
table.grid2 td.m.ink{color:var(--fg-1)}
table.grid2 tr.off td{color:var(--fg-3)}
table.grid2 td.acts-col,table.grid2 th.acts-col{white-space:nowrap;text-align:right;width:1%}
/* A row's actions: one line, never wrapped; the table scrolls inside its card instead. */
.cell-acts{display:inline-flex;gap:4px;align-items:center;justify-content:flex-end;flex-wrap:nowrap}
/* An empty value in a cell is a dash in fg-3, never the word none. */
td .dash,.dash{color:var(--fg-3)}
/* The fact list: label left in fg-3, value right; the machine face where the value is machine-shaped. */
dl.facts{display:grid;grid-template-columns:minmax(140px,max-content) minmax(0,1fr);gap:0 16px;margin:0}
dl.facts > dt{color:var(--fg-3);font-size:var(--t-body);padding:9px 0;border-top:1px solid var(--line-1);display:flex;align-items:flex-start}
dl.facts > dd{margin:0;padding:9px 0;border-top:1px solid var(--line-1);font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-1);min-width:0;overflow-wrap:anywhere;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
dl.facts > :nth-child(1),dl.facts > :nth-child(2){border-top:0}
dl.facts > dd .sub,dl.facts > dd .unsaid,dl.facts > dd p{font-family:var(--font-ui);width:100%}
/* A meter inside a fact list takes the whole row. */
dl.facts > dd .tr{flex:1 1 100%}
dl.facts > dd .btn,dl.facts > dd .btn-primary,dl.facts > dd .btn-outline,dl.facts > dd .btn-ghost,dl.facts > dd .btn-danger,dl.facts > dd .input,dl.facts > dd .select{font-family:var(--font-ui);font-size:var(--t-body)}
/* A list under a fact list: always a block below, never a row inside it. */
.sublist{margin-top:16px;border-top:1px solid var(--line-1);padding-top:12px}
.sublist > .cap{color:var(--fg-3);font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;margin-bottom:4px}
/* A numbered manifest of what a confirm is about to do, in order. */
ol.manifest{list-style:none;counter-reset:m;padding:0;margin:0;font-size:var(--t-body);color:var(--fg-2);line-height:1.5}
ol.manifest li{display:flex;gap:12px;padding:6px 0;border-top:1px solid var(--line-1)}
ol.manifest li:first-child{border-top:0}
ol.manifest li::before{counter-increment:m;content:counter(m,decimal-leading-zero);font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-3);flex:none}
ol.manifest li.done{color:var(--fg-3)}
ol.manifest li > span{min-width:0}

/* == Bars and meter: a proportion, in neutral, with the words beside it ==== */
.bars{display:grid;gap:10px}
.bar{display:grid;grid-template-columns:140px 1fr 56px;align-items:center;gap:12px;font-size:var(--t-small)}
.tr{display:block;height:var(--track,4px);border-radius:2px;background:var(--line-1);overflow:hidden}
.tr i{display:block;height:100%;background:var(--fg-2);border-radius:2px}
.tr i.warn{background:var(--amber)}
.bar .n{text-align:right;color:var(--fg-2);font-variant-numeric:tabular-nums}
.meter{display:grid;gap:12px}
.meter .m{display:grid;grid-template-columns:1fr auto;gap:6px;font-size:var(--t-small);color:var(--fg-2)}
.meter .m .tnum{color:var(--fg-1)}
.meter .tr{grid-column:1/-1}

/* == Fields: label above, help below, error replaces help and turns the border red == */
.field{display:grid;gap:6px;margin-bottom:16px}
.label{font-size:var(--t-small);font-weight:500;color:var(--fg-2)}
.input,.select,.textarea{border:1px solid var(--line-2);border-radius:var(--r-ctl);background:var(--bg-2);color:var(--fg-1);font:inherit;font-size:var(--t-body);width:100%}
.input,.select{height:var(--ctl-h,32px);padding:var(--ctl-pad,0 10px)}
.textarea{padding:8px 10px;min-height:80px;resize:vertical}
.input:focus-visible,.select:focus-visible,.textarea:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.input.mono{font-family:var(--font-mono);font-size:var(--t-mono)}
.hint{font-size:var(--t-small);color:var(--fg-3);line-height:1.5}
.err{font-size:var(--t-small);color:var(--red);display:flex;gap:6px;align-items:flex-start;margin-top:6px;line-height:1.5}
.input.is-error,.select.is-error,.textarea.is-error{border-color:var(--red)}
.actions{display:flex;align-items:center;gap:8px;margin-top:4px;flex-wrap:wrap}
.check{display:flex;align-items:center;gap:8px;font-weight:400}
.check input{width:16px;height:16px;accent-color:var(--accent);margin:0}
.switch{position:relative;width:28px;height:16px;border-radius:var(--r-pill);background:var(--bg-3);border:1px solid var(--line-2);display:inline-block;vertical-align:middle;flex:none}
.switch::after{content:"";position:absolute;top:1px;left:1px;width:12px;height:12px;border-radius:50%;background:var(--fg-2)}
.switch.on{background:var(--accent);border-color:var(--accent)}
.switch.on::after{left:13px;background:var(--accent-fg)}
/* The site picker on the New job form. */
.pickall{display:inline-flex;align-items:center;gap:6px;font-size:var(--t-small);color:var(--fg-2);cursor:pointer}
.picks{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:6px}
.pickbox{display:flex;align-items:flex-start;gap:8px;padding:8px 10px;border:1px solid var(--line-1);border-radius:var(--r-ctl);cursor:pointer;min-width:0}
.pickbox:hover{border-color:var(--line-2)}
.pickbox input{margin:1px 0 0;flex:0 0 auto;accent-color:var(--accent)}
/* A site the queue is busy on: the box is disabled and the reason is words beside it, not a faded card. */
.pickbox.busy{cursor:not-allowed;color:var(--fg-3)}

/* == The filter row: fields that wrap, then their two buttons ============ */
.filter-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;align-items:end}
.filter-grid > .field{margin:0}
.filter-grid .actions{margin:0}
/* SITE-CONTROLS-1: the fifteen settings as a grid of fields that top-align. */
.ctl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px 16px;align-items:start}
.ctl-grid > .field{margin:0}
.filters .card-body{padding-bottom:16px}

/* == The settings sub-nav: the sidebar's own item, stood beside the sections == */
.side-tabs{flex-direction:column;border-bottom:0;gap:1px;overflow:visible;margin:0}
.side-tabs a{height:30px;padding:0 10px;border-bottom:0;margin-bottom:0;border-radius:var(--r-ctl);display:flex;align-items:center}
.side-tabs a.here{border-color:transparent;background:var(--bg-3);box-shadow:inset 2px 0 0 var(--accent)}
.side-tabs a.danger{color:var(--red)}
/* A section heading that opens a page needs no gap above it. */
h2.section.first,h3.section.first{margin-top:0}
/* The price cards: one row, each its own card. */
.plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:12px;margin-top:12px}
.plan .price{font-size:var(--t-display);font-weight:600;letter-spacing:-.01em;margin:8px 0}
.price-line{display:block}
.plan-list{list-style:none;margin:8px 0 0;padding:0;color:var(--fg-2);font-size:var(--t-body);display:grid;gap:4px}
.plan-list li{position:relative;padding-left:14px}
.plan-list li::before{content:"";position:absolute;left:0;top:.62em;width:4px;height:4px;border-radius:999px;background:var(--fg-3)}
.plan .price small{font-size:var(--t-small);color:var(--fg-2);font-weight:400}
.plan.here{border-color:var(--line-2);background:var(--bg-2)}
/* An input whose meaning ends in a fixed suffix (a short name, then .redock.xyz). */
.suffixed{display:flex;align-items:center;gap:8px}
.suffixed small{color:var(--fg-3);font:var(--t-mono) var(--font-mono);white-space:nowrap}
/* A secret shown once: select-all, and it wraps rather than scrolling away. */
.console.selectable{margin-top:8px;user-select:all;-webkit-user-select:all;word-break:break-all}
/* One policy switch: the box, the sentence, and the sentence under it. */
.rule{display:flex;align-items:flex-start;gap:8px;font-weight:400}
.rule input{width:16px;height:16px;accent-color:var(--accent);margin:2px 0 0;flex:none}
.rule .blurb{display:block;margin-top:2px;color:var(--fg-3);font-weight:400;font-size:var(--t-small);line-height:1.5}
/* A row or a line that needs its own padding inside a padding-less card. */
.pad12{padding:10px var(--pad)}

/* == A list with no bullet: a report's sub-lines under a row ============== */
.bare-list{list-style:none;margin:6px 0 0;padding:0}
.tight-li{padding:3px 0}
/* One reason, with its dot beside it. */
.reason-li{display:flex;gap:10px;align-items:flex-start;padding:6px 0}
.reason-li > .light{margin-top:7px;flex:none}
.mb12{margin-bottom:12px}

/* == Notices, the empty state, the toast ================================= */
/* A notice is the same card as everything else, inline where the fact belongs, with a 2px left rule in the severity colour. Not a toast. */
.notice{display:flex;gap:10px;align-items:flex-start;padding:12px 14px;border-radius:var(--r-card);border:1px solid var(--line-1);background:var(--bg-1);font-size:var(--t-body);line-height:1.5;margin-bottom:12px}
.notice:last-child{margin-bottom:16px}
.notice > .light{margin-top:7px}
.notice.ok,.notice-ok{border-left:2px solid var(--line-2)}
.notice.warn,.notice-warn{border-left:2px solid var(--amber)}
.notice.error,.notice-error{border-left:2px solid var(--red)}
.notice b{font-weight:600}
.notice p{margin:0}
.notice p + p{margin-top:6px}
/* An empty state: a sentence, one primary and at most one secondary, in the space the content would fill. */
.empty{padding:40px 24px;text-align:center;border:1px dashed var(--line-2);border-radius:var(--r-card);background:var(--bg-1);color:var(--fg-2)}
.empty > b,.empty > h1{display:block;color:var(--fg-1);font-size:var(--t-section);font-weight:600;margin-bottom:6px}
.empty .actions{justify-content:center;margin-top:16px}
/* The toast region: one line after a POST, fed by ?toast= (design/script.ts). It floats, so it carries the shadow. */
#toast-region{position:fixed;left:50%;bottom:20px;transform:translateX(-50%);z-index:9;display:flex;flex-direction:column;gap:8px;align-items:center}
.toast{display:inline-flex;align-items:center;gap:8px;height:var(--ctl);padding:0 14px;border-radius:var(--r-ctl);background:var(--bg-2);border:1px solid var(--line-2);color:var(--fg-1);font-weight:500;font-size:var(--t-body);box-shadow:var(--shadow-float)}
.toast i{width:6px;height:6px;border-radius:50%;background:var(--fg-2);flex:none}
.toast a{text-decoration:underline}

/* == Settings: a left sub-nav beside the sections ========================= */
.settings-layout{display:grid;grid-template-columns:200px minmax(0,1fr);gap:40px;align-items:start}
@media (max-width:820px){
  .settings-layout{display:block}
  .settings-layout .tabs{flex-direction:row;flex-wrap:wrap;overflow-x:visible;gap:2px 4px;margin-bottom:16px;border-bottom:1px solid var(--line-1)}
  .settings-layout .side-tabs a{box-shadow:none;border-radius:var(--r-ctl) var(--r-ctl) 0 0}
  .settings-layout .side-tabs a.here{background:transparent;box-shadow:inset 0 -2px 0 var(--accent)}
}

/* == The site page's head: identity left, state and verbs right =========== */
.site-head{display:flex;align-items:flex-start;gap:24px;flex-wrap:wrap;margin-bottom:20px}
.site-head .acts{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.site-head h1{margin:0;font-size:var(--t-title);font-weight:600;line-height:1.3;overflow-wrap:anywhere}
/* A site with no name yet: the address stands in, in the machine face. */
.site-head h1.host{font-family:var(--font-mono);font-size:var(--t-section);font-weight:500}

/* == Tabs: 13/500, a 2px accent underline on the active one ============== */
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--line-1);margin:0 0 12px;overflow-x:auto;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tabs a{padding:10px 12px;font-weight:500;color:var(--fg-2);border-bottom:2px solid transparent;margin-bottom:-1px;font-size:var(--t-body);white-space:nowrap;flex:none}
.tabs a:hover{color:var(--fg-1)}
.tabs a.here{color:var(--fg-1);border-color:var(--accent)}
.tabs a .n{color:var(--fg-3);font-weight:400;margin-left:4px;font-variant-numeric:tabular-nums}
/* A 6px red dot on a tab that holds something red. */
.tabs a .dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--red);vertical-align:middle;margin-left:4px}
/* The strip's frame: on a narrow screen a fade at the right edge says it scrolls. */
.tabs-wrap{position:relative}
.tabs-wrap::after{content:"";position:absolute;right:0;top:0;bottom:13px;width:32px;background:linear-gradient(90deg,transparent,var(--bg-0));pointer-events:none;opacity:0}
/* The secondary strip under a grouped tab: the sections of Manage, the three logs. */
.subtabs{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 12px}
.subtabs a{display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 10px;border-radius:var(--r-pill);border:1px solid var(--line-2);color:var(--fg-2);font-size:var(--t-small);font-weight:500;white-space:nowrap}
.subtabs a:hover{color:var(--fg-1)}
.subtabs a.here{background:var(--bg-3);border-color:var(--bg-3);color:var(--fg-1)}
.subtabs a .n{color:var(--fg-3);font-weight:400;font-variant-numeric:tabular-nums}
/* SITEREAD-1: how old what you are reading is, and the button that makes it new. Plain words under the strip, no fill. */
.tabs + .asof,.tabs-wrap + .asof,.subtabs + .asof{margin-top:-4px}
.asof{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 16px;padding:0;font-size:var(--t-small);color:var(--fg-3)}
.asof-words{color:var(--fg-3);font-size:var(--t-small);line-height:1.5;min-width:0}
.asof .act{margin-left:auto}
@media (max-width:560px){.asof .act{margin-left:0}}


/* == Dialog: a native dialog, or the same look on a plain page. It floats == */
dialog,.dialog{max-width:480px;padding:0;border:1px solid var(--line-2);border-radius:var(--r-card);background:var(--bg-2);color:var(--fg-1);box-shadow:var(--shadow-float)}
dialog::backdrop{background:rgba(0,0,0,.5)}
.dialog-pad{padding:20px}
.dialog h2,dialog h2{margin:0 0 6px;font-size:var(--t-section);font-weight:600}
.dialog .acts,dialog .acts{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}
.confirm-card{max-width:600px;padding:20px}
.confirm-card h2{font-size:var(--t-title);font-weight:600}
.lead{margin:var(--lead-gap,8px) 0 0;color:var(--fg-2);font-size:var(--t-body);line-height:1.5;max-width:64ch}
.confirm-card{--lead-gap:6px}
.confirm-card .lead{font-size:var(--t-body)}
.confirm-acts{margin-top:20px;display:flex;gap:8px}
/* A caution inside a confirm: an amber left rule, one level up. */
.act-caution{margin:12px 0 0;padding:10px 12px;border-radius:var(--r-ctl);border:1px solid var(--line-1);border-left:2px solid var(--amber);background:var(--bg-1);font-size:var(--t-small);line-height:1.5;color:var(--fg-1)}
.act-why,.act-note{margin-top:12px;max-width:64ch;color:var(--fg-3)}
pre.act-report{margin:8px 0 0;padding:10px 12px;border-radius:var(--r-ctl);border:1px solid var(--line-1);background:var(--bg-2);font-family:var(--font-mono);font-size:var(--t-mono);line-height:1.6;color:var(--fg-2);white-space:pre-wrap;overflow-x:auto;max-height:220px}

/* == Skeleton: the loading state; never a spinner alone =================== */
@keyframes shimmer{0%{background-position:-120px 0}100%{background-position:120px 0}}
.skel{border-radius:4px;background:linear-gradient(90deg,var(--bg-2) 25%,var(--bg-3) 37%,var(--bg-2) 63%);background-size:200px 100%;animation:shimmer 1.4s linear infinite}
.skel-row{height:14px;margin:8px 0}
.skel-line{display:block;height:12px;margin:6px 0}
@media (prefers-reduced-motion: reduce){.skel{animation:none}}

/* == kbd and code blocks: machine truth, always mono ====================== */
kbd{font:var(--t-label) var(--font-mono);padding:0 4px;border:1px solid var(--line-2);border-radius:4px;background:transparent;line-height:16px}
/* A short secret shown once: a pairing code, a token. Select-all in one click, spaced so it can be read aloud. */
.code-chip{display:inline-block;font-family:var(--font-mono);font-size:var(--t-section);letter-spacing:2px;padding:4px 10px;border:1px solid var(--line-2);border-radius:var(--r-ctl);background:var(--bg-2);user-select:all;-webkit-user-select:all}
.console{background:var(--bg-2);border:1px solid var(--line-1);border-radius:var(--r-ctl);padding:10px 12px;font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-2);line-height:1.6;overflow-x:auto}
.console .k{color:var(--fg-3)}
/* DEBUG-1: a log view is bounded; a 64 KB log is not nineteen thousand pixels tall. */
.log-view{max-height:60vh;overflow:auto;overscroll-behavior:contain}

/* == Hero and steps: the first run, the sign-in card's siblings =========== */
.hero h1{font-size:var(--t-display);font-weight:600;letter-spacing:-.01em;line-height:1.2}
/* The three steps as one panel of numbered rows, one under the other. */
.steps{display:grid;grid-template-columns:minmax(0,1fr);gap:0;margin-top:24px;list-style:none;padding:0;border:1px solid var(--line-1);border-radius:var(--r-card);background:var(--bg-1);overflow:hidden}
.steps > *{border:0;border-top:1px solid var(--line-1);border-radius:0;background:transparent}
.steps > :first-child{border-top:0}
.steps .card{padding:20px}
.steps .n{font-family:var(--font-mono);font-size:var(--t-label);color:var(--fg-3);letter-spacing:.06em}
.steps h3{margin-top:6px;font-size:var(--t-section);font-weight:600}
.steps p{margin-top:4px;color:var(--fg-2);font-size:var(--t-body);max-width:560px}
.steps .state{margin-top:12px}
/* The dashed what-connects-to-what strip. */
.berth{border:1px dashed var(--line-2);border-radius:var(--r-card);padding:16px 20px;font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-3);display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.berth .arrow{color:var(--fg-3)}
.berth .you{color:var(--fg-2)}

/* == The sign-in card ===================================================== */
.auth-wrap{flex:1;display:grid;place-items:start center;padding:9vh 24px 60px}
.auth{width:100%;max-width:400px;padding:24px 24px 20px}
.auth h1{font-size:var(--t-title);font-weight:600}
.auth{--lead-gap:4px}
.auth .lead{margin-bottom:24px}
.auth .social{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}
/* The two ways in sit side by side where they fit and one under the other on a phone; a card is never wider than its page. */
@media (max-width:560px){.auth .social{grid-template-columns:minmax(0,1fr)}}
.auth{min-width:0}
.auth .divider{display:flex;align-items:center;gap:12px;color:var(--fg-3);font-size:var(--t-small);margin:8px 0 16px}
.auth .divider::before,.auth .divider::after{content:"";height:1px;flex:1;background:var(--line-1)}
.auth-row{margin-top:12px;font-size:var(--t-small);color:var(--fg-2);display:flex;gap:6px;flex-wrap:wrap}
.msg{margin-top:12px;font-size:var(--t-small);line-height:1.5;display:flex;gap:8px;align-items:flex-start}
.msg-error{color:var(--red)}
.msg-ok{color:var(--fg-2)}
.msg-busy{color:var(--blue)}

/* == Consent: the four levels as one column of radio cards ================ */
.levels{display:flex;flex-direction:column;gap:6px;margin:6px 0 4px}
.level{display:grid;grid-template-columns:16px minmax(0,1fr);gap:10px;align-items:start;padding:10px 12px;border-radius:var(--r-ctl);border:1px solid var(--line-1);background:var(--bg-2);cursor:pointer}
.level:hover{border-color:var(--line-2)}
.level:has(input:checked){border-color:var(--line-2);background:var(--bg-3)}
.level input{margin:2px 0 0;accent-color:var(--accent)}
.level .lv{display:flex;gap:8px;align-items:baseline;flex-wrap:wrap;font-weight:500}
.level .lv .mono{font-weight:400;color:var(--fg-3)}
.level .why{display:block;margin-top:2px;color:var(--fg-2);font-size:var(--t-small);line-height:1.5}

/* The one-line sub a page shows under its title, or a fact under itself. */
.sub{color:var(--fg-2);font-size:var(--t-small)}

/* == Measures: page widths, named. Gutter 32, content max 1200 ============ */
main.page{width:100%;margin:0;padding:24px var(--gutter) 48px}
main.page.m-workspace{max-width:calc(var(--content-max) + 2 * var(--gutter))}
main.page.m-rail{max-width:calc(1040px + 2 * var(--gutter))}
main.page.m-detail{max-width:calc(800px + 2 * var(--gutter))}
main.page.m-reading{max-width:calc(560px + 2 * var(--gutter))}
/* Kept for pages that still mark a block as screen-only; the customer footer itself is gone. */
.no-print{display:revert}

/* == Responsive ============================================================
   Sidebar: full, then an icon rail under 1024, then an off-canvas drawer
   under 820 opened by the menu button (design/script.ts). Nothing scrolls
   the page sideways: every wide table sits in .scroll-x inside its card. */
@media (max-width:1100px){.g-kpi{grid-template-columns:repeat(2,minmax(0,1fr))}.g-kpi > .kpi:nth-child(2){border-right:0}.g-kpi > .kpi:nth-child(-n+2){border-bottom:1px solid var(--line-1)}.g-main{grid-template-columns:minmax(0,1fr)}}
@media (max-width:1024px) and (min-width:821px){
  .shell{grid-template-columns:56px minmax(0,1fr)}
  .side{width:56px;padding:14px 8px}
  .side .brand b,.side .group h4,.side .nav a span.label,.side .nav a .n,.side .nav a .tail,.side .foot .version,.side-collapse span{display:none}
  .side .nav a{justify-content:center}
  .side .nav a svg{display:block}
  .side-collapse{display:none}
}
@media (max-width:820px){
  .shell{grid-template-columns:minmax(0,1fr)}
  .side{position:fixed;left:0;top:0;bottom:0;z-index:9;width:var(--side-w);padding:14px 12px;transform:translateX(-100%);visibility:hidden;transition:transform var(--motion) var(--ease),visibility 0s var(--motion)}
  .side .brand b,.side .group h4,.side .nav a span.label,.side .nav a .n,.side .nav a .tail,.side .foot .version{display:revert}
  .side .nav a{justify-content:flex-start}
  .side.open{transform:translateX(0);visibility:visible;transition:transform var(--motion) var(--ease)}
  .side.open::after{content:"";position:fixed;inset:0;z-index:-1;background:rgba(0,0,0,.45)}
  .side-collapse{display:none}
  .menu-btn{display:inline-flex}
  .search-btn{display:inline-flex}
  .top{padding:0 8px 0 4px;gap:8px}
  .top .right{gap:4px}
  .ws{max-width:50vw}
  .jump{display:none}
  .g-kpi{grid-template-columns:repeat(2,minmax(0,1fr))}
  .start{grid-template-columns:1fr}
  .head{margin-bottom:16px}
  .tabs-wrap::after{opacity:1}
  .tabs a{padding:12px 10px}
}
@media (max-width:820px){main.page{padding:16px 16px 32px}}
@media (max-width:640px){.g-kpi{grid-template-columns:minmax(0,1fr)}.g-kpi > .kpi{border-right:0;border-bottom:1px solid var(--line-1)}.g-kpi > .kpi:last-child{border-bottom:0}}

/* == PINPOINT-3: the add flow's step strip, a place's row, the folded explanation == */
.flow{list-style:none;margin:0 0 16px;padding:0;display:flex;gap:6px;flex-wrap:wrap;counter-reset:f}
.flow li{display:flex;align-items:center;gap:8px;height:28px;padding:0 10px 0 4px;border-radius:var(--r-pill);border:1px solid var(--line-2);background:transparent;font-size:var(--t-small);color:var(--fg-3);font-weight:500}
.flow li::before{counter-increment:f;content:counter(f);width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:var(--t-label);font-weight:500;border:1px solid var(--line-2);flex:none}
.flow li a{color:var(--fg-2);font-weight:500;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px}
.flow li a:hover{color:var(--fg-1);text-decoration-color:var(--line-2)}
.flow li.done{color:var(--fg-2)}
.flow li.done::before{background:var(--bg-3);border-color:var(--bg-3);color:var(--fg-2);content:"\2713"}
.flow li.now{color:var(--fg-1);font-weight:500;border-color:var(--bg-3);background:var(--bg-3)}
.flow li.now::before{border-color:var(--fg-1);color:var(--fg-1)}
/* The question a step asks, as the card's own heading. */
.q{font-size:var(--t-section);font-weight:600;margin:0 0 6px}
.q + .hint{margin-bottom:12px}
/* One place on a pinpoint page: under the name, where it is, what it reads, and how it stands. */
.row .where{font-size:var(--t-small);color:var(--fg-3);margin-top:2px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.row .said{font-size:var(--t-body);color:var(--fg-1);margin-top:4px;overflow-wrap:anywhere}
.row .fate{margin-top:6px;font-size:var(--t-small);color:var(--fg-2);line-height:1.5;max-width:72ch;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.row .fate .pill{flex:none}
.row .fate p{margin:0;flex:1 1 100%}
.row .name .tag{margin-left:8px;vertical-align:middle}
/* An offer under a place: one sentence and the one button that takes it. Neutral, one level up. */
.offer{margin:8px 0 0;padding:10px 12px;border-radius:var(--r-ctl);border:1px solid var(--line-1);background:var(--bg-2);font-size:var(--t-small);color:var(--fg-1);line-height:1.5;display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.offer span{flex:1 1 320px}
.offer .btn-outline{flex:none}
@media (max-width:640px){
  .row{grid-template-columns:20px minmax(0,1fr)}
  .row .acts{grid-column:2}
  .row.simple{grid-template-columns:minmax(0,1fr)}
  .row.simple .acts{grid-column:1}
}
/* A choice whose label is a block's own words: it wraps, where a button label never does. */
.chips-wrap{display:flex;flex-wrap:wrap;gap:6px}
.choice{display:inline-flex;align-items:flex-start;min-height:28px;padding:5px 10px;border-radius:var(--r-ctl);border:1px solid var(--line-2);background:var(--bg-2);font-weight:500;font-size:var(--t-small);color:var(--fg-1);text-align:left;line-height:1.4;white-space:normal;overflow-wrap:anywhere;cursor:pointer;transition:background var(--motion-fast) var(--ease)}
.choice:hover{background:var(--bg-3)}
/* A folded explanation: the one sentence stays out, the rest opens on a press. */
details.more{margin-top:8px}
details.more summary{cursor:pointer;font-size:var(--t-small);color:var(--fg-2);font-weight:500;list-style:none;display:flex;align-items:center;gap:6px}
details.more summary::-webkit-details-marker{display:none}
details.more summary::before{content:"";width:6px;height:6px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(-45deg);transition:transform var(--motion-fast) var(--ease);flex:none}
details.more[open] summary::before{transform:rotate(45deg)}
details.more summary:hover{color:var(--fg-1)}
details.more > div{margin-top:8px}
details.more > div > p + p{margin-top:8px}
/* The block a person chose, said once: the kind, the page, the words. */
.chosen{display:grid;gap:4px;padding:10px 12px;border-radius:var(--r-ctl);border:1px solid var(--line-1);background:var(--bg-2);margin-bottom:12px}
.chosen .kind{font-size:var(--t-small);color:var(--fg-2)}
.chosen .words{font-size:var(--t-body);color:var(--fg-1);overflow-wrap:anywhere}

/* == Print: reports print on white regardless of theme ==================== */
@media print{
  @page{size:A4;margin:16mm 14mm}
  :root{--bg-0:#FFFFFF;--bg-1:#FFFFFF;--bg-2:#F0F2F5;--bg-3:#E7EAEF;--line-1:#E3E7EC;--line-2:#CFD6DE;--fg-1:#14181E;--fg-2:#4C5663;--fg-3:#5F6B78;--accent:#158252;--accent-fg:#FFFFFF;--ok:#2E8A5F;--red:#B93832;--red-soft:#FBEAE9;--red-fg:#FFFFFF;--amber:#8A5A00;--amber-soft:#FBF1DC;--blue:#2A62C9;--blue-soft:#E6EEFC;--shadow-float:none;--group:#2A5D7A;color-scheme:light}
  .shell{display:block}
  .side,.top,.topbar,.menu-btn,.no-print,#toast-region,.side-collapse{display:none}
  html,body{background:#fff}
  main.page{max-width:none;padding:0}
  .card{break-inside:avoid}
  section{break-inside:avoid}
  main.page a{color:var(--fg-1);text-decoration:none}
  .scroll-x{overflow-x:visible}
  table{table-layout:fixed;width:100%}
  th{white-space:nowrap}
  td.host{overflow-wrap:anywhere}
  td.num{white-space:nowrap;text-align:right}
  /* REPORT-2: a printed page has no sideways scroll, so a machine cell may wrap on paper. Addresses break at their dots (a wbr after each). */
  table.grid2 td.m{white-space:normal;overflow-wrap:anywhere}
  /* Pills print as outlined text so they survive greyscale. */
  .pill,.pill-ok,.pill-busy,.pill-warn,.pill-error,.pill-stopped{border:1px solid currentColor;background:none}
}

/* == The site row's identity: an icon, a name, and its machine facts ====== */
.card>.rows>.row,.card>.rows>li>.row{padding:10px 0}
/* An underlined action inside prose: the ink, never the accent. */
.link{color:var(--fg-1);font-weight:500;text-decoration:underline;text-decoration-color:var(--line-2);text-underline-offset:3px}
.link:hover{text-decoration-color:var(--fg-1)}
/* The two-column grid a detail page lays its cards out on. */
.cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px;align-items:start}
.cards .wide{grid-column:1/-1}
@media (max-width:900px){.cards{grid-template-columns:minmax(0,1fr)}}
/* One row's identity block: the dot, the icon, the name, the nickname. */
.ident{min-width:0}
.ident-line{display:flex;align-items:center;gap:8px;min-width:0}
/* A machine address: the thing a person copies, greps and compares. */
.host{font-family:var(--font-mono);font-size:var(--t-mono);font-weight:400;color:var(--fg-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
a.host{display:inline-block;max-width:100%;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px}
a.host:hover{text-decoration-color:var(--line-2);color:var(--fg-1)}
/* ...unless the site told us its own name, in which case that leads and the address follows. */
a.host.named,.host.named{font-family:var(--font-ui);font-size:var(--t-body);font-weight:500;color:var(--fg-1)}
/* The line of small facts under a name. */
.fact{margin-top:2px;color:var(--fg-3);font-size:var(--t-small);display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.fact .addr{color:var(--fg-3);font-family:var(--font-mono)}
.fact-act{display:inline-flex;margin-left:8px;vertical-align:middle}
/* The site's own icon, with its monogram underneath for a site that has none. */
.favicon{position:relative;display:inline-flex;align-items:center;justify-content:center;flex:none;width:var(--fav,26px);height:var(--fav,26px);border-radius:var(--r-ctl);overflow:hidden;background:var(--bg-3);border:1px solid var(--line-2)}
.favicon > i{font-style:normal;font-family:var(--font-ui);font-weight:600;font-size:calc(var(--fav,26px) * .42);line-height:1;color:var(--fg-1)}
.favicon > img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:var(--bg-3)}
/* The person's own word for a site. */
.nick{display:inline-flex;align-items:center;height:20px;padding:0 8px;border-radius:var(--r-pill);flex:none;max-width:22ch;font-size:var(--t-label);color:var(--fg-2);background:transparent;border:1px solid var(--line-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nick-form{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:2px 0 0}
.nick-form{--ctl-h:auto;--ctl-pad:6px 10px}
.nick-form .input,.nick-form .select{font-family:var(--font-ui);flex:1 1 150px;max-width:210px}
/* The detail page's own head: the icon, the name, the address, the state. */
.site-id{display:flex;align-items:flex-start;gap:14px;min-width:0}
.site-id-text{min-width:0}
.site-id .addr{margin-top:4px;display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:var(--t-small);color:var(--fg-2)}
.site-id .addr a{color:var(--fg-2);text-decoration:underline;text-decoration-color:transparent}
.site-id .addr a:hover{color:var(--fg-1);text-decoration-color:var(--line-2)}
.site-id .sub{margin-top:2px}
/* Prose where a fact would be: what a host would not say, in words. */
.unsaid{font-size:var(--t-small);color:var(--fg-3);line-height:1.5}
/* The people connected to one site. */
.people{display:flex;flex-direction:column}
.person{display:grid;grid-template-columns:20px minmax(0,1fr);gap:10px;align-items:start;padding:10px 0;border-top:1px solid var(--line-1)}
.person:first-child{border-top:0}
.person > .light{margin-top:7px}
.person .nm{font-size:var(--t-body);color:var(--fg-1);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.person .meta{margin-top:2px;color:var(--fg-3);font-size:var(--t-small);display:flex;gap:8px;flex-wrap:wrap;align-items:center}
/* The New job form's site picker: grouped headers, and a busy site's reason. */
.job-form .field{max-width:340px}
.picks-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:20px}
.pickwrap{margin-top:8px;display:flex;flex-direction:column;gap:12px}
.pickgroup .cap{font-size:var(--t-label);letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);margin-bottom:6px;font-weight:500}
.pickbox .pick-text{display:flex;flex-direction:column;gap:1px;min-width:0}
.pickbox .pick-name{color:var(--fg-1);font-size:var(--t-small);line-height:1.4;overflow-wrap:anywhere}
.pickbox.busy .pick-name{color:var(--fg-3)}
.pickbox .pick-host{color:var(--fg-3);font-size:var(--t-label);font-family:var(--font-mono);line-height:1.4;overflow-wrap:anywhere}
/* A toggle's help is a SENTENCE, so it wears the reading face. The pick-host
   beside it is the machine face because an address is machine truth; prose in
   that face reads as a command somebody typed. */
.pickbox .pick-help{color:var(--fg-2);font-size:var(--t-small);line-height:1.5;overflow-wrap:anywhere}
/* The reason a site cannot be picked, as words beside it. */
.pickbox .pick-busy{margin-left:auto;padding-left:8px;color:var(--fg-3);font-size:var(--t-small);white-space:nowrap}
/* A job step's expander, and which of a site's two steps a row is. */
.job-detail{margin-top:4px}
.job-detail summary{cursor:pointer;color:var(--fg-2);font-size:var(--t-small)}
.job-detail summary:hover{color:var(--fg-1)}
table.grid2 td .step-phase{display:block;margin-top:2px;font-family:var(--font-ui);font-size:var(--t-label);color:var(--fg-3);letter-spacing:.06em;text-transform:uppercase}
/* What an action did, and the way back from it. */
.act-audit{color:var(--fg-3)}
.act-back{margin-top:10px}
.act-undo{display:inline-flex;margin:0}
.act-undo-note{margin:0;max-width:64ch}
.act-verbatim{line-height:1.5}
.act-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:16px;padding-top:12px;border-top:1px solid var(--line-1)}

/* == REPORT-2: the agency's own marks, on the document their client reads == */
/* The band at the head of a client's report: its two colours arrive as custom properties on the body (harbor.ts). print-color-adjust keeps the brand colour on paper. */
.brandbar{display:flex;align-items:center;gap:16px;padding:20px 22px;border-radius:var(--r-card);background:var(--rb,var(--accent));color:var(--rbi,#fff);print-color-adjust:exact;-webkit-print-color-adjust:exact}
.brandbar img{max-height:46px;max-width:190px;width:auto;flex:none}
.brandbar b{font-size:var(--t-title);font-weight:600;color:inherit;display:block}
.brandbar span{display:block;margin-top:2px;font-size:var(--t-small);color:inherit;opacity:.85}
@media (max-width:560px){.brandbar{flex-direction:column;align-items:flex-start;gap:10px}}
/* The shell's brand mark when a workspace has given us a logo: the same 18px square. */
.brand .mark-img{width:18px;height:18px;border-radius:5px;flex:none;object-fit:contain;background:var(--bg-3)}
/* A colour a person is choosing, beside the field they type it into. */
.swatch-lg{display:inline-block;width:32px;height:32px;border-radius:var(--r-ctl);border:1px solid var(--line-2);flex:none;vertical-align:middle}
.colorline{display:flex;align-items:flex-end;gap:8px}
.colorline .field{margin:0;flex:1 1 auto}
/* The logo as it stands, on the checkerboard that shows a transparent edge. */
.logo-now{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.logo-now img{max-height:56px;max-width:220px;width:auto;padding:8px;border-radius:var(--r-ctl);border:1px solid var(--line-2);background:#fff}

/* == The status vocabulary table on the component gallery ================= */
.vocab{display:grid;grid-template-columns:200px 160px minmax(0,1fr);gap:16px;align-items:center;padding:10px var(--pad);border-top:1px solid var(--line-1);font-size:var(--t-body)}
.vocab:first-child{border-top:0}
.vocab.head{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3)}
.vocab .to{color:var(--fg-2)}
@media (max-width:640px){.vocab{grid-template-columns:minmax(0,1fr)}}

/* == WAVE 5: each lane's own block, restyled to the system in place ======= */

/* One protection: what it is on the left, its state and its button on the right. */
.protect-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px 16px;align-items:start;padding:12px 0;border-top:1px solid var(--line-1)}
.protect-list .protect-row:first-child{border-top:0}
.protect-row .nm{font-weight:500}
/* The sentence under a switch's name: what it does, and what it costs. */
.protect-why{margin-top:2px;font-size:var(--t-small);color:var(--fg-2);max-width:62ch}
/* The pill and the button, on one line, never wrapping under each other. */
.protect-act{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}
/* A count that belongs on the right of a row: the machine face, because it is machine truth. */
.protect-count{font-family:var(--font-mono);font-size:var(--t-title);line-height:1;color:var(--fg-1)}
@media (max-width:560px){.protect-row{grid-template-columns:minmax(0,1fr)}.protect-act{justify-content:flex-start}}


/* == MONITOR-2: what the five-minute visit adds to a row == */
/* The response time on a site row: machine truth, tabular so the column does not jitter, the fact line's quiet colour when nothing is wrong. */
.rt{font-family:var(--font-mono);font-size:var(--t-mono);font-variant-numeric:tabular-nums;color:var(--fg-3)}
/* Slow is amber: a person should look. Down is red, and says when. */
.rt-slow{color:var(--amber);font-weight:500}
.rt-down{color:var(--red);font-weight:500}


/* Words inside a facts list rather than machine truth: the reading face. */
.drive-plain{font-family:var(--font-ui);font-size:var(--t-body)}
.facts > dd.drive-plain{color:var(--fg-2)}
/* The section's own opening line, tighter than a page lead because a card is not a page. */
.drive-lead{--lead-gap:0;margin-bottom:8px;color:var(--fg-1)}
/* The facts list inside a card sits under a paragraph, so it needs its own top gap. */
.drive-facts{margin-top:12px}
/* How much of a copy Google has taken, in the cell that says what the copy is doing. */
.drive-tr{--track:4px;margin-top:6px;max-width:180px}
/* Google's or the site's own words about one site, under the row they are about. */
.drive-why{margin-top:6px;max-width:52ch;overflow-wrap:anywhere}
/* The site's own cell: the name a person gave it, the address under it. It wraps. */
.drive-site{max-width:22ch}
.drive-site > b{display:block;font-weight:500}
.drive-site > .sub,.facts > dd > .sub{display:block;font-size:var(--t-small);color:var(--fg-2);width:100%}
/* When the copy was, on its own line under the pill. */
.drive-when{display:block;margin-top:4px;font-size:var(--t-small)}


/* == LINKS-1: the broken-link screen and the public crawler page == */
/* An address in a cell: machine truth before it is a link, so the ink and the mono face, and it wraps anywhere. */
.lk-url{display:block;color:var(--fg-1);font-family:var(--font-mono);font-size:var(--t-mono);overflow-wrap:anywhere;max-width:46ch;text-decoration:underline;text-decoration-color:var(--line-2);text-underline-offset:3px}
.lk-url:hover{text-decoration-color:var(--fg-1)}
.lk-on{display:block;margin-top:2px;color:var(--fg-3);font-size:var(--t-label);line-height:1.4;overflow-wrap:anywhere;max-width:46ch}
.lk-line{color:var(--fg-1);font-size:var(--t-body);line-height:1.5;max-width:78ch}
.lk-heading{margin:20px 0 8px;font-size:var(--t-section);font-weight:600;color:var(--fg-1)}
.lk-asked{color:var(--fg-2);font-size:var(--t-small)}
.lk-method{margin:0;padding-left:20px;color:var(--fg-2);font-size:var(--t-small);line-height:1.6}
.lk-method li{margin:0 0 4px}
.lk-method-quiet{color:var(--fg-3);font-size:var(--t-small)}
/* The findings as a table on a desk and a stack of blocks on a phone. */
@media (max-width:700px){
  table.lk-grid,table.lk-grid tbody,table.lk-grid tr,table.lk-grid td{display:block;width:auto;height:auto}
  table.lk-grid thead{display:none}
  table.lk-grid tr{padding:12px 0;border-top:1px solid var(--line-1)}
  table.lk-grid tbody tr:first-child{border-top:0;padding-top:4px}
  table.lk-grid td{padding:0 0 8px;white-space:normal;border-bottom:0}
  table.lk-grid td:last-child{padding-bottom:0}
  table.lk-grid td::before{content:attr(data-label);display:block;margin-bottom:2px;font-family:var(--font-ui);font-size:var(--t-label);color:var(--fg-3);letter-spacing:.08em;text-transform:uppercase}
  .lk-url{max-width:none}
}
.lk-code{margin:8px 0 0;padding:10px 12px;border-radius:var(--r-ctl);border:1px solid var(--line-1);background:var(--bg-2);color:var(--fg-1);font:var(--t-mono) var(--font-mono);white-space:pre;overflow-x:auto}


/* The list: the ordinary row anatomy with a fold under each row. */
.reach-rows > li{border-top:1px solid var(--line-1)}
.reach-rows > li:first-child{border-top:0}
.reach-rows > li > .row{border-top:0}
/* The fold. Closed it is one quiet line; open it is the whole answer. */
.reach-detail > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;font-size:var(--t-small);color:var(--fg-2);padding:2px 0 8px}
.reach-detail > summary::-webkit-details-marker{display:none}
.reach-detail > summary::before{content:"";width:0;height:0;border-left:5px solid var(--fg-3);border-top:4px solid transparent;border-bottom:4px solid transparent;transition:transform var(--motion-fast) var(--ease)}
.reach-detail[open] > summary::before{transform:rotate(90deg)}
.reach-detail > summary:hover{color:var(--fg-1)}
.reach-detail-body{padding:4px 0 10px;max-width:74ch}
.reach-sub{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);margin:12px 0 8px}
.reach-detail-body > .reach-sub:first-child{margin-top:0}
/* The score: the number in the machine face, the band word beside it. */
.reach-score{display:inline-flex;align-items:baseline;gap:6px;font-size:var(--t-small);color:var(--fg-2);white-space:nowrap}
.reach-score b{font-family:var(--font-mono);font-size:var(--t-body);font-weight:600;font-variant-numeric:tabular-nums}
.reach-score.good b{color:var(--fg-1)}
.reach-score.fair b{color:var(--amber)}
.reach-score.poor b{color:var(--red)}
/* The trend: an arrow and a number of points. The arrow carries the direction. */
.reach-trend{display:inline-flex;align-items:center;gap:4px;font-size:var(--t-small);font-variant-numeric:tabular-nums;color:var(--fg-2);white-space:nowrap}
.reach-trend.up{color:var(--fg-2)}
.reach-trend.down{color:var(--red)}
.reach-trend.same{color:var(--fg-3)}
/* Prose inside a fact list: the reading face, not the machine face. */
.reach-said{font-family:var(--font-ui);font-size:var(--t-body);color:var(--fg-2)}
.reach-num{font-family:var(--font-mono);font-weight:600;color:var(--fg-1);font-variant-numeric:tabular-nums}
/* A DNS record, as published. It wraps: a record is read character by character. */
.reach-record{font:var(--t-mono) var(--font-mono);color:var(--fg-1);background:var(--bg-2);border:1px solid var(--line-1);border-radius:4px;padding:2px 6px;overflow-wrap:anywhere;display:inline-block;max-width:100%}
/* The fixes: one sentence each, each naming a fact and what to do about it. */
.reach-fixes{margin:12px 0 0;padding:0 0 0 18px;display:grid;gap:8px}
.reach-fix{font-size:var(--t-body);color:var(--fg-2);line-height:1.5;max-width:70ch}
/* The three vitals: one column on a phone, three where there is room. */
.reach-vitals{display:grid;grid-template-columns:repeat(auto-fit,minmax(232px,1fr));gap:10px;margin-top:4px}
.reach-vital{display:grid;gap:2px;padding:10px 12px;border:1px solid var(--line-1);border-radius:var(--r-ctl);background:var(--bg-2)}
.reach-vital-k{font-size:var(--t-small);font-weight:500;color:var(--fg-2);display:flex;align-items:baseline;gap:6px;flex-wrap:wrap}
.reach-vital-abbr{font:var(--t-label) var(--font-mono);color:var(--fg-3);letter-spacing:.06em}
.reach-vital-n{font-family:var(--font-mono);font-size:var(--t-title);font-weight:600;font-variant-numeric:tabular-nums;color:var(--fg-1)}
.reach-vital-n.good{color:var(--fg-1)}
.reach-vital-n.fair{color:var(--amber)}
.reach-vital-n.poor{color:var(--red)}
/* A vital with no reading: quiet, and never a hue. */
.reach-vital-n.none{font-size:var(--t-body);color:var(--fg-3);font-family:var(--font-ui);font-weight:500}
.reach-vital-m{font-size:var(--t-small);color:var(--fg-2);line-height:1.5}
@media (max-width:560px){
  .reach-rows > li > .row{grid-template-columns:20px minmax(0,1fr)}
  .reach-rows > li > .row > .acts{grid-column:2;justify-content:flex-start}
  .reach-detail-body dl.facts{grid-template-columns:minmax(0,1fr);gap:0}
  .reach-detail-body dl.facts > dt{padding:8px 0 0;border-top:1px solid var(--line-1)}
  .reach-detail-body dl.facts > dd{padding:2px 0 8px;border-top:0}
  .reach-detail{padding-left:0}
}


/* WordPress itself, at the head of the Manage tab. A card like any other, with
   its version in the mono face because a version is machine truth. */
.core-card .card-body{display:flex;flex-direction:column;gap:12px}
.core-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.core-head h2{font-size:var(--t-title);font-weight:600;margin:0}
/* The button and its reason, side by side while there is room and stacked when
   there is not. with-reason is the system's own name for a control that is off
   with its reason as text; this adds only the layout. */
.core-offer{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.core-offer .reason{margin:0;color:var(--fg-2);font-size:var(--t-small);max-width:72ch}
.core-offer form{margin:0}
@media (max-width:560px){.core-offer{flex-direction:column;align-items:flex-start;gap:8px}}

/* The version picker: the theme picker's rows, with the version leading. */
.ver-list .ver-row .name{font-size:var(--t-body)}
.ver-list .ver-row .fact{color:var(--fg-3)}

/* Installed themes, under the active one it belongs with. */
.theme-list{margin-top:20px;padding-top:16px;border-top:1px solid var(--line-1)}
.sub-h{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);margin:0 0 10px}


/* One site's row in "What a visitor saw": the verdict sentence under its name. */
.su-why{font-size:var(--t-small);color:var(--fg-2);margin-top:2px;line-height:1.5;overflow-wrap:anywhere}
/* The pages a click away. Quiet by default: a site that is fine says so once. */
.su-look{margin:2px 0 8px 32px}
.su-look > summary{cursor:pointer;color:var(--fg-2);font-size:var(--t-small);list-style:revert}
.su-look > summary:hover{color:var(--fg-1)}
.su-look-body{margin-top:8px;border:1px solid var(--line-1);border-radius:var(--r-ctl);background:var(--bg-2)}
/* Three facts stacked in one cell: what a visitor got, in reading order. */
.su-facts{display:grid;gap:2px;min-width:0}
/* The status code. Machine truth, so the machine face, and never a hue of its own. */
.su-st{font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-1);font-variant-numeric:tabular-nums}
/* The theme's body class list. Long, machine truth, and it wraps rather than scrolls the page. */
.su-cls{font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-2);overflow-wrap:anywhere}
/* The page title. A person wrote it, so it renders in the reading face. */
.su-ttl{font-size:var(--t-small);color:var(--fg-2);overflow-wrap:anywhere}
/* Nothing to say: not looked at, no title, not read that far. Never a colour. */
.su-none{font-size:var(--t-small);color:var(--fg-3)}
/* The after column when the page did not change. Quiet on purpose: the whole
   point of collapsing it is that the rows which DID change are the only ones
   with anything in them. */
.su-same{font-size:var(--t-small);color:var(--fg-3);font-style:italic}
/* Nothing a theme drew. This is one of the two facts that puts a site back, so it is red. */
.su-gone{font-size:var(--t-small);color:var(--red);font-weight:500}
/* A four-column table of addresses inside a scroller is unusable on a phone
   (GOTCHAS LINKS-1), so at 560 the rows become blocks and every cell says what
   it is. The markup stays one table. */
@media (max-width:560px){
  .su-look{margin-left:0}
  table.su-pages thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  table.su-pages tr{display:block;border-bottom:1px solid var(--line-1);padding:8px 0}
  table.su-pages tr:last-child{border-bottom:0}
  table.su-pages td{display:grid;grid-template-columns:72px minmax(0,1fr);gap:8px;border-bottom:0;height:auto;padding:4px var(--pad)}
  table.su-pages td::before{content:attr(data-label);font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3)}
  table.su-pages td.m{white-space:normal}
}

/* The one line the whole feature exists for: the COUNTS, then the percentage
   beside them (ADR-M188). The counts are the loud half on purpose - they are
   the fact the agency can stand behind, and the percentage is what it works
   out to. Both halves wrap onto their own line under 560, where a single line
   would otherwise break inside a number. */
.sla-line{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px;margin:0;font-size:var(--t-body);line-height:1.4}
.sla-counts{font-size:var(--t-section);font-weight:600;letter-spacing:-.01em;color:var(--fg-1);font-variant-numeric:tabular-nums}
.sla-verdict{color:var(--fg-2);font-variant-numeric:tabular-nums}
/* A missed promise is the loudest thing on the page. Met is neutral with the
   6px green dot in the pill beside the heading, which is the one place the
   system lets the green token appear. */
.sla-missed{color:var(--red);font-weight:500}
/* The target field, its three common choices, and the sentence under them. */
.sla-form{display:flex;flex-direction:column;gap:4px}
/* Its OWN name rather than a descendant override of .field: the collision test
   reads the LAST compound of a selector, so .sla-form .field setting a width
   is a second max-width for .field, which .job-form .field already sets. Two
   contexts giving one class two widths is the shape that test exists to
   refuse (GOTCHAS SYSTEM-1). */
.sla-field{max-width:420px;margin-bottom:8px}
.sla-input{max-width:130px}
.sla-choices{gap:8px;margin-bottom:4px}
.sla-choice[aria-current="true"]{border-color:var(--fg-3);color:var(--fg-1)}
@media (max-width:560px){.sla-line{gap:2px 0}.sla-counts{font-size:var(--t-body)}}

/* == ENTRY-1 (ADR-M220): the way in ======================================
   Three screens, to 01 Sign in and 02 Empty workspace. Two shapes only: the
   SPLIT (the product's promise beside one form, worn by sign-in and sign-up)
   and the FIRST RUN (what to do first, in a workspace with nothing in it).

   The split lives inside the shell's nav:false frame rather than replacing
   it: the frame's 48px brand header stays, because hiding it means giving
   .top a second display and sheet-collisions.test.ts refuses one class two
   geometries. The artboard's mark-on-the-panel is that header's mark
   instead, and the panel starts under it (ENTRY-1-REPORT section 3). == */
/* The entry pages are the only ones that spend the whole window, so the
   reading measure and the page gutter come off. Scoped to main.page.m-reading
   (the measure every entry page renders at) rather than to .page, so the rule
   is a second selector and never a second geometry for one class name. */
body:has(.entry) main.page.m-reading{max-width:none;padding:0}
/* The promise on the left, the form on the right, the way in on top of it. */
.entry{display:grid;grid-template-columns:minmax(0,1fr) 560px;min-height:calc(100vh - 48px)}
/* The left panel: one background level up, its own line, the promise in the
   middle and the small print at the foot. */
.entry-pitch{background:var(--bg-1);border-right:1px solid var(--line-1);padding:48px 64px 88px;display:flex;flex-direction:column;justify-content:center;position:relative}
.entry-say{max-width:520px}
.entry-say .entry-headline{font-size:var(--t-display);font-weight:600;letter-spacing:-.015em;line-height:1.2;color:var(--fg-1)}
.entry-blurb{margin-top:16px;color:var(--fg-2);font-size:var(--t-section);line-height:1.5;max-width:460px}
/* What ReDock watches, does and reports: three equal columns, one line each. */
.entry-triad{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:24px;margin-top:48px;padding-top:24px;border-top:1px solid var(--line-1)}
.entry-triad b{display:block;font-weight:600}
.entry-triad span{display:block;margin-top:2px;color:var(--fg-2)}
.entry-legal{position:absolute;left:64px;bottom:40px;font-size:var(--t-small);color:var(--fg-3)}
.entry-legal a{color:var(--fg-3)}
.entry-legal a:hover{color:var(--fg-1)}
/* The right half: the form column, centred in it. Layered over .auth-wrap. */
.entry-form{display:flex;align-items:center;justify-content:center;padding:48px 40px}
/* The column itself, at the artboard's width, with no card around it: the
   panel beside it is what separates the form from the page. Over .auth. */
.entry-col{max-width:360px;padding:0}
.entry-col h1{font-size:var(--t-title);font-weight:600}
/* The fields, as one grid of named areas. The AREAS put "Forgot it?" beside
   the Password label the way the artboard draws it while the DOM keeps it
   after the button, so tab goes email, password, sign in, then the rest
   (test/signin.test.ts, "tab order"). */
/* One column, in the order a person fills it: the DOM order IS the visual
   order, so tab goes email, password, sign in with no tabindex anywhere
   (test/signin.test.ts, "tab order"), and a field the page hides — the
   password, when the address turns out to belong to a company that signs in
   its own way — takes its own row away with it. */
.entry-fields{display:grid;grid-template-columns:minmax(0,1fr);gap:6px}
.entry-pl{margin-top:10px}
.entry-go{margin-top:14px}
.entry-go .btn-primary{width:100%}
/* The password rule, printed BEFORE the field rather than after the refusal. */
.entry-rule{font-size:var(--t-small);color:var(--fg-3);line-height:1.5}
/* The second way in, under the primary: a full-width quiet control, never a
   button of the same weight. */
.entry-alt{width:100%;margin-top:8px;justify-content:center;color:var(--fg-2)}
/* The company sign-in, as a line rather than a third button. */
.entry-sso{margin-top:12px;text-align:center;font-size:var(--t-small);color:var(--fg-2)}
/* The link on its own line: at this column's width the sentence broke it
   in half and underlined both halves. */
.entry-sso a{display:block;margin-top:2px;color:var(--fg-1);text-decoration:underline;text-decoration-color:var(--line-2);text-underline-offset:3px}
/* The foot of the column: the other door, once, on its own line. */
.entry-foot{margin-top:40px;padding-top:20px;border-top:1px solid var(--line-1);text-align:center;font-size:var(--t-small);color:var(--fg-2)}
/* What sign-up promises happens next, and the plan it lands on. */
.entry-next{margin-top:16px;padding:12px 14px;border:1px solid var(--line-1);border-radius:var(--r-card);background:var(--bg-1);font-size:var(--t-small);color:var(--fg-2);line-height:1.5}
.entry-next b{color:var(--fg-1);font-weight:500}
.entry-next p + p{margin-top:6px}
/* A notice inside the column is the page's width, not the shell's. */
.entry-col .notice{margin-bottom:16px}
/* Under 960 the split stacks, and the FORM goes first: the promise is why
   somebody is here, the form is what they came to do. */
@media (max-width:960px){
  .entry{grid-template-columns:minmax(0,1fr);min-height:0}
  .entry-form{order:1;padding:32px 24px 24px}
  .entry-pitch{order:2;border-right:0;border-top:1px solid var(--line-1);padding:32px 24px;position:static}
  .entry-say .entry-headline{font-size:var(--t-title)}
  .entry-blurb{font-size:var(--t-body)}
  .entry-triad{grid-template-columns:minmax(0,1fr);gap:16px;margin-top:24px}
  .entry-legal{position:static;margin-top:24px}
}
@media (max-width:420px){
  .entry-form{padding:24px 16px 16px}
  .entry-pitch{padding:24px 16px}
}

/* == The first run: a workspace with nothing in it ========================
   ONE screen with one thing to do. The three steps are one panel of numbered
   rows; the one accent on the view is the button in step 1, so the numbers
   are drawn in ink and never in a second green (harbor.test.ts, "one
   accent"). Nothing here pretends to be data. == */
.first-run{max-width:760px;margin:56px auto 0}
.first-run h2{font-size:var(--t-display);font-weight:600;letter-spacing:-.01em;line-height:1.2}
.first-lead{margin-top:8px;color:var(--fg-2);font-size:var(--t-section);line-height:1.5}
.first-steps{margin-top:32px;border:1px solid var(--line-1);border-radius:var(--r-card);background:var(--bg-1);overflow:hidden}
.first-step{display:grid;grid-template-columns:28px minmax(0,1fr);gap:16px;padding:20px 20px 24px;border-top:1px solid var(--line-1)}
.first-step:first-child{border-top:0}
/* The step's number: the one you are on is filled in ink, the rest outlined. */
.first-n{width:28px;height:28px;border-radius:50%;border:1px solid var(--line-2);color:var(--fg-2);display:grid;place-items:center;font-size:var(--t-body);font-weight:600}
.first-n.now{background:var(--bg-3);border-color:var(--bg-3);color:var(--fg-1)}
.first-step h3{font-size:var(--t-section);font-weight:600}
.first-step h3 span{font-weight:400;color:var(--fg-3);margin-left:6px}
.first-why{margin-top:4px;color:var(--fg-2);max-width:560px;line-height:1.5}
/* The row's own action, and the fact beside it. */
.first-do{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-top:16px}
.first-do .hint{margin:0}
.first-file{font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-3)}
/* What the workspace will show once a site is paired: three equal, short
   columns, and no number in any of them. */
.first-triad{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:24px;margin-top:32px;padding-top:24px;border-top:1px solid var(--line-1)}
.first-triad b{display:block;font-weight:600}
.first-triad span{display:block;margin-top:2px;color:var(--fg-2);font-size:var(--t-small);line-height:1.5}
/* The two lines under the panel: bringing over many, and the plan. */
.first-note{display:flex;justify-content:space-between;gap:24px;margin-top:20px;font-size:var(--t-small);color:var(--fg-3);flex-wrap:wrap}
.first-note a{color:var(--fg-2);text-decoration:underline;text-decoration-color:var(--line-2);text-underline-offset:3px}
@media (max-width:820px){
  .first-run{margin-top:24px}
  .first-run h2{font-size:var(--t-title)}
  .first-lead{font-size:var(--t-body)}
  .first-step{padding:16px}
  .first-triad{grid-template-columns:minmax(0,1fr);gap:16px}
}

/* == WAVE 8 SLOTS, INSIDE the template (GOTCHAS §SLOT-OUTSIDE-THE-TEMPLATE). Insert in
      your own slot and nowhere else; a class here reaches every page. == */
/* SITEOPS-1 (ADR-M221): the three sections of the Manage tab. Structure only.
   Every colour is a token, nothing floats (borders, not shadows), and no
   selector here is a bare class that already carries geometry elsewhere. */
/* The people list: a name and what it is, with the four things beside it. */
.ops-people{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:0}
.ops-person{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap;padding:12px 0;border-top:1px solid var(--line-1)}
.ops-people > .ops-person:first-child{border-top:0}
.ops-who{min-width:0;flex:1 1 260px}
.ops-sub{margin-top:2px;color:var(--fg-2);font-size:var(--t-small);line-height:1.5;overflow-wrap:anywhere}
.ops-acts{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}
/* A fold, so four controls per person do not become a wall of buttons. */
.ops-fold > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;font-size:var(--t-small);color:var(--fg-2);height:var(--ctl-sm);padding:0 10px;border:1px solid var(--line-2);border-radius:var(--r-ctl)}
.ops-fold > summary::-webkit-details-marker{display:none}
.ops-fold > summary:hover{color:var(--fg-1);border-color:var(--fg-3)}
.ops-fold[open] > summary{border-color:var(--fg-3);color:var(--fg-1)}
/* Every form in these sections: labelled fields down the page, never a row of
   naked inputs somebody has to guess at. */
.ops-form{display:grid;gap:10px;margin-top:12px;max-width:520px}
.ops-form label{display:grid;gap:4px;font-size:var(--t-small);color:var(--fg-2)}
/* The controls are the system's own .input and .select, so the focus ring is
   the system's one accent and not a second one (harbor.test.ts pins that green
   appears on the primary button, the focus ring and the active nav item and
   nowhere else; a rule here would have been a fourth place). NO BACKTICK in
   this file, comments included: the sheet is one template literal and a stray
   one ends it, with the error reported two hundred lines away. */
.ops-form button{justify-self:start}
.ops-form .hint{margin:0}
/* The invite fold sits under the list with air above it, because it is the one
   control on the section that makes something rather than changing something. */
.ops-fold.ops-invite{margin-top:16px;padding-top:16px;border-top:1px solid var(--line-1);display:block}
/* The sideload form is the section's primary control, so it leads rather than
   sitting under a fold. */
.ops-form.ops-sideload{margin-top:4px}
/* The one-press bar under a section's own sentence: a button and why it is safe. */
.ops-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:12px 0}
.ops-bar .hint{margin:0;max-width:62ch}
/* The seven kinds, named before anything has been counted. */
.ops-kinds{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:0}
.ops-kinds > li{padding:10px 0;border-top:1px solid var(--line-1)}
.ops-kinds > li:first-child{border-top:0}
/* The counts, each with its own button. */
.ops-counts{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:0}
.ops-count{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:10px 0;border-top:1px solid var(--line-1)}
.ops-counts > .ops-count:first-child{border-top:0}
.ops-count .ops-sub{font-family:var(--font-mono);font-size:var(--t-body);font-weight:600;color:var(--fg-1);font-variant-numeric:tabular-nums}
/* The tables. A wide table scrolls inside its own box: a grid child defaults
   to min-width auto, so without this the whole page widens instead. */
.ops-scroll{overflow-x:auto;margin-top:12px;min-width:0}
table.ops-tables{border-collapse:collapse;width:100%;font-size:var(--t-small)}
table.ops-tables th{text-align:left;font-weight:500;color:var(--fg-3);font-size:var(--t-label);letter-spacing:.08em;text-transform:uppercase;padding:0 12px 6px 0;white-space:nowrap}
table.ops-tables td{padding:8px 12px 8px 0;border-top:1px solid var(--line-1);vertical-align:middle;white-space:nowrap}
table.ops-tables td:first-child{white-space:normal;overflow-wrap:anywhere}
table.ops-tables tbody tr:first-child td{border-top:1px solid var(--line-2)}
/* A reset link is read character by character, so it wraps rather than scrolls. */
pre.ops-link{white-space:pre-wrap;overflow-wrap:anywhere}
@media (max-width:640px){
  .ops-person{flex-direction:column;gap:8px}
  /* The basis is a WIDTH in a row and a HEIGHT in a column, so the same
     shorthand that keeps the name column from collapsing on a desk made every
     person 260px tall on a phone, with the buttons stranded at the bottom of
     an empty box. Only a picture at 375 said so. */
  .ops-who{flex:0 0 auto}
  .ops-acts{width:100%}
  .ops-count{flex-direction:column;align-items:flex-start;gap:8px}
}

/* The console's own rail, to the artboard: the way back sits under the
   wordmark, where a person looks for it on the way in, rather than at the
   bottom of a rail. It is a nav row like any other, in the quiet colour. */
.console-back{margin-bottom:12px}
.console-back a{color:var(--fg-3)}
/* An eyebrow over a group of figures: what these numbers are ABOUT. The
   overview has two, and finding 25 is why -- business figures and build
   hygiene are not the same kind of number and never share a strip. */
.eyebrow{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);margin-top:28px}
.eyebrow:first-child{margin-top:0}
.eyebrow + .grid,.eyebrow + .g-kpi{margin-top:8px}
/* A copyable machine id, with the label that says what it is. The console is
   the one place a person needs one; it is never the row's identity. It WRAPS
   rather than clips, because a clipped id is not a copyable one and the
   longest of them (a dependency's pin key) is wider than the column it sits
   in. Found by a picture: "pin engine:stable-diffusio". */
.idchip{display:inline-flex;align-items:baseline;gap:6px;min-height:22px;padding:2px 8px;border-radius:4px;background:var(--bg-2);border:1px solid var(--line-1);font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-2);max-width:100%}
.idchip b{font-family:var(--font-ui);font-size:var(--t-small);font-weight:500;color:var(--fg-3);flex:none}
/* The value wraps INSIDE the chip, beside its label, rather than dropping to a
   line of its own and stretching the chip to the width of the cell. */
.idchip span{min-width:0;overflow-wrap:anywhere}
/* The console's two-column figure rows: a strip of tiles beside a panel, and
   the health pair. Both are the system's grid with the artboard's tracks. */
.g-health{grid-template-columns:repeat(2,minmax(0,1fr));margin-top:8px;align-items:start}
@media (max-width:1100px){.g-health{grid-template-columns:minmax(0,1fr)}}
/* A sparse day strip: fourteen or thirty columns of nothing is a wall as a
   bar list and a shape as a strip, which is what the artboard draws. */
.daystrip{display:flex;gap:2px;align-items:flex-end;height:36px;margin-top:16px}
.daystrip i{flex:1;min-height:2px;border-radius:1px;background:var(--line-1)}
.daystrip i.on{background:var(--amber)}
.daystrip-ends{display:flex;justify-content:space-between;font-size:var(--t-small);color:var(--fg-3);margin-top:6px}

/* The settings rail: the artboard's sticky column of section names, and the
   line that separates Danger from the rest of them. The rail itself is
   .side-tabs, which SYSTEM-1 already shapes; these three rules are the
   artboard's sticky and its divider, and nothing else. */
.settings-rail{position:sticky;top:72px}
.rail-split{height:1px;background:var(--line-1);margin:8px 10px}
/* Danger keeps its own colour when it is the CURRENT section as well as when
   it is not: .tabs a.here paints fg-1 and is declared after .side-tabs a.danger,
   so without this the one section a person should read twice before pressing
   anything looks like the other nine. Seen on the picture, not by a test. */
.side-tabs a.danger.here{color:var(--red)}
/* One section at a time, at the artboard's measure. Its heading is the first
   thing in the panel and so wants no gap above it; the selector is written
   with :is() because a plain .settings-panel h2.section keys to "section"
   for sheet-collisions.test.ts and would read as a second geometry for a class
   that already has one (GOTCHAS SYSTEM-1: write the selector to the test). */
.settings-panel{max-width:760px;min-width:0}
.settings-panel h2:is(.section){margin-top:0}
/* At phone width the rail is a wrapped ROW of tabs (SYSTEM-1's media query),
   where a horizontal rule between the ninth and the tenth is a line across the
   middle of a row rather than a divider. The tabs' own underline carries the
   separation there. */
@media (max-width:820px){.settings-rail{position:static}.rail-split{display:none}}

/* The New job form's site picker as a LIST with a search over it, which is
   what a person picking nine of thirty sites reads. The grid it replaces drew
   twelve cards over rows of 2, 2, 2, 3, 2 and 1 (FINDINGS 17). */
.picks.picklist{display:flex;flex-direction:column;gap:0}
.pickbox.listed{border:0;border-top:1px solid var(--line-1);border-radius:0;padding:8px 2px}
.picks.picklist .pickbox:first-child{border-top:0}
.pick-search{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:8px}
.pick-field{max-width:280px}
/* How many sites the search is showing, kept true by the script and honest
   without it: with no script the field does nothing and every site is here. */
.pick-shown{font-size:var(--t-small);color:var(--fg-3)}
/* WO-1073: what a kind IS, under the select that chooses it. Every kind's
   line is in the markup; the chosen one is the one without [hidden], so the
   page says it with scripting off as well. */
.kind-help{margin:8px 0 0;padding:10px 12px;border:1px solid var(--line-1);border-radius:var(--r-ctl);background:var(--bg-2);color:var(--fg-2);font-size:var(--t-small);line-height:1.5;max-width:74ch}
/* A machine value a person copies: readonly, selected on focus, in the
   machine face. It is a field rather than a chip because a chip cannot be
   selected with the keyboard. */
.idfield{font-family:var(--font-mono);font-size:var(--t-mono);width:auto;max-width:26ch;--ctl-h:24px;--ctl-pad:0 8px;color:var(--fg-2)}

/* The printed report's Sites table: the artboard's six columns, at its
   widths. Screen and paper both, so what a person sees is what prints. The
   figures right-align on both, which the sheet's print block already does for
   td.num and this adds on screen. */
.t-sites{table-layout:fixed}
.t-sites .c-site{width:28%}
.t-sites .c-group{width:17%}
.t-sites .c-answered{width:14%;text-align:right}
.t-sites .c-down{width:10%;text-align:right}
.t-sites .c-updates{width:12%;text-align:right}
.t-sites .c-now{width:19%}
.t-sites td.num{text-align:right;white-space:nowrap}
/* The Site cell is the artboard's two lines: the client's name, then the
   address in the machine face, breaking only at its dots. The selectors end in
   a TAG on purpose, so neither keys to a bare class in sheet-collisions. */
.t-sites td.site-cell b{display:block;font-weight:500;color:var(--fg-1)}
.t-sites td.site-cell span{display:block;margin-top:2px;font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-3);overflow-wrap:anywhere}
.t-sites td.site-cell i{display:block;margin-top:2px;font-style:normal;font-size:var(--t-small);color:var(--fg-3)}
/* The two facts that were columns and are sentences now, under the table. */
.aside-list{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:4px;font-size:var(--t-small);color:var(--fg-3);line-height:1.5}
.aside-list b{color:var(--fg-2);font-weight:500}


/* == ENTRY-2 (ADR-M224): the way back in ================================
   The password reset wears the SAME split as the way in (.entry, the pitch
   panel, the 360px column), so the door and the room behind it are one
   screen family and this slot owes two classes, not a page.

   NO BACKTICK anywhere in this file, comments included: the sheet is one
   template literal and a stray one ends it two hundred lines away. == */
/* The Password label and the way out of it, on one line, where the artboard
   draws them. The link sits in the DOM inside this row, so the keyboard
   reaches it where the eye does. ENTRY-1 tried the other arrangement (named
   grid areas, so the DOM could keep the link after the button) and it left
   empty rows behind every time the password was hidden. */
.entry-pwrow{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
/* When an address turns out to belong to a company that signs in its own way,
   the password field goes, and the way back to a password goes with it. The
   last compound of this selector is not a bare class, so it is a second
   SELECTOR and never a second geometry for .entry-pwrow. */
.entry-pwrow:has(> .label.hidden){display:none}
/* Quiet, one line, never a button: the primary on this view is Sign in. */
.entry-forgot{font-size:var(--t-small);color:var(--fg-2);text-decoration:underline;text-decoration-color:var(--line-2);text-underline-offset:3px;white-space:nowrap}
.entry-forgot:hover{color:var(--fg-1)}
/* The reset page's answer takes the form's place rather than sitting under
   it, so there is nothing left to press a second time. This is the line that
   follows the answer: what to do if nothing arrives. */
.entry-after{margin-top:16px;color:var(--fg-3);font-size:var(--t-small);line-height:1.5}


/* == INTEGRITY-1 (ADR-M225): the File integrity card on the Security tab ==
   Three classes, and no fourth. The card is otherwise the system's own card,
   notice, pill and hint; what it needs that nothing else does is a LIST OF
   FILE PATHS, and a path is machine truth that can be a hundred characters
   long and must not push the card sideways on a phone.

   The shape is deliberately .protect-row's, one card up, rather than a second
   geometry for the same idea: two lists on one tab that line up differently
   read as two designs.

   NO BACKTICK anywhere in this file, comments included: the sheet is one
   template literal and a stray one ends it two hundred lines away. == */
.integrity-list{margin-top:12px;margin-bottom:14px}
/* The three lines under a verdict (what is missing, what the plugins said,
   what moved under wp-content) are three separate FACTS, and set solid they
   read as one paragraph nobody finishes. They get the rhythm of a list
   without being one: a list would promise the reader items that can be
   counted, and these are sentences. */
.integrity-notes > p{margin-top:8px}
.integrity-notes > p:first-child{margin-top:12px}
/* The path and what is wrong with it. The path column may shrink to nothing
   before the row wraps, which is what minmax(0,1fr) is for: without the 0 a
   grid track refuses to go under its content's intrinsic width and a long
   path widens the whole card. */
.integrity-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 16px;align-items:baseline;padding:10px 0;border-top:1px solid var(--line-1)}
.integrity-list .integrity-row:first-child{border-top:0}
/* Mono for machine truth (Harbor). It ELLIPSISES rather than wrapping: a
   wrapped path reads as two paths, and the whole string is on the title
   attribute for anyone who needs it. */
.integrity-path{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--t-small)}
.integrity-why{font-size:var(--t-small);color:var(--fg-2);white-space:nowrap}
/* On a phone the two stack and the reason stops being a nowrap column. */
@media (max-width:560px){.integrity-row{grid-template-columns:minmax(0,1fr)}.integrity-why{white-space:normal}}

/* == COMPLIANCE-1 (ADR-M226): Settings > Data, the account page, and the
   retention sentence.

   NO BACKTICK anywhere in this block, comments included: the sheet is one
   template literal and a stray one ends it two hundred lines away (GOTCHAS
   §WORK-1, said there for the third time). == */
/* The three dials. They ride .filter-grid, and this only widens the column
   minimum: a number field with "1,000 to 50,000" under it wraps to two lines
   at the 150px the filter row uses, and a range that wraps reads as a second
   field. One property, so it can never be a second geometry for .filter-grid
   in the way sheet-collisions means. */
.retention-grid{grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}
/* The workspaces on the account page: one row per membership, the role and the
   figures on the right, and the blocked ones carrying their own way out. It is
   .ws-rows and not .rows because .row is the system's own primitive with a
   20px status lane in it (GOTCHAS §WORK-1), and nothing here has a status. */
.ws-rows{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:8px}
.ws-rows li{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;padding:10px 12px;border:1px solid var(--line-1);border-radius:var(--r-ctl);background:var(--bg-2)}
.ws-rows .ws-name{font-weight:500;color:var(--fg-1)}
.ws-rows .ws-tail{margin-left:auto;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
/* A workspace this person alone owns: the one thing standing between them and
   deleting their account, so it is marked rather than left to be counted. The
   modifier is on the element itself, which is the shape sheet-collisions asks
   for. */
.ws-rows li.blocking{border-color:var(--amber);background:var(--amber-soft)}
/* The account page's own lead figures: the address and what it is in, side by
   side above the danger. */
.acct-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:0}

/* CONTENT-1 (ADR-M227): the Content view under Manage, and revisions. */

/* The search box and its button on one line, the filters under it. */
.cnt-search{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:14px 0 10px}
.cnt-search .input{flex:1 1 260px;min-width:0}
/* One row of filters. They are LINKS and not a select: the filter is in the
   address, so it survives a reload, a bookmark and the redirect after a press. */
.cnt-filters{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:8px}
.cnt-chip{display:inline-flex;align-items:center;height:26px;padding:0 10px;border-radius:var(--r-pill);border:1px solid var(--line-2);color:var(--fg-2);font-size:var(--t-small);font-weight:500;white-space:nowrap;text-decoration:none}
.cnt-chip:hover{color:var(--fg-1)}
/* The chosen one, exactly the way .subtabs a.here reads: filled, and the
   border painted the fill so the shape does not gain an outline nothing else
   in the row has. */
.cnt-chip.here{background:var(--bg-3);border-color:var(--bg-3);color:var(--fg-1)}

/* The list, and the bar that acts on what is ticked in it. */
.cnt-list{margin-top:14px;border:1px solid var(--line-1);border-radius:var(--r-ctl);overflow:hidden}
.cnt-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:10px 12px;background:var(--bg-2);border-bottom:1px solid var(--line-1);margin:0}
.cnt-bar-words{font-size:var(--t-small);font-weight:500;color:var(--fg-1)}
.cnt-bar .hint{flex:1 1 100%;margin:0}
/* The convenience, and only where the selector exists to carry it. Without
   :has() the bar simply stays where it is and keeps working. */
@supports selector(:has(*)){
  .cnt-list:not(:has(.cnt-tick:checked)) .cnt-bar{display:none}
}
.cnt-rows{list-style:none;margin:0;padding:0}
.cnt-row{display:grid;grid-template-columns:28px minmax(0,1fr) auto auto;align-items:center;gap:12px;padding:10px 12px;border-top:1px solid var(--line-1)}
.cnt-rows > .cnt-row:first-child{border-top:0}
.cnt-pick{display:flex;align-items:center;justify-content:center;margin:0}
.cnt-tick{margin:0}
.cnt-what{min-width:0}
.cnt-title{font-size:var(--t-body);font-weight:500;color:var(--fg-1);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cnt-title a{color:inherit;text-decoration:none}
.cnt-title a:hover{text-decoration:underline;text-underline-offset:3px}
/* The facts under a title: quiet, small, and separated by rule rather than by
   a character somebody has to read. */
.cnt-facts{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:2px;font-size:var(--t-small);color:var(--fg-3)}
.cnt-facts .mono{font-family:var(--font-mono)}
/* The status, in a COLUMN. It is a fixed width and not auto, because four of
   the six statuses carry a raw-status chip beside the pill and two do not, so
   an auto column made the pills start at a different place on nearly every
   row. Found by looking at the picture; the width is the widest pair the
   vocabulary can produce (a pill plus a chip) with room to breathe. */
.cnt-state{display:flex;align-items:center;gap:6px;flex:none;width:184px;justify-content:flex-start}
.cnt-acts{display:flex;align-items:center;gap:6px;flex-wrap:wrap;justify-content:flex-end;flex:none}
.cnt-acts form{margin:0}
.cnt-pager{display:flex;align-items:center;gap:12px;margin-top:12px}
.cnt-pager .hint{margin:0}

/* The revisions view: the same row, with the moment leading it. */
.cnt-rev-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:12px 0}
.cnt-revs{list-style:none;margin:14px 0 0;padding:0;border:1px solid var(--line-1);border-radius:var(--r-ctl);overflow:hidden}
.cnt-rev{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;padding:10px 12px;border-top:1px solid var(--line-1)}
.cnt-revs > .cnt-rev:first-child{border-top:0;background:var(--bg-2)}
.cnt-rev-what{min-width:0}
.cnt-rev-when{font-size:var(--t-body);font-weight:500;color:var(--fg-1);font-variant-numeric:tabular-nums}
.cnt-rev-when .hint{display:inline;margin:0}

/* A phone: the state and the buttons go under the title rather than squeezing
   it to nothing, which is the shape .ops-person keeps one file over. */
@media (max-width:720px){
  .cnt-row{grid-template-columns:28px minmax(0,1fr);row-gap:8px}
  /* On a phone there is no column to line up with: it is one thing under the
     title, and a fixed width would only push the chip off the screen. */
  .cnt-state{grid-column:2;width:auto}
  .cnt-acts{grid-column:2;justify-content:flex-start}
  .cnt-rev{grid-template-columns:minmax(0,1fr);row-gap:8px}
  .cnt-rev .cnt-acts{justify-content:flex-start}
}


/* == POLISH-2 (ADR-M228): the last pass before the product is shown =====
   NO BACKTICK anywhere in this block, comments included. == */
/* Finding 19: seven tabs do not fit 343px however they are padded, and a
   strip that scrolls with a fade is a sign a thumb misses. Under 480 the
   strip WRAPS, so every tab is on the screen; between 480 and 820 it still
   scrolls with the fade and the active tab scrolled into view. */
@media (max-width:480px){
  .tabs{flex-wrap:wrap;overflow-x:visible}
  .tabs-wrap::after{display:none}
}
/* Finding 20: the confirm's own verb repeats the thing's name ("Revoke
   northgate-community-allotments-association.org.uk"), and a button that
   never wraps pushed the no-script confirm 130px past a phone's edge. Inside
   a confirm the danger button may wrap. Written with :is() so the last
   compound is not a bare class and sheet-collisions.test.ts does not read it
   as a second geometry for .btn-danger. */
dialog :is(.btn-danger),.dialog :is(.btn-danger),.confirm-card :is(.btn-danger){white-space:normal;height:auto;min-height:var(--ctl);padding:6px 12px;line-height:1.3;text-align:left;overflow-wrap:anywhere}
/* Finding 13: a disabled control's reason stays on the button's line inside a table cell (the cell scrolls in its box; a wrapped reason read as a second row). */
.cell-acts .with-reason{flex-wrap:nowrap}
/* Finding 11: a site that has never said its name is titled by its address, which is machine truth and wears the machine face. Colour and face only, never geometry. */
.head h1.host{font-family:var(--font-mono);font-size:var(--t-section);font-weight:500}
/* The one table (ADR-M228 section 5, harbor.ts portalTable). At a phone's width
   the first column, which is the row's identity, stays put while the rest
   scrolls under it (CONSOLE-2's rule), so a wide table never loses its names.
   A line, not a shadow, marks the seam. */
@media (max-width:820px){
  table.pt th:first-child,table.pt td:first-child{position:sticky;left:0;z-index:1;background:var(--bg-1);border-right:1px solid var(--line-1)}
  table.pt tbody tr:hover td:first-child{background:var(--bg-2)}
}
/* Words for a screen reader only: the actions column's heading, the skip link
   until it is focused. */
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* Finding 20: the component gallery's class-name chips are the one place a
   tag is a sentence long; a tag that never wraps pushed that page 219px past
   the edge. A modifier on the element itself, which the collision test allows. */
.tag.wrap{white-space:normal;height:auto;min-height:20px;padding:2px 6px;line-height:1.5;overflow-wrap:anywhere}


/* --- WAVE-12 SLOT: LOOSE-ENDS-1 (the Health tab's certificate, email and overdue-task lines; the Media section; the two job kinds' screens). Your classes go HERE. --- */

/* The certificate card's head: the pill and the countdown on one line, the
   countdown in tabular figures because it is a number a person compares
   against the same number on another site's page. */
.cert-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px}
.cert-days{font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-2)}
.cert-days.cert-soon{color:var(--amber)}
.cert-days.cert-gone{color:var(--red)}

/* Scheduled tasks that are overdue, listed on demand. A row is the name, how
   late it is and its schedule, with the run-now button at the end - the shape
   the protect rows already use, so the tab reads as one page. */
.cron-list{display:flex;flex-direction:column}
.cron-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0;border-top:1px solid var(--line-2)}
.cron-row:first-child{border-top:0}
.cron-row .hook{font-family:var(--font-mono);font-size:var(--t-mono);overflow-wrap:anywhere}
.cron-row .late{color:var(--amber);font-variant-numeric:tabular-nums}
.cron-row .when{color:var(--fg-3);font-size:var(--t-small)}
.cron-act{flex:none;display:flex;align-items:center;gap:8px}
@media (max-width:560px){.cron-row{flex-direction:column;align-items:flex-start;gap:8px}}

/* The database cleanup's counting result: one block per site, with the shared
   portal table of kinds and counts inside it. The table is the system's own
   (harbor.ts::portalTable), so only what is specific to this one is here. */
.clean-site{border-top:1px solid var(--line-1);padding-top:14px;margin-top:14px}
.clean-site:first-child{border-top:0;padding-top:0;margin-top:0}
.clean-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.clean-head .nm{font-weight:600}
.clean-head .total{font-family:var(--font-mono);font-size:var(--t-mono);color:var(--fg-2)}
.clean-kinds td .blurb{display:block;color:var(--fg-3);font-size:var(--t-small);max-width:64ch}
.clean-none{color:var(--fg-2)}

/* The confirm screen's own list of what will and will not happen, per site.
   Two columns of names, each under a heading that says what it is. */
.will-not{margin-top:14px;padding-top:12px;border-top:1px solid var(--line-1)}
.will-not .cap{font-size:var(--t-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);margin-bottom:6px}
.will-not ul{margin:0;padding-left:18px;color:var(--fg-2)}
.will-not li{padding:2px 0}
.will-not li .why{color:var(--fg-3)}


/* --- WAVE-12 SLOT: CLIENT-VIEW-1 (the client's own read-only pages) --- */

/* The shell, with no rail: the content column is the whole width. */
.client-main{min-height:100vh;display:flex;flex-direction:column}
.client-main>.content{flex:1}
/* The header has no class of its own: it is .top, with the agency's NAME where
   ReDock's wordmark would be and nothing else in it. A second class would be a
   second geometry for a bar that is deliberately the same bar. The agency's
   LOGO is not up there either: it lives in the band, where their colours are
   painted under it (harbor.ts::clientTopBar says why; both reasons were
   measured in a picture). */
/* A site's name and its address in one cell, the address on its own line.
   Without this the two run together as "Simply Agile Shopshop.simplyagile.com",
   which is the whole cell reading as one word. Found in a picture, and the
   census could not see it: both classes existed. */
.client-site{max-width:26ch}
.client-site > b{display:block;font-weight:600}
/* NOT overflow-wrap:anywhere. A domain has no spaces, so "anywhere" breaks it
   one letter per line in a narrow sticky column; the markup carries a wbr after
   each dot instead (pages/client.ts::hostWords), which is REPORT-2's own answer
   for the same shape on paper. */
.client-host{display:block;font-family:var(--font-mono);font-size:var(--t-small);color:var(--fg-2)}
/* The one ReDock line: small, quiet, under everything, and not a link. LEFT,
   with the page's own gutter, because the content column is left-aligned at
   every measure and a centred foot under it floats in empty space at 1440. */
.client-made{padding:24px var(--gutter) 32px;color:var(--fg-3);font-size:var(--t-label)}
/* The months a client may open: a plain list that wraps, not a table. */
.client-months{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px 20px}
.client-months li{font-size:var(--t-body)}
/* An ordinary bulleted list inside a card. The one place this product draws one. */
.client-list{margin:6px 0 0 0;padding-left:18px;color:var(--fg-2);font-size:var(--t-body)}
.client-list li{margin:0 0 4px 0}
/* The per-site lines under a job's own name, in the What was done table. */
.client-lines{display:block;margin-top:4px;color:var(--fg-3);font-size:var(--t-small)}
/* One site that needs attention, with its reasons under it. */
.client-attn{margin:0 0 12px 0}
.client-attn:last-child{margin-bottom:0}
/* A colour is a claim and it belongs on the clause making it (REPORT-2): the
   days down are the warning, not the checks beside them. */
.client-down{color:var(--amber)}
/* How long a site has been in the state its pill says. */
.client-since{display:block;margin-top:3px;font-size:var(--t-label);font-variant-numeric:tabular-nums}
/* The chooser's own link, when somebody is a client of more than one agency. */
.client-pick{font-weight:600}
/* The report's own foot: who prepared it, when, and against which standard. */
.client-prepared{margin-top:24px;font-size:var(--t-label)}
/* The one control at the foot of a client page, away from everything about the
   sites: quiet, right-aligned, and gone from the printed page. */
.client-foot-acts{margin-top:32px;display:flex;justify-content:flex-end}
@media print{
  /* A client pressing Save as PDF gets the document and not the furniture. The
     shell's own print block already hides the header and the toast region;
     these are this page's own two. */
  .client-made,.client-foot-acts{display:none}
  /* The band is the whole point of a white label, so it prints in colour. */
  .brandbar{print-color-adjust:exact;-webkit-print-color-adjust:exact}
}
@media (max-width:560px){
  .client-months{gap:6px 14px}
}


