/* ============================================================================
   SmartHost Managed DNS — stylesheet
   ----------------------------------------------------------------------------
   The SmartHost design system (docs/BRAND-SYSTEM.txt): a white page, Atlantic
   type, action teal for buttons / links / focus / selected state, mist for quiet
   bands and selected fill, hairline dividers, one restrained apricot accent per
   view (here: the delegation panel, on Atlantic), error red for invalid input
   only. Bricolage Grotesque for headings and numerals, Source Sans 3 for body,
   forms and controls — both SELF-HOSTED from /assets/fonts (OFL; LICENSE beside
   them) so the page still runs under Content-Security-Policy: default-src 'self'.
   Every url() in this file is a same-origin /assets/ path; nothing is fetched
   from anywhere else. No gradients, shadows, arcs or illustrations; radii 10px
   on controls, 12–14px on panels, nothing rounder; targets at least 44px, main
   controls 52px. The logo teal (#379682) lives only in the logo asset and is
   never used here. There is no dark theme: the system is a bright page.
   The editor section styles templates/partials/record-form.php and the staged-
   changes list assets/app.js builds (diff rows: add / edit / remove / merge).
   2026-09-08 UX pass: one workspace, not stacked panels. The zone page is a
   title, a meta line, one toolbar and ONE record table that scrolls inside
   itself with sticky group and column headers; a drawer opens as the second
   column and the table never moves. Values are one truncated monospace line
   that opens on click or focus; row actions are revealed by hover or focus and
   keep a 44px hit area through a pseudo-element, never a smaller control.
   ============================================================================ */

/* ---------- fonts (self-hosted, latin subset, variable weight) ---------- */
@font-face{font-family:"Bricolage Grotesque";font-style:normal;font-weight:500 600;font-display:swap;src:url(/assets/fonts/bricolage-grotesque-latin.woff2) format("woff2");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:"Source Sans 3";font-style:normal;font-weight:400 600;font-display:swap;src:url(/assets/fonts/source-sans-3-latin.woff2) format("woff2");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}

/* ---------- tokens ---------- */
:root{
  --white:#FFFFFF;
  --atlantic:#063B46;        /* all type, dark bands */
  --atlantic-deep:#052F38;   /* the footer */
  --on-atlantic:#BEDBD4;     /* body copy on an Atlantic band; headings there are white */
  --action:#087F73;          /* buttons, links, focus, selected state */
  --action-hover:#066B61;
  --mist:#E9F5F1;            /* quiet bands, selected fill */
  --divider:#DCEBE6;         /* every rule and border */
  --control:#C6E0D8;         /* control edges */
  --apricot:#FFBD8A;         /* one accent per view, never body text on white */
  --muted:#5A7378;           /* secondary copy */
  --error:#B4432B;           /* invalid input only */
  --radius-control:10px; --radius-panel:12px; --radius-panel-lg:14px;
  /* record-type badge families (2026-09-09). Muted, low-chroma tints derived from the palette so a
     type reads as a category at a glance and none of them competes with the action teal. Every pair
     clears 5.5:1. */
  --t-addr-bg:#E4F1EC; --t-addr-fg:#0A5A50;    /* A / AAAA               */
  --t-cname-bg:#EDEBF4; --t-cname-fg:#4B4477;  /* CNAME / ALIAS          */
  --t-mx-bg:#E7EEF6; --t-mx-fg:#26536F;        /* MX                     */
  --t-txt-bg:#F0EFEA; --t-txt-fg:#5B5548;      /* TXT                    */
  --t-sec-bg:#FBEEE0; --t-sec-fg:#8A5320;      /* CAA / TLSA / SSHFP     */
  --t-svc-bg:#EAEFEE; --t-svc-fg:#3F5A5E;      /* SRV / NS / PTR / HTTPS */
  /* the record row pitch, and the two elevations the slide-over needs (nothing else is raised) */
  --row-h:44px;
  --lift-sm:0 1px 2px rgba(6,59,70,.06);
  --lift-lg:-14px 0 40px rgba(6,59,70,.18);
  --lift-modal:0 18px 48px rgba(6,59,70,.22);
  --sans:"Source Sans 3",system-ui,-apple-system,"Segoe UI",sans-serif;
  --display:"Bricolage Grotesque",system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
}

/* ---------- base ---------- */
*{box-sizing:border-box}
html{color-scheme:light;background:var(--white)}
body{margin:0;background:var(--white);color:var(--atlantic);font-family:var(--sans);font-size:17px;line-height:1.55;-webkit-font-smoothing:antialiased;min-height:100vh;display:flex;flex-direction:column}
@media (min-width:760px){body{font-size:18px}}
button,input,select,textarea{font:inherit;color:inherit}
a{color:var(--action);text-decoration:none}
a:hover{text-decoration:underline}
:focus-visible{outline:3px solid var(--action);outline-offset:2px}
h1,h2,h3{font-family:var(--display);font-weight:600;color:var(--atlantic);margin:0}
h1{font-size:clamp(28px,2.2vw + 18px,40px);line-height:1.12;letter-spacing:-.024em}
h2{font-size:clamp(19px,.8vw + 15px,22px);line-height:1.2;letter-spacing:-.022em}
h3{font-size:19px;line-height:1.2;letter-spacing:-.022em}
code,.mono{font-family:var(--mono)}
code{font-size:.94em}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip{position:absolute;left:-999px;top:12px;background:var(--white);color:var(--action);font-weight:600;padding:12px 18px;border:1.5px solid var(--action);border-radius:var(--radius-control);z-index:100}
.skip:focus{left:12px}
.muted{color:var(--muted)}
.small{font-size:15px}
.wrap{width:100%;max-width:1320px;margin:0 auto;padding:0 28px}
[hidden]{display:none !important}
.js-only{display:none}
html.js .js-only{display:inline-flex}
html.js div.js-only{display:flex}
/* Without the script the page is the read-only view: a control that does nothing is not shown at
   all, whatever a later rule says about its own class. */
html:not(.js) .js-only{display:none !important}
html:not(.js) .rr .c-sel,html:not(.js) .rr .c-act{width:0;min-width:0;padding:0}

/* ---------- header: 80px white sticky bar on a hairline, the 34px colour logo ---------- */
.topbar{position:sticky;top:0;z-index:20;background:var(--white);border-bottom:1px solid var(--divider)}
.topbar-in{display:flex;align-items:center;gap:26px;min-height:80px}
.brand{display:flex;align-items:center;gap:26px;padding:8px 0;color:var(--atlantic)}
.brand:hover{text-decoration:none}
.brand-logo{display:block;height:34px;width:auto}
.brand-product{font-family:var(--display);font-weight:500;font-size:19px;line-height:34px;letter-spacing:-.01em;color:var(--atlantic);padding-left:26px;border-left:1px solid var(--divider);white-space:nowrap}
.nav{margin-left:auto;display:flex;align-items:center;gap:6px;font-size:16px;font-weight:600}
.nav a{display:inline-flex;align-items:center;min-height:44px;padding:0 14px;border-radius:var(--radius-control);color:var(--atlantic)}
.nav a:hover{color:var(--action);background:var(--mist);text-decoration:none}
.nav .who{color:var(--muted);font-weight:400;max-width:28ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:0 10px}
.nav .logout{color:var(--action);border:1.5px solid var(--action);padding:0 20px;margin-left:6px}
.nav .logout:hover{background:var(--mist)}
main.wrap{flex:1;padding-top:22px;padding-bottom:32px}

/* ---------- footer: deep Atlantic band, the white logo at 32px ---------- */
.foot{background:var(--atlantic-deep);color:var(--on-atlantic);padding:14px 0;font-size:15px}
.foot-in{display:flex;align-items:center;gap:20px;flex-wrap:wrap}
.foot-logo{display:block;height:24px;width:auto}
.foot-text{margin:0;flex:1 1 280px}
.foot-links{display:flex;gap:8px;margin-left:auto}
.foot a{display:inline-flex;align-items:center;min-height:44px;padding:0 10px;border-radius:var(--radius-control);color:var(--white);font-weight:600}
.foot a:hover{text-decoration:underline}

/* ---------- page head ---------- */
.crumbs{margin:0 0 8px;color:var(--muted);font-size:14px;display:flex;gap:8px;align-items:center;flex-wrap:wrap;min-height:22px}
.crumbs a{position:relative;display:inline-flex;align-items:center;min-height:22px}
.crumbs a::after{content:"";position:absolute;left:-6px;right:-6px;top:-11px;bottom:-11px}
/* The head is a title and one meta line, nothing more: the state of the zone belongs beside its
   name, not in a panel of its own (operator decision 2026-09-08). */
.page-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px 24px;flex-wrap:wrap;margin:0 0 14px}
.page-head h1{margin:0 0 2px}
.head-main{min-width:0;flex:1 1 420px}
.lede{margin:0;font-size:16px;line-height:1.45;color:var(--muted);max-width:none}
.lede .muted{color:var(--muted)}
.zone-meta{color:var(--atlantic);font-weight:600}
.zone-meta .muted{font-weight:400}
.meta-sep{color:var(--divider)}
h1{font-size:clamp(24px,1.5vw + 16px,30px)}
.zone-title{font-family:var(--display);word-break:break-all}
/* one toolbar row: the filters on the left, the drawer controls on the right */
.toolbar,.actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 12px}
.toolbar .spacer{flex:1 1 auto}
.filter{align-items:center}
.filter input,.filter select,.admin-search input{height:44px;padding:0 12px;border-radius:var(--radius-control);border:1px solid var(--control);background:var(--white);color:var(--atlantic);font-size:15px}
.filter input{width:min(280px,60vw)}
.typefilter select{font-family:var(--sans);cursor:pointer}

/* ---------- buttons: primary (teal fill), secondary (white, teal edge), quiet action, unavailable ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:48px;padding:0 20px;border-radius:var(--radius-control);border:1.5px solid var(--action);background:var(--action);color:var(--white);cursor:pointer;font-size:16px;font-weight:600;line-height:1.2;white-space:nowrap}
.btn:hover{background:var(--action-hover);border-color:var(--action-hover);color:var(--white);text-decoration:none}
.btn-cta{background:var(--action);border-color:var(--action);color:var(--white)}   /* the system has one primary colour: teal */
.btn-ghost{background:var(--white);color:var(--action);border-color:var(--action)}
.btn-ghost:hover{background:var(--mist);color:var(--action);border-color:var(--action)}
.btn-sm{min-height:44px;padding:0 14px;font-size:15px}
/* quiet: the toolbar's default. A hairline edge and Atlantic type, so the one filled control on
   the page (Add record) is the only thing that shouts. */
.btn-quiet{background:var(--white);color:var(--atlantic);border:1px solid var(--control);font-weight:600}
.btn-quiet:hover{background:var(--mist);color:var(--action);border-color:var(--action)}
.btn:disabled,.btn:disabled:hover,.rowbtn:disabled,.copy:disabled{background:var(--mist);border-color:var(--divider);color:var(--muted);cursor:default}
.copy,.rowbtn{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:0 12px;border-radius:var(--radius-control);border:1.5px solid transparent;background:transparent;color:var(--action);font-size:15px;font-weight:600;cursor:pointer;white-space:nowrap}
.copy:hover,.rowbtn:hover{background:var(--mist);text-decoration:none}
.copy.copied{border-color:var(--action);background:var(--mist)}
.rowbtn-danger{color:var(--muted)}
.rowbtn-danger:hover{color:var(--atlantic);background:var(--mist)}
.btn-x{width:44px;height:44px;border-radius:var(--radius-control);border:1px solid var(--control);background:var(--white);color:var(--atlantic);font-size:22px;line-height:1;cursor:pointer}
.btn-x:hover{background:var(--mist);border-color:var(--action);color:var(--action)}
/* the row action: a 20px line-art glyph in a 46x34 box whose ::after gives it the brand's 44px hit
   area. Its accessible name is the .sr text beside the icon, so the glyph is aria-hidden. */
.icobtn{position:relative;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:46px;height:40px;padding:0;border:1.5px solid transparent;border-radius:8px;background:transparent;color:var(--action);cursor:pointer}
.icobtn::after{content:"";position:absolute;left:0;right:0;top:-2px;bottom:-3px}
.icobtn:hover{background:var(--mist)}
.icobtn .ico{display:block;width:20px;height:20px}
.icobtn-danger{color:var(--muted)}
.icobtn-danger:hover{background:var(--mist);color:var(--error)}
.icobtn.copied{border-color:var(--action);background:var(--mist)}

/* ---------- panels / notices (hairline borders, flat tints, no elevation) ---------- */
.card{background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel);padding:16px 18px}
.empty{background:var(--mist);border-color:transparent;color:var(--atlantic)}
.empty p{margin:4px 0;max-width:78ch;font-size:15px}
.notice{border-radius:var(--radius-panel);padding:14px 18px;margin:0 0 14px;border:1px solid var(--divider);background:var(--white)}
.notice p{margin:6px 0 0;max-width:78ch;font-size:15px}
.notice-title{margin:0}
.notice-warn{background:var(--mist)}
.notice-ok{background:var(--mist);border-color:var(--action)}
.notice-ok .notice-title{color:var(--action)}
.notice-error{border:1.5px solid var(--error)}
.notice-error .notice-title{color:var(--error)}
.signin{border-color:var(--divider)}
.notice-state code{background:var(--mist);padding:2px 8px;border-radius:6px;border:1px solid var(--divider)}
.notice-list{margin:6px 0 0;padding-left:20px}
.notice-list li+li{margin-top:4px}
.notice-actions{margin-top:16px}
.notice:focus{outline:3px solid var(--action);outline-offset:2px}
/* the delegation panel (delegated elsewhere / not live at the registry): an Atlantic band with the page's one apricot accent (7.5:1 on Atlantic) */
.notice-delegation{background:var(--atlantic);border-color:var(--atlantic);border-left:6px solid var(--apricot);color:var(--on-atlantic)}
.notice-delegation .notice-title,.notice-delegation .notice-state,.notice-delegation .notice-list{color:var(--white)}
.notice-delegation .notice-state code{background:transparent;border-color:var(--apricot);color:var(--apricot)}
.notice-delegation .notice-list{font-size:15px;display:flex;gap:6px 16px;flex-wrap:wrap;list-style:none;padding:0}
.notice-delegation .notice-title{font-size:17px}
.notice-delegation a{color:var(--white);text-decoration:underline}
/* ---- "this zone cannot be saved" (ticket 3T4-VSY-SV24) ----
   The one apricot accent of a zone page that carries it: the same Atlantic band as the delegation
   panel, because it is the same class of statement - something outside the record list is stopping
   the page from doing its job - and it outranks the delegation note when both appear. The action on
   it is apricot-filled (Atlantic type on apricot clears 9:1) rather than teal, so the one thing that
   can be pressed on a dark band is unmistakably the accent. */
.notice-zonecheck{background:var(--atlantic);border-color:var(--atlantic);border-left:6px solid var(--apricot);color:var(--on-atlantic);margin:0 0 16px}
.notice-zonecheck .notice-title{color:var(--white);font-size:18px}
.notice-zonecheck p{color:var(--on-atlantic);max-width:78ch}
.notice-zonecheck .notice-state{color:var(--white);margin-top:12px;font-weight:600}
.notice-zonecheck .notice-list{margin:6px 0 0;padding-left:20px;color:var(--white)}
.notice-zonecheck .zc-raw{list-style:none;padding:0;display:flex;flex-direction:column;gap:6px}
.notice-zonecheck .zc-raw li{font-size:14px;color:var(--apricot);background:rgba(255,189,138,.10);border:1px solid rgba(255,189,138,.45);border-radius:8px;padding:6px 10px;overflow-wrap:anywhere}
.notice-zonecheck .notice-actions{margin-top:16px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.notice-zonecheck .zc-note{font-size:14px;color:var(--on-atlantic)}
.btn-fix{background:var(--apricot);border-color:var(--apricot);color:var(--atlantic)}
.btn-fix:hover{background:var(--white);border-color:var(--white);color:var(--atlantic);text-decoration:none}
.notice-zonecheck .btn-fix:focus-visible{outline:3px solid var(--white);outline-offset:2px}
/* Wide enough for two columns: the statement keeps a readable measure on the left and the one
   action sits beside the headline rather than at the foot of a half-empty band. */
@media (min-width:900px){
  .notice-zonecheck{display:grid;grid-template-columns:minmax(0,78ch) auto;column-gap:32px;align-items:start}
  .notice-zonecheck > *{grid-column:1}
  /* spans every row of the statement and sits at its top, so the action never stretches the
     headline's row and the paragraphs stay one after another */
  .notice-zonecheck > .notice-actions{grid-column:2;grid-row:1 / span 30;align-self:start;margin-top:0;flex-direction:column;align-items:flex-start;gap:8px;max-width:26ch}
}

/* ---- the fix drawer ----
   ☠️ A LIST, NOT THE RECORD TABLE: .rr hides its TTL column below 760px, and the before/after TTL
   is the entire content of this panel. Three columns while there is room, stacked when there is
   not, and the two TTLs are visible at every width. */
.ttlfix-rows{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;max-height:min(46vh,420px);overflow:auto}
.ttlfix-row{display:grid;grid-template-columns:1fr;gap:4px 18px;padding:10px 14px;border:1px solid var(--divider);border-radius:var(--radius-panel);background:var(--mist)}
.ttlfix-row p{margin:0;font-size:15px;display:flex;align-items:center;gap:8px;min-width:0}
.ttlfix-id .name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ttlfix .ttl-lbl{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);white-space:nowrap}
.ttlfix .ttl{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:15px}
.ttlfix .ttl-from{color:var(--muted);text-decoration:line-through}
.ttlfix .ttl-to{color:var(--action);font-weight:700}
.ttlfix .ttlfix-val .val{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
@media (min-width:640px){
  .ttlfix-row{grid-template-columns:minmax(0,1fr) auto;align-items:center}
  .ttlfix-row .ttlfix-val{grid-column:1 / -1}
}
@media (max-width:520px){
  .ttlfix-rows{max-height:none}
  .notice-zonecheck .notice-actions .btn{width:100%}
}

/* live on SmartHost: one quiet line on a mist band; not checked: one muted line, no panel */
/* the delegation state is one compact line under the zone name, not a band across the page */
.delegation{margin:4px 0 0;font-size:15px;max-width:none;line-height:1.4}
.delegation-live{background:var(--mist);border-radius:8px;padding:3px 10px;color:var(--atlantic);display:inline-block}
.delegation-live strong{color:var(--action)}
.delegation-unknown{color:var(--muted);font-size:14px}

/* ---------- tables: one bordered card, sticky headers, hairline rules ----------
   Every list on the site is the same object: a white card on a hairline border with a mist header
   band, a body that scrolls inside itself, and a mist foot band. (2026-09-09: the pattern proved on
   dns.securehost.ie, in the SmartHost palette.) */
.tablewrap{background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel);overflow:hidden;box-shadow:var(--lift-sm)}
.scroller{overflow:auto;max-height:min(62vh,640px);min-height:120px}
table{width:100%;border-collapse:separate;border-spacing:0}
thead th{background:var(--mist);text-align:left;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);padding:0 12px;height:38px;border-bottom:1px solid var(--divider);white-space:nowrap;user-select:none}
tbody td{padding:0 12px;border-bottom:1px solid var(--divider);vertical-align:middle;font-size:15px;height:var(--row-h)}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover td{background:var(--mist)}
.tfoot{display:flex;align-items:center;gap:16px;padding:10px;border-top:1px solid var(--divider);font-size:14px;color:var(--muted);flex-wrap:wrap}
.tfoot-note{margin:10px 0 0;font-size:13px;line-height:1.45}
.tablewrap > .tfoot-note{margin:0;padding:9px 14px;border-top:1px solid var(--divider);background:var(--mist)}

/* ---------- the domains list: a list of NAMES in the same card ----------
   The name is the link. On a wide page the names flow into as many columns as fit, so 30 domains
   are one screen rather than 30 rows with a filled button and a gulf of white beside each. */
.zones{table-layout:fixed;display:block}
.zones thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.zones tbody{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));column-gap:0}
#admin-zones tbody{grid-template-columns:repeat(auto-fill,minmax(400px,1fr))}
.zones tr{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;box-shadow:inset 0 -1px 0 var(--divider),inset -1px 0 0 var(--divider)}
.zones td{display:block;border:0;padding:0;height:auto;background:none}
.zones tr:hover td{background:none}
.zones tr:hover,.zones tr:focus-within{background:var(--mist)}
.zone-link{font-size:15px;font-weight:600;display:flex;align-items:center;min-height:44px;padding:0 14px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zones .c-act{text-align:right;white-space:nowrap;padding-right:6px}
/* a quiet row action, revealed by hover or keyboard focus; always in the tab order */
.rowlink{display:inline-flex;align-items:center;justify-content:center;min-height:44px;min-width:44px;padding:0 10px;font-size:14px;font-weight:600;opacity:0;border-radius:8px}
tr:hover .rowlink,tr:focus-within .rowlink,.rowlink:focus-visible{opacity:1}

/* ---------- the records workspace ----------
   The record table IS the page and never moves. Every tool opens in the fixed slide-over #drawer
   (see "the slide-over" below), so nothing here reflows when a panel opens. */
.editor{display:flex;flex-direction:column;gap:14px;margin:0}
.editor:empty{display:none}
.editor > [hidden]{display:none !important}
.editor .notice{margin:0}

/* the table region scrolls inside itself, so the page stays one screen tall however many
   records a zone carries, and the group and column headers stay in view while it does */
#records{background:var(--white)}
.groups{display:block}
.group{background:var(--white)}
.group + .group{border-top:1px solid var(--divider)}
.tablescroll{overflow:visible;background:transparent}
.group-head{display:flex;align-items:center;gap:10px;margin:0;padding:0 12px;height:32px;position:sticky;top:0;z-index:4;background:var(--mist);border-bottom:1px solid var(--divider)}
.group-head h2{display:flex;align-items:center;gap:8px;font-family:var(--sans);font-size:14px;font-weight:600;letter-spacing:0;color:var(--atlantic);white-space:nowrap}
.group-label{font-size:13px;font-weight:400;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.group-count{margin-left:auto;font-family:var(--mono);font-weight:600;font-size:13px;color:var(--muted);font-variant-numeric:tabular-nums;flex:0 0 auto}
#records .rr thead th{position:sticky;top:32px;z-index:3;height:44px;background:var(--white)}
.group-system .rr thead th{background:var(--mist)}

/* sortable Name / Type / TTL. The control is built by the script (it does nothing without it), fills
   its cell, and its ::after carries the 44px hit area past the cell's own 44px. Name and TTL sort the
   rows inside every group; Type reorders the groups themselves, which is what a type sort means when
   the table is grouped by type. A third click restores zone-file order. */
#records .rr thead th.sortable{padding:0}
.th-sort{position:relative;display:flex;align-items:center;gap:6px;width:100%;height:44px;padding:0 12px;margin:0;border:0;background:transparent;font-family:inherit;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:inherit;text-align:left;cursor:pointer}
.th-sort::after{content:"";position:absolute;left:0;right:0;top:-3px;bottom:-3px}
.th-sort:hover{color:var(--action)}
.th-sort .arrow{font-size:9px;line-height:1;visibility:hidden}
th[aria-sort="ascending"] .th-sort,th[aria-sort="descending"] .th-sort{color:var(--action)}
th[aria-sort="ascending"] .th-sort .arrow,th[aria-sort="descending"] .th-sort .arrow{visibility:visible}
.rr .c-ttl .th-sort{justify-content:flex-end}

/* fixed columns: a value can never widen the table, so the page never scrolls sideways */
.rr{table-layout:fixed}
.rr .c-sel{width:44px;padding-left:5px;padding-right:0}
.rr .c-name{width:250px;max-width:250px}
.rr .c-type{width:84px}
.rr .c-ttl{width:112px;text-align:right}
.rr .c-act{width:auto;min-width:56px;text-align:right;white-space:nowrap}
.rr .c-val{overflow:hidden;max-width:1px}
.valwrap{display:flex;align-items:center;gap:8px;min-width:0}
.name{font-family:var(--mono);font-size:13px;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.name .rel{color:var(--atlantic);font-weight:600}
.name .rel.apex{font-weight:700}
.name .sfx{color:var(--muted)}
.ttl{font-family:var(--mono);font-size:13px;font-variant-numeric:tabular-nums;color:var(--muted)}
/* ONE line, monospace, ellipsised. A DKIM key is a row like any other; click it (or tab into the
   row) to read it in full; click anywhere else in the row to open it in the drawer. */
.val{font-family:var(--mono);font-size:13px;color:var(--atlantic);display:block;flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}
.val-txt{color:var(--atlantic)}
tr[data-open] .val,.rr tbody tr:focus-within .val{white-space:pre-wrap;word-break:break-all;overflow:visible;cursor:auto}
tr[data-open] td,.rr tbody tr:focus-within td{height:auto;padding-top:6px;padding-bottom:6px}
.more{display:inline-block;flex:0 0 auto;font-family:var(--sans);font-size:12px;font-weight:600;color:var(--muted);background:var(--mist);padding:1px 7px;border-radius:6px;white-space:nowrap}
tr:hover .more{background:var(--white)}
/* the type badge, tinted by family so the eye sorts the table before it reads it */
.badge{display:inline-block;font-family:var(--mono);font-size:12px;font-weight:700;line-height:1.3;padding:2px 7px;border-radius:6px;letter-spacing:.02em;background:var(--mist);color:var(--atlantic)}
.t-A,.t-AAAA{background:var(--t-addr-bg);color:var(--t-addr-fg)}
.t-CNAME,.t-ALIAS{background:var(--t-cname-bg);color:var(--t-cname-fg)}
.t-MX{background:var(--t-mx-bg);color:var(--t-mx-fg)}
.t-TXT{background:var(--t-txt-bg);color:var(--t-txt-fg)}
.t-CAA,.t-TLSA,.t-SSHFP,.t-DS,.t-DNSKEY{background:var(--t-sec-bg);color:var(--t-sec-fg)}
.t-SRV,.t-NS,.t-PTR,.t-HTTPS,.t-SVCB,.t-NAPTR{background:var(--t-svc-bg);color:var(--t-svc-fg)}
.t-SOA,.t-other{background:var(--divider);color:var(--muted)}

/* the system-managed group (SOA, apex NS): the same list, visibly locked — muted ink, no hover, no actions */
.group-system{background:var(--mist)}
.group-system .group-head{background:var(--divider)}
.group-system .group-head h2{color:var(--muted)}
.group-system .tablescroll{background:transparent}
.group-system thead th{background:var(--mist);border-color:var(--control)}
.group-system tbody td{border-color:var(--control)}
.lock{display:inline-block;width:10px;height:11px;border:2px solid currentColor;border-radius:3px;position:relative;top:1px}
.lock::before{content:"";position:absolute;left:0;top:-7px;width:6px;height:6px;border:2px solid currentColor;border-bottom:0;border-radius:6px 6px 0 0}
.rr-system tbody tr:hover td{background:transparent}
.rr-system .name .rel,.rr-system .val,.rr-system .ttl{color:var(--muted)}
.rr-system .val{cursor:auto}
.rr-system .badge{background:var(--white);color:var(--muted)}

/* error / sign-in / return pages */
.error{max-width:640px;margin:32px auto}
.error-code{font-family:var(--display);font-weight:500;font-size:17px;color:var(--muted);margin:0 0 8px;letter-spacing:.04em}
.error h1{margin-bottom:12px}
.error p{max-width:64ch}
.error-actions{display:flex;gap:12px;margin:24px 0 12px;flex-wrap:wrap}

/* ============================================================================
   The records editor (templates/partials/record-form.php + app.js)
   ============================================================================ */

/* staged rows = the selected state: teal 1.5px edge and mist fill */
tr[data-staged] td{background:var(--mist);border-top:1.5px solid var(--action);border-bottom:1.5px solid var(--action)}
tr[data-staged] td:first-child{border-left:1.5px solid var(--action);border-radius:8px 0 0 8px}
tr[data-staged] td:last-child{border-right:1.5px solid var(--action);border-radius:0 8px 8px 0}
tr[data-staged="remove"] .val,tr[data-staged="remove"] .name{text-decoration:line-through;color:var(--muted)}
tr[data-staged="edit"] td.c-val::after,tr[data-staged="remove"] td.c-val::after{display:inline-block;margin-left:8px;font-family:var(--sans);font-size:13px;font-weight:600;padding:2px 8px;border-radius:6px;vertical-align:middle;background:var(--white);border:1px solid var(--action);color:var(--action)}
tr[data-staged="edit"] td.c-val::after{content:"Staged change"}
tr[data-staged="remove"] td.c-val::after{content:"Staged removal";color:var(--atlantic);border-color:var(--control)}
/* Row actions are compact icon buttons in a right-aligned column, ALWAYS visible (2026-09-09):
   the column is narrow now, and a control the customer cannot see is a control they do not have.
   The visible box is 46x40 and .icobtn::after carries the 44px hit area, so four of them fit in
   192px without any of them dropping under the brand's target size. Undo appears only on a row
   with a staged change; on a staged removal it replaces Edit and Delete. */
html.js .rr .c-act{width:192px;padding-right:6px;padding-left:0}
.rr tbody .c-act .acts,.rr thead .c-act .acts{display:flex;gap:0;justify-content:flex-end;flex-wrap:nowrap}
/* the selection box: a 34px control in a label whose hit area is the full 44px */
.selwrap{position:relative;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;cursor:pointer}
.selwrap::after{content:"";position:absolute;top:-5px;bottom:-6px;left:-6px;right:-6px}
/* the cell's 1px bottom rule makes its content box 43px, which would sit a 34px control half a
   pixel above the row's middle and cost it half a pixel of target. One pixel of padding-top puts
   the control back on the row's centre line, so its ::after covers exactly its own 44px row. */
#records .rr tbody td.c-sel,#records .rr tbody td.c-act{padding-top:1px}
#records .rr tbody td.c-sel{padding-left:2px}
#records .rr tbody .selwrap{width:40px;height:40px}
#records .rr tbody .selwrap::after{top:-2px;bottom:-3px;left:-2px;right:-2px}
.selwrap input{width:17px;height:17px;accent-color:var(--action);cursor:pointer}
thead .selwrap{height:34px}
#records .rr thead th.c-sel{padding-left:0}
#records .rr thead .selwrap{width:44px;height:44px}
/* the sticky header's own target stops at the header: it must not eat the first row's checkbox */
#records .rr thead .selwrap::after{bottom:0}
/* the row the keyboard is on (j / k), and the row a click opened in the drawer */
.rr tbody tr.rowfocus td{background:var(--mist);box-shadow:inset 0 1px 0 var(--action),inset 0 -1px 0 var(--action)}
.rr tbody tr.rowfocus td:first-child{box-shadow:inset 1px 1px 0 var(--action),inset 0 -1px 0 var(--action)}
.rr tbody tr.rowfocus td:last-child{box-shadow:inset -1px 1px 0 var(--action),inset 0 -1px 0 var(--action)}

/* editor and pending panels (the .editor container itself is declared with the workspace above) */
.editor-card,.pending{padding:16px 18px}
.editor-head{display:flex;align-items:center;gap:12px;margin:0 0 12px}
.editor-head h2{display:flex;align-items:center;gap:10px;font-size:18px}
.editor-head .btn-x{margin-left:auto}
.count-pill{display:inline-grid;place-items:center;min-width:28px;height:28px;padding:0 9px;border-radius:8px;background:var(--action);color:var(--white);font-family:var(--display);font-weight:600;font-size:15px;font-variant-numeric:tabular-nums}
.editor-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px 16px}
.field{display:flex;flex-direction:column;gap:6px;min-width:0}
.field label,.editor-values legend{font-size:16px;font-weight:600;color:var(--atlantic)}
.field input,.field select,.field textarea{height:44px;padding:0 12px;border-radius:var(--radius-control);border:1px solid var(--control);background:var(--white);color:var(--atlantic);font-family:var(--mono);font-size:15px;min-width:0;width:100%}
.field select{font-family:var(--sans);font-size:16px}
.field textarea{height:auto;min-height:96px;padding:10px 12px;resize:vertical;line-height:1.5}
/* focus: the border moves to action teal (a 1px ring makes it a 2px edge); invalid: error red */
.field input:focus,.field select:focus,.field textarea:focus,.filter input:focus,.admin-search input:focus{border-color:var(--action);box-shadow:0 0 0 1px var(--action);outline:none}
/* a keyboard focus always gets the 3px teal ring, whatever the control is */
.field input:focus-visible,.field select:focus-visible,.field textarea:focus-visible,.filter input:focus-visible,.filter select:focus-visible,.admin-search input:focus-visible{outline:3px solid var(--action);outline-offset:2px}
.field input[aria-invalid="true"],.field textarea[aria-invalid="true"],.field select[aria-invalid="true"]{border-color:var(--error);box-shadow:0 0 0 1px var(--error)}
.field-num{flex:0 0 140px}
.field-row{display:flex;gap:16px;flex-wrap:wrap}
.field-row .field{flex:1 1 200px}
.field-row .field-num{flex:0 0 140px}
.suffixwrap{display:flex;align-items:stretch}
.suffixwrap input{border-radius:var(--radius-control) 0 0 var(--radius-control)}
.suffixwrap .sfx{display:flex;align-items:center;padding:0 14px;border:1px solid var(--control);border-left:0;border-radius:0 var(--radius-control) var(--radius-control) 0;background:var(--mist);color:var(--muted);font-family:var(--mono);font-size:14px;white-space:nowrap;max-width:50%;overflow:hidden;text-overflow:ellipsis}
.ttlwrap{display:flex;gap:10px}
.ttlwrap select{flex:1 1 auto}
.ttlwrap input{flex:0 0 120px}
.hint{margin:0;font-size:14px;color:var(--muted);line-height:1.45;max-width:72ch}
.hint code{background:var(--mist);padding:1px 6px;border-radius:5px;font-size:14px}
.editor-values{margin-top:14px}
.editor-values fieldset{border:1px solid var(--divider);border-radius:var(--radius-panel);padding:12px 14px 14px;margin:0;background:var(--white);display:flex;flex-direction:column;gap:10px}
.editor-values fieldset[hidden]{display:none}
.editor-values legend{padding:0 8px}
/* what is wrong and how to fix it: error red text on white, error edge */
.editor-msgs{margin-top:16px;padding:14px 18px;border-radius:var(--radius-control);background:var(--white);border:1.5px solid var(--error);color:var(--error);font-size:16px}
.editor-msgs ul{margin:0;padding-left:20px}
.editor-msgs li+li{margin-top:4px}
.editor-foot{display:flex;align-items:center;gap:10px;margin-top:14px;flex-wrap:wrap}
.editor-foot .btn{min-height:44px}
.editor-foot .spacer,.spacer{flex:1 1 auto}

/* the staged-changes list: one editorial row per change on hairline rules — sign + body + actions */
.difflist{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column}
.diff{display:flex;gap:14px;align-items:flex-start;padding:14px 4px;border-top:1px solid var(--divider)}
.diff:last-child{border-bottom:1px solid var(--divider)}
.diff .sig{display:grid;place-items:center;flex:0 0 30px;height:30px;border-radius:8px;font-family:var(--display);font-weight:600;font-size:17px}
.diff-add .sig{background:var(--action);color:var(--white)}
.diff-edit .sig{background:var(--mist);color:var(--action);border:1.5px solid var(--action)}
.diff-remove .sig{background:var(--atlantic);color:var(--white)}
.diff-merge .sig{background:var(--mist);color:var(--atlantic);border:1.5px solid var(--action)}
.diff-body{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:6px}
.diff-kind{font-size:16px;font-weight:600;color:var(--atlantic)}
.diff-merge .diff-kind{color:var(--action)}
.diff-line{display:flex;gap:10px;align-items:baseline;min-width:0}
.diff-line code{font-size:15px;word-break:break-all;white-space:pre-wrap;color:var(--atlantic)}
.diff-old code{color:var(--muted);text-decoration:line-through}
.diff-merge .diff-old code{text-decoration:none;color:var(--muted)}
.diff-tag{flex:0 0 auto;font-family:var(--sans);font-size:13px;font-weight:600;padding:2px 8px;border-radius:6px;background:var(--mist);color:var(--muted)}
.diff-new .diff-tag{background:var(--action);color:var(--white)}
.diff-old .diff-tag{background:var(--white);border:1px solid var(--control);color:var(--muted)}
.diff-arrow{color:var(--muted);font-size:16px;line-height:1;padding-left:2px}
.diff-error{margin-top:6px;padding:10px 14px;border-radius:8px;border:1.5px solid var(--error);color:var(--error);font-size:15px}
.diff-error p{margin:0}
.diff-acts{display:flex;gap:6px;flex:0 0 auto}
.diff-warn{margin:12px 0 0;padding:12px 16px;border-radius:var(--radius-control);background:var(--mist);border:1px solid var(--divider);font-size:15px}
.pending[aria-busy="true"]{opacity:.7}

/* ---------- staff pages, the service templates drawer ---------- */
.badge.staff{background:var(--white);border:1px solid var(--action);color:var(--action);font-family:var(--sans);font-weight:600;font-size:13px;letter-spacing:0}
.admin-search{display:flex;gap:12px;margin:0 0 24px;align-items:center;flex-wrap:wrap}
.admin-search input{flex:1 1 320px;max-width:560px}
.audit td{vertical-align:top}
.audit-detail div{margin:3px 0;word-break:break-word}
.outcome{font-weight:600}
.outcome-ok{color:var(--action)}
.outcome-denied,.outcome-error,.outcome-refused,.outcome-invalid,.outcome-stale,.outcome-slow,.outcome-warning{color:var(--atlantic);font-weight:700}

/* ---------- the log viewer (/admin/logs, templates/admin/logs.php) ----------
   No new design language: the same bordered card, the same mist sticky header, the same dense
   44px rows and the same quiet foot band as every other list on the site. The filter block is
   the record editor's field grid; a row's full JSON opens in place with <details>, styled as the
   drawer's flat panel, so the page carries no script at all and works with JavaScript off. */
.logfilter{margin:0 0 18px;padding:14px 16px;background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel)}
.logfilter-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px 14px}
.logfilter-wide{grid-column:1 / -1}
.logfilter .field label{font-size:14px;font-weight:600;color:var(--muted)}
.logfilter .field input,.logfilter .field select{height:44px;font-size:15px}
.logfilter .field select{font-family:var(--sans)}
.logfilter-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:14px 0 0}
.logcounts{margin:0 0 12px}
#admin-logs thead th{position:sticky;top:0;z-index:3}
.logs{table-layout:fixed}
.logs td{vertical-align:top;padding-top:8px;padding-bottom:8px;height:auto}
.logs .c-when{width:180px}
.logs .c-stream{width:86px}
.logs .c-actor{width:150px}
.logs .c-ip{width:130px}
.logs .c-zone{width:170px;overflow:hidden;text-overflow:ellipsis}
.logs .c-action{width:170px;overflow:hidden;text-overflow:ellipsis}
.logs .c-outcome{width:96px}
.logs .c-detail{width:auto}
.logs .logday{color:var(--muted)}
.streamtag{display:inline-block;font-family:var(--mono);font-size:12px;font-weight:700;line-height:1.3;padding:2px 7px;border-radius:6px;letter-spacing:.02em}
.stream-audit{background:var(--t-addr-bg);color:var(--t-addr-fg)}
.stream-diag{background:var(--t-svc-bg);color:var(--t-svc-fg)}
.logsummary{margin:0 0 3px;word-break:break-word;line-height:1.4}
.logref{font-size:13px;word-break:break-all}
.logrow{margin:4px 0 0}
.logrow summary{display:inline-flex;align-items:center;min-height:28px;font-size:13px;font-weight:600;color:var(--action);cursor:pointer}
.logrow summary:hover{text-decoration:underline}
.logrow[open] summary{color:var(--atlantic)}
.logjson{margin:6px 0 0;padding:12px 14px;background:var(--mist);border:1px solid var(--divider);border-radius:var(--radius-control);font-size:12.5px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:420px;overflow:auto}
.templates .tpl-list{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.tpl{border:1px solid var(--divider);border-radius:var(--radius-panel);padding:14px 16px;background:var(--white);display:flex;flex-direction:column;gap:10px}
.tpl-head{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;min-height:44px}
.tpl-doc{display:inline-flex;align-items:center;min-height:44px;padding:0 2px}
.tpl-name{margin:0}
.tpl-summary{margin:0;color:var(--muted);font-size:16px}
.tpl-records{list-style:none;margin:0;padding:0;font-size:14px;display:flex;flex-direction:column;gap:4px}
.tpl .editor-foot{margin-top:6px}

/* ---------- the zone-file import panel (templates/partials/import.php; app.js section 3c) ----------
   A mist band, because the panel is a quiet workspace, not an alert. Apricot is spent HERE and
   only here on the zone page: the deletion warning of a `replace` import is the one accent of the
   view. Error red is used for the problem list and nothing else. Controls are 44px or more, radii
   10px on controls and 12-14px on the panel, focus is the 3px teal ring the rest of the page uses.
   Every row in the preview is a text node the script built; nothing here styles markup from a file. */
.import{background:var(--mist);border:1px solid var(--divider)}
.import textarea{width:100%;min-height:150px;font-family:var(--mono);font-size:14px;line-height:1.5;padding:12px 14px;border:1px solid var(--control);border-radius:var(--radius-control);background:var(--white);resize:vertical}
.import textarea:focus-visible{outline:3px solid var(--action);outline-offset:2px}
.import-file input[type=file]{min-height:44px;padding:9px 12px;border:1px dashed var(--control);border-radius:var(--radius-control);background:var(--white);width:100%}
.import-modes{border:1px solid var(--divider);border-radius:var(--radius-panel);padding:14px 18px;margin:0;background:var(--white)}
.import-modes legend{font-weight:600;padding:0 6px}
.import .radio{display:flex;gap:12px;align-items:flex-start;min-height:44px;padding:8px 0;cursor:pointer}
.import .radio input{margin-top:6px;width:20px;height:20px;accent-color:var(--action);flex:0 0 auto}
.import .radio span{font-size:16px;color:var(--atlantic)}
.import-preview{background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel-lg);padding:18px 20px;display:flex;flex-direction:column;gap:16px}
.imp-summary{margin:0;font-weight:600}
.imp-danger{margin:0;padding:14px 16px;border-radius:var(--radius-panel);background:var(--atlantic);color:var(--on-atlantic);border-left:6px solid var(--apricot)}
.imp-danger strong{color:var(--apricot);display:block}
.imp-group{display:flex;flex-direction:column;gap:8px}
.imp-h{display:flex;align-items:baseline;gap:10px;font-size:17px}
.imp-count{font-family:var(--display);font-size:15px;color:var(--muted);border:1px solid var(--divider);border-radius:999px;padding:0 10px;min-width:34px;text-align:center}
.imp-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px;max-height:340px;overflow:auto}
.imp-row,.imp-err,.imp-warn{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;padding:6px 10px;border-radius:var(--radius-control);background:var(--mist)}
.imp-tag{font-size:13px;font-weight:600;color:var(--muted);white-space:nowrap;min-width:76px}
.imp-val,.imp-src{font-size:14px;word-break:break-all}
.imp-msg{flex:1 1 260px}
.imp-add .imp-row{background:#EAF6F2}
.imp-remove .imp-row{background:#FBEDE9}
.imp-remove .imp-tag{color:var(--error)}
.imp-errors .imp-err{background:#FBEDE9;border-left:4px solid var(--error)}
.imp-errors .imp-h,.imp-errors .imp-tag{color:var(--error)}
.imp-errors .imp-src{display:block;width:100%;color:var(--muted)}
.imp-warnings .imp-warn{background:var(--mist)}
.imp-none{margin:0;color:var(--muted)}
.import-confirm{border:1px solid var(--apricot);border-radius:var(--radius-panel);padding:10px 16px;background:var(--white)}
.import-confirm .radio input{accent-color:var(--error)}
.import .editor-foot .btn{min-height:44px}

/* ---------- bulk operations (templates/partials/bulk.php; app.js section 3d) ----------
   The bar is a quiet mist strip above the records; a selected row takes the same mist fill and
   teal edges a staged row takes, so "selected" and "staged" read as one system. The panel is the
   import panel's twin: mist band, white preview card, 44px controls, 10px control radii, 12-14px
   panel radii, the 3px teal focus ring. Apricot is spent ONLY on the deletion confirmation, and
   error red ONLY on the problem list. Every row in the preview is a text node the script built. */
/* The bulk bar is the table card's foot band, not a strip of its own above the table: at rest it is
   a 44px line carrying the count and Select all, and the four operations appear only once something
   is selected (2026-09-09 — it used to hold 54px of dead space on every zone page). */
.bulkbar{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:0;padding:0 8px 0 12px;background:var(--mist);border-top:1px solid var(--divider);min-height:44px}
.bulkbar .spacer{flex:1 1 auto}
.bulk-count{font-family:var(--sans);font-weight:600;font-size:15px;color:var(--atlantic)}
.bulkbar .bulk-danger{color:var(--error);border-color:var(--control)}
.bulkbar .bulk-danger:hover:enabled{color:var(--error);border-color:var(--error);background:var(--white)}
#bulk-bar[data-bulk-empty] .bulk-act{display:none}
.c-sel{width:44px;text-align:center}
tr[data-selected] td{background:var(--mist)}
tr[data-selected] .c-sel{box-shadow:inset 3px 0 0 var(--action)}
.bulk{background:var(--mist);border:1px solid var(--divider)}
.bulk-fields{display:flex;flex-direction:column;gap:18px}
.bulk .field{background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel);padding:14px 18px;display:flex;flex-direction:column;gap:10px}
.bulk .radio{display:flex;gap:12px;align-items:center;min-height:44px;cursor:pointer}
.bulk .radio input{width:20px;height:20px;accent-color:var(--action);flex:0 0 auto}
.bulk input[type=text],.bulk input[type=number]{min-height:44px;padding:9px 12px;border:1px solid var(--control);border-radius:var(--radius-control);background:var(--white);font-family:var(--mono);font-size:15px;max-width:34ch}
.bulk input:focus-visible{outline:3px solid var(--action);outline-offset:2px}
.bulk-replace-grid{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px 14px;align-items:center}
.bulk-replace-grid label{font-weight:600;font-size:15px}
.bulk-confirm{border-color:var(--apricot)}
.bulk-preview{background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel-lg);padding:18px 20px;display:flex;flex-direction:column;gap:16px}
.blk-summary{margin:0;font-weight:600}
.blk-danger,.bulk .bulk-danger{margin:0;padding:14px 16px;border-radius:var(--radius-panel);background:var(--atlantic);color:var(--on-atlantic);border-left:6px solid var(--apricot)}
.blk-danger strong{color:var(--apricot);display:block}
.blk-group{display:flex;flex-direction:column;gap:8px}
.blk-h{display:flex;align-items:baseline;gap:10px;font-size:17px}
.blk-count{font-family:var(--display);font-size:15px;color:var(--muted);border:1px solid var(--divider);border-radius:999px;padding:0 10px;min-width:34px;text-align:center}
.blk-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px;max-height:340px;overflow:auto}
.blk-row,.blk-err,.blk-warn{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;padding:6px 10px;border-radius:var(--radius-control);background:var(--mist)}
.blk-tag{font-size:13px;font-weight:600;color:var(--muted);white-space:nowrap;min-width:76px}
.blk-body{display:flex;gap:8px;align-items:baseline;flex-wrap:wrap;flex:1 1 260px}
.blk-old,.blk-new{font-size:14px;word-break:break-all}
.blk-arrow{color:var(--muted)}
.blk-note{font-size:13px;font-weight:600;color:var(--muted);background:var(--white);padding:2px 8px;border-radius:6px}
.blk-msg{flex:1 1 260px}
.blk-edit .blk-row{background:#EAF6F2}
.blk-remove .blk-row{background:#FBEDE9}
.blk-remove .blk-tag{color:var(--error)}
.blk-errors .blk-err{background:#FBEDE9;border-left:4px solid var(--error)}
.blk-errors .blk-h,.blk-errors .blk-tag{color:var(--error)}
.blk-none{margin:0;color:var(--muted)}
.bulk .editor-foot .btn{min-height:44px}

/* ============================================================================
   THE SLIDE-OVER (templates/zone.php #drawer; app.js section 3f)
   ----------------------------------------------------------------------------
   The pattern from dns.securehost.ie, in the SmartHost palette: every tool — Add record, Services,
   Import, Bulk, History and the record editor a row click opens — renders into ONE fixed panel over
   a scrim, one at a time. The record table behind it never moves. role=dialog + aria-modal, focus
   moves to the first control in .dbody on open and back to the control that opened it on close,
   Escape closes, Tab is trapped inside, the scrim is click-to-close. When it is shut it is
   visibility:hidden, so nothing inside it is in the tab order or the accessibility tree.
   Each panel keeps its own <h2> for its section label, but that head is clipped inside the drawer:
   the drawer's own head carries the title (the script copies it) and the one close control.
   ============================================================================ */
.scrim{position:fixed;inset:0;background:rgba(6,59,70,.5);z-index:50;opacity:0;pointer-events:none;transition:opacity .18s}
.scrim.on{opacity:1;pointer-events:auto}
.drawer{position:fixed;top:0;right:0;bottom:0;width:min(470px,100%);background:var(--white);border-left:1px solid var(--divider);box-shadow:var(--lift-lg);z-index:60;transform:translateX(100%);visibility:hidden;transition:transform .22s cubic-bezier(.4,0,.2,1),visibility 0s linear .22s;flex-direction:column}
.drawer.on{transform:none;visibility:visible;transition:transform .22s cubic-bezier(.4,0,.2,1)}
.dhead{display:flex;align-items:center;gap:10px;flex:0 0 auto;padding:10px 14px 10px 18px;border-bottom:1px solid var(--divider)}
.dhead h2{margin:0;min-width:0;font-size:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dhead .btn-x{flex:0 0 auto}
.dhead .spacer{flex:1 1 auto}
.dbody{flex:1 1 auto;overflow:auto;padding:18px}
.dfoot{display:flex;align-items:center;gap:12px;flex:0 0 auto;padding:8px 14px 8px 18px;border-top:1px solid var(--divider);background:var(--mist)}
.dfoot .spacer{flex:1 1 auto}
/* a panel inside the drawer is flat: the drawer is the card */
.drawer .card{border:0;border-radius:0;padding:0;background:transparent}
.drawer .editor-head{position:absolute;width:1px;height:1px;margin:0;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.drawer .editor-head .btn-x{display:none}
.drawer .editor-grid{grid-template-columns:1fr}
.drawer .editor-foot{margin-top:18px;padding-top:14px;border-top:1px solid var(--divider);flex-wrap:wrap}
.drawer .tpl-list{grid-template-columns:1fr}
/* the drawer is a 470px column: the long explanatory copy the panels carry is set one step
   down there, and the name suffix keeps its whole domain rather than ellipsising it */
.drawer .hint{max-width:none;font-size:14px;line-height:1.45}
.drawer .field label,.drawer .editor-values legend,.drawer .import-modes legend,.drawer .import .radio span,.drawer .bulk-replace-grid label{font-size:15px}
.drawer .suffixwrap{min-width:0}
.drawer .suffixwrap input{min-width:0}
.drawer .suffixwrap .sfx{max-width:none;flex:0 0 auto;padding:0 10px;font-size:13px}
.drawer .import-preview,.drawer .bulk-preview,.drawer .hist-view,.drawer .hist-preview{padding:14px 16px}
.drawer .imp-list,.drawer .blk-list{max-height:260px}
.drawer .hist-text{max-height:300px}

/* ---------- the active-filter chips (app.js buildFilterChips) ---------- */
.filterbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 12px}
.fchip{display:inline-flex;align-items:center;gap:4px;max-width:min(100%,460px);height:40px;padding:0 4px 0 14px;border-radius:var(--radius-control);background:var(--mist);border:1px solid var(--divider);color:var(--atlantic);font-size:15px;font-weight:600}
.fchip .fchip-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fchip button{position:relative;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:0;border-radius:8px;background:transparent;color:var(--muted);font-size:19px;line-height:1;cursor:pointer}
.fchip button::after{content:"";position:absolute;top:-6px;bottom:-6px;left:-6px;right:-6px}
.fchip button:hover{background:var(--white);color:var(--action)}

/* ---------- keyboard hints ---------- */
.kbdhint{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;margin:0;font-size:13px;color:var(--muted)}
.tfoot-note .kbdhint{margin-left:10px}
.note-js{display:inline}
html.js span.note-js{display:inline}
kbd{font-family:var(--mono);font-size:12px;font-weight:600;padding:1px 6px;border:1px solid var(--control);border-bottom-width:2px;border-radius:5px;background:var(--white);color:var(--atlantic)}

/* ---------- the domain list: listed, but not editable (operator instruction 2026-09-09) ----------
   A domain the customer may not open is a muted BUTTON, never a link: it opens the same slide-over
   the zone page uses and the drawer carries the sentence, while the chip carries the meaning at a
   glance. Measured over the estate, the `elsewhere` bucket is larger than the manageable list for
   half of all client accounts, so it is a collapsed <details> group rather than inline rows. */
/* A chip eats about 150px of the cell, so a table that carries chips gets wider columns: the
   domain name is what the customer came to read and must not be the part that ellipsises. Only
   above 760px - below it the grid is already ONE column and a 400px track would overflow it. */
@media (min-width:761px){.zones.has-chips tbody{grid-template-columns:repeat(auto-fill,minmax(400px,1fr))}}
.zone-why{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:0 14px;border:0;background:none;font-family:var(--mono);font-size:15px;font-weight:600;color:var(--muted);text-align:left;cursor:pointer;min-width:0;overflow:hidden}
.zone-why:hover{background:var(--mist);color:var(--atlantic)}
.zone-why .zn{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.chip{flex:0 0 auto;font-family:var(--sans);font-size:12px;font-weight:700;line-height:1.3;padding:2px 8px;border-radius:6px;letter-spacing:.02em;white-space:nowrap;background:var(--mist);color:var(--muted);border:1px solid var(--divider)}
.chip-registering,.chip-transferring{background:var(--t-sec-bg);color:var(--t-sec-fg);border-color:var(--t-sec-bg)}

.cat-group{margin-top:16px;background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel);overflow:hidden;box-shadow:var(--lift-sm)}
.cat-group > summary{display:flex;align-items:center;gap:12px;flex-wrap:wrap;min-height:52px;padding:6px 14px;cursor:pointer;font-weight:600;color:var(--atlantic);background:var(--mist);list-style:none}
.cat-group > summary::-webkit-details-marker{display:none}
.cat-group > summary::before{content:"+";flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:6px;border:1px solid var(--control);background:var(--white);color:var(--action);font-weight:700;line-height:1}
.cat-group[open] > summary::before{content:"\2212"}
.cat-group > summary:hover{color:var(--action)}
.cat-group > summary .sum-hint{font-weight:400;font-size:15px}
.cat-group .tablewrap{border:0;border-radius:0;box-shadow:none;border-top:1px solid var(--divider)}

/* Without the script the rows are inert, so the same words are printed under the table instead. */
.cat-notes{margin-top:18px;padding:14px 18px;background:var(--mist);border-radius:var(--radius-panel);color:var(--atlantic)}
.cat-notes-title{font-size:17px}
.cat-notes p{margin:8px 0 0;max-width:78ch;font-size:15px;line-height:1.45}
html.js .cat-notes{display:none}

/* the one drawer panel the list opens; its h2 is clipped because the drawer head carries the title */
.why .phead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.why-domain{margin:0 0 12px;font-size:17px;font-weight:600;color:var(--atlantic);overflow-wrap:anywhere}
.why-text{margin:0 0 14px;font-size:16px;line-height:1.5}
.why-h3{margin:18px 0 6px;font-size:16px}
.why-state{margin:0;font-size:15px;line-height:1.45}
.why-ns{margin:6px 0 0;padding-left:20px;font-size:15px}
.why-ns li{margin:2px 0;overflow-wrap:anywhere}
.why-points p{margin:6px 0 0;font-size:15px;line-height:1.45}
.why-help{margin:20px 0 0;font-size:14px;border-top:1px solid var(--divider);padding-top:12px}

/* ---------- responsive ---------- */
@media (max-width:1180px){
  .nav .who{display:none}
}
@media (max-width:1100px){
  .rr .c-name{width:190px;max-width:190px}
  .rr .c-ttl{width:88px}
}
@media (max-width:960px){
  .group-label{display:none}
  .rr .c-name{width:160px;max-width:160px}
}
@media (max-width:760px){
  .wrap{padding:0 16px}
  .topbar{position:static}
  .topbar-in{min-height:0;padding:6px 0;flex-wrap:wrap;gap:10px}
  .brand{gap:14px}
  .brand-product{padding-left:14px;font-size:17px}
  .nav{margin-left:0;width:100%;justify-content:space-between;gap:2px}
  .nav a{padding:0 10px}
  .rr .c-ttl{display:none}
  .rr .c-type{width:58px}
  .rr .c-name{width:28%;min-width:0;max-width:none}
  .rr .c-val{font-size:12px}
  /* On a phone there is no hover and no room for a permanent actions column: the row's actions
     come out as a small chip bar over the top-right of the row when the row is opened (tap its
     value) or when a control in it takes keyboard focus. The column itself costs nothing until
     then, so the value keeps the width. Tapping anywhere ELSE in the row opens it in the
     full-width drawer, which is where a phone edits a record. */
  .rr tbody tr{position:relative}
  html.js .rr .c-act{display:table-cell;width:0;min-width:0;padding:0}
  .rr tbody .c-act .acts{display:none}
  .rr tbody tr[data-open] .c-act,.rr tbody tr:focus-within .c-act{position:absolute;right:4px;top:5px;width:auto;display:flex;gap:0;background:var(--white);border:1px solid var(--divider);border-radius:10px;padding:0 2px;z-index:2}
  .rr tbody tr[data-open] .c-act .acts,.rr tbody tr:focus-within .c-act .acts{display:flex}
  .bulk-replace-grid{grid-template-columns:1fr}
  .bulkbar{gap:4px;padding:0 6px 0 10px}
  .page-head{align-items:flex-start}
  .toolbar .spacer,.actions .spacer{display:none}
  .toolbar,.actions{width:100%}
  .filter{flex:1 1 100%}
  .filter input,.filter select{width:100%}
  .editor-grid{grid-template-columns:1fr}
  .rowlink{opacity:1}
  .bulkbar .btn-sm,.bulkbar .rowbtn{font-size:14px;padding:0 10px}
  .zones tbody{grid-template-columns:1fr}
  .zones tr{box-shadow:inset 0 -1px 0 var(--divider)}
  .scroller{max-height:min(58vh,560px)}
  .fchip{max-width:100%}
  .diff{flex-wrap:wrap}
  .diff-acts{width:100%;justify-content:flex-end}
  .foot-in{gap:10px}
  .foot-text{flex:1 1 100%;order:3}
  .foot-links{margin-left:auto}
  /* the slide-over takes the whole screen on a phone; it is still the same one panel */
  .drawer{width:100%;border-left:0}
  .dbody{padding:14px}
}
@media (max-width:520px){
  .rr .c-type{width:52px}
  .rr .c-name{width:32%}
}
/* ---------- zone history and revert (templates/partials/history.php; app.js section 3e) ----------
   The panel is the import panel's twin again: mist band, white cards, 44px controls, the 3px teal
   focus ring. A version row is a quiet white card with a display-face timestamp and muted metadata;
   the stored zone file is a scrolling <pre> of mono text the script wrote with textContent and
   nothing else. Apricot is spent ONLY on the restore confirmation — the one destructive step —
   and error red only on the problem list the shared .imp-errors rules already carry. */
.history{background:var(--mist);border:1px solid var(--divider);display:flex;flex-direction:column;gap:12px}
.hist-list{display:flex;flex-direction:column;gap:12px}
.hist-summary{margin:0;color:var(--muted)}
.hist-none{margin:0;color:var(--muted)}
.hist-rows{display:flex;flex-direction:column;gap:8px}
.hist-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel);padding:6px 12px;min-height:54px}
.hist-when{font-family:var(--display);font-weight:500;font-size:16px;color:var(--atlantic);white-space:nowrap}
.hist-meta{display:flex;gap:14px;flex-wrap:wrap;color:var(--muted);font-size:15px;flex:1 1 220px}
.hist-meta .hist-serial{font-family:var(--mono);font-size:14px}
.hist-acts{display:flex;gap:8px;align-items:center;margin-left:auto}
.hist-acts .rowbtn{min-height:44px;display:inline-flex;align-items:center}
.hist-dl{text-decoration:none}
.hist-bad{color:var(--error);font-size:15px}
.hist-view{background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel-lg);padding:18px 20px;display:flex;flex-direction:column;gap:12px}
.hist-view-h{font-size:17px;word-break:break-all}
.hist-text{margin:0;padding:14px 16px;background:var(--mist);border:1px solid var(--divider);border-radius:var(--radius-panel);max-height:420px;overflow:auto;font-size:14px;line-height:1.5;white-space:pre;tab-size:8}
.hist-text:focus-visible{outline:3px solid var(--action);outline-offset:2px}
.hist-restore{display:flex;flex-direction:column;gap:16px}
.hist-restore-h{font-size:17px}
.hist-preview{background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel-lg);padding:18px 20px;display:flex;flex-direction:column;gap:16px}
.hist-confirm{background:var(--white);border:1px solid var(--apricot);border-radius:var(--radius-panel);padding:14px 18px;display:flex;flex-direction:column;gap:10px}
.hist-confirm label{font-weight:600;font-size:15px}
.hist-confirm input{min-height:44px;padding:9px 12px;border:1px solid var(--control);border-radius:var(--radius-control);background:var(--white);font-family:var(--mono);font-size:15px;max-width:12ch}
.hist-confirm input:focus-visible{outline:3px solid var(--action);outline-offset:2px}
.history .editor-foot .btn{min-height:44px}

@media (max-width:480px){
  .brand-logo{height:28px}
  .brand-product{display:none}
}
@media (max-width:760px){
  .hist-row{align-items:flex-start;flex-direction:column;gap:6px}
  .hist-acts{margin-left:0;flex-wrap:wrap}
}
/* A viewer who asks for less motion gets none: every state change here is instant anyway. */
@media (prefers-reduced-motion:reduce){*{transition:none !important;animation:none !important}}

/* ============================================================================
   THE UNSAVED-CHANGES GUARD (app.js section 3g)
   ----------------------------------------------------------------------------
   A small centred modal over the same scrim the slide-over uses, in the same palette: white
   card, hairline border, Atlantic type, 48px controls, the 3px teal focus ring. Teal is the
   primary action (apply and leave); the one apricot edge marks the destructive choice (leave
   without applying) and is the only accent this dialog spends. role=dialog + aria-modal,
   focus moves into it on open and back to the link on cancel, Escape cancels, Tab is trapped.
   It is position:fixed, so it adds nothing to the height of the page behind it.
   ============================================================================ */
.scrim-guard{z-index:70}
.gmodal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:80;display:flex;flex-direction:column;gap:12px;width:min(520px,calc(100% - 24px));max-height:calc(100vh - 24px);overflow:auto;padding:22px 24px;background:var(--white);border:1px solid var(--divider);border-radius:var(--radius-panel-lg);box-shadow:var(--lift-modal)}
.gmodal[hidden]{display:none}
.gmodal h2{font-size:21px}
.gsum{margin:0;font-weight:600;font-family:var(--display);font-size:17px}
.gmodal .hint{margin:0;max-width:none;color:var(--muted);font-size:15px;line-height:1.45}
.gacts{display:flex;flex-direction:column;gap:10px;margin-top:6px}
.gacts .btn{width:100%;min-height:48px}
.gacts .btn[hidden]{display:none}
.btn-warn{background:var(--white);color:var(--atlantic);border-color:var(--apricot)}
.btn-warn:hover{background:var(--apricot);color:var(--atlantic);border-color:var(--apricot);text-decoration:none}
@media (min-width:560px){
  .gacts{flex-direction:row;flex-wrap:wrap;justify-content:flex-end}
  .gacts .btn{width:auto}
  .gacts .btn-cta{order:3}
  .gacts .btn-warn{order:2}
  .gacts .btn-quiet{order:1;margin-right:auto}
}

/* the domain list on a phone: the chip stays, the name truncates, the summary stays a 52px target */
@media (max-width:520px){
  .zone-why{gap:8px;font-size:14px}
  .chip{font-size:11px;padding:2px 6px}
  .cat-group > summary{gap:8px;padding:8px 14px}
  .cat-group > summary .sum-hint{font-size:14px;flex-basis:100%}
}

/* ---------------------------------------------------------------------------
   The first-zone wizard (templates/setup.php, ticket A76-97Y-DQ7R).
   Only what the existing vocabulary does not already cover: the radio/check
   rows, the indented sub-fields they reveal, the MX table and the review list.
   --------------------------------------------------------------------------- */
.setup{display:flex;flex-direction:column;gap:18px;max-width:760px}
.setup .card{padding:18px 20px}
.setup .card h2{margin:0 0 6px;font-size:16px}
.setup .card > .muted{margin:0 0 14px}
.field-check{display:flex;align-items:flex-start;gap:10px;margin:8px 0}
.field-check input{margin-top:3px;flex:0 0 auto}
.field-check label{margin:0;font-weight:400}
.field-radios{display:flex;flex-direction:column;gap:4px}
.setup .indent{margin:2px 0 10px 26px;padding-left:14px;border-left:2px solid var(--line,#e3e6ea)}
.mx-rows{width:100%;border-collapse:collapse;margin:6px 0}
.mx-rows th{text-align:left;font-size:12px;font-weight:600;padding:4px 6px 4px 0}
.mx-rows td{padding:3px 6px 3px 0;vertical-align:top}
.mx-rows .mx-pri{width:6em}
.mx-rows .mx-host{width:100%;min-width:12em}
.review-list{margin:8px 0 12px;padding-left:20px}
.review-list li{margin:4px 0}
.setup-errors{border-left:4px solid var(--warn,#b4522a);background:var(--warn-bg,#fdf5f1);padding:10px 14px}
.err-list{margin:0;padding-left:20px}
.err-list li{margin:3px 0}
@media (max-width:640px){
  .setup .indent{margin-left:12px;padding-left:10px}
  .mx-rows .mx-pri{width:4.5em}
}

/* The review step of the first-zone wizard: visually distinct from the questions above it, so
   "nothing has happened yet" and "this is about to happen" cannot be confused. */
.card-review{border-left:4px solid var(--cta,#0a7);background:var(--cta-bg,#f4fbf8)}
.card-review .actions{margin-top:14px;display:flex;gap:10px;flex-wrap:wrap}
#setup-actions{display:flex;gap:10px;flex-wrap:wrap}
#setup-nojs{margin-bottom:18px}

/* The first-zone wizard's progress region. The steps behind it are real round trips to WHMCS and
   the nameserver hub - seconds, not milliseconds - so silence reads as breakage. */
.setup-working{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  border-left:4px solid var(--cta,#0a7);background:var(--cta-bg,#f4fbf8);padding:12px 16px}
.setup-working .working-main{font-weight:600}
.setup-working .working-sub{flex-basis:100%;margin-left:26px;font-size:13px}
.spinner{flex:0 0 auto;width:16px;height:16px;border-radius:50%;
  border:2px solid rgba(0,0,0,.15);border-top-color:var(--cta,#0a7);
  animation:shdns-spin .7s linear infinite}
@keyframes shdns-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
  .spinner{animation:none;border-top-color:rgba(0,0,0,.15)}
}

/* ---------------------------------------------------------------------------
   The domain list for a small account (<=5 domains, which is 92% of customers).
   Measured 2026-09-11: 68.2% hold exactly one domain. A two-column table with a
   header row, a collapsed group and a filter is the right shape for the 1.4%
   who hold 26+; for everyone else it is chrome around a single name.
   --------------------------------------------------------------------------- */
/* ☠️ Tightened 2026-09-11 when the threshold went to 10 PER SECTION: an account can now show 20
   cards, and at the original 147px each that was a very long page. The information is unchanged -
   only the spacing - and the actions sit beside the name rather than below it on a wide screen. */
.zone-cards{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;max-width:860px}
.zone-card{border:1px solid var(--line,#e3e6ea);border-radius:8px;padding:10px 14px;background:var(--card,#fff);
  display:grid;grid-template-columns:1fr auto;grid-template-areas:"head actions" "state actions";
  align-items:center;column-gap:16px}
.zone-card .zc-head{grid-area:head}
.zone-card .zc-state{grid-area:state}
.zone-card .zc-actions{grid-area:actions}
.zone-card-live{border-left:4px solid var(--cta,#0a7)}
.zone-card-elsewhere{border-left:4px solid var(--warn,#b4522a)}
.zone-card-registering,.zone-card-transferring{border-left:4px solid var(--line,#e3e6ea)}
.zc-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.zc-name{font-size:18px;font-weight:600;line-height:1.3;word-break:break-all}
.zc-state{margin:2px 0 0;font-size:13px}
.zc-actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}
@media (max-width:760px){
  /* stack again on a narrow screen: the two-column grid is what saves the height, not the padding */
  .zone-card{grid-template-columns:1fr;grid-template-areas:"head" "state" "actions";row-gap:8px;padding:12px 14px}
  .zone-card .zc-actions{justify-content:flex-start}
  .zc-actions .btn{flex:1 1 auto;text-align:center}
}

/* The wizard's two questions read as one page unless they are visibly separated: a numbered badge,
   a subtitle naming the step, alternating grounds, and tighter vertical rhythm. */
.setup .step{padding:14px 18px 16px}
.step-head{display:flex;align-items:center;gap:10px;margin:0 0 4px;font-size:16px}
.step-num{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:26px;height:26px;border-radius:50%;background:var(--cta,#0a7);color:#fff;
  font-size:14px;font-weight:700;line-height:1}
.step-num-done{background:var(--ok,#0a7)}
.step-title{font-weight:600}
.step-of{font-weight:400;font-size:13px;color:var(--muted,#5b6572)}
.step-lede{margin:0 0 12px 36px;font-size:14px;color:var(--muted,#5b6572)}
.setup .step .field:first-of-type{margin-top:0}
.setup .step-alt{background:var(--alt,#fafbfc)}
@media (max-width:640px){
  .step-lede{margin-left:0}
  .step-of{display:block;margin-left:0}
}

/* ☠️ A checkbox or radio must never be stretched by the generic .field input sizing (44px tall,
   100% wide) - that turns it into a large detached square with its label adrift. Guarded by type
   so it holds wherever the two classes are combined. */
.field input[type="checkbox"],.field input[type="radio"],
.field-check input[type="checkbox"],.field-check input[type="radio"]{
  height:auto;width:auto;min-width:0;flex:0 0 auto;padding:0}
.field-check-inline{margin-top:10px}

/* ============================================================================================
   /admin/usage — the staff usage view. Counts, what changed, and who looked and left.
   Reuses .logfilter, .rr, .tablewrap, .notice, .empty and .badge; only the parts below are new.
   ============================================================================================ */

/* the counter strip: a row of figures that wraps to a grid on narrow screens */
.ustats{list-style:none;margin:18px 0 6px;padding:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:10px}
.ustat{display:flex;flex-direction:column;gap:2px;padding:12px 14px;background:var(--mist);
  border:1px solid var(--divider);border-radius:var(--radius-panel)}
.ustat-n{font-family:var(--display);font-weight:600;font-size:26px;line-height:1.1;
  color:var(--atlantic);font-variant-numeric:tabular-nums}
.ustat-l{font-size:14px;color:var(--muted);line-height:1.3}
/* the one counter that should catch the eye when it is not zero */
.ustat-warn{background:#FBEEE0;border-color:#E8C9A6}
.ustat-warn .ustat-n{color:#8A5320}

/* section headings down the page */
h2.usec{font-family:var(--display);font-size:22px;font-weight:600;color:var(--atlantic);
  margin:32px 0 10px;padding-top:18px;border-top:1px solid var(--divider)}

/* one record operation, inline in the change row */
/* ☠️ NOT nowrap: a record name is arbitrary customer text — a DKIM selector, a verification
   hash like efc350ac65db5dfef6dd9edb992781d2 — and a non-wrapping chip pushed the cell wider
   than its column and overlapped the one beside it. Caught in a screenshot, not by a test. */
.uop{display:inline-block;padding:1px 7px;margin:1px 2px 1px 0;border-radius:6px;
  font-size:13px;max-width:100%;overflow-wrap:anywhere;vertical-align:top}
.uop-add{background:var(--t-addr-bg);color:var(--t-addr-fg)}
.uop-edit{background:var(--t-mx-bg);color:var(--t-mx-fg)}
.uop-remove{background:var(--t-txt-bg);color:var(--t-txt-fg)}

/* the compact lists: busiest zones, by day */
.uzones{list-style:none;margin:10px 0 0;padding:0;display:grid;
  grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:2px 16px}
.uzones li{display:flex;justify-content:space-between;gap:10px;padding:5px 0;
  border-bottom:1px solid var(--divider);min-width:0}
.uzones li a{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* the change table leans on the zone and the operations, not the timestamp. The change column
   is bounded so a zone with many operations wraps inside its own cell instead of stretching
   the table. */
.usage-changes td:first-child{white-space:nowrap}
.usage-changes td:nth-child(3){max-width:380px}
.usage-changes td:nth-child(2){max-width:220px;overflow-wrap:anywhere}

/* Tool-shell alignment with SafePW and IP Checker, 2026-10-05. */
.topbar{background:#F7FBF9;border-bottom-color:var(--control)}
.topbar-in{min-height:76px;gap:18px;flex-wrap:wrap}
.brand{gap:18px;flex-shrink:0}
.brand-product{font-family:var(--sans);font-weight:600;font-size:16px;line-height:1.55;letter-spacing:0;color:var(--atlantic);padding:4px 12px;border:1px solid var(--control);border-radius:999px;background:var(--mist);display:inline-block}
.nav{flex-wrap:wrap}
.nav .logout,.nav .client-area{border:1px solid var(--control);color:var(--atlantic);background:var(--white);padding:0 16px;margin-left:6px}
.nav .logout:hover,.nav .client-area:hover{background:var(--mist);border-color:var(--action)}
.foot-logo{height:32px}
.foot-text{flex:1 1 190px}
.foot-links{flex-wrap:wrap;gap:4px}
@media(max-width:960px){.topbar-in{padding-top:8px;padding-bottom:8px;gap:8px 18px}.nav{width:100%;margin-left:0;justify-content:flex-end}}
@media(max-width:760px){.topbar-in{padding:8px 16px;gap:8px 10px}.brand{gap:10px}.brand-logo{height:26px}.brand-product{display:inline-block;font-size:14px;padding:4px 8px;line-height:1.55}.nav{gap:4px;justify-content:flex-start}.nav a{padding:0 10px;font-size:14px}.nav .logout,.nav .client-area{margin-left:0;padding:0 12px}.foot-logo{height:26px}.foot-in{gap:10px}.foot-text{flex:1 1 160px;order:0}.foot-links{width:100%;margin-left:0}.foot-links a{font-size:14px;padding:0 8px}}
