/* Palette and typography mirror landing/public/styles.css */
/* --site-header-h is the height of the sticky .site-header: .header-inner's 24px+24px padding, the
   ~30px line box of the 26px .brand and the 1px .reading-track. Anything scrolled to by a #hash
   offsets by it (scroll-margin-top) so the header does not cover the heading it landed on. */
:root{--paper:#f6f8f7;--white:#fff;--ink:#1c302b;--muted:#65746f;--line:#d9e1dd;--accent:#ff825b;--rust:#a84428;--site-header-h:80px;color-scheme:light;font-family:Arial,Helvetica,sans-serif;color:var(--ink);background:var(--paper)}
*{box-sizing:border-box}body{margin:0}a{color:inherit;text-decoration:none}::selection{background:#ffd6c7}
.wrap{width:min(1000px,calc(100% - 48px));margin:40px auto}
.site-header{position:sticky;top:0;background:rgba(246,248,247,.95);z-index:30}
.header-inner{max-width:1440px;margin:auto;padding:24px 56px;display:flex;justify-content:space-between;align-items:center;gap:20px}
.brand{font-size:26px;font-weight:700;letter-spacing:0;display:inline-flex;align-items:center}
.brand svg,.empty svg{width:29px;height:29px;margin-right:9px;fill:none;stroke:var(--ink);stroke-width:1.7}
.brand-dot{color:var(--rust)}
nav{display:flex;align-items:center;gap:28px;font-size:14px}
.reading-track{height:1px;background:var(--line)}
.eyebrow{font-size:12px;letter-spacing:1.6px;font-weight:600;margin:0 0 20px;display:flex;align-items:center;gap:12px}
.tiny-line{width:24px;height:2px;background:var(--rust)}
h1{font-size:clamp(32px,4vw,48px);line-height:1.1;letter-spacing:-.04em;font-weight:400;margin:0 0 18px}
.hero-claim{word-break:break-all}
h2{font-weight:400;letter-spacing:-.02em}
.lead{font-size:18px;line-height:1.55;color:#576860}
.muted{color:var(--muted)}
.card{background:var(--white);border:1px solid var(--line);border-radius:6px;padding:40px;margin-bottom:24px}
.narrow{max-width:460px;margin:40px auto}
.stack{display:grid;gap:18px}
.row{display:flex;gap:14px;flex-wrap:wrap}.grow{flex:1;min-width:220px}
label{display:grid;gap:8px;font-size:14px;font-weight:600}
input{font:inherit;font-weight:400;padding:15px 16px;border:1px solid var(--line);border-radius:4px;background:var(--paper);color:var(--ink);width:100%}
input:focus{outline:3px solid #ffd6c7;border-color:var(--accent)}
.button{min-height:56px;padding:0 25px;display:inline-flex;align-items:center;justify-content:space-between;gap:40px;border-radius:4px;font-size:15px;font-weight:600;border:0;cursor:pointer;transition:transform .25s,box-shadow .25s}
.button:hover{transform:translateY(-3px);box-shadow:0 8px 18px #1c302b12}
.button span{font-size:23px}
.primary{background:var(--accent);color:var(--ink)}
.link{color:var(--rust);text-decoration:underline}
.link-button{background:none;border:0;padding:0;cursor:pointer;font-weight:600;color:var(--ink)}
.inline{display:inline}
.error{background:#fff1ec;border-left:3px solid var(--rust);padding:12px 16px;color:var(--rust)}
.domain-list{list-style:none;padding:0;margin:0}
.domain-list li{display:flex;justify-content:space-between;border-top:1px solid var(--line);padding:16px 0}
.domain-list a{font-weight:600}
.empty{text-align:center;padding:40px 0;border:1px dashed var(--line);border-radius:6px;margin:20px 0}
.empty svg{width:48px;height:48px;stroke:var(--accent);margin:0}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:20px}
.panel{border:1px solid var(--line);border-radius:6px;padding:20px}.panel h3{margin:0 0 8px;font-size:15px}.panel p{margin:0}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
@media(max-width:700px){.header-inner{padding:18px 20px}.card{padding:24px}nav{gap:14px}}
.verify{border:1px dashed var(--accent);border-radius:6px;padding:24px;margin:20px 0}
.record{display:grid;grid-template-columns:max-content 1fr;gap:8px 16px;margin:0 0 20px}
.record dt{font-weight:600}.record dd{margin:0;word-break:break-all}
code{background:var(--paper);padding:2px 6px;border-radius:3px}
.verified{color:#2c6b4f;font-weight:600}
/* report */
.badge{display:inline-block;font-size:12px;font-weight:600;padding:3px 8px;border-radius:3px;background:var(--paper);border:1px solid var(--line);vertical-align:middle}
.badge.ok{color:#2c6b4f;border-color:#b9d9c8}.badge.warn{color:var(--rust);border-color:#f3c3b3}
/* "Sample data" (darknet placeholder): the label has to read as a warning on its own peach chip, so
   its text is a darker rust than var(--rust) - 6.9:1 on #fff1ec, and the chip outline 4.1:1 against
   the white card, i.e. past 1.4.3 (4.5:1 text) and 1.4.11 (3:1 non-text). Pinned by a test. */
.badge.sample{background:#fff1ec;color:#8c3a22;border-color:#d4552c}
.small{font-size:13px}
.facts{display:grid;grid-template-columns:max-content 1fr;gap:6px 16px;margin:0}.facts dt{color:var(--muted)}.facts dd{margin:0;font-weight:600}
.sev{display:inline-block;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;padding:3px 8px;border-radius:3px;background:var(--paper)}
.sev-critical{background:#5c1a0b;color:#fff}.sev-high{background:var(--rust);color:#fff}.sev-medium{background:var(--accent);color:var(--ink)}
/* #338: every severity badge carries its name as text; text contrast is >= 4.5:1 (WCAG AA)
   on its own background - critical 13.1, high 6.0, medium 5.7, low 11.1, info 7.7 (pinned by a test) */
.sev-low{background:#ffe2a8;color:var(--ink)}.sev-info{background:#e6ece9;color:#3f4a46}
.group{margin-top:36px}.group h2{display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.pre{white-space:pre-wrap;overflow-wrap:anywhere}
pre{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--paper);padding:12px;border-radius:4px;font-size:12px;max-height:400px;overflow:auto}
/* severity colour of a left border. The .finding.sev-border-* twin (#467) outranks the later .finding
   rule's border shorthand by specificity, not by source order, so the colour survives a CSS reshuffle */
.sev-border-critical,.finding.sev-border-critical{border-left-color:#5c1a0b}
.sev-border-high,.finding.sev-border-high{border-left-color:var(--rust)}
.sev-border-medium,.finding.sev-border-medium{border-left-color:var(--accent)}
.sev-border-low,.finding.sev-border-low{border-left-color:#ffd27a}
.sev-border-info,.finding.sev-border-info{border-left-color:var(--line)}

/* darknet research */
/* the note that goes with the "Sample data" badge: var(--muted) is only 4.9:1 on the white card and
   4.6:1 on var(--paper), too thin a margin for the one line that says the records are invented, so
   it gets its own darker ink (7.2:1 / 6.8:1). Pinned by the same test as the badge. */
.darknet .sample-note { color: #4e5a55; }
.darknet table { width: 100%; border-collapse: collapse; font-size: .9rem; margin: .5rem 0 1rem; }
.darknet th, .darknet td { text-align: left; padding: .35rem .5rem; border-bottom: 1px solid rgba(127,127,127,.2); }
.darknet tr.cookie-valid { background: rgba(220, 60, 60, .08); }
.darknet tr.cookie-expired { opacity: .7; }
.darknet .trend-up { color: #d9534f; } .darknet .trend-down { color: #3c9d5d; }
.darknet .devices li { margin: .4rem 0; }
/* manager summary (#36) */
.report-nav { margin: .5rem 0 1rem; font-size: .9rem; }
.mgr { margin: 1rem 0 2rem; }
.mgr-top { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: center; }
.mgr figure { margin: 0; }
.mgr figcaption { font-size: .85rem; opacity: .75; text-align: center; }
.gauge-bg { stroke: rgba(127,127,127,.2); }
.gauge-grade { font-size: 34px; font-weight: 700; }
.gauge-num { font-size: 13px; fill: currentColor; }
.sevbars { flex: 1 1 260px; max-width: 420px; }
.bar-label, .bar-num { font-size: 12px; fill: currentColor; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: .75rem; margin: 1rem 0; }
.scard { display: flex; flex-direction: column; gap: .2rem; padding: .75rem; border-radius: 10px;
         border: 1px solid rgba(127,127,127,.3); text-decoration: none; color: inherit; }
.scard .dot { width: 12px; height: 12px; border-radius: 50%; background: #9ca3af; }
.light-green .dot { background: #16a34a; } .light-amber .dot { background: #ca8a04; } .light-red .dot { background: #dc2626; }
.risks li, .steps li { margin: .35rem 0; }
.filter { display: flex; flex-wrap: wrap; gap: .75rem; align-items: end; margin: .75rem 0; }
@media print {
  .no-print, nav, header form, .filter, .demo-convert { display: none !important; }
  .mgr { page-break-after: always; }
  details { display: block; } details > * { display: block; }
  a { color: inherit; text-decoration: none; }
}
/* report history (#30) */
.history table { border-collapse: collapse; width: 100%; margin: .5rem 0; font-size: .9rem; }
.history th, .history td { padding: .25rem .5rem; border-bottom: 1px solid rgba(127,127,127,.25); text-align: left; }
svg.trend { max-width: 360px; display: block; margin: .5rem 0; overflow: visible; }
svg.trend .grid { stroke: rgba(127,127,127,.3); stroke-width: 1; }
svg.trend .axis { font-size: 11px; fill: currentColor; opacity: .75; }
svg.trend .plabel { font-size: 11px; fill: currentColor; font-weight: 600; }
svg.trend .plabel.latest { font-size: 12px; }
svg.trend .band { opacity: .07; } svg.trend .band-a { fill: #16a34a; } svg.trend .band-b { fill: #65a30d; }
svg.trend .band-c { fill: #ca8a04; } svg.trend .band-d { fill: #ea580c; } svg.trend .band-f { fill: #dc2626; }
svg.trend .line { stroke: #3b82f6; stroke-width: 2; }
svg.trend .dot { fill: #3b82f6; }
svg.trend .dot.latest { fill: #1d4ed8; stroke: #fff; stroke-width: 2; }
svg.trend .dot.partial { fill: #f59e0b; }
.trend-card { display: inline-block; border: 1px solid rgba(127,127,127,.35); border-radius: 8px; padding: .5rem .85rem; margin: .5rem 0; }
.trend-card p { margin: .15rem 0; }
.delta { font-weight: 600; white-space: nowrap; } .delta-up { color: #15803d; } .delta-down { color: #b91c1c; }
.delta-flat, .delta-none { opacity: .8; font-weight: 400; }
.trend-data summary { cursor: pointer; font-size: .85rem; }
.trend-table { font-size: .85rem; border-collapse: collapse; } .trend-table td, .trend-table th { padding: .15rem .6rem; text-align: left; }
@media print { svg.trend .band { opacity: .12; } .trend-data[open] summary, .trend-data summary { display: none; } .trend-data .trend-table { display: table; } }

.benchmark{margin:.8rem 0 0}
.mgr-headline{border-left:4px solid #16a34a;padding:.6rem .9rem;margin:.6rem 0}
.site-footer{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;border-top:1px solid var(--line);padding:24px 0 32px;margin-top:24px}
.footer-links{display:flex;gap:18px;font-size:13px}.footer-links a{color:inherit;opacity:.8}.footer-links a:hover{opacity:1;text-decoration:underline}
.hp{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}/* checkbox rows (#185): exactly two grid cells, box + one text <span>, so text and links wrap as prose */
.check{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;align-items:start;font-size:14px;font-weight:400;line-height:1.5;cursor:pointer}
.check>span{min-width:0;overflow-wrap:anywhere}
input[type=checkbox],input[type=radio]{width:18px;height:18px;padding:0;margin:2px 0 0;accent-color:var(--accent);flex:none}
input[type=checkbox]:focus-visible,input[type=radio]:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
.qr{display:block;margin:16px auto;background:#fff;border:1px solid var(--line);border-radius:8px;image-rendering:pixelated}
.mono{font-family:'Courier New',monospace}
.recovery-codes{columns:2;list-style:none;padding:0;font-size:16px;line-height:2}
/* verification card (#31) + start flow (#33): no JS, CSP-safe */
.verify-card{border:1px solid var(--line);border-left:4px solid var(--accent);border-radius:6px;padding:24px;margin:20px 0;background:var(--white)}
.verify-card.state-failed,.verify-card.state-dns_error,.verify-card.state-stale{border-left-color:var(--rust)}
.verify-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.verify-card-head h2{margin:0}
.verify-steps{margin:12px 0 20px}.verify-steps summary{cursor:pointer;font-weight:600}
.vsteps{padding-left:20px}.vsteps li{margin:8px 0}
.copy-fields{display:grid;grid-template-columns:1fr;gap:8px;margin-top:8px}
.copy-fields label{display:grid;gap:4px;font-size:13px;font-weight:600}
input.copy{font-family:ui-monospace,monospace;font-size:13px;width:100%;padding:8px;border:1px solid var(--line);border-radius:4px;background:var(--paper)}
input.copy.narrow{max-width:80px}
.topup-form input[type=number]{max-width:8rem}  /* #556: Quantity on /billing and the dashboard, not full card width */
.flow-steps{display:flex;gap:16px;flex-wrap:wrap;list-style:none;padding:0;margin:0 0 20px;font-size:14px}
.flow-steps li{color:var(--muted,#6b7a76)}.flow-steps li.current{font-weight:700;color:inherit}.flow-steps li.done{color:#2c6b4f}
.start-form fieldset{border:0;padding:0;margin:0 0 16px}.start-form .radio{display:block;margin:8px 0}.start-form .check{margin:8px 0}
.small-btn{min-height:40px;padding:0 16px;gap:16px;margin-left:8px}
.notice{background:#eef6f1;border-left:3px solid #2c6b4f;padding:12px 16px}
.start-form .radio.disabled{color:#5f6368;cursor:not-allowed}.start-form .radio.disabled input{cursor:not-allowed}.notice.warn{background:#fff7e6;border-left-color:#8a5a00;margin:4px 0 8px}
@media (min-width:720px){.copy-fields{grid-template-columns:2fr 80px 3fr}}
/* #208: no horizontal page overflow at 375px. Wide tables scroll inside .scroll-x; long URLs in findings wrap (table cells stay intact and scroll);
   the header nav wraps (Log out stays on screen) and a long email is truncated. */
.scroll-x{overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch}.scroll-x>table{margin-top:0}
.finding-body code,.finding-body a{overflow-wrap:anywhere}
@media(max-width:700px){.header-inner{flex-wrap:wrap;row-gap:10px}.site-header nav{flex-wrap:wrap;row-gap:8px;min-width:0;max-width:100%}.site-header nav .muted{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}

/* ---- report page redesign (#338) ------------------------------------------------------------- */
/* header: domain + badge on the left, actions in one row on the right */
.rep-head{display:flex;flex-wrap:wrap;gap:16px;align-items:flex-end;justify-content:space-between}
.rep-head .rep-title{min-width:0;flex:1 1 320px}
.rep-head h1{margin:0 0 8px}
.rep-head .verified{margin:0}
.rep-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px}
.rep-actions .small-btn{margin-left:0}
.pdf-dl{display:block}
/* one compact status bar instead of a stack of separate banners */
.rep-status{display:grid;gap:4px;margin:16px 0 8px;padding:10px 14px;border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:4px;background:var(--paper)}
.rep-status:empty{display:none}
.rep-status .note{margin:0}
.rep-status .note.error{background:none;border:0;padding:0;color:var(--rust)}
.rep-status .note.started{font-weight:600}
/* summary on top: one score box (gauge) + severity pills */
.score-box{flex:0 0 160px;max-width:160px}
.score-box svg{max-width:100%;height:auto}
.mgr-facts{flex:1 1 280px;min-width:0}
.sevpills{list-style:none;display:flex;flex-wrap:wrap;gap:8px;padding:0;margin:0 0 10px}
.sevpills .sev{font-size:13px;padding:7px 11px}
.sevpills a.pill{text-decoration:none}
.sevpills a.pill:hover{text-decoration:underline}
.posture{margin:.4rem 0}
.score-formula{margin:.6rem 0 1rem}
.score-formula summary,.low-info-group>summary,.hist-compare>summary,.hist-full>summary,.pentest-exec>summary{cursor:pointer;font-weight:600;font-size:14px}
.pentest-exec{margin:1rem 0}
/* one prioritized findings list */
.findings{margin-top:28px}
/* #470: the group's <summary> is a full-width bar in the style of the finding cards (border, padding,
   a chevron that turns on [open]) - it used to be a bare 16px line of text. Text and markup unchanged. */
.low-info-group{margin:16px 0}
.low-info-group>summary{
  list-style:none;display:flex;align-items:center;gap:8px;min-height:52px;padding:12px 20px;
  background:var(--white);border:1px solid var(--line);border-left-width:4px;border-radius:6px}
.low-info-group>summary::-webkit-details-marker{display:none}
.low-info-group>summary:hover{background:#fbfcfb}
.low-info-group>summary:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
.low-info-group>summary::after{
  content:"";flex:none;width:9px;height:9px;margin:0 6px 0 auto;border-right:2px solid var(--ink);
  border-bottom:2px solid var(--ink);transform:rotate(45deg) translateY(-3px)}
.low-info-group[open]>summary::after{transform:rotate(-135deg) translateY(-1px)}
.low-info-body{margin-top:8px}
/* ---- finding card (#467): template + CSS only; layout from the findings UX spec, part B ---------- */
/* collapsed: tags row, h3 title, affected URL, chips, excerpt, toggle - all inside the <summary>, which
   stays the whole tap target. Secondary text is #4e5a55 (7.2:1 on white, 6.8:1 on paper), not
   var(--muted). Only URLs and code break anywhere; badges, chips and short labels never mid-word.
   <summary> takes phrasing content only: the URL, chips and excerpt are spans, displayed as blocks here. */
.finding{
  background:var(--white);border:1px solid var(--line);border-left-width:4px;border-radius:6px;
  margin:12px 0}
.finding>summary{list-style:none;cursor:pointer;padding:18px 20px 16px;display:grid;gap:10px;border-radius:6px}
.finding>summary::-webkit-details-marker{display:none}
.finding>summary:hover{background:#fbfcfb}
.finding>summary:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
.finding[open]>summary{border-bottom:1px solid var(--line);border-radius:6px 6px 0 0}
.finding-tags{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.finding-tags .sev,.finding-tags .badge{white-space:nowrap}
.finding-tags .sev{padding:4px 9px}
.src-tag{
  display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;letter-spacing:.3px;color:#4e5a55;
  padding:3px 8px;border:1px solid var(--line);border-radius:999px;background:var(--white);white-space:nowrap}
.src-tag::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--muted)}
.src-ai-pentest::before{background:var(--rust)}
.finding-title{
  margin:0;font-size:19px;line-height:1.3;font-weight:600;letter-spacing:-.01em;overflow-wrap:anywhere}
.finding-url{display:block;margin:0;font-size:13px;color:#4e5a55;min-width:0}
.finding-url code{
  font-family:ui-monospace,'Courier New',monospace;font-size:13px;overflow-wrap:anywhere;word-break:break-all}
.chips{margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.chips>span{
  font-size:12px;font-weight:600;background:var(--paper);border:1px solid var(--line);border-radius:4px;
  padding:3px 8px;white-space:nowrap;max-width:100%}
/* the OWASP value is free text up to 100 chars ("A07:2021 – Identification and ..."): it wraps between
   words; a single token wider than the card is broken (overflow-wrap:anywhere, as #195 requires) */
.chips>.chip-owasp,.chips>.chip-cwe{white-space:normal;overflow-wrap:anywhere}
.chips abbr{text-decoration:none}
.finding-excerpt{
  display:block;margin:0;font-size:15px;line-height:1.55;color:#4e5a55;max-width:72ch;overflow-wrap:anywhere}
.finding-toggle{
  justify-self:start;display:inline-flex;align-items:center;gap:8px;min-height:24px;font-size:14px;font-weight:600;
  color:var(--rust);white-space:nowrap}
.finding-toggle::after{
  content:"";width:8px;height:8px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(45deg) translateY(-3px)}
.finding-toggle .when-open{display:none}
.finding[open] .finding-toggle .when-open{display:inline}
.finding[open] .finding-toggle .when-closed{display:none}
.finding[open] .finding-toggle::after{transform:rotate(-135deg) translateY(-2px)}
/* the full description is right below, so the excerpt goes once the card is open */
.finding[open] .finding-excerpt{display:none}
/* open: facts box on top (2 columns) on a phone, a sticky side column with jump links from 900px */
.finding-body{
  padding:8px 20px 24px;display:grid;grid-template-columns:minmax(0,1fr);grid-template-areas:"side" "main"}
.finding-main{grid-area:main;min-width:0}
.finding-side{grid-area:side;min-width:0}
.finding-facts{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 16px;margin:8px 0 6px;padding:14px 16px;
  background:var(--paper);border:1px solid var(--line);border-radius:6px}
.finding-facts div{min-width:0}
.finding-facts dt{font-size:12px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:#4e5a55}
.finding-facts dd{margin:2px 0 0;font-size:14px;font-weight:600;overflow-wrap:anywhere}
.finding-facts dd .sub{display:block;font-weight:400;font-size:13px;color:#4e5a55}
/* the found date and time wrap only between each other, never inside "2026-10-11" or "20:59 CEST" */
.finding-facts .nowrap{white-space:nowrap}
.finding-toc{display:none}
.fsec{border-bottom:1px solid var(--line)}
.fsec:last-child{border-bottom:0}
.fsec>summary{
  list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px;
  min-height:52px;padding:6px 0}
.fsec>summary::-webkit-details-marker{display:none}
.fsec>summary:focus-visible{outline:3px solid var(--ink);outline-offset:2px;border-radius:2px}
.fsec>summary h4{margin:0;font-size:17px;font-weight:600;letter-spacing:-.01em}
.fsec>summary::after{
  content:"";flex:none;width:9px;height:9px;margin-right:6px;border-right:2px solid var(--ink);
  border-bottom:2px solid var(--ink);transform:rotate(45deg) translateY(-3px)}
.fsec[open]>summary::after{transform:rotate(-135deg) translateY(-1px)}
.fsec-body{padding:2px 0 22px}
.fsec-body .prose{margin:0;font-size:16px;line-height:1.6;max-width:68ch}
.fsec>summary h4 .hint{margin-left:8px;font-size:13px;font-weight:400;letter-spacing:0;color:#4e5a55}
/* #467 PR2: structured description blocks (only when the upstream finding has them) */
.dblock{margin:0 0 18px;max-width:68ch}
.dblock:last-child{margin-bottom:0}
.dblock h5{
  margin:0 0 6px;font-size:12px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:#4e5a55}
.dblock p{margin:0;font-size:16px;line-height:1.6}
/* numbered remediation steps: a real <ol>, the number drawn in a circle from a CSS counter */
.fsec-body ol.steps{list-style:none;counter-reset:step;margin:0;padding:0;display:grid;gap:12px;max-width:68ch}
.fsec-body ol.steps>li{
  counter-increment:step;position:relative;padding-left:40px;min-height:28px;font-size:16px;line-height:1.6}
.fsec-body ol.steps>li::before{
  content:counter(step);position:absolute;left:0;top:0;width:28px;height:28px;border-radius:50%;
  background:var(--paper);border:1px solid var(--line);font-size:13px;font-weight:700;line-height:1;
  display:flex;align-items:center;justify-content:center}
/* raw evidence: unchanged text, but long lines scroll inside the block, never the page; the <pre> is a
   role=region named by its h4, and tabindex=0 makes the scroll region keyboard-reachable */
.finding pre.evidence{
  margin:0;padding:14px;border-radius:6px;background:var(--paper);border:1px solid var(--line);white-space:pre;
  overflow-wrap:normal;overflow:auto;max-height:320px;font-family:ui-monospace,'Courier New',monospace;
  font-size:13px;line-height:1.5}
.finding pre.evidence:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
@media(min-width:900px){
  .finding>summary{padding:20px 24px 18px}
  .finding-body{
    grid-template-columns:minmax(0,1fr) 248px;grid-template-areas:"main side";column-gap:36px;
    padding:8px 24px 28px}
  .finding-side{position:sticky;top:calc(var(--site-header-h) + 16px);align-self:start;margin-top:14px}
  .finding-facts{grid-template-columns:1fr;margin:0}
  .finding-toc{display:block;margin-top:14px}
  .finding-toc h4{
    margin:0 0 6px;font-size:12px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:#4e5a55}
  .finding-toc ul{list-style:none;margin:0;padding:0;border-left:2px solid var(--line)}
  .finding-toc a{display:flex;align-items:center;min-height:36px;padding:0 12px;font-size:14px}
  .finding-toc a:hover{color:var(--rust);text-decoration:underline}
  .finding-toc a:focus-visible{outline:3px solid var(--ink);outline-offset:0}
  .finding-toc .toc-hint{margin-left:6px;font-size:12px;font-weight:400;color:#4e5a55;white-space:nowrap}
}
@media(max-width:700px){
  /* report page only: the report card reaches 12px from the screen edge (the .wrap gives 24px; .wrap
     is shared by every page, so the card widens itself instead) and gets slimmer padding: a 390px
     phone gets ~300px of finding text instead of ~256px */
  .card.report-page{padding:20px 16px;margin-left:-12px;margin-right:-12px}
  .finding>summary{padding:16px 16px 14px}
  .finding-body{padding:4px 16px 20px}
  .finding-title{font-size:18px}
}
@media print{
  /* on paper: no toggle or jump links, the side facts above the text and evidence wrapped instead of
     scrolling. Open cards and sections print in full. */
  .finding-toggle,.finding-toc{display:none!important}
  .finding-body{display:block}
  .finding pre.evidence{white-space:pre-wrap;overflow-wrap:anywhere;max-height:none;overflow:visible}
}
/* closed <details> content is not printed by "details > * {display:block}" (the content slot stays
   hidden). Where ::details-content is supported (Chromium 131+, Safari 18.4+) closed cards, sections and
   the low/info group print expanded too, and the excerpt (the description follows in full) is dropped;
   elsewhere closed ones print collapsed, summary only. CSS only, the page itself is not changed. Own rule
   inside @supports: an unknown pseudo-element would void a whole selector list. */
@supports selector(::details-content){
  @media print{
    .finding::details-content,.fsec::details-content,.low-info-group::details-content{
      display:block;content-visibility:visible}
    .finding-excerpt{display:none}
  }
}
/* per-scan overview */
.scans{margin-top:32px}
.scan-cards .scard .sevpills{margin:6px 0 0}
.scan-cards .scard .sevpills .sev{font-size:12px;padding:3px 8px}
/* history: compact table first, the rest in <details> */
.history-compact{border-collapse:collapse;width:100%;margin:.5rem 0;font-size:.9rem}
.history-compact th,.history-compact td{padding:.25rem .5rem;border-bottom:1px solid rgba(127,127,127,.25);text-align:left}
.hist-compare,.hist-full{margin:.5rem 0}
@media(max-width:700px){
  /* single column: header, summary top, cards and pills all stack */
  .rep-head,.mgr-top{flex-direction:column;align-items:stretch}
  /* the 320px basis is a column width; in a column it would be a 320px-tall title block */
  .rep-head .rep-title{flex-basis:auto}
  .rep-actions{flex-direction:column;align-items:stretch}
  .rep-actions .button{justify-content:center;gap:12px}
  /* #493: in a column flex sizes the height. Stretched to the column width, the figure's height came from
     the SVG's height="132" while the SVG drew 200px tall, so the pills overlapped the gauge and its caption:
     the gauge gets a definite width and its content height. The facts' 280px basis must not become a
     280px-tall block (blank gap below the pills). */
  .score-box{flex:0 0 auto;width:200px;max-width:100%}
  .mgr-facts{flex:0 0 auto}
  .cards{grid-template-columns:1fr}
  .sevpills{gap:6px}
  /* wide report tables become stacked cards; each cell keeps its header via data-label */
  .history-compact thead,.history-table thead,.compare-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .history-compact tr,.history-table tr,.compare-table tr{display:block;border:1px solid var(--line);border-radius:6px;padding:8px 10px;margin:8px 0;background:var(--white)}
  .history-compact td,.history-table td,.compare-table td,.compare-table th[scope=row]{display:flex;justify-content:space-between;gap:12px;border:0;padding:3px 0;text-align:left}
  .history-compact td::before,.history-table td::before,.compare-table td::before{content:attr(data-label);font-weight:600;color:var(--muted)}
  .scroll-x>table{min-width:0}
}

/* ---- report tabs (#355): five tab panels, CSS only (strict CSP forbids script) ---------------- */
/* The bar is a <nav> of links to the panel ids and the state is the URL fragment: the panel shown is
   the one that is :target or :has(:target) - the second half makes a deep link inside a panel
   (#portscan, #ai-pentest, #darknet-research, a finding anchor) open the panel holding it. Every rule
   that HIDES a panel lives inside @supports selector(:has(*)), so a browser without :has() renders
   all five panels stacked, i.e. the page exactly as it was before #355. */
.tabbar{display:flex;flex-wrap:wrap;gap:4px;margin:22px 0 20px;padding:0;border-bottom:1px solid var(--line);font-size:15px}
.tabbar a{display:inline-flex;align-items:center;min-height:44px;padding:0 16px;margin-bottom:-1px;border:1px solid transparent;border-radius:6px 6px 0 0;color:var(--muted);font-weight:600;text-decoration:none;white-space:nowrap}
.tabbar a:hover{color:var(--ink);background:var(--paper)}
.tabbar a:focus-visible{outline:3px solid var(--ink);outline-offset:-3px}
.dn-empty{margin:.4rem 0 0}
/* The tab state IS the fragment, so every tab click is a scroll to an anchor - and .site-header is
   sticky, so without this the browser parks the panel heading underneath it. Offset the panels, the
   headings inside them and every in-panel anchor (#portscan, #ai-pentest, #darknet-research, the
   benchmark line) by the header height; .report-page [id] also covers the un-tabbed layout the page
   falls back to while there is no score (#darknet-research and #history as plain sections). */
.tabs,.tabpanel,.tabpanel h2,.tabpanel h3,.tabpanel [id],.report-page [id]{scroll-margin-top:var(--site-header-h)}
@supports selector(:has(*)){
  /* only one panel is on screen at a time, so it starts right under the bar; in the stacked
     fallback the sections keep the spacing that separates them */
  .tabpanel{display:none;margin-top:0}
  .tabpanel>h2:first-child,.tabpanel>h3:first-child{margin-top:0}
  .tabpanel:target,.tabpanel:has(:target){display:block}
  /* no panel targeted (plain /reports/<domain>) -> the default panel, Executive summary */
  .tabs:not(:has(.tabpanel:target)):not(:has(.tabpanel :target)) .tab-default{display:block}
  /* the current tab is highlighted from the same :target state - there is no aria-current to key
     off, because the server never sees the fragment and nothing can move the attribute (#355
     follow-up); these selectors are the single source of truth for "which tab is current" */
  .tabs:not(:has(.tabpanel:target)):not(:has(.tabpanel :target)) .tabbar a[href="#summary"],
  .tabs:has(#summary:target) .tabbar a[href="#summary"],
  .tabs:has(#summary :target) .tabbar a[href="#summary"],
  .tabs:has(#findings:target) .tabbar a[href="#findings"],
  .tabs:has(#findings :target) .tabbar a[href="#findings"],
  .tabs:has(#scans:target) .tabbar a[href="#scans"],
  .tabs:has(#scans :target) .tabbar a[href="#scans"],
  .tabs:has(#darknet:target) .tabbar a[href="#darknet"],
  .tabs:has(#darknet :target) .tabbar a[href="#darknet"],
  .tabs:has(#history:target) .tabbar a[href="#history"],
  .tabs:has(#history :target) .tabbar a[href="#history"]{background:var(--white);border-color:var(--line);border-bottom-color:var(--tab-cut,var(--white));color:var(--ink);--tab-mark:var(--rust)}
}
@media(max-width:700px){
  /* #470: the five tabs WRAP into rows of touch-sized buttons. They used to be one nowrap strip with
     overflow-x:auto (570px of tabs in a 332px bar at 390px): Darknet and History sat off-screen, and the
     strip is a scroll container whose scrollLeft survives every same-page #fragment jump - once it was
     swiped (or a focused/tapped tab was scrolled into view) every later tab switch showed a bar with the
     first tab cut off, and no CSS can reset that without JS. A wrapping bar is no scroll container at
     all, so nothing can leave it scrolled and every tab is always in view. Each tab is a bordered
     button here (a folder tab cannot join a bottom line from the upper row); the current one is white
     with a rust underline (--tab-mark, set by the :target rules above). */
  .tabbar{flex-wrap:wrap;gap:6px;border-bottom:0;--tab-cut:var(--line)}
  .tabbar a{
    flex:1 1 auto;justify-content:center;min-height:44px;padding:0 12px;margin:0;border-color:var(--line);
    border-radius:6px;background:var(--paper);box-shadow:inset 0 -3px 0 var(--tab-mark,transparent)}
  /* .header-inner and the nav both wrap here, so the sticky header is TALLER on a phone: with two nav
     rows plus the 8px row-gap it totals 117px, and a long e-mail address wraps the nav to a third row,
     about 141px. Rounded up on purpose - overshooting only leaves blank space above the heading,
     undershooting hides the heading under the header, which is the bug being fixed. */
  :root{--site-header-h:144px}
}
@media print{
  /* on paper there are no tabs: the bar is dropped and every panel is printed in order */
  .tabbar{display:none!important}
  .tabpanel{display:block!important}
}

/* ---- onboarding checklist (#48): dashboard card + /onboarding wizard; no JS, CSP-safe ------------ */
.ob-card{border-top:4px solid var(--accent)}
.ob-card-head{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:8px 16px}
.ob-card-head h2{margin:0}
.ob-progress{appearance:none;-webkit-appearance:none;display:block;width:100%;height:8px;margin:14px 0 18px;border:0;border-radius:4px;background:var(--line);color:var(--accent);overflow:hidden}
.ob-progress::-webkit-progress-bar{background:var(--line);border-radius:4px}
.ob-progress::-webkit-progress-value{background:var(--accent);border-radius:4px}
.ob-progress::-moz-progress-bar{background:var(--accent);border-radius:4px}
.ob-mark{flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;border:1px solid var(--line);background:var(--paper);font-size:13px;font-weight:700}
.ob-done .ob-mark{background:#2c6b4f;border-color:#2c6b4f;color:#fff}
.ob-current .ob-mark{background:var(--accent);border-color:var(--accent);color:var(--ink)}
.ob-mini{list-style:none;padding:0;margin:0 0 20px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px 18px}
.ob-mini li{display:flex;align-items:center;gap:10px;font-size:14px;min-width:0}
.ob-mini li>span:last-child{min-width:0;overflow-wrap:anywhere}
.ob-mini .ob-done{color:#2c6b4f}.ob-mini .ob-current{font-weight:700}.ob-mini .ob-todo{color:var(--muted)}
.ob-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px 24px;margin-top:8px}
.ob-actions .small-btn{margin-left:0}
.ob-steps{list-style:none;padding:0;margin:8px 0 24px}
.ob-step{border:1px solid var(--line);border-radius:6px;padding:18px 20px;margin:12px 0;background:var(--white)}
.ob-step.ob-current{border-left:4px solid var(--accent);padding:22px 24px}
.ob-step.ob-done{background:var(--paper)}
.ob-step-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.ob-step-head h2{margin:0;font-size:20px;flex:1 1 200px;min-width:0}
.ob-step-body{margin-left:40px}
.ob-step-body>p:last-child{margin-bottom:0}
.ob-step-body .verify-card{margin:16px 0 0}
.ob-empty h3{font-weight:400;font-size:20px;margin:12px 0 8px}
.ob-empty p{margin:8px 16px}
.ob-reopen{margin:16px 0 0}
@media(max-width:700px){
  .ob-step,.ob-step.ob-current{padding:16px}
  .ob-step-body{margin-left:0;margin-top:8px}
  .ob-step-head h2{font-size:18px}
  .ob-step .row .button,.ob-step-body>p>.button{width:100%;justify-content:center;gap:12px}
  .ob-actions{flex-direction:column;align-items:stretch}
  .ob-actions .button{justify-content:center;gap:12px}
  .ob-mini{grid-template-columns:1fr}
  .ob-step-body .verify-card{padding:16px}
}
.ob-step-body .copy-fields input.copy.narrow{justify-self:start}
/* #362 live test status in the report status bar (no progress bar: phase, elapsed, last activity) */
.live-status{display:grid;gap:4px}
.live-tests{list-style:none;margin:0;padding:0;display:grid;gap:4px}
.live-status .badge.live{color:var(--rust);border-color:#f3c3b3}
.live-status p{margin:0}

/* ---- dashboard domain rows (#363): row actions are buttons, not underlined links ---------------- */
/* Same classes as the report header actions (.button primary small-btn): "Start security test" is the
   primary action, "View report" the outline one. .button itself has no background, so .secondary is
   the first real outline style: ink on white is 13.9:1 and 13.1:1 on the var(--paper) hover (WCAG AA
   needs 4.5:1), and the border is var(--muted) at 4.9:1 against the card, past 1.4.11's 3:1 for a
   control boundary. The primary button keeps ink on var(--accent), 5.7:1, hover-invariant (.button:hover
   only moves and shadows). Pinned by tests/test_dashboard_buttons_363.py. */
.button.secondary{background:var(--white);color:var(--ink);border:1px solid var(--muted)}
.button.secondary:hover{background:var(--paper);border-color:var(--ink)}
/* .domain-rows is the dashboard's own list: .domain-list is shared with the admin, monitoring and
   start pages, whose rows keep the plain two-column layout */
.domain-rows li{align-items:center;gap:12px 16px;flex-wrap:wrap}
.domain-rows .domain-name{min-width:0;overflow-wrap:anywhere}
.domain-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:10px 12px}
.domain-actions .small-btn{margin-left:0}
.domain-actions .button:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
@media(max-width:700px){
  /* actions stack full-width under the domain name, each a 44px tap target */
  .domain-rows li{flex-direction:column;align-items:stretch}
  .domain-actions{flex-direction:column;align-items:stretch;justify-content:flex-start}
  .domain-actions .badge{align-self:start}
  .domain-actions .button{min-height:44px;justify-content:center;gap:12px}
  /* the unverified row's "Verify" stays a text link, but gets the same 44px tap target (2.5.5) */
  .domain-actions .link{display:inline-flex;align-items:center;min-height:44px;gap:.3em}  /* #336: inline-flex drops the space before the arrow */
}

/* ---- monitoring page redesign (#393): the #338 report-page shape for /monitoring --------------- */
/* Eyebrow + title + intro (shared .rep-head), a compact summary on top, an info notice, then one
   .mon-card per verified domain. Strict CSP forbids script, so the "switches" are plain checkboxes:
   they are styled as labelled rows with helper text, never as colour-only state. Every new colour
   below is >= 4.5:1 against the surface it sits on (pinned by tests/test_monitoring_redesign_393.py):
   #4e5a55 helper/status ink 7.2:1 on white and 6.7:1 on var(--paper), the "active" green
   #2c6b4f 6.3:1 / 5.9:1, and the notice's ink 12.4:1 on its own #eef2f7 with an 8.1:1 bar. */
.mon-page .lead{margin:0}
.mon-summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;margin:24px 0 20px}
.mon-stat{border:1px solid var(--line);border-radius:6px;padding:14px 16px;background:var(--paper)}
.mon-stat dt{font-size:12px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;color:#4e5a55}
.mon-stat dd{margin:4px 0 0;font-size:16px;font-weight:600}
/* its own blue-ink bar, so the explanatory notice does not read as the green "Saved." status */
.notice.info{background:#eef2f7;border-left-color:#1f4b73;color:var(--ink)}
/* #261: non-blocking "Privacy Policy updated" notice above the page content (base.html), info style */
.privacy-notice{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px 24px;margin:0 0 24px}
.privacy-notice p{margin:0}.privacy-notice .button{min-height:44px}
/* #397 LOW: the notice needs its own top margin. With domains the .mon-summary grid above it brings
   the gap (margin collapses to the larger of the two: 24px), but the empty state has no summary at
   all, so the box used to sit straight against the intro line (.mon-page .lead{margin:0}). */
.mon-note{display:block;margin:24px 0 28px}
.mon-list-h{font-size:22px;margin:0 0 14px}
.domain-cards{list-style:none;padding:0;margin:0;display:grid;gap:16px}
.mon-card{border:1px solid var(--line);border-radius:6px;padding:20px 22px;background:var(--white);scroll-margin-top:var(--site-header-h)}
.mon-card-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px}
.mon-card-head .verified{margin:0}
.mon-domain{margin:0;font-size:19px;font-weight:600;letter-spacing:-.01em;min-width:0;overflow-wrap:anywhere}
.mon-form{display:grid;gap:16px;margin-top:16px}
.mon-toggles{border:1px solid var(--line);border-radius:6px;background:var(--paper);padding:10px 16px 14px;margin:0}
.mon-toggles legend{padding:0 6px;font-size:12px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;color:#4e5a55}
.mon-parts{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:8px 28px}
/* tap target: the whole row is the label, at least 44px tall at every width (2.5.5) */
.mon-card .check{min-height:44px;align-content:center;padding:6px 0}
.mon-help{display:block;margin-top:2px;font-size:13px;color:#4e5a55}
.mon-status{margin:0;color:#4e5a55}
.mon-state{font-weight:600}
.mon-on{color:#2c6b4f}
.mon-off{color:#4e5a55}
.mon-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px}
.mon-actions .small-btn{margin-left:0}
.mon-card .button:focus-visible,.mon-page .link:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
.mon-empty h3{font-weight:400;font-size:20px;margin:12px 0 8px}
.mon-empty p{margin:8px 16px}
@media(max-width:700px){
  .mon-summary{grid-template-columns:1fr}
  .mon-parts{grid-template-columns:1fr}
  .mon-card{padding:16px}
  .mon-card .check{min-height:44px;padding:10px 0}
  .mon-actions{flex-direction:column;align-items:stretch}
  .mon-actions .button{min-height:44px;width:100%;justify-content:center;gap:12px}
}

/* ---- admin pages at 375px (#195, #235) --------------------------------------------------------- */
/* /admin/users and /admin/users/<id> print data no other page shows at this width - whole e-mail
   addresses, punycode domain names, job ids - and they used to push the page wider than the viewport
   (#195: 467px on the demo user, the nav clipped and the Override "Reason (required)" input past the
   card edge; #235: the override-review table alone made it 432px). Nothing here changes behaviour:
   the long words wrap, the wide tables scroll inside .scroll-x like the report tables (#220), and the
   per-domain controls are one wrapping group. */
.admin-page h1,.admin-page h2,.admin-page h3,.admin-page code,.admin-page .domain-list li{overflow-wrap:anywhere}
/* one row of the Domains list (admin user page) / of the user list: the name, then its controls */
.admin-page .domain-list li{flex-wrap:wrap;gap:10px 16px}
.admin-page .domain-name{min-width:0;overflow-wrap:anywhere}
.admin-page .domain-ctl{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px 12px;min-width:0;max-width:100%}
.admin-page .domain-ctl>*{min-width:0;max-width:100%}
/* #235: the admin tables (override review, credit refunds) sit in a .scroll-x region. Above 700px
   they keep their four columns and scroll sideways if the window is narrower than that, so they must
   not be squeezed into one word per line by the rule that collapses the report tables
   (.scroll-x>table{min-width:0}); a job id stays on one line. */
.admin-page .scroll-x>table{min-width:720px}
.admin-table{border-collapse:collapse;font-size:14px;width:100%}
.admin-table th,.admin-table td{text-align:left;vertical-align:top;padding:6px 10px;border-bottom:1px solid var(--line)}
.admin-table code{white-space:nowrap;font-size:13px}
/* #199: admin sub-nav (Users / Security log), the security log's filter form and its pager */
.admin-nav{display:flex;flex-wrap:wrap;gap:8px 18px;margin:0 0 12px;font-size:14px}
.admin-nav a{font-weight:600;border-bottom:2px solid transparent;padding:4px 0}
.admin-nav a.current{border-bottom-color:var(--accent)}
.audit-filters{align-items:end;margin:16px 0}
.audit-filters label{min-width:0}
.audit-filters select{font:inherit;font-weight:400;padding:14px 12px;border:1px solid var(--line);border-radius:4px;background:var(--paper);color:var(--ink);width:100%}
.audit-pager{margin-top:16px}
@media(max-width:700px){
  /* #199: one filter per line, full-width controls and pager buttons (44px+ tap targets) */
  .audit-filters>label,.audit-filters>.button,.audit-pager>.button{flex-basis:100%;width:100%;justify-content:center}
  /* the name on its own line, the row's controls left-aligned underneath it */
  .admin-page .domain-list li{flex-direction:column;align-items:stretch}
  .admin-page .domain-ctl{justify-content:flex-start}
  /* an Override / Renew override form (and the Revoke / Remove buttons) gets the full card width, so
     its "Reason (required)" input is the width of the card instead of .grow's 220px basis plus the
     button next to it, which is what overflowed */
  .admin-page .domain-ctl>details,.admin-page .domain-ctl>form{width:100%}
  .admin-page .domain-ctl .grow{flex-basis:100%;min-width:0}
  .admin-page input,.admin-page select,.admin-page .domain-ctl .button{max-width:100%;box-sizing:border-box}
  /* 44px tap targets (2.5.5) for the row's buttons, its <summary> toggles and the form buttons */
  .admin-page .domain-ctl .button{width:100%;min-height:44px;justify-content:center;gap:12px}
  /* a job row is taller than the viewport is wide: each table row becomes a card whose cells carry
     their column header (data-label), so nothing scrolls sideways on a phone (#235) */
  .admin-page .scroll-x>table{min-width:0}
  .admin-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .admin-table tr{display:block;border:1px solid var(--line);border-radius:6px;padding:8px 10px;margin:8px 0;background:var(--white)}
  .admin-table td{display:flex;justify-content:space-between;gap:12px;border:0;padding:3px 0;text-align:left;overflow-wrap:anywhere}
  .admin-table td::before{content:attr(data-label);font-weight:600;color:var(--muted);flex:none}
  .admin-table code{white-space:normal}
  /* #400 CR: scoped to button.link-button on purpose. .link-button is also the class of the
     Override / Renew override <summary>, and an unscoped .admin-page .domain-ctl .link-button
     (specificity 0,3,0) beat the summary rule below (0,2,1), so display:inline-flex won and the
     <summary> lost its disclosure triangle at <= 700px. */
  .admin-page .domain-ctl button.link-button{display:inline-flex;align-items:center;min-height:44px}
  /* display stays list-item (never set here): an inline-flex <summary> loses its disclosure triangle */
  .admin-page .domain-ctl summary{min-height:44px;padding:11px 0;cursor:pointer}
}
/* #423 PR 13: pre-screen pages (neutral info boxes, never a green "OK" style) */
.ps-box p{margin:0}.ps-box p+p{margin-top:6px}
.ps-icon{display:inline-block;width:1.4em;height:1.4em;line-height:1.4em;text-align:center;border-radius:50%;border:1px solid currentColor;font-weight:700;font-style:normal}
.ps-list{margin:0 0 12px;padding-left:20px}.ps-list li{margin:4px 0;overflow-wrap:anywhere}
.ps-actions{display:flex;flex-wrap:wrap;gap:12px;align-items:center}.ps-actions .button{min-height:44px}
/* #423/#455: keep the checked-on date (2026-10-27) on one line in the result heading */
.ps-nowrap { white-space: nowrap; }
/* #455 UX polish (CSS only): 44px tap targets for the text links and the checkbox, the existing focus ring,
   and on narrow screens full-width stacked actions with a little more spacing */
.ps-actions{margin:16px 0}
.ps-actions .link{display:inline-flex;align-items:center;min-height:44px;gap:.3em}
.ps-actions .button:focus-visible,.prescreen .link:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
.prescreen .check{min-height:44px;align-content:center;padding:6px 0}
.prescreen h2{margin-top:24px}
@media(max-width:700px){
  .ps-actions{flex-direction:column;align-items:stretch}
  .ps-actions .button{width:100%;justify-content:center;gap:12px}
  .prescreen .check{padding:10px 0}
}
/* #489 B5: the purchase forms (_billing_buttons.html) sat flush under "Credit history" and against each other
   once they wrap (390px): space above the block and between the forms; the note takes its own line */
.billing-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px 16px;margin-top:16px}
.billing-actions>p{flex-basis:100%;margin:0}
/* #546: the Billing page blocks (billing_account.html) and the confirmation recap (billing_confirm.html) */
.billing-block{margin-top:20px}
.billing-block>h2{margin-bottom:8px}
.billing-recap{display:grid;grid-template-columns:max-content 1fr;gap:6px 16px;margin:12px 0 20px}
.billing-recap dt{font-weight:600}
.billing-recap dd{margin:0}
@media (max-width:480px){.billing-recap{grid-template-columns:1fr}.billing-recap dd{margin-bottom:6px}}
