  :root{
    --bg:#f3f2ee; --card:#fbfbf9; --ink:#17181b; --muted:#6b6f76; --line:#e4e2da;
    --accent:#1a7a49; --danger:#c62828; --safe:#1a7a49;
    --tbg:#14161b; --tfg:#cfd3da;
    --mono:ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace;
    --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  }
  *{box-sizing:border-box}
  html{scroll-behavior:smooth;scroll-padding-top:70px}
  body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--sans);line-height:1.55;-webkit-font-smoothing:antialiased}
  a{color:inherit}
  :focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}
  /* SIGNATURE: shell-prompt eyebrow -- the section labels read as terminal prompts */
  .kicker::before,.catname::before{content:"$ ";color:var(--accent);opacity:.85}
  code{font-family:var(--mono);font-size:.88em;color:var(--ink);background:rgba(23,24,27,.06);padding:.11em .4em;border-radius:5px;unicode-bidi:isolate}
  .wrap{max-width:1000px;margin:0 auto;padding:0 20px}

  header.nav{position:sticky;top:0;z-index:10;background:rgba(243,242,238,.93);backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
  .nav > .wrap{display:flex;align-items:center;gap:12px;min-height:56px;position:relative}
  .brand{font-family:var(--mono);font-weight:700;letter-spacing:-.02em;text-decoration:none;display:inline-flex;align-items:center;gap:9px;white-space:nowrap;font-size:1.02rem;flex:0 0 auto}
  .brand .logo{width:1.4em;height:1.4em;flex:0 0 auto}
  .brand .brandmark{height:30px;width:auto;max-width:100%;display:block}
  /* narrow phones: the wordmark at 30px is ~324px wide and would overflow a
     320-375px viewport, so shrink it there (the sibling sites do the same) */
  /* the wordmark is very wide (~10.8:1); on a phone it must be small enough to
     fit undistorted beside the status pill + toggle, so scale it down here. */
  @media(max-width:640px){ .brand .brandmark{height:16px} }
  /* only on the very narrowest screens is there no room for the pill too
     (higher specificity than the base .nav .status so source order is moot) */
  @media(max-width:340px){ .nav > .wrap > .status{display:none} }
  .brand b{color:var(--accent)}
  .brand .tm{font-size:.72em;color:var(--muted);margin-left:.14em;font-weight:600;align-self:flex-start;line-height:1}
  /* Auto margin after the badge keeps brand+badge clustered left; when the
     9-item nav wraps to its own row it sits LEFT-aligned under them, not shoved
     to the right edge (the odd empty indent it had). */
  .nav .status{margin-left:12px;display:inline-block;font-family:var(--mono);font-size:.66rem;letter-spacing:.08em;text-transform:uppercase;color:#fff;background:#c21a74;border-radius:5px;padding:3px 8px;white-space:nowrap;text-decoration:none;cursor:pointer;transition:filter .15s,box-shadow .15s}
  .nav a.status:hover{filter:brightness(1.12);box-shadow:0 1px 5px rgba(0,0,0,.28);text-decoration:none}
  .nav a.status:focus-visible{outline:2px solid #fff;outline-offset:2px}
  .nav .navtoggle{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
  .nav .menubtn{margin-left:auto;display:inline-block;cursor:pointer;user-select:none;font-size:0;
    color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:9px 10px}
  .nav .menubtn::before{content:"";display:inline-block;width:15px;height:11px;
    background:linear-gradient(currentColor 0 2px,transparent 2px 4.5px,currentColor 4.5px 6.5px,transparent 6.5px 9px,currentColor 9px 11px)}
  .nav .navtoggle:focus-visible + .menubtn{outline:2px solid var(--accent);outline-offset:2px}
  .nav nav a{font-size:.9rem;color:var(--muted);text-decoration:none;white-space:nowrap}
  .nav nav a:hover{color:var(--ink)}
  /* mark an off-site nav link (GitHub) with a small external-link arrow (decorative; the
     link text is the accessible name) */
  .nav nav a[href^="http"]::after{content:"\2197";font-size:.82em;opacity:.6;margin-left:1px;vertical-align:.05em}
  .nav nav a[href^="http"]:hover::after{opacity:.95}
  .nav nav a.active{color:var(--ink);font-weight:650}
  .nav nav{display:none}
  .nav .navtoggle:checked ~ nav{position:absolute;left:0;right:0;top:100%;display:flex;flex-direction:column;
    align-items:stretch;gap:0;background:var(--bg);z-index:2;border-bottom:1px solid var(--line);
    padding:2px 20px 10px;box-shadow:0 12px 26px rgba(0,0,0,.10)}
  .nav .navtoggle:checked ~ nav a{padding:11px 2px;border-top:1px solid var(--line);font-size:1rem;white-space:normal;color:var(--ink)}
  .nav .navscrim{display:none}
  .nav .navtoggle:checked ~ .navscrim{display:block;position:fixed;inset:0;z-index:1}
  @media(min-width:1000px){
    .nav .menubtn{display:none}
    /* the 10-item nav is wider than the 1000px content column, so let it wrap to
       a second row here (as it did before) rather than shrink the logo/overflow */
    .nav > .wrap{flex-wrap:wrap;row-gap:6px}
    .nav nav{display:flex;gap:16px;align-items:center;position:static;margin-left:auto}
  }

  .notice{background:#eef7f1;border-bottom:1px solid #cfe6da;color:#274b39}
  .notice .wrap{padding:11px 20px;font-size:.92rem}
  .notice b{color:var(--accent)}

  .hero{padding:clamp(28px,7vw,48px) 0 clamp(22px,5vw,40px)}
  .kicker{font-family:var(--mono);font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin:0 0 14px}
  .hero h1{font-size:clamp(2rem,6vw,3.6rem);line-height:1.05;letter-spacing:-.03em;margin:0 0 18px;font-weight:800;text-wrap:balance}
  .hero h1 .u{text-decoration:underline;text-decoration-color:var(--accent);text-underline-offset:6px}
  .hero p.sub,.hero p.lede{font-size:clamp(1.05rem,2.4vw,1.3rem);color:#2c2e33;margin:0}
  .hero p.sub{max-width:60ch}
  .hero p.lede{max-width:72ch}
  .cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:26px}
  .btn{display:inline-block;padding:11px 18px;border-radius:9px;font-weight:650;text-decoration:none;font-size:.95rem;border:1px solid var(--ink)}
  .btn.primary{background:var(--ink);color:var(--bg)}
  .btn.ghost{background:transparent;color:var(--ink)}

  .whatis{background:var(--card);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
  .whatis .wrap{padding:22px 20px}
  .whatis p{margin:0;max-width:72ch;color:#33353a;font-size:1.02rem}
  .whatis b{color:var(--accent)}

  section.cat{padding:clamp(26px,6vw,52px) 0 8px}
  .catname{font-size:.82rem;font-family:var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--accent);margin:0 0 4px}
  .catdesc{margin:0 0 18px;color:var(--muted);max-width:72ch}
  /* comparison intro: compact so the switcher + matrix are the focus near the top.
     .lede here is outside .hero, so it needs its own reading-measure + spacing. */
  #compare{padding-top:26px}
  #compare .catname{margin:0 0 8px}
  #compare .lede{max-width:72ch;margin:0 0 12px;color:#2c2e33;font-size:1.05rem;line-height:1.5}
  .issue{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:22px;margin:16px 0}
  .issue h3{margin:0 0 8px;font-size:1.2rem;letter-spacing:-.01em}
  .issue p{margin:0 0 8px;color:#3a3c41;max-width:72ch}
  .issue p:last-child{margin-bottom:0}
  /* A prose issue card hugs the reading measure (like .cmp-wrap) so its border
     does not trail empty space to the right of the text. Cards holding a wide
     table or terminal block stay full-width. Grid (.fg) columns still win. */
  .issue:not(:has(table, .term, .pre)){max-width:calc(72ch + 44px)}
  .modenote{margin-top:10px;padding-top:10px;border-top:1px solid var(--line);color:var(--muted);font-size:.9rem}
  .modenote b{color:var(--ink)}
  .no{color:var(--danger);font-weight:700}
  .yes{color:var(--accent);font-weight:700}
  .tbl{width:100%;border-collapse:collapse;margin:6px 0 0;font-size:.95rem}
  .tbl th,.tbl td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line)}
  .tbl th{font-family:var(--mono);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
  .tbl td code{font-family:var(--mono)}
  .tbl tr:last-child td{border-bottom:0}
  .term{background:var(--tbg);color:var(--tfg);font:.92rem/1.7 var(--mono);padding:16px;border-radius:11px;border:1px solid #23262e;overflow-x:auto;white-space:pre;unicode-bidi:isolate}
  .term .g{color:#9ece6a}.term .r{color:#f7768e}.term .d{color:#7d8593}.term .y{color:#e0af68}
  .fg{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:16px 0;align-items:start}
  .fg .issue{margin:0}
  @media(max-width:640px){ .fg{grid-template-columns:1fr} }
  .risk{border-left:4px solid #e5a50a;background:#fbf6ec}
  .flag{color:#b9770a;font-weight:700}
  .pre{background:var(--tbg);color:var(--tfg);font:.9rem/1.65 var(--mono);padding:16px;border-radius:11px;border:1px solid #23262e;overflow-x:auto;white-space:pre;unicode-bidi:isolate}
  /* Data tables fill their column (like the comparison matrix): a 3-4 column verdict /
     coverage / fingerprint table reads far better with room than clamped to the 72ch prose
     measure, which forces heavy wrapping. Prose stays capped elsewhere; tables get the width.
     overflow-x:auto + min-width on .cmp keeps them scrollable on narrow screens. */
  .cmp-wrap{overflow-x:auto;margin:16px 0;max-width:none;
    /* self-hiding scroll shadows: a soft shadow appears on whichever edge still
       has table to scroll to, so the hidden third column (secure-terminal) is
       discoverable on narrow screens. Pure CSS, no script. */
    background:
      linear-gradient(to right, var(--bg) 20%, rgba(243,242,238,0)) left center,
      linear-gradient(to left,  var(--bg) 20%, rgba(243,242,238,0)) right center,
      linear-gradient(to right, rgba(0,0,0,.13), rgba(0,0,0,0)) left center,
      linear-gradient(to left,  rgba(0,0,0,.13), rgba(0,0,0,0)) right center;
    background-repeat:no-repeat;
    background-size:36px 100%,36px 100%,16px 100%,16px 100%;
    background-attachment:local,local,scroll,scroll}
  .cmp-hint{display:none}
  @media(max-width:640px){
    .cmp-hint{display:block;margin:8px 2px 0;text-align:right;color:var(--muted);
      font-family:var(--mono);font-size:.72rem;letter-spacing:.02em}
  }
  .cmp{width:100%;border-collapse:collapse;font-size:.95rem;min-width:560px}
  .cmp th,.cmp td{text-align:left;padding:11px 12px;border-bottom:1px solid var(--line);vertical-align:top}
  .cmp thead th{font-family:var(--mono);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
  .cmp td:first-child{font-weight:600;color:var(--ink)}
  .cmp .trad{color:#5a5c61}
  @media(max-width:640px){ .cmp{font-size:.86rem} .cmp th,.cmp td{padding:9px 8px} }
  .shotgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(440px,1fr));gap:20px;margin:8px 0 0}
  @media(max-width:520px){ .shotgrid{grid-template-columns:1fr} }
  .shotsrc{font-size:.82rem;color:var(--muted);margin:14px 0 0;text-align:center}
  .boxlegend{font-size:.9rem;color:var(--ink);margin:16px 0 0;line-height:1.7}
  .boxlegend .sw{display:inline-block;width:.85em;height:.85em;border-radius:3px;vertical-align:-1px;border:1px solid rgba(0,0,0,.2)}
  .pastedemo{margin:16px 0 2px}
  .cmdrow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
  .pastedemo .cmd{font-family:var(--mono);font-size:1.05rem;padding:9px 15px;background:var(--card);border:1px solid var(--line);border-radius:8px}
  .pd-btn{padding:8px 15px;font-size:.85rem;font-weight:650;cursor:pointer;font-family:inherit}
  .pd-status{color:var(--muted);font-size:.85rem}
  .pd-out{margin:14px 0 0;background:#14161b;color:#e9e9e9;border-radius:11px;padding:15px 16px;overflow-x:auto;white-space:pre-wrap;font-family:var(--mono);font-size:.9rem;line-height:1.7}
  .shot{margin:0;border:1px solid var(--line);border-radius:11px;overflow:hidden;background:var(--card);display:flex;flex-direction:column}
  /* direct child only: this kills the inline-image descender gap on the figure's
     own image link. A descendant selector would also hit links inside the
     figcaption, turning them into zero-height blocks that break the sentence and
     overlap the neighbouring lines. */
  .shot > a{display:block;line-height:0}
  .shot img{display:block;width:100%;height:auto;background:#000}
  /* name-on-top caption: identifies the terminal above its screenshot */
  .shot figcaption.shotname{padding:10px 12px;font-size:.9rem;color:var(--muted);border-bottom:1px solid var(--line);order:-1}
  .shot figcaption.shotname b{color:var(--ink)}
  .shot figcaption{padding:10px 12px;font-size:.9rem;color:var(--muted)}

  /* Homepage hero before/after slider. Two identical-size screenshots of the SAME
     hostile file: a traditional terminal (base image, shown to the right of the
     divider) under secure-terminal Show mode (overlay, shown to the left). No-JS
     baseline: the overlay is a resize:horizontal box with a red divider -- drag its
     corner to wipe. Progressive enhancement (.js) adds a centred grip plus pointer,
     touch and keyboard control; with JS off the resize corner still works. */
  .herocmp{max-width:760px;margin:30px auto 0}
  /* pan-y pinch-zoom: the browser keeps vertical scroll AND native two-finger pinch-zoom;
     single-finger horizontal is routed to the slider JS. */
  .herocmp-stage{position:relative;width:100%;line-height:0;background:#fff;overflow:hidden;touch-action:pan-y pinch-zoom}
  .herocmp-stage img{display:block;width:100%;height:auto;max-width:100%;background:#fff;-webkit-user-drag:none;user-select:none}
  .herocmp-top{position:absolute;top:0;left:0;bottom:0;width:52%;min-width:0;max-width:100%;
    overflow:hidden;resize:horizontal;border-right:3px solid #e5484d;box-sizing:border-box}
  /* inner image pinned to the full stage size so it never squishes as the box narrows;
     max-width:none defeats the global img{max-width:100%}. */
  .herocmp-top img{position:absolute;top:0;left:0;height:100%;width:auto;max-width:none}
  /* Click-to-open: a transparent <a> over each side opens that screenshot full size in a
     new tab (native anchor, so middle / Ctrl / right-click + keyboard keep "open in new
     tab"). The base link covers the whole stage -- its uncovered right half opens the
     traditional shot; the overlay link covers the clipped secure side. JS distinguishes a
     drag (slide) from a click (open); no-JS, the click just opens and the resize corner slides. */
  .herocmp-link{position:absolute;top:0;left:0;right:0;bottom:0;display:block;cursor:zoom-in;-webkit-user-drag:none}
  /* no-JS only: keep the overlay's bottom-right resize corner reachable for the CSS slider */
  .herocmp:not(.js) .herocmp-link-top{bottom:18px}
  /* No-JS: the resize corner is the divider control; the grip button stays hidden. */
  .herocmp-handle{display:none}
  .herocmp.js .herocmp-top{resize:none}
  .herocmp.js .herocmp-handle{display:block;position:absolute;top:0;bottom:0;left:52%;width:40px;
    margin-left:-20px;padding:0;border:0;background:none;cursor:ew-resize;touch-action:none;z-index:3}
  .herocmp-grip{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:34px;height:34px;
    border-radius:50%;background-color:#e5484d;border:2px solid #fff;box-shadow:0 1px 5px rgba(0,0,0,.4);
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.5 7l-4 5 4 5M13.5 7l4 5-4 5'/%3E%3C/svg%3E");
    background-repeat:no-repeat;background-position:center;background-size:20px 20px}
  .herocmp-handle:focus-visible{outline:none}
  .herocmp-handle:focus-visible .herocmp-grip{outline:3px solid var(--accent);outline-offset:2px}
  .herocmp-hint{display:block;margin-top:6px;font-family:var(--mono);font-size:.78rem;color:var(--muted)}
  .herocmp.js .herocmp-hint::after{content:" Or use the arrow keys."}

  .pre .c{color:#7d8593}

  footer{border-top:1px solid var(--line);color:var(--muted);font-size:.9rem;margin-top:40px}
  footer .ftop{display:flex;gap:40px 56px;flex-wrap:wrap;justify-content:space-between;padding:36px 20px 28px;max-width:1000px;margin:0 auto}
  footer .fbrand .ftag{font-family:var(--mono);font-weight:700;font-size:1.05rem;color:var(--ink);letter-spacing:-.02em;display:inline-flex;align-items:center;gap:8px}
  footer .fbrand .ftag b{color:var(--accent)}
  footer .fbrand p{margin:8px 0 0;max-width:30ch;color:var(--muted)}
  footer .fcols{display:flex;gap:52px;flex-wrap:wrap}
  footer .fcol{display:flex;flex-direction:column;gap:9px}
  footer .fcol h3{margin:0 0 3px;font-family:var(--mono);font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600}
  footer .fcol a{color:var(--ink);text-decoration:none;font-size:.88rem}
  footer .fcol a:hover{color:var(--accent)}
  /* self-link: the current site appears in the uniform Family list but is not
     clickable and is marked as the current page. */
  footer .fcol a.self{color:var(--muted);pointer-events:none;cursor:default;text-decoration:none}
  footer .fcol a.self::after{content:" (this site)";font-size:.8em;opacity:.7}
  footer .fbot{display:flex;gap:20px;flex-wrap:wrap;padding:16px 20px 44px;border-top:1px solid var(--line);align-items:center;max-width:1000px;margin:0 auto}
  footer .fbot .sp{margin-left:auto}
  footer .fcopy{color:var(--muted);font-size:.84rem}
  @media(max-width:640px){ footer .fcols{display:grid;grid-template-columns:1fr 1fr;gap:20px 22px} }

footer .fshare{display:flex;align-items:center;gap:8px 12px;flex-wrap:wrap;max-width:1080px;margin:0 auto;padding:6px 20px 12px;font-size:.85rem;color:var(--muted)}
footer .fshare .fshare-l{color:var(--muted)}
footer .fshare .sh{color:var(--ink);text-decoration:none;border:1px solid var(--line);border-radius:7px;padding:4px 10px;background:transparent;cursor:pointer;font:inherit}
footer .fshare .sh:hover{border-color:var(--accent);color:var(--accent)}
footer .fshare .sh-msg{color:var(--safe);font-family:var(--mono);font-size:.8rem}

/* freedom-software footer badges (OSI + GNU), open source / AGPL */
footer .ffree{display:flex;align-items:center;gap:12px 26px;flex-wrap:wrap;max-width:1000px;margin:0 auto;padding:14px 20px 2px}
.freebadge{display:inline-flex;align-items:center;gap:8px;color:var(--muted);text-decoration:none;font-size:.85rem;font-weight:600}
.freebadge img{height:22px;width:auto;filter:grayscale(1);opacity:.55;transition:filter .12s,opacity .12s}
.freebadge:hover{color:var(--ink)}
.freebadge:hover img{filter:grayscale(0);opacity:1}
@media(max-width:640px){
  footer .ffree{flex-direction:column;align-items:flex-start;gap:11px;padding-bottom:10px}
}

/* clickable section anchors (matches output-lies) */
.catname a.h-anchor,.issue h3 a.h-anchor{color:inherit;text-decoration:none}
.catname a.h-anchor:hover,.issue h3 a.h-anchor:hover{color:var(--accent)}
.catname a.h-anchor::after,.issue h3 a.h-anchor::after{content:"#";margin-left:.3em;color:var(--muted);font-weight:400;opacity:0;transition:opacity .12s}
.catname:hover a.h-anchor::after,.issue h3:hover a.h-anchor::after,a.h-anchor:focus::after{opacity:.5}

/* install accordion boxes (native <details>, no JS; inline SVG icons) */
.inst{border:1px solid var(--line);border-radius:12px;background:var(--card);margin:10px 0;overflow:hidden}
.inst > summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:12px;padding:14px 16px}
.inst > summary::-webkit-details-marker{display:none}
.inst > summary::after{content:"+";color:var(--muted);font-weight:400;font-size:1.25rem;line-height:1}
.inst[open] > summary::after{content:"\2212"}
.inst > summary:hover{background:rgba(31,138,84,.05)}
.inst .ilogo{width:24px;height:24px;flex:0 0 auto;fill:var(--accent)}
.inst .ititle{flex:1;font-size:1.02rem;font-weight:600}
.inst .ibadge{font-family:var(--mono);font-size:.66rem;letter-spacing:.06em;text-transform:uppercase;padding:2px 7px;border-radius:5px;white-space:nowrap}
.inst .ibadge.ok{background:rgba(31,138,84,.13);color:#166f40}
.inst .ibadge.soon{background:rgba(107,111,118,.15);color:#595d63}
.inst .ibody{padding:2px 16px 16px}
.inst .ibody > p{margin:0 0 10px;color:#3a3c41;max-width:72ch}
.inst .ibody > p:last-child{margin-bottom:0}
/* Evidence tables live in a full-width .inst card, not the 72ch reading column. The
   default .cmp-wrap max-width:72ch (sized for the matrix's 72ch ibody) would cap the
   table narrower than the card and leave dead space to its right, so let it fill the
   card. min-width on .cmp still makes it scroll on narrow/mobile viewports. */
.inst .ibody .cmp-wrap{max-width:none}
/* terminal-logo attribution list (footer icon-credits collapsible) */
.credits{margin:6px 0 12px;padding-left:20px;color:#3a3c41;font-size:.9rem;line-height:1.7;max-width:72ch}
.credits li{margin:2px 0}
.credits b{color:var(--ink)}

/* clearer expand affordance for the evidence / reproduce boxes: a rotating
   chevron on the left and a Show/Hide pill on the right (item: obvious expand). */
.inst .ichevron{width:0;height:0;flex:0 0 auto;border-left:7px solid var(--muted);
  border-top:5px solid transparent;border-bottom:5px solid transparent;transition:transform .15s}
.inst[open] .ichevron{transform:rotate(90deg);border-left-color:var(--accent)}
.inst > summary:hover .ichevron{border-left-color:var(--accent)}
.inst .ihint{margin-left:auto;font-family:var(--mono);font-size:.66rem;letter-spacing:.06em;
  text-transform:uppercase;padding:3px 10px;border-radius:999px;border:1px solid var(--line);
  color:var(--muted);white-space:nowrap;transition:color .12s,border-color .12s}
.inst > summary:hover .ihint{border-color:var(--accent);color:var(--accent)}
.inst .ihint .ihint-hide{display:none}
.inst[open] .ihint .ihint-show{display:none}
.inst[open] .ihint .ihint-hide{display:inline}
/* the chevron + pill replace the +/- marker on boxes that carry them */
.inst > summary:has(.ihint)::after{display:none}

/* clickable per-row anchor in the matrix (jump-to + :target highlight) */
.matrix th[scope=row] a.rowlink{color:inherit;text-decoration:none}
.matrix th[scope=row] a.rowlink:hover{color:var(--accent)}
.matrix th[scope=row] a.rowlink::after{content:"#";margin-left:.35em;color:var(--muted);
  font-weight:400;opacity:0;transition:opacity .12s}
.matrix th[scope=row]:hover a.rowlink::after,.matrix a.rowlink:focus::after{opacity:.55}

/* memory-safety language badge (per-terminal, linked to the parser source) */
.matrix td.verdict a.langbadge{display:inline-block;line-height:0}
.matrix td.verdict a.langbadge img{height:26px;width:auto;display:block;border-radius:6px}
.matrix td.verdict a.langbadge:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:8px}

/* copy-paste-able command boxes (output-lies style); button is a JS enhancement */
.cmdlabel{font-family:var(--mono);font-size:.78rem;color:var(--muted);margin:16px 0 5px;white-space:pre-wrap}
.copybox{display:flex;align-items:stretch;margin:7px 0;border:1px solid #23262e;
  border-radius:9px;overflow:hidden;background:var(--tbg)}
.copybox .cmd{flex:1 1 auto;font-family:var(--mono);font-size:.82rem;color:var(--tfg);
  padding:11px 13px;overflow-x:auto;white-space:pre;user-select:all;-webkit-user-select:all}
.copybox .copybtn{flex:0 0 auto;border:0;border-left:1px solid #23262e;background:#1c1f26;
  color:#aab0bd;font:600 .72rem/1 var(--mono);padding:0 15px;cursor:pointer;letter-spacing:.05em}
.copybox .copybtn:hover{background:#262b34;color:#fff}
.copybox .copybtn.ok{color:var(--safe)}

  /* jump-to-anchor highlight: a red ring around the element you navigated to
     (the sticky header needs the scroll-margin so the target is not hidden). */
  :target{scroll-margin-top:76px}
  /* Narrow viewports wrap the nav onto three rows, so the sticky header is far
     taller than 76px and an anchor landed UNDER it -- the heading you navigated
     to was hidden. Scale the offset with the header instead of pinning it. */
  @media(max-width:640px){ html{scroll-padding-top:80px} :target{scroll-margin-top:86px} }
  /* Contained targets ring themselves; a full-bleed section rings its inner
     .wrap instead, so the vertical ring edges stay on-screen (a ring on the
     edge-to-edge section would sit at the viewport edges). */
  .issue:target, .shot:target, figure:target, article:target, .level:target{
    box-shadow:0 0 0 2px #e5484d; border-radius:8px;
  }
  /* Many boxes carry the id on their heading (e.g. an FAQ or feature <h3 id>),
     so :target lands on the h3, not the box. Ring the containing box instead, so
     a jump to #faq-ai / #ascii-output highlights the whole card like a section. */
  .issue:has(> h3:target), .level:has(> h3:target), article:has(> h3:target){
    box-shadow:0 0 0 2px #e5484d; border-radius:8px;
  }
  h3:target, h2:target{ scroll-margin-top:76px; }
  /* A bare section column has no padding of its own, so a box-shadow hugging its
     border box rings the text too tightly. Use an offset outline instead: it
     keeps an even gap around the content and adds no layout shift. The generous
     offset only applies once the column is narrower than the viewport (there is
     room beside it); on a full-width narrow viewport it stays tight so the ring
     does not run off-screen. */
  section:target > .wrap{
    outline:2px solid #e5484d; outline-offset:2px; border-radius:10px;
  }
  @media(min-width:1100px){
    section:target > .wrap{ outline-offset:14px; }
  }

  /* ---- comparison: noJS terminal switcher (CSS radio + :checked sibling combinator) ----
     INVARIANT: the 10 radios, their 10 chip labels, and the single .panel are ALL direct
     children of fieldset.cmp-switch. `~` reaches only FOLLOWING SIBLINGS, so the .panel
     (and everything it contains) must follow the radios and share their parent. Wrapping
     the radios in a sub-div silently breaks every `#t-*:checked ~ .panel .var.*` rule. */
  .cmp-switch{display:flex;flex-wrap:wrap;gap:9px;align-items:flex-start;border:0;margin:14px 0 0;padding:0;min-width:0}
  .cmp-switch .swlead{flex:1 0 100%;margin:0 0 4px;font-family:var(--mono);font-size:.74rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
  .sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;white-space:nowrap}
  /* radios visually hidden but keyboard-focusable -- NEVER display:none */
  .tsel{position:absolute;width:1px;height:1px;margin:-1px;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}
  .chip{display:inline-flex;align-items:center;gap:8px;cursor:pointer;user-select:text;
    border:1px solid var(--line);border-radius:999px;background:var(--card);
    padding:6px 13px 6px 8px;font-size:.9rem;font-weight:650;color:var(--muted);
    transition:color .12s,background .12s,border-color .12s}
  .chip .cico{width:20px;height:20px;flex:0 0 auto;display:block}
  .chip:hover{color:var(--ink);border-color:var(--muted)}
  .tsel:checked + .chip{color:#fff;background:var(--ink);border-color:var(--ink)}
  .tsel:focus-visible + .chip{outline:2px solid var(--accent);outline-offset:2px}
  .panel{flex:1 0 100%;margin-top:22px;min-width:0}

  /* one variant engine drives BOTH inline cells (span -> inline) and figures (div -> block) */
  .panel .var{display:none}
  #t-gnome:checked     ~ .panel .var.x-gnome,
  #t-konsole:checked   ~ .panel .var.x-konsole,
  #t-xfce4:checked     ~ .panel .var.x-xfce4,
  #t-mate:checked      ~ .panel .var.x-mate,
  #t-qterminal:checked ~ .panel .var.x-qterminal,
  #t-xterm:checked     ~ .panel .var.x-xterm,
  #t-urxvt:checked     ~ .panel .var.x-urxvt,
  #t-st:checked        ~ .panel .var.x-st,
  #t-alacritty:checked ~ .panel .var.x-alacritty,
  #t-kitty:checked     ~ .panel .var.x-kitty{display:revert}
  /* .vonly self-labels a varying cell when CSS is ON it is hidden (only the selected
     variant shows); with CSS OFF every variant shows and its terminal name shows with it */
  .vonly{display:none}

  /* ---- secure-terminal view switcher: CLI/TUI mode x Box/Show/Detail unicode ----
     Two CSS-only axes. Same INVARIANT as the terminal switcher: these radios are direct
     children of fieldset.cmp-switch, ahead of .panel, so `~ .panel .sv` reaches them. Five
     .sv board variants (cli+box, cli+show, cli+detail, tui+box, tui+show) show by default
     and each checked radio hides the variants that do not match its axis -- cli+box (the
     defaults) leave exactly .sv.m-cli.u-box. Detail (and Reveal) are CLI-only: the fixed
     TUI grid cannot expand a codepoint inline, so the app disables Detail in TUI and
     auto-switches to Box. The page mirrors that -- selecting TUI greys the Detail chip and,
     if Detail was the remembered choice, forces tui+box; Show stays valid in TUI. Switching
     back to CLI restores Detail. With CSS OFF all .sv show, each captioned (no-CSS fallback). */
  .mchip{display:inline-flex;align-items:center;cursor:pointer;user-select:text;
    border:1px solid var(--line);background:var(--card);
    padding:5px 12px;font-size:.82rem;font-weight:650;color:var(--muted);
    transition:color .12s,background .12s,border-color .12s}
  .mchip.first{border-radius:999px 0 0 999px;border-right-width:0}
  .mchip.mid{border-right-width:0}
  .mchip.last{border-radius:0 999px 999px 0}
  .mchip.gap{margin-left:8px}
  .mchip:hover{color:var(--ink);border-color:var(--muted)}
  .tsel:checked + .mchip{color:#fff;background:var(--ink);border-color:var(--ink)}
  .tsel:focus-visible + .mchip{outline:2px solid var(--accent);outline-offset:2px}
  .panel .sv{display:block}
  #st-cli:checked    ~ .panel .sv.m-tui,
  #st-tui:checked    ~ .panel .sv.m-cli,
  #st-box:checked    ~ .panel .sv.u-show,
  #st-box:checked    ~ .panel .sv.u-detail,
  #st-show:checked   ~ .panel .sv.u-box,
  #st-show:checked   ~ .panel .sv.u-detail,
  #st-detail:checked ~ .panel .sv.u-box,
  #st-detail:checked ~ .panel .sv.u-show{display:none}
  /* TUI has no Detail/Reveal board (the fixed grid cannot expand a codepoint inline): when
     TUI+Detail is the remembered pair, force tui+box (2 ids beat the u-box hide above) and
     grey the Detail chip -- mirrors the app disabling Detail and auto-switching to Box in
     TUI. Show IS valid in TUI, so it is neither forced nor greyed. */
  #st-tui:checked ~ #st-detail:checked ~ .panel .sv.m-tui.u-box{display:block}
  /* Detail is unavailable in TUI: make its chip read clearly as DISABLED -- dimmed, struck
     through, not-allowed cursor -- and override the `.tsel:checked + .mchip` selected fill so
     it never looks like the active choice while Box is actually shown. The id in the selector
     outranks that rule, so no !important is needed. Pure CSS cannot re-select the Box radio,
     so returning to CLI reshows Detail (the app does the real re-select). */
  #st-tui:checked ~ label[for="st-detail"]{opacity:.5;cursor:not-allowed;text-decoration:line-through;
    color:var(--muted);background:var(--card);border-color:var(--line)}

  /* per-row screenshot inside a matrix row's info-expander: reuse .board2/.shot, a touch
     tighter than the hero board. The .var engine already swaps the competitor shot. */
  .rowinfo .ibody .shotgrid{margin:10px 0 2px}
  .rowinfo .ibody .shotname{font-size:.82rem}

  /* two-up screenshot board */
  .board2{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin:6px 0 0;align-items:start}
  @media(max-width:640px){ .board2{grid-template-columns:1fr} }
  .board2 .shot{margin:0}

  /* ---- comparison: the verdict matrix (Whonix-style) ---- */
  table.matrix{width:100%;border-collapse:collapse;font-size:.95rem;margin:6px 0 0}
  .matrix thead th{font-family:var(--mono);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);text-align:left;padding:11px 12px;border-bottom:1px solid var(--line)}
  .matrix thead th.col-st{color:var(--accent)}
  .matrix th[scope=row]{text-align:left;font-weight:600;color:var(--ink);padding:12px;vertical-align:top}
  .matrix td.verdict{width:1%;white-space:nowrap;padding:12px;vertical-align:top}
  .matrix tr.mrow > *{border-top:1px solid var(--line)}
  .matrix tr.mrow:first-of-type > *{border-top:0}
  .vd{display:inline-flex;align-items:center;gap:6px;font-weight:700;font-size:.9rem;white-space:nowrap}
  .vd .vico{width:15px;height:15px;flex:0 0 auto}
  .vd.ok{color:var(--safe)} .vd.bad{color:var(--danger)} .vd.warn{color:#b9770a} .vd.na{color:var(--muted)}
  /* per-row info-expander: a full-width row holding a CSS-only checkbox+label toggle
     (same hidden-input + :checked-sibling idiom as the chips -- no JS). The marker is a
     rotating chevron: an EXPAND affordance, not a circled "i" tooltip. */
  .matrix tr.minfo > td{padding:0 12px 6px}
  .rowinfo{border:0;background:transparent;margin:0}
  /* checkbox visually hidden but keyboard-focusable -- NEVER display:none */
  .rowtoggle{position:absolute;width:1px;height:1px;margin:-1px;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}
  /* Full-width framed control mirroring the .inst evidence boxes: rotating chevron on
     the left, a Show/Hide pill on the right -- an obvious, button-like expand affordance
     (the bare inline chevron+text before it read as plain text, not a control). */
  .rowsum{list-style:none;cursor:pointer;display:flex;align-items:center;gap:8px;padding:7px 11px;font-size:.85rem;color:var(--muted);user-select:text;
    border:1px solid var(--line);border-radius:9px;background:var(--card);transition:color .12s,background .12s,border-color .12s}
  .rowsum::before{content:"\25B8";display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:0 0 auto;font-size:.8rem;color:var(--muted);transition:transform .12s}
  .rowsum:hover{color:var(--ink);background:rgba(31,138,84,.05);border-color:var(--muted)}
  /* right-aligned Show/Hide pill; flips on the row's own toggle OR the master expand-all */
  .rowsum .ihint{margin-left:auto;font-family:var(--mono);font-size:.64rem;letter-spacing:.06em;
    text-transform:uppercase;padding:3px 10px;border-radius:999px;border:1px solid var(--line);
    color:var(--muted);white-space:nowrap;transition:color .12s,border-color .12s}
  .rowsum:hover .ihint{border-color:var(--accent);color:var(--accent)}
  .rowsum .ihint .ihint-hide{display:none}
  .rowtoggle:checked + .rowsum .ihint .ihint-show,
  #expand-all:checked ~ .cmp-wrap .rowsum .ihint .ihint-show{display:none}
  .rowtoggle:checked + .rowsum .ihint .ihint-hide,
  #expand-all:checked ~ .cmp-wrap .rowsum .ihint .ihint-hide{display:inline}
  .rowtoggle:checked + .rowsum .ihint,
  #expand-all:checked ~ .cmp-wrap .rowsum .ihint{border-color:var(--accent);color:var(--accent)}
  .rowtoggle:focus-visible + .rowsum{outline:2px solid var(--accent);outline-offset:2px}
  /* open state (own toggle OR the master expand-all): chevron rotates to point down,
     label + marker take the accent. The master must precede .cmp-wrap as its sibling. */
  .rowtoggle:checked + .rowsum,
  #expand-all:checked ~ .cmp-wrap .rowsum{color:var(--ink)}
  .rowtoggle:checked + .rowsum::before,
  #expand-all:checked ~ .cmp-wrap .rowsum::before{transform:rotate(90deg);color:var(--accent)}
  /* The expanded body holds BOTH prose and the side-by-side screenshot grids. Cap only the
     prose to the 72ch reading measure; let the shot grids / evidence tables fill the full
     (now 960px) matrix cell -- otherwise a 72ch body squeezes the comparison shots to ~320px
     each. Mirrors the .inst .ibody > p / .cmp-wrap{max-width:none} split. */
  .rowinfo .ibody{display:none;padding:4px 0 14px;color:#3a3c41;font-size:.92rem}
  .rowinfo .ibody > p{max-width:72ch}
  .rowtoggle:checked ~ .ibody,
  #expand-all:checked ~ .cmp-wrap .rowinfo .ibody{display:block}
  /* Master expand-all + per-row toggle would conflict under a plain OR (the master wins, so a
     per-row Hide is inert). So while expand-all is on, a row is open by DEFAULT and its OWN
     toggle INVERTS to a Hide -- checking it collapses THAT row while the rest stay open. No row
     is checked by default, so the two states stay consistent. */
  #expand-all:checked ~ .cmp-wrap .rowtoggle:checked ~ .ibody{display:none}
  #expand-all:checked ~ .cmp-wrap .rowtoggle:checked + .rowsum{color:var(--muted)}
  #expand-all:checked ~ .cmp-wrap .rowtoggle:checked + .rowsum::before{transform:none;color:var(--muted)}
  #expand-all:checked ~ .cmp-wrap .rowtoggle:checked + .rowsum .ihint{border-color:var(--line);color:var(--muted)}
  #expand-all:checked ~ .cmp-wrap .rowtoggle:checked + .rowsum .ihint .ihint-hide{display:none}
  #expand-all:checked ~ .cmp-wrap .rowtoggle:checked + .rowsum .ihint .ihint-show{display:inline}
  .rowinfo .ibody p{margin:0 0 9px}
  .rowinfo .ibody p:last-child{margin-bottom:0}
  .rowinfo .ibody .cmp-wrap{margin:10px 0}

  /* master expand-all / collapse-all control (CSS checkbox, no JS). Sits in .panel just
     ahead of .cmp-wrap so `~ .cmp-wrap` reaches every row body. Label text swaps on :checked. */
  .expand-all-cb{position:absolute;width:1px;height:1px;margin:-1px;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}
  .expand-all{display:inline-flex;align-items:center;gap:7px;cursor:pointer;user-select:text;margin:14px 0 2px;
    font-family:var(--mono);font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);
    border:1px solid var(--line);border-radius:999px;background:var(--card);padding:5px 13px;
    transition:color .12s,background .12s,border-color .12s}
  .expand-all::before{content:"\25B8";font-size:.8rem;transition:transform .12s}
  .expand-all:hover{color:var(--ink);border-color:var(--muted)}
  .expand-all-cb:checked + .expand-all{color:#fff;background:var(--ink);border-color:var(--ink)}
  .expand-all-cb:checked + .expand-all::before{transform:rotate(90deg)}
  .expand-all-cb:focus-visible + .expand-all{outline:2px solid var(--accent);outline-offset:2px}
  .expand-all .collapse-txt{display:none}
  .expand-all-cb:checked + .expand-all .expand-txt{display:none}
  .expand-all-cb:checked + .expand-all .collapse-txt{display:inline}
  @media(max-width:640px){ .matrix{font-size:.88rem} .matrix th,.matrix td{padding:10px 7px} .matrix td.verdict{white-space:normal} }

  /* deep-link ring extends to a matrix row and an opened info-body */
  tr.mrow:target > *{box-shadow:inset 0 2px 0 #e5484d, inset 0 -2px 0 #e5484d}
  .rowinfo:target{outline:2px solid #e5484d;outline-offset:3px;border-radius:6px}

  @media(prefers-reduced-motion:reduce){
    html{scroll-behavior:auto}
    .inst .ibadge,.h-anchor::after{transition:none}
  }
