/* InverseZero — site stylesheet
   Design system: console/SOC aesthetic. Archivo + IBM Plex Mono. */

:root{
  --ink:#0B0A0E;
  --panel:#14121A;
  --panel-2:#1A1822;
  --rule:#2B2836;
  --text:#DCE6EE;
  --muted:#7B90A1;
  --crit:#FF5C3E;
  --high:#FF9F45;
  --med:#F2D45C;
  --ok:#31D0AA;
  --crit-hover:#ff7357;
  --ok-hover:#4ce0bc;
  --on-crit:#12060A;
  --on-ok:#05201A;
  /* Brand accent — deliberately separate from --crit, which now means
     "this is a critical finding" and nothing else. Swap these three to
     re-skin the site without touching severity semantics. */
  --accent:#9B7BA8;
  --accent-hover:#AE8FBA;
  --on-accent:#0F0812;
  --ink-deep:#070609;
  --prose:#C5D2DC;
  --syn-key:#7FA6FF;
  --syn-cm:#7A94A3;
  --syn-ln:#5B7183;
  /* RGB channel triples. rgba() cannot accept a hex custom property, so any
     semi-transparent use of a token colour needs its channels separately.
     These MUST stay in sync with the hex values above. */
  --ok-rgb:49,208,170;
  --crit-rgb:255,92,62;
  --ink-rgb:11,10,14;
  /* Type scale. Eight steps, ~1.22 ratio anchored at 16px. Every size in the
     sheet snaps to one of these; sizes half a pixel apart did no perceptual
     work and made the page read as assembled rather than composed. */
  --t-3xs:11px;   /* uppercase mono labels */
  --t-2xs:12px;   /* mono metadata */
  --t-xs:13px;    /* dense data, code */
  --t-sm:14px;    /* secondary UI */
  --t-md:16px;    /* body */
  --t-lg:18px;    /* lede, prose */
  --t-xl:21px;    /* h3 */
  --t-2xl:26px;

  /* Spacing. 4px grid. Named by role, not by size, so the rhythm survives
     a change of value. */
  --s-1:4px;  --s-2:8px;  --s-3:12px; --s-4:16px;
  --s-5:20px; --s-6:24px; --s-8:32px; --s-10:40px;
  --s-12:48px; --s-16:64px; --s-20:80px;

  --maxw:1180px;
  --narrow:820px;
}
*{box-sizing:border-box;margin:0;padding:0}
/* The hidden attribute is applied by the UA stylesheet, so any author rule
   that sets display (a grid row, a flex item) silently outranks it and the
   element stays visible. Anything toggled with el.hidden needs this. */
[hidden]{display:none!important}
html{scroll-behavior:smooth;scroll-padding-top:var(--s-20);-webkit-text-size-adjust:100%}
body{background:var(--ink);color:var(--text);font-family:'Archivo',system-ui,-apple-system,sans-serif;
  -webkit-font-smoothing:antialiased;line-height:1.6;overflow-x:hidden}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--s-6)}
.wrap-narrow{max-width:var(--narrow);margin:0 auto;padding:0 var(--s-6)}
a{color:inherit;text-decoration:none}
img{max-width:100%;height:auto}
:focus-visible{outline:2px solid var(--ok);outline-offset:3px}
.mono{font-family:'IBM Plex Mono',ui-monospace,monospace;font-variant-numeric:tabular-nums}
.skip{position:absolute;left:-9999px;top:0;background:var(--accent);color:var(--on-accent);padding:var(--s-3) var(--s-4);z-index:200}
.skip:focus{left:0}

/* ---------- status strip ---------- */
.status{border-bottom:1px solid var(--rule);background:var(--ink-deep);font-family:'IBM Plex Mono',monospace;
  font-size:var(--t-3xs);letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.status .wrap{display:flex;gap:var(--s-4);align-items:center;height:34px;overflow:hidden;white-space:nowrap}
.dot{width:6px;height:6px;border-radius:50%;background:var(--ok);display:inline-block;margin-right:var(--s-2);
  box-shadow:0 0 0 0 rgba(var(--ok-rgb),.6);animation:pulse 2.6s infinite}
@keyframes pulse{70%{box-shadow:0 0 0 7px rgba(var(--ok-rgb),0)}100%{box-shadow:0 0 0 0 rgba(var(--ok-rgb),0)}}
.status .push{margin-left:auto}

/* ---------- nav ---------- */
nav.site{position:sticky;top:0;z-index:100;background:rgba(var(--ink-rgb),.9);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--rule)}
nav.site .wrap{display:flex;align-items:center;gap:var(--s-6);height:66px}
.logo{font-weight:700;font-size:var(--t-lg);letter-spacing:-.02em;display:flex;align-items:center;gap:var(--s-2);flex:none}
.mark{width:26px;height:20px;flex:none;background:var(--ok);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3E%3Cpath d='M484.4 96C407 96 349.7 164.1 320 208.5C290.3 164.1 233 96 155.6 96C69.7 96 0 165.7 0 251.6C0 337.4 69.7 407.1 155.6 407.1C233 407.1 290.3 339 320 294.6C349.7 339 407 407.1 484.4 407.1C570.3 407.1 640 337.4 640 251.5C640 165.7 570.3 96 484.4 96zM155.6 353.1C99.5 353.1 54 307.6 54 251.5C54 195.4 99.5 149.9 155.6 149.9C201.9 149.9 251.6 196.5 279.3 251.5C251.6 306.6 201.9 353.1 155.6 353.1zM484.4 353.1C430.1 353.1 380.4 306.5 352.7 251.5C380.4 196.4 430.1 149.9 484.4 149.9C540.5 149.9 586 195.4 586 251.5C586 307.6 540.5 353.1 484.4 353.1z'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3E%3Cpath d='M484.4 96C407 96 349.7 164.1 320 208.5C290.3 164.1 233 96 155.6 96C69.7 96 0 165.7 0 251.6C0 337.4 69.7 407.1 155.6 407.1C233 407.1 290.3 339 320 294.6C349.7 339 407 407.1 484.4 407.1C570.3 407.1 640 337.4 640 251.5C640 165.7 570.3 96 484.4 96zM155.6 353.1C99.5 353.1 54 307.6 54 251.5C54 195.4 99.5 149.9 155.6 149.9C201.9 149.9 251.6 196.5 279.3 251.5C251.6 306.6 201.9 353.1 155.6 353.1zM484.4 353.1C430.1 353.1 380.4 306.5 352.7 251.5C380.4 196.4 430.1 149.9 484.4 149.9C540.5 149.9 586 195.4 586 251.5C586 307.6 540.5 353.1 484.4 353.1z'/%3E%3C/svg%3E") center/contain no-repeat}
.navlinks{display:flex;gap:var(--s-5);font-size:var(--t-sm);color:var(--muted)}
.navlinks a:hover,.navlinks a.on{color:var(--text)}
.navcta{margin-left:auto;display:flex;gap:var(--s-2);align-items:center}
.burger{display:none;margin-left:auto;background:none;border:1px solid var(--rule);color:var(--text);
  padding:var(--s-2) var(--s-3);min-height:44px;font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);cursor:pointer;letter-spacing:.06em}
.mobilemenu{display:none;border-bottom:1px solid var(--rule);background:var(--panel)}
.mobilemenu.open{display:block;position:fixed;top:67px;left:0;right:0;z-index:99;
  max-height:calc(100vh - 67px);overflow-y:auto}
.mobilemenu a{display:block;padding:var(--s-3) var(--s-6);border-bottom:1px solid var(--rule);font-size:var(--t-sm);color:var(--muted)}
.mobilemenu a:hover{color:var(--text);background:var(--panel-2)}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s-2);font-family:'IBM Plex Mono',monospace;
  font-size:var(--t-2xs);letter-spacing:.06em;text-transform:uppercase;padding:var(--s-3) var(--s-4);min-height:44px;
  border:1px solid var(--rule);color:var(--text);
  transition:background-color .18s,border-color .18s,color .18s;cursor:pointer;background:none;text-align:center}
.btn:hover{border-color:var(--muted)}
.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:600}
.btn-primary:hover{background:var(--accent-hover);border-color:var(--accent-hover)}
.btn-ok{background:var(--ok);border-color:var(--ok);color:var(--on-ok);font-weight:600}
.btn-ok:hover{background:var(--ok-hover);border-color:var(--ok-hover)}

/* ---------- typography ---------- */
/* Optical tracking: tighter as size grows, looser as it shrinks. A single
   letter-spacing across a scale is the thing that makes type read as set by
   default rather than set on purpose. Headings balance so a two-line title
   never leaves one orphaned word. */
h1{font-size:clamp(32px,4.6vw,52px);line-height:1.04;letter-spacing:-.038em;
  font-weight:700;margin-bottom:var(--s-5);text-wrap:balance}
h2{font-size:clamp(24px,3.1vw,34px);line-height:1.12;letter-spacing:-.028em;
  font-weight:600;margin-bottom:var(--s-3);text-wrap:balance}
h3{font-size:var(--t-xl);line-height:1.25;letter-spacing:-.016em;
  font-weight:600;margin-bottom:var(--s-2);text-wrap:balance}
h4{font-size:var(--t-md);line-height:1.35;letter-spacing:-.008em;
  font-weight:600;margin-bottom:var(--s-2)}
h3.compact{font-size:var(--t-md);line-height:1.35;letter-spacing:-.006em;
  font-weight:600;margin-bottom:var(--s-2)}

/* Headings own the space above them, not below. Anything following a heading
   belongs to it; the gap that matters is the one separating it from what came
   before. */
h2+p,h3+p,h4+p{margin-top:0}
.prose>*+h2{margin-top:var(--s-12)}
.prose>*+h3{margin-top:var(--s-8)}
.eyebrow{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.16em;text-transform:uppercase;
  color:var(--accent);margin-bottom:var(--s-4)}
.eyebrow.mute{color:var(--muted)}
.lede{font-size:var(--t-lg);line-height:1.52;color:var(--muted);
  max-width:62ch;margin-bottom:var(--s-6);text-wrap:pretty}

/* ---------- page header ---------- */
.pagehead{padding:var(--s-16) 0 var(--s-12);border-bottom:1px solid var(--rule);position:relative}
.crumb{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);margin-bottom:var(--s-5)}
.crumb a:hover{color:var(--text)}
.crumb span{color:var(--rule);padding:0 var(--s-1)}

.hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:var(--s-12);align-items:start}
.contact-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-12);align-items:start}

/* ---------- sections ---------- */
section{padding:var(--s-16) 0;border-bottom:1px solid var(--rule)}
section.tight{padding:var(--s-12) 0}
section:last-of-type{border-bottom:none}
.shead{margin-bottom:var(--s-10);max-width:64ch}
.shead p{color:var(--muted);font-size:var(--t-md)}

/* ---------- section rhythm primitives ----------
   Used to break the default "heading on top, grid below" cadence.
   .split  — heading sits beside the content, not above it
   .band   — section rides on a raised surface, edge to edge
   .bleed  — grid escapes the wrap and runs the full viewport width
   .narrow — measured column, for sections that should feel quieter   */
.split{display:grid;grid-template-columns:.82fr 1.18fr;gap:var(--s-12);align-items:start}
.split>.shead{margin-bottom:0;position:sticky;top:92px;max-width:none}
.split>.shead h2{margin-bottom:var(--s-3)}
.split .grid-2{grid-template-columns:1fr}
.band{background:var(--panel);border-top:1px solid var(--rule)}
.band .cell{background:var(--panel)}
.band .cell:hover{background:var(--panel-2)}
.band .grid-2,.band .grid-3,.band .grid-4{background:var(--rule)}
.bleed{max-width:none;padding:0;border-left:none;border-right:none}
.bleed.grid-4,.bleed.grid-3,.bleed.grid-2{border-left:0;border-right:0}
.sec-narrow{max-width:var(--narrow);margin:0 auto;padding:0 var(--s-6)}
.rule-lead{display:flex;align-items:baseline;gap:var(--s-4);margin-bottom:var(--s-8)}
.rule-lead h2{margin-bottom:0;flex:none}
.rule-lead:after{content:"";height:1px;background:var(--rule);flex:1}
@media (max-width:900px){
  .split{grid-template-columns:1fr;gap:var(--s-8)}
  .split>.shead{position:static;margin-bottom:0}
}

/* ---------- prose ---------- */
.prose{max-width:68ch;font-size:var(--t-lg);line-height:1.72}
.prose p{margin-bottom:var(--s-5);color:var(--prose)}
.prose h2{margin-top:var(--s-10);margin-bottom:var(--s-4)}
.prose h2:first-child{margin-top:0}
.prose h3{margin-top:var(--s-8);margin-bottom:var(--s-3);color:var(--text)}
.prose ul,.prose ol{margin:0 0 var(--s-5) var(--s-5);color:var(--prose)}
.prose li{margin-bottom:var(--s-2)}
.prose strong{color:var(--text);font-weight:600}
.prose a{color:var(--ok);border-bottom:1px solid rgba(var(--ok-rgb),.35)}
.prose a:hover{border-bottom-color:var(--ok)}
.prose code{font-family:'IBM Plex Mono',monospace;font-size:.88em;background:var(--panel-2);
  padding:2px var(--s-1);border:1px solid var(--rule);color:var(--med)}
.prose blockquote{border-left:2px solid var(--accent);padding-left:var(--s-5);margin:var(--s-6) 0;color:var(--muted);font-style:italic}
.prose table{width:100%;border-collapse:collapse;margin-bottom:var(--s-6);font-size:var(--t-sm)}
.prose th{text-align:left;padding:var(--s-2) var(--s-3);border-bottom:1px solid var(--rule);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.prose td{padding:var(--s-3);border-bottom:1px solid var(--rule);color:var(--prose)}

/* ---------- code blocks ---------- */
pre{background:var(--panel);border:1px solid var(--rule);padding:var(--s-4);overflow-x:auto;margin-bottom:var(--s-5);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-xs);line-height:1.75}
pre code{background:none;border:none;padding:0;color:var(--text);font-size:var(--t-xs)}
.c-key{color:var(--syn-key)}.c-fn{color:var(--med)}.c-str{color:var(--ok)}.c-cm{color:var(--syn-cm)}.c-num{color:var(--high)}
.codelabel{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin-bottom:var(--s-2);display:flex;align-items:center;gap:var(--s-2)}
.codelabel.bad:before{content:"";width:8px;height:8px;border-radius:50%;background:var(--crit)}
.codelabel.good:before{content:"";width:8px;height:8px;border-radius:50%;background:var(--ok)}

/* ---------- cards / grids ---------- */
.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--rule);border:1px solid var(--rule)}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--rule);border:1px solid var(--rule)}
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--rule);border:1px solid var(--rule)}
.cell{background:var(--ink);padding:var(--s-6) var(--s-6);transition:background-color .18s}
.cell:hover{background:var(--panel)}
.cell .tag{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.12em;text-transform:uppercase;
  color:var(--accent);margin-bottom:var(--s-3);display:block}
.cell .tag.mute{color:var(--muted)}
.cell .tag.ok{color:var(--ok)}
.cell p{color:var(--muted);font-size:var(--t-sm);margin-bottom:var(--s-3)}
.cell .go{font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);letter-spacing:.06em;text-transform:uppercase;
  color:var(--text)}
.cell .go:after{content:" →"}
.cell .n{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--accent);letter-spacing:.1em;margin-bottom:var(--s-3)}

/* ---------- finding card ---------- */
.finding{background:var(--panel);border:1px solid var(--rule);font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs)}
.f-head{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-3) var(--s-3);border-bottom:1px solid var(--rule);
  background:var(--panel-2);font-size:var(--t-3xs);letter-spacing:.06em;text-transform:uppercase;flex-wrap:wrap}
.sev{padding:3px var(--s-2);font-weight:600;color:var(--on-crit);background:var(--crit)}
.sev.high{background:var(--high)}.sev.med{background:var(--med)}.sev.low{background:var(--muted)}
.f-id{color:var(--muted)}
.f-head .push{margin-left:auto;color:var(--ok)}
.f-code{padding:var(--s-4) var(--s-3);line-height:1.85;overflow-x:auto}
.f-code .ln{color:var(--syn-ln);user-select:none;display:inline-block;width:24px}
.hit{background:rgba(var(--crit-rgb),.13);border-left:2px solid var(--crit);display:block;margin-left:-14px;padding-left:var(--s-3)}
.f-note{border-top:1px solid var(--rule);padding:var(--s-3);color:var(--muted);line-height:1.7}
.f-note b{color:var(--text);font-weight:500}
.f-foot{border-top:1px solid var(--rule);padding:var(--s-3) var(--s-3);display:flex;gap:var(--s-2);align-items:center;flex-wrap:wrap;
  font-size:var(--t-3xs);letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.chip{border:1px solid var(--rule);padding:3px var(--s-2)}
.chip.crit{border-color:rgba(var(--crit-rgb),.5);color:var(--crit)}
.chip.ok{border-color:rgba(var(--ok-rgb),.45);color:var(--ok)}

/* ---------- scope columns ---------- */
.scol h3{display:flex;align-items:center;gap:var(--s-2);margin-bottom:var(--s-4)}
.scol h3:before{content:"";width:9px;height:9px;border-radius:50%;flex:none}
.scol.yes h3:before{background:var(--ok)}
.scol.no h3:before{background:var(--crit)}
.scol ul{list-style:none}
.scol li{padding:var(--s-3) 0;border-top:1px solid var(--rule);color:var(--muted);font-size:var(--t-sm)}
.scol li b{color:var(--text);font-weight:500}

/* ---------- pricing table ---------- */
.ptwrap{overflow-x:auto}
.price-tbl{width:100%;border-collapse:collapse;font-size:var(--t-sm)}
.price-tbl th{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);text-align:left;padding:0 var(--s-3) var(--s-3);border-bottom:1px solid var(--rule);font-weight:500}
.price-tbl td{padding:var(--s-5) var(--s-3);border-bottom:1px solid var(--rule);vertical-align:top}
.price-tbl tr:hover td{background:var(--panel)}
.price-tbl .tier{font-weight:600;font-size:var(--t-md)}
.price-tbl .desc{color:var(--muted);font-size:var(--t-sm);margin-top:var(--s-1)}
.price-tbl .amt{font-family:'IBM Plex Mono',monospace;font-size:var(--t-lg);white-space:nowrap;text-align:right}
.price-tbl .amt small{display:block;color:var(--muted);font-size:var(--t-3xs);margin-top:var(--s-1);letter-spacing:.05em}
.free-row td{background:rgba(var(--ok-rgb),.05)}
.free-row .amt{color:var(--ok)}

/* ---------- forms ---------- */
.form{background:var(--panel);border:1px solid var(--rule);padding:var(--s-6)}
.field{margin-bottom:var(--s-4)}
label{display:block;font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);margin-bottom:var(--s-2)}
input,select,textarea{width:100%;background:var(--panel-2);border:1px solid var(--rule);color:var(--text);
  padding:var(--s-3) var(--s-3);font-family:'Archivo',sans-serif;font-size:var(--t-sm)}
textarea{min-height:90px;resize:vertical}
input:focus,select:focus,textarea:focus{border-color:var(--ok)}
input:focus:not(:focus-visible),select:focus:not(:focus-visible),textarea:focus:not(:focus-visible){outline:none}
.form .btn{width:100%;margin-top:var(--s-1)}
.formnote{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--muted);margin-top:var(--s-3);
  text-align:center;line-height:1.7}
.formstatus{margin-top:var(--s-3);padding:var(--s-3);font-size:var(--t-sm);display:none}
.formstatus.ok{display:block;border:1px solid rgba(var(--ok-rgb),.4);color:var(--ok);background:rgba(var(--ok-rgb),.06)}
.formstatus.err{display:block;border:1px solid rgba(var(--crit-rgb),.4);color:var(--crit);background:rgba(var(--crit-rgb),.06)}

/* ---------- checklist ---------- */
.checklist{list-style:none;font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);color:var(--muted)}
.checklist li{padding:var(--s-2) 0;border-top:1px solid var(--rule)}
.checklist li:before{content:"→ ";color:var(--ok)}

/* ---------- index list (vulnerability hub, blog, reports) ---------- */
.ilist{border-top:1px solid var(--rule)}
.irow{display:grid;grid-template-columns:auto 1fr auto;gap:var(--s-5);padding:var(--s-5) 0;border-bottom:1px solid var(--rule);
  align-items:baseline;transition:background-color .18s}
.irow:hover{background:var(--panel)}
.irow .swc{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--accent);letter-spacing:.06em;
  min-width:74px}
.irow h3{font-size:var(--t-lg);margin-bottom:var(--s-1)}
.irow p{color:var(--muted);font-size:var(--t-sm);margin:0}
.irow .meta{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--muted);letter-spacing:.06em;
  white-space:nowrap;text-transform:uppercase}

/* ---------- faq ---------- */
.faq{border-top:1px solid var(--rule)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{padding:var(--s-5) 0;cursor:pointer;font-weight:600;font-size:var(--t-lg);list-style:none;
  display:flex;align-items:center;gap:var(--s-3)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:before{content:"+";font-family:'IBM Plex Mono',monospace;color:var(--accent);font-size:var(--t-lg);flex:none}
.faq details[open] summary:before{content:"−"}
.faq details p{padding:0 0 var(--s-5) var(--s-6);color:var(--muted);font-size:var(--t-md);max-width:70ch}

/* ---------- callout ---------- */
.callout{border:1px solid var(--rule);border-left:2px solid var(--accent);background:var(--panel);
  padding:var(--s-5) var(--s-6);margin:var(--s-6) 0}
.callout.ok{border-left-color:var(--ok)}
.callout h4{margin-bottom:var(--s-2)}
.callout p{color:var(--muted);font-size:var(--t-md);margin:0}

/* ---------- CTA band ---------- */
.ctaband{background:var(--panel);border-top:1px solid var(--rule)}
.ctaband .wrap{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-12);align-items:start;
  padding-top:var(--s-16);padding-bottom:var(--s-16)}
.ctaband h2{margin-bottom:var(--s-3)}
.ctaband p{color:var(--muted);margin-bottom:var(--s-5);font-size:var(--t-md)}

/* ---------- footer ---------- */
footer.site{padding:var(--s-12) 0 var(--s-10);font-size:var(--t-sm);border-top:1px solid var(--rule)}
.fgrid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:var(--s-8);margin-bottom:var(--s-10)}
footer.site h5{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin-bottom:var(--s-4);font-weight:500}
footer.site ul{list-style:none}
footer.site li{margin-bottom:var(--s-2);color:var(--muted)}
footer.site li a:hover{color:var(--text)}
.fbot{border-top:1px solid var(--rule);padding-top:var(--s-5);display:flex;gap:var(--s-4);flex-wrap:wrap;
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--muted)}
.fbot .push{margin-left:auto}

/* ---------- live scanner ---------- */
.scanner{border:1px solid var(--rule);background:var(--rule);display:grid;
  grid-template-columns:1fr 1fr;gap:1px}
.scan-pane{background:var(--ink);display:flex;flex-direction:column;min-width:0}
.scan-bar{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;padding:var(--s-3) var(--s-3);
  border-bottom:1px solid var(--rule);background:var(--panel-2);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.scan-bar .push{margin-left:auto}
.scan-chipbtn{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.1em;
  text-transform:uppercase;background:none;border:1px solid var(--rule);color:var(--muted);
  padding:var(--s-2) var(--s-2);min-height:44px;cursor:pointer;transition:border-color .18s,color .18s}
.scan-chipbtn:hover{color:var(--text);border-color:var(--muted)}
.scan-chipbtn[aria-pressed="true"]{color:var(--ok);border-color:rgba(var(--ok-rgb),.45)}

.scan-editor{position:relative;display:flex;background:var(--panel);flex:1;min-height:340px}
.scan-gutter{flex:none;width:46px;padding:var(--s-4) var(--s-2) var(--s-4) 0;text-align:right;overflow:hidden;
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-xs);line-height:1.75;color:var(--syn-ln);
  white-space:pre;user-select:none;border-right:1px solid var(--rule);background:var(--ink-deep)}
.scan-input{flex:1;min-width:0;background:var(--panel);color:var(--text);border:none;
  padding:var(--s-4) var(--s-3);font-family:'IBM Plex Mono',monospace;font-size:var(--t-xs);line-height:1.75;
  resize:none;white-space:pre;overflow:auto;tab-size:4}
.scan-input:focus{outline:none;background:var(--panel)}
.scan-editor:focus-within{box-shadow:inset 0 0 0 1px var(--ok)}

.scan-results{min-height:340px;max-height:560px;overflow-y:auto;padding:var(--s-3);display:flex;
  flex-direction:column;gap:var(--s-3);background:var(--ink)}
.scan-results .finding{background:var(--panel)}
.scan-empty{padding:var(--s-6) var(--s-5);color:var(--muted);font-size:var(--t-2xs);line-height:1.8;
  border:1px dashed var(--rule);text-align:center}
.scan-stat{padding:var(--s-3) var(--s-3);border-top:1px solid var(--rule);background:var(--ink-deep);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.06em;color:var(--muted)}
.scan-note{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--muted);
  line-height:1.8;margin-top:var(--s-3)}
.scan-note b{color:var(--text);font-weight:500}

@media (max-width:900px){
  .scanner{grid-template-columns:1fr}
  .scan-editor{min-height:260px}
  .scan-results{max-height:420px}
}

/* ---------- threat model ----------
   Reuses the scanner shell (.scanner/.scan-pane/.scan-bar/.scan-editor).
   Only the report side needs its own vocabulary. */
.tm-gutter{flex:none;width:46px;padding:var(--s-4) var(--s-2) var(--s-4) 0;text-align:right;overflow:hidden;
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-xs);line-height:1.75;color:var(--syn-ln);
  white-space:pre;user-select:none;border-right:1px solid var(--rule);background:var(--ink-deep)}
.tm-input{flex:1;min-width:0;background:var(--panel);color:var(--text);border:none;
  padding:var(--s-4) var(--s-3);font-family:'IBM Plex Mono',monospace;font-size:var(--t-xs);line-height:1.75;
  resize:none;white-space:pre;overflow:auto;tab-size:4}
.tm-input:focus{outline:none}
.tm-out{min-height:340px;max-height:640px;overflow-y:auto;background:var(--ink)}

.tm-stats{display:grid;grid-template-columns:repeat(5,1fr);gap:1px;background:var(--rule);
  border-bottom:1px solid var(--rule)}
.tm-stat{background:var(--ink);padding:var(--s-3) var(--s-2);text-align:center}
.tm-stat b{display:block;font-family:'IBM Plex Mono',monospace;font-size:var(--t-xl);
  font-weight:500;color:var(--text);line-height:1.2}
.tm-stat span{display:block;font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-top:var(--s-1)}
.tm-stat.hot b{color:var(--crit)}

.tm-block{border-bottom:1px solid var(--rule);padding:var(--s-4)}
.tm-block:last-child{border-bottom:none}
.tm-bhead{display:flex;align-items:baseline;gap:var(--s-2);margin-bottom:var(--s-2)}
.tm-bhead h3{font-size:var(--t-sm);margin:0;letter-spacing:-.005em}
.tm-count{margin-left:auto;font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--muted)}
.tm-note{font-size:var(--t-2xs);color:var(--muted);line-height:1.65;margin-bottom:var(--s-3)}

.tm-objs{display:flex;flex-direction:column;gap:var(--s-2)}
.tm-obj{border:1px solid var(--rule);background:var(--panel)}
.tm-ohead{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-3);font-size:var(--t-xs);
  border-bottom:1px solid var(--rule);background:var(--panel-2)}
.tm-path{display:flex;gap:var(--s-2);padding:var(--s-2) var(--s-3);font-size:var(--t-2xs);align-items:baseline}
.tm-path+.tm-path{border-top:1px solid var(--rule)}
.tm-who{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted);flex:none;min-width:88px}
.tm-path.bad .tm-who{color:var(--crit)}
.tm-path code{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);background:var(--panel-2);
  border:1px solid var(--rule);padding:1px var(--s-1);margin-right:var(--s-1);display:inline-block}

.tm-list{list-style:none;display:flex;flex-direction:column;gap:var(--s-2);font-size:var(--t-xs);color:var(--prose)}
.tm-list li:before{content:"→ ";color:var(--accent)}
.tm-fns{display:flex;flex-wrap:wrap;gap:var(--s-1);margin-top:var(--s-3)}
.tm-fns code{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);background:var(--panel-2);
  border:1px solid var(--rule);padding:2px var(--s-1)}

.tm-scroll{overflow-x:auto}
.tm-table{width:100%;border-collapse:collapse;font-size:var(--t-2xs)}
.tm-table th{text-align:left;font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
  padding:0 var(--s-2) var(--s-2);border-bottom:1px solid var(--rule);font-weight:500}
.tm-table td{padding:var(--s-2);border-bottom:1px solid var(--rule);vertical-align:top;color:var(--prose)}
.tm-table code{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--text)}
.tm-table .chip{margin-left:var(--s-2);font-size:var(--t-3xs);padding:1px var(--s-1)}
tr.tm-group td{background:var(--panel-2);font-family:'IBM Plex Mono',monospace;
  font-size:var(--t-3xs);letter-spacing:.09em;text-transform:uppercase;color:var(--muted);padding:var(--s-2) var(--s-2)}
.tm-caps{line-height:1.7}
.tm-line{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);color:var(--muted);white-space:nowrap}
.tm-dim{color:var(--muted)}
.tm-empty{padding:var(--s-6) var(--s-5);margin:var(--s-4);color:var(--muted);font-size:var(--t-2xs);line-height:1.8;
  border:1px dashed var(--rule);text-align:center}

@media (max-width:900px){
  .tm-stats{grid-template-columns:repeat(2,1fr)}
  .tm-out{max-height:480px}
}

/* ---------- attack flow ---------- */
.flow{border:1px solid var(--rule);background:var(--rule);display:grid;
  grid-template-columns:1.15fr .85fr;gap:1px}
.flow-stage{background:var(--ink-deep);padding:var(--s-5);display:flex;align-items:center;justify-content:center}
.flow-svg{width:100%;height:auto;max-width:560px;font-family:'IBM Plex Mono',monospace}
.flow-svg .lifeline{stroke:var(--rule);stroke-width:1;stroke-dasharray:3 5}
.flow-svg .actor{fill:var(--panel-2);stroke:var(--rule)}
.flow-svg .actor-t{fill:var(--text);font-size:var(--t-3xs);letter-spacing:.1em}
.flow-svg .lbl{fill:var(--muted);font-size:var(--t-3xs);letter-spacing:.04em}

.flow-svg .fstep{opacity:0;transition:opacity .3s ease}
.flow-svg .fstep.on{opacity:1}
.flow-svg .fstep path,.flow-svg .fstep line{stroke-dasharray:520;stroke-dashoffset:520;
  transition:stroke-dashoffset .5s ease}
.flow-svg .fstep.on path,.flow-svg .fstep.on line{stroke-dashoffset:0}
.flow-svg .arrow{stroke:var(--ok);stroke-width:1.6;fill:none}
.flow-svg .arrow.bad{stroke:var(--crit)}
.flow-svg .head{fill:var(--ok);stroke:none}
.flow-svg .head.bad{fill:var(--crit)}
.flow-svg .fstep.on .lbl{fill:var(--text)}

.flow-side{background:var(--ink);display:flex;flex-direction:column;min-width:0}
.flow-narr{padding:var(--s-5);font-size:var(--t-sm);line-height:1.7;color:var(--prose);flex:1;
  border-bottom:1px solid var(--rule);min-height:104px}
.flow-narr b{color:var(--text);font-weight:600}
.flow-readout{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--rule);
  border-bottom:1px solid var(--rule)}
.flow-cellv{background:var(--ink);padding:var(--s-3) var(--s-4)}
.flow-cellv span{display:block;font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin-bottom:var(--s-1)}
.flow-cellv b{font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xl);font-weight:500;color:var(--text)}
.is-bug .flow-cellv.watch b{color:var(--crit)}

.flow-code{padding:var(--s-4) var(--s-4);border-bottom:1px solid var(--rule);background:var(--panel);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);line-height:1.9;overflow-x:auto}
.flow-code div{color:var(--syn-cm);transition:color .25s,background-color .25s;
  padding:0 var(--s-1);margin:0 calc(var(--s-1) * -1);white-space:pre}
.flow-code div.lit{color:var(--text);background:rgba(255,255,255,.05)}
.flow-code div.lit.warn{color:var(--crit);background:rgba(var(--crit-rgb),.1)}

.flow-ctl{display:flex;gap:var(--s-2);align-items:center;padding:var(--s-3) var(--s-4);background:var(--ink-deep)}
.flow-ctl .btn{padding:var(--s-2) var(--s-3);min-height:44px;font-size:var(--t-3xs)}
.flow-count{margin-left:auto;font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);
  letter-spacing:.08em;color:var(--muted)}
.flow-ctl .btn:disabled{opacity:.35;cursor:not-allowed}
.flow-ctl .btn:disabled:hover{border-color:var(--rule)}

@media (max-width:900px){
  .flow{grid-template-columns:1fr}
  .flow-narr{min-height:0}
}
@media (prefers-reduced-motion:reduce){
  .flow-svg .fstep,.flow-svg .fstep path,.flow-svg .fstep line{transition:none}
}

/* ---------- responsive ---------- */
@media (max-width:900px){
  .grid-2,.grid-3,.grid-4,.hero-grid,.contact-grid{grid-template-columns:1fr}
  .ctaband .wrap{grid-template-columns:1fr;gap:var(--s-8)}
  .navlinks,.navcta{display:none}
  .burger{display:block}
  .fgrid{grid-template-columns:1fr 1fr}
  .price-tbl{min-width:560px}
  .irow{grid-template-columns:1fr;gap:var(--s-2)}
  .irow .meta{display:none}
  section{padding:var(--s-12) 0}
  .pagehead{padding:var(--s-12) 0 var(--s-10)}
}
@media (max-width:520px){
  .fgrid{grid-template-columns:1fr}
  .status .wrap{gap:var(--s-3);font-size:var(--t-3xs)}
  .prose{font-size:var(--t-md)}
}
@media (prefers-reduced-motion:reduce){
  /* Movement is removed; state feedback is not. A blanket animation:none kill
     also strips the hover, focus and press cues people rely on to operate the
     page, which is a worse outcome than the motion it was suppressing. Colour
     and opacity transitions stay; anything that travels stops. */
  .dot{animation:none}
  html{scroll-behavior:auto}
  .flow-svg .fstep path,.flow-svg .fstep line{transition:none}
}

/* ---------- invariant bullets (metric vs threshold) ----------
   Bullet-chart pattern. Values are always rendered as text, never
   conveyed by bar length or colour alone, and state carries a glyph
   as well as a hue so it survives colour-blindness and greyscale. */
.bullets{display:flex;flex-direction:column;gap:1px;background:var(--rule);
  border:1px solid var(--rule)}
.bullet{background:var(--ink);padding:var(--s-3) var(--s-4);display:grid;
  grid-template-columns:minmax(150px,1.1fr) minmax(90px,2fr) auto;
  gap:var(--s-4);align-items:center}
.bullet-name{display:flex;align-items:baseline;gap:var(--s-2);min-width:0}
.bullet-name b{font-size:var(--t-xs);font-weight:500;color:var(--text)}
.bullet-name span{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted);flex:none}
.bullet-track{position:relative;height:9px;background:var(--panel-2);
  border:1px solid var(--rule)}
.bullet-fill{position:absolute;left:0;top:0;right:0;bottom:0;background:var(--ok);
  transform:scaleX(var(--v,1));transform-origin:left;
  transition:background-color .3s ease}
.bullet.warn .bullet-fill{background:var(--med)}
.bullet.breach .bullet-fill{background:var(--crit)}
.bullet-target{position:absolute;top:-4px;bottom:-4px;width:2px;background:var(--text)}
.bullet-val{font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);
  font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right;color:var(--text)}
.bullet-val i{font-style:normal;color:var(--muted);font-size:var(--t-3xs);display:block;margin-top:3px}
.bullet-flag{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.09em;
  text-transform:uppercase;flex:none}
.bullet.ok    .bullet-flag{color:var(--ok)}
.bullet.warn  .bullet-flag{color:var(--med)}
.bullet.breach .bullet-flag{color:var(--crit)}
@media (max-width:700px){
  .bullet{grid-template-columns:1fr auto;gap:var(--s-2) var(--s-3)}
  .bullet-track{grid-column:1/-1}
}

/* ---------- sparkline with breach band ----------
   Anomaly-detection pattern: the breach point carries a ring marker
   (a shape) plus a text annotation, so it does not depend on colour. */
.spark{border:1px solid var(--rule);background:var(--panel)}
.spark-head{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-3) var(--s-3);
  border-bottom:1px solid var(--rule);background:var(--panel-2);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);flex-wrap:wrap}
.spark-head b{color:var(--text);font-weight:500;letter-spacing:.04em;text-transform:none;font-size:var(--t-2xs)}
.spark-head .push{margin-left:auto}
.spark svg{display:block;width:100%;height:auto}
.spark .band{fill:rgba(var(--crit-rgb),.09)}
.spark .limit{stroke:var(--crit);stroke-width:1;stroke-dasharray:3 4}
.spark .series{fill:none;stroke:var(--ok);stroke-width:1.6;
  stroke-linejoin:round;stroke-linecap:round}
.spark .marker{fill:none;stroke:var(--crit);stroke-width:2}
.spark .axis{stroke:var(--rule);stroke-width:1}
.spark-note{border-top:1px solid var(--rule);padding:var(--s-3) var(--s-3);font-size:var(--t-2xs);
  color:var(--muted);line-height:1.65}
.spark-note b{color:var(--text);font-weight:500}

/* ---------- coverage matrix (ATT&CK-style) ----------
   Cell state is encoded in fill AND in the legend text below, and every
   cell carries a title attribute for keyboard and screen-reader users. */
.matrix{display:grid;grid-template-columns:repeat(auto-fill,minmax(22px,1fr));
  gap:3px;margin-bottom:var(--s-3)}
.mcell{aspect-ratio:1;border:1px solid var(--rule);background:var(--panel-2)}
.mkey{display:inline-block;width:11px;height:11px;border:1px solid var(--rule);flex:none}
/* State classes work on both the grid cells and the legend keys. */
.mcell.c2,.mkey.c2{background:var(--ok);border-color:var(--ok)}
.mcell.c1,.mkey.c1{background:rgba(var(--ok-rgb),.38);border-color:rgba(var(--ok-rgb),.45)}
/* Empty cells sat at 1.13:1 against the page — a gap you cannot see is
   not a gap. This border clears the 3:1 WCAG floor for non-text UI. */
.mcell.c0,.mkey.c0{background:var(--panel-2);border-color:#625C76}
.mlegend{display:flex;gap:var(--s-4);flex-wrap:wrap;align-items:center;
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.mlegend span{display:flex;align-items:center;gap:var(--s-2)}
.mlegend .push{margin-left:auto}

/* ---------- detection library filter ---------- */
.lib-bar{border:1px solid var(--rule);background:var(--panel);margin-bottom:var(--s-6)}
.lib-row{display:flex;gap:var(--s-2);align-items:center;flex-wrap:wrap;padding:var(--s-3) var(--s-3);
  border-bottom:1px solid var(--rule)}
.lib-row:last-child{border-bottom:none}
.lib-label{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.11em;
  text-transform:uppercase;color:var(--muted);min-width:104px;flex:none}
.lib-btn{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.08em;
  text-transform:uppercase;background:none;border:1px solid var(--rule);color:var(--muted);
  padding:var(--s-2) var(--s-3);min-height:44px;cursor:pointer;
  transition:border-color .18s,color .18s,background-color .18s}
.lib-btn:hover{color:var(--text);border-color:var(--muted)}
.lib-btn[aria-pressed="true"]{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}
.lib-foot{display:flex;gap:var(--s-3);align-items:center;flex-wrap:wrap;padding:var(--s-3) var(--s-3);
  background:var(--ink-deep);font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);
  letter-spacing:.06em;color:var(--muted)}
.lib-foot .push{margin-left:auto}
.lib-empty{padding:var(--s-8) var(--s-5);text-align:center;color:var(--muted);font-size:var(--t-xs);
  border:1px dashed var(--rule)}
.irow .bt{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.09em;
  text-transform:uppercase;border:1px solid var(--rule);padding:2px var(--s-2);color:var(--muted)}
.irow .bt.done{color:var(--ok);border-color:rgba(var(--ok-rgb),.45)}

/* ---------- invariant block on library entries ---------- */
.inv{border:1px solid var(--rule);background:var(--panel);margin:var(--s-6) 0}
.inv-head{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-3) var(--s-3);flex-wrap:wrap;
  border-bottom:1px solid var(--rule);background:var(--panel-2);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.inv-head .push{margin-left:auto}
.inv-body{padding:var(--s-4) var(--s-3)}
.inv-claim{font-size:var(--t-md);color:var(--text);margin:0 0 var(--s-3);line-height:1.6}
.inv-expr{font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);line-height:1.8;
  background:var(--ink-deep);border:1px solid var(--rule);padding:var(--s-3) var(--s-3);
  overflow-x:auto;margin:0;white-space:pre;color:var(--text)}
.inv-bt{border-top:1px solid var(--rule);padding:var(--s-3) var(--s-3);font-size:var(--t-xs);
  color:var(--muted);line-height:1.65}
.inv-bt b{color:var(--text);font-weight:500}
.inv-bt.pending{border-left:2px solid var(--rule)}
.inv-bt.done{border-left:2px solid var(--ok)}
.inv-stat{display:flex;gap:var(--s-5);flex-wrap:wrap;margin-top:var(--s-2);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);font-variant-numeric:tabular-nums}
.inv-stat span{color:var(--muted)}
.inv-stat b{display:block;color:var(--text);font-size:var(--t-sm);font-weight:500;margin-bottom:2px}

/* Table-view twin. Colour-only encoding needs a WCAG-clean equivalent, and a
   96-cell grid must not become 96 keyboard tab stops to achieve it. */
.mtable{margin-top:var(--s-4);border:1px solid var(--rule);background:var(--panel)}
.mtable summary{padding:var(--s-3) var(--s-3);cursor:pointer;font-family:'IBM Plex Mono',monospace;
  font-size:var(--t-3xs);letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
  list-style:none;display:flex;align-items:center;gap:var(--s-2);min-height:44px}
.mtable summary::-webkit-details-marker{display:none}
.mtable summary:before{content:"+";font-family:'IBM Plex Mono',monospace;color:var(--accent)}
.mtable[open] summary:before{content:"\2212"}
.mtable summary:hover{color:var(--text)}
.mtable .tm-table{padding:0 var(--s-3) var(--s-3)}
.mtable .tm-scroll{padding:0 var(--s-3) var(--s-3)}
.mtable .tm-table td{font-variant-numeric:tabular-nums}

/* Status marks carry a shape as well as a hue, so state survives greyscale,
   colour-blindness and forced-colours mode. */
.bullet-flag:before{content:"";display:inline-block;width:8px;height:8px;
  margin-right:var(--s-2);vertical-align:0;background:currentColor}
.bullet.ok    .bullet-flag:before{border-radius:50%}
.bullet.warn  .bullet-flag:before{transform:rotate(45deg)}
.bullet.breach .bullet-flag:before{clip-path:polygon(50% 0,100% 100%,0 100%)}

/* Rows are scannable; a hover tint follows the pointer without implying the
   row is a link. */
.bullet{transition:background-color .15s}
.bullet:hover{background:var(--panel)}

/* ---------- motion ----------------------------------------------------
   One authored moment: the invariant strip resolving. Bars sweep to their
   measured values in sequence and the breaching one crosses its marker and
   turns critical. Everything else on the site stays still so this reads as
   the moment it is.

   The default state is the finished state. Motion is opt-in via .anim,
   added by an IntersectionObserver, so a failed or absent script leaves the
   data fully visible rather than blank. ------------------------------- */

/* Focal: invariant strip */
.bullets.anim .bullet-fill{transform:scaleX(0);
  transition:transform .62s cubic-bezier(.16,1,.3,1),background-color .3s ease}
.bullets.anim .bullet-target{opacity:0;transition:opacity .3s ease .35s}
.bullets.anim.run .bullet-fill{transform:scaleX(var(--v,1))}
.bullets.anim.run .bullet-target{opacity:1}
.bullets.anim .bullet:nth-child(1) .bullet-fill{transition-delay:.02s}
.bullets.anim .bullet:nth-child(2) .bullet-fill{transition-delay:.09s}
.bullets.anim .bullet:nth-child(3) .bullet-fill{transition-delay:.16s}
.bullets.anim .bullet:nth-child(4) .bullet-fill{transition-delay:.23s}
.bullets.anim .bullet:nth-child(5) .bullet-fill{transition-delay:.30s}
/* The breaching bar arrives green and only turns critical once it has passed
   its marker, so the colour change reads as consequence, not decoration. */
.bullets.anim .bullet.breach .bullet-fill{background:var(--ok)}
.bullets.anim.run .bullet.breach .bullet-fill{background:var(--crit);transition-delay:.02s,.5s}
.bullets.anim .bullet.breach .bullet-flag{opacity:0;transition:opacity .25s ease .62s}
.bullets.anim.run .bullet.breach .bullet-flag{opacity:1}

/* Supporting: the sparkline draws to its breach */
.spark.anim .series{stroke-dasharray:var(--len,1400);stroke-dashoffset:var(--len,1400);
  transition:stroke-dashoffset .8s cubic-bezier(.16,1,.3,1)}
.spark.anim.run .series{stroke-dashoffset:0}
.spark.anim .marker{opacity:0;transform-box:fill-box;transform-origin:center;
  transform:scale(.4);transition:opacity .28s ease .72s,transform .32s cubic-bezier(.16,1,.3,1) .72s}
.spark.anim.run .marker{opacity:1;transform:scale(1)}

/* Supporting: matrix cells acknowledge the pointer. No entrance stagger —
   96 cells arriving in sequence would be decoration, not explanation. */
.mcell{transition:transform .12s ease,border-color .12s ease}
.mcell:hover{transform:scale(1.35);border-color:var(--text);position:relative;z-index:2}

@media (prefers-reduced-motion:reduce){
  /* Everything lands in its final state with no travel. */
  .bullets.anim .bullet-fill,.bullets.anim.run .bullet-fill{transform:scaleX(var(--v,1));transition:none}
  .bullets.anim .bullet-target,.bullets.anim .bullet.breach .bullet-flag{opacity:1;transition:none}
  .bullets.anim .bullet.breach .bullet-fill{background:var(--crit)}
  .spark.anim .series{stroke-dashoffset:0;transition:none}
  .spark.anim .marker{opacity:1;transform:none;transition:none}
  .mcell{transition:none}
  .mcell:hover{transform:none}
}

/* Filter bar affordances: say what it does, show what is behind each control
   before it is clicked, and grey out anything that would empty the page. */
.lib-help{padding:var(--s-3) var(--s-4) 0;font-size:var(--t-2xs);color:var(--muted)}
.lib-n{opacity:.6;margin-left:var(--s-1);font-variant-numeric:tabular-nums}
.lib-btn[aria-pressed="true"] .lib-n{opacity:.75}
.lib-btn[disabled]{opacity:.4;cursor:not-allowed}
.lib-btn[disabled]:hover{color:var(--muted);border-color:var(--rule)}
.lib-count{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-3);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-2xs);letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.lib-clear{margin-left:auto;min-height:36px;padding:var(--s-2) var(--s-3)}

/* ---------- detection rule block ----------
   The same invariant, expressed for the other buyer. An entry may carry the
   on-chain form, the SIEM form, or both; each renders only when present. */
.rule{border:1px solid var(--rule);background:var(--panel);margin:var(--s-6) 0}
.rule-head{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-3) var(--s-4);
  flex-wrap:wrap;border-bottom:1px solid var(--rule);background:var(--panel-2);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.rule-head .push{margin-left:auto}
.rule-lang{border:1px solid var(--rule);padding:2px var(--s-2);color:var(--accent)}
.rule-body{padding:var(--s-4)}
.rule-why{font-size:var(--t-sm);color:var(--prose);line-height:1.65;margin-bottom:var(--s-3)}
.rule-why b{color:var(--text);font-weight:500}
.rule pre{margin:0;background:var(--ink-deep);border:1px solid var(--rule);
  padding:var(--s-3) var(--s-4);overflow-x:auto;font-size:var(--t-xs);line-height:1.75}
.rule-foot{border-top:1px solid var(--rule);padding:var(--s-3) var(--s-4);
  font-size:var(--t-2xs);color:var(--muted);line-height:1.6}
.irow .rl{font-family:'IBM Plex Mono',monospace;font-size:var(--t-3xs);letter-spacing:.09em;
  text-transform:uppercase;border:1px solid var(--rule);padding:2px var(--s-2);color:var(--muted)}
.irow .rl.has{color:var(--accent);border-color:var(--accent)}
