/* ============================================================================
   BREACH PROTOCOL — public site stylesheet
   breachprotocol.info

   Self-contained on purpose: no CDN, no webfont, no external request of any
   kind. Every face below is a system stack. The site must render identically
   on a machine with no network beyond the document itself.

   Owned by: the public-site pass. Nothing here is imported by the game
   bundle (src/) and nothing in src/ imports this.
   ========================================================================= */

:root{
  /* Ground */
  --bg:        #07090c;
  --bg-2:      #0b0f14;
  --panel:     #10151c;
  --panel-2:   #161d26;
  --line:      #1e2733;
  --line-2:    #2a3543;

  /* Type */
  --text:      #e9eff6;
  --dim:       #93a3b5;
  --faint:     #64748b;

  /* Accents. Gold is the house colour — it is the boot screen's #d8a44a.
     Outbreak gets its own sick green so the two modes read apart at a glance,
     exactly as they do in the in-game menus. */
  --gold:      #d8a44a;
  --gold-dim:  #8a6a2e;
  --outbreak:  #7fae4a;
  --blue:      #5b8fd0;
  --red:       #c9524a;
  --green:     #4ea86b;

  --max:       1320px;
  --radius:    10px;
  --shadow:    0 18px 40px rgba(0,0,0,.45);
}

*{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
/* The masthead is sticky and 62 px tall, so a link to #download or #smartscreen
   scrolls its target to y=0 — underneath the bar — and the reader arrives at a
   section whose heading is hidden by the site's own navigation. Every anchorable
   element keeps the bar's height plus air above it. */
[id]{scroll-margin-top:78px}
body{
  margin:0;background:var(--bg);color:var(--text);
  font:16px/1.65 "Segoe UI",system-ui,-apple-system,"Helvetica Neue",Arial,sans-serif;
  overflow-x:hidden;
}
img{max-width:100%;height:auto;display:block}
a{color:var(--gold);text-decoration:none}
a:hover{text-decoration:underline}
hr{border:0;border-top:1px solid var(--line);margin:40px 0}

/* Condensed display face for headings — system stack, no download. */
.display,h1,h2,h3,.nav a,.btn,.tag,.kicker{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
}
h1,h2,h3{margin:0;font-weight:600;letter-spacing:.06em;text-transform:uppercase;line-height:1.15}
h1{font-size:clamp(30px,5.2vw,58px);letter-spacing:.1em}
h2{font-size:clamp(20px,2.6vw,30px)}
h3{font-size:17px;letter-spacing:.09em}

.wrap{max-width:var(--max);margin:0 auto;padding:0 22px}
.narrow{max-width:860px}

.kicker{
  color:var(--gold);font-size:12px;letter-spacing:.28em;text-transform:uppercase;
  margin:0 0 10px;font-weight:600;
}
.lede{color:var(--dim);font-size:17px;max-width:70ch}
.muted{color:var(--faint)}
.small{font-size:13.5px}

/* ── Skip link ───────────────────────────────────────────────────────────── */
.skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--gold);
      color:#12100a;padding:10px 16px;border-radius:0 0 6px 0;font-weight:700}
.skip:focus{left:0}

/* ── Masthead ────────────────────────────────────────────────────────────── */
.mast{
  position:sticky;top:0;z-index:60;
  background:rgba(7,9,12,.92);border-bottom:1px solid var(--line);
  backdrop-filter:blur(10px);
}
.mast .bar{display:flex;align-items:center;gap:26px;height:62px}
.brand{display:flex;align-items:center;gap:11px;flex:0 0 auto}
.brand svg{display:block}
.brand b{
  font-family:"Barlow Condensed","Oswald",system-ui,sans-serif;
  font-size:19px;letter-spacing:.24em;text-transform:uppercase;font-weight:600;color:var(--text);
}
.brand:hover{text-decoration:none}

.nav{display:flex;gap:4px;align-items:center;margin-left:auto;flex-wrap:wrap}
.nav a{
  color:var(--dim);font-size:14.5px;letter-spacing:.14em;text-transform:uppercase;
  padding:8px 12px;border-radius:6px;font-weight:600;
}
.nav a:hover{color:var(--text);background:var(--panel);text-decoration:none}
.nav a.on{color:var(--gold);background:rgba(216,164,74,.1)}
.navtoggle{display:none;margin-left:auto;background:none;border:1px solid var(--line-2);
           color:var(--text);border-radius:6px;padding:7px 12px;font-size:14px;cursor:pointer}

@media (max-width:900px){
  .navtoggle{display:block}
  .nav{
    display:none;position:absolute;left:0;right:0;top:62px;flex-direction:column;
    align-items:stretch;gap:0;background:var(--bg-2);border-bottom:1px solid var(--line);
    padding:8px 14px 16px;
  }
  .nav.open{display:flex}
  .nav a{padding:12px 10px;border-radius:0;border-bottom:1px solid var(--line)}
}

/* ⚠ MEASURED: at 390 px the wordmark plus the 26 px bar gap plus the Menu
   button came to 394 px and pushed the document 4 px wide on EVERY page.
   The masthead is the only row on the site that cannot wrap, so it is the
   only row that can do this. Tighten the three contributors together. */
@media (max-width:520px){
  .mast .bar{gap:12px}
  .brand b{font-size:16px;letter-spacing:.15em}
  .brand svg{width:22px;height:22px}
  .navtoggle{padding:7px 10px;font-size:13px}
}

/* ── Hero ────────────────────────────────────────────────────────────────── */
.hero{position:relative;border-bottom:1px solid var(--line);overflow:hidden}
.hero .shot{position:absolute;inset:0;background-size:cover;background-position:center;
            filter:saturate(.85) contrast(1.05)}
/* Two layers, not one. A flat vertical scrim dims the whole capture to keep the
   headline legible and takes the artwork down with it. The horizontal pass does
   the legibility work under the text column only, so the right two-thirds of the
   frame stays as bright as it was captured. */
.hero .veil{position:absolute;inset:0;
  background:
    linear-gradient(90deg,rgba(5,7,10,.90) 0%,rgba(5,7,10,.72) 34%,rgba(5,7,10,.12) 72%,rgba(5,7,10,0) 100%),
    linear-gradient(180deg,rgba(7,9,12,.30) 0%,rgba(7,9,12,.10) 40%,rgba(7,9,12,.86) 88%,var(--bg) 100%);}
@media (max-width:760px){
  /* Narrow: the text sits over the middle of the frame, so the horizontal pass
     no longer covers it and the vertical one has to carry the contrast. */
  .hero .veil{background:linear-gradient(180deg,rgba(7,9,12,.72) 0%,rgba(7,9,12,.80) 55%,var(--bg) 100%);}
}
/* padding-block, NOT the four-value shorthand: .inner is also a .wrap, and a shorthand
   here silently zeroes .wrap's 22px gutter, putting the headline against pixel 0. */
.hero .inner{position:relative;padding-block:clamp(56px,10vw,132px) clamp(40px,7vw,86px)}
.hero h1{text-shadow:0 4px 26px rgba(0,0,0,.6)}
.hero .lede{margin-top:18px;font-size:clamp(15px,1.6vw,19px)}
.hero .cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:30px}

/* Page header (non-landing pages) */
.pagehead{border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,var(--bg-2),var(--bg));padding:52px 0 40px}
.pagehead .lede{margin-top:14px}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn{
  display:inline-block;padding:12px 26px;border-radius:6px;font-size:15px;
  letter-spacing:.16em;text-transform:uppercase;font-weight:700;border:1px solid transparent;
  cursor:pointer;
}
.btn:hover{text-decoration:none}
.btn.primary{background:var(--gold);color:#141007;border-color:var(--gold)}
.btn.primary:hover{background:#e8b75f}
.btn.ghost{background:transparent;color:var(--text);border-color:var(--line-2)}
.btn.ghost:hover{border-color:var(--gold);color:var(--gold)}
.btn.outbreak{background:var(--outbreak);color:#0e1407;border-color:var(--outbreak)}
.btn.outbreak:hover{background:#93c25c}

/* ── Sections & grids ────────────────────────────────────────────────────── */
section{padding:56px 0}
section.tight{padding:34px 0}
.sechead{display:flex;align-items:baseline;justify-content:space-between;gap:20px;
         flex-wrap:wrap;margin-bottom:8px}
.sechead h2{color:var(--text)}
.sechead a{font-size:13px;letter-spacing:.16em;text-transform:uppercase;font-weight:600}
.secnote{color:var(--faint);font-size:14px;margin:0 0 26px;max-width:78ch}

/* ⚠ THE `min(…,100%)` IS LOAD-BEARING AND IT IS NOT DECORATION. A bare
   minmax(330px,1fr) track is 330px wide even when the grid container is 276px —
   at a 320px viewport, minus the .wrap gutter — so every .g2 on the site pushed
   the document to 352px and body{overflow-x:hidden} swallowed the evidence.
   site/tools/check_overflow.mjs measured that as a pre-existing baseline, floored
   its document-width assertion at 390px to avoid arriving red, and wrote down
   that the repair belongs to whoever next changes these minimums. The download
   cards are a .g2 and a phone is where a player reads them, so: min() clamps the
   track to the container when the container is the smaller of the two. Above
   330px nothing changes — min(330px,100%) IS 330px there. */
.grid{display:grid;gap:18px}
.g2{grid-template-columns:repeat(auto-fit,minmax(min(330px,100%),1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(min(290px,100%),1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(min(230px,100%),1fr))}

/* ── Cards ───────────────────────────────────────────────────────────────── */
.card{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;display:flex;flex-direction:column;
}
.card .body{padding:20px 22px 22px}
.card h3{margin-bottom:8px}
.card p{margin:0;color:var(--dim);font-size:14.5px}
.card p + p{margin-top:10px}
a.card{color:inherit}
a.card:hover{border-color:var(--gold-dim);text-decoration:none}
a.card:hover h3{color:var(--gold)}
.card .thumb{aspect-ratio:16/9;background:#0d1218 center/cover no-repeat;border-bottom:1px solid var(--line)}
/* The same thumbnail as a real <img>. A background-image cannot carry alt text and
   cannot be `loading="lazy"`; the maps page shows sixteen of these, so it needs both. */
.card img.thumb{display:block;width:100%;height:auto;object-fit:cover}
.card .meta{color:var(--faint);font-size:12px;letter-spacing:.14em;text-transform:uppercase;
            margin:0 0 9px;font-weight:600}

/* ── Tags / pills ────────────────────────────────────────────────────────── */
.tag{
  display:inline-block;padding:3px 11px;border-radius:99px;font-size:11.5px;
  letter-spacing:.14em;text-transform:uppercase;font-weight:700;white-space:nowrap;
  border:1px solid var(--line-2);color:var(--dim);
}
.tag.live{color:#8ddba6;border-color:rgba(78,168,107,.45);background:rgba(78,168,107,.12)}
.tag.vault{color:var(--faint);border-color:rgba(100,116,139,.4);background:rgba(100,116,139,.1)}
.tag.gold{color:var(--gold);border-color:rgba(216,164,74,.45);background:rgba(216,164,74,.1)}
.tag.ob{color:#a9d47c;border-color:rgba(127,174,74,.45);background:rgba(127,174,74,.12)}
.tag.att{color:#8ab4e8;border-color:rgba(91,143,208,.45);background:rgba(91,143,208,.12)}
.tag.def{color:#e0975f;border-color:rgba(201,120,60,.45);background:rgba(201,120,60,.12)}
.tags{display:flex;gap:7px;flex-wrap:wrap;margin-top:12px}

/* ── Tables ──────────────────────────────────────────────────────────────── */
.tablewrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius);
           background:var(--panel)}
table{width:100%;border-collapse:collapse;font-size:14.5px;min-width:560px}
th{
  text-align:left;color:var(--faint);font-size:11.5px;letter-spacing:.16em;
  text-transform:uppercase;font-weight:700;padding:12px 16px;
  border-bottom:1px solid var(--line);background:var(--panel-2);white-space:nowrap;
}
td{padding:12px 16px;border-bottom:1px solid #18202b;color:var(--dim);vertical-align:top}
tr:last-child td{border-bottom:0}
td:first-child{color:var(--text);font-weight:600}
tbody tr:hover td{background:#141b24}

/* ── Command blocks ──────────────────────────────────────────────────────────
   A command is typed exactly or it does not work, so a line in here is never
   wrapped and never hyphenated — which means a long one is simply wider than the
   column holding it.

   ⚠ MEASURED, and it was live: at a 390 px viewport the support article's
   `Get-FileHash .\BreachProtocol.exe -Algorithm SHA256` came out 476 px wide and
   pushed the WHOLE DOCUMENT sideways. Nothing in that column clips or scrolls, so
   there was nothing to absorb it — every page on a phone got a horizontal
   scrollbar because of one line on one article. overflow-x here keeps the scroll
   inside the block, which is where a reader expects to find it. */
pre{
  margin:0;padding:10px 12px;overflow-x:auto;
  background:#0a0e13;border:1px solid var(--line);border-radius:6px;
}
/* pre-WRAP, not pre. `pre` scrolls a long line, and a horizontal scroller inside
   a card has no visible scrollbar on a phone: at 320 px `chmod +x
   BreachProtocol.x86_64` rendered as "chmod +x BreachProtocol." with nothing to
   say the rest existed, which is a command a reader would copy wrong. pre-wrap
   breaks at the space instead — every character stays on screen, the newline
   between two commands is still preserved, and selecting the block still copies
   exactly what was written. overflow-x above stays as the backstop for a single
   token too long to break. */
pre code{
  display:block;white-space:pre-wrap;color:var(--text);
  /* ⚠ AND IT MUST NEVER BREAK INSIDE A TOKEN. With break-anywhere inherited from
     a neighbouring rule, 320 px produced
         ./BreachProtocol.x86_6
         4
     in a block that already uses one real line per command — so the wrap is
     indistinguishable from a third command. Wrapping at spaces is unambiguous;
     wrapping mid-token is a typo waiting to be copied. */
  overflow-wrap:normal;word-break:normal;
  font-family:ui-monospace,"Cascadia Mono",Consolas,"DejaVu Sans Mono",monospace;
  font-size:12.5px;line-height:1.75;
}
/* On a narrow phone the longest token (./BreachProtocol.x86_64, 23 characters)
   is wider than the box at 12.5px, and since it may not be broken it would have
   to scroll out of sight. One step down in size fits it whole. */
@media (max-width:420px){
  pre code{font-size:11px}
}

/* ── Notes / callouts ────────────────────────────────────────────────────── */
.note{
  border:1px solid var(--line);border-left:3px solid var(--gold);
  background:var(--panel);border-radius:0 var(--radius) var(--radius) 0;
  padding:18px 22px;color:var(--dim);font-size:14.5px;
}
.note b,.note strong{color:var(--text)}
.note.warn{border-left-color:var(--red)}
.note.ok{border-left-color:var(--green)}
.note.ob{border-left-color:var(--outbreak)}
.note h3{margin-bottom:8px;color:var(--text)}
.note + .note{margin-top:16px}
.note ul{margin:10px 0 0;padding-left:20px}
.note li{margin-bottom:7px}

/* ── Stat strip ──────────────────────────────────────────────────────────── */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
.stat{background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:16px 18px}
.stat b{display:block;font-size:27px;font-weight:700;font-variant-numeric:tabular-nums;
        letter-spacing:.02em;line-height:1.15}
.stat span{color:var(--faint);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
           font-weight:600}

/* ── Timeline (roadmap) ──────────────────────────────────────────────────── */
.timeline{position:relative;margin-top:10px}
.timeline::before{
  content:"";position:absolute;left:11px;top:6px;bottom:6px;width:2px;background:var(--line);
}
.tl{position:relative;padding:0 0 30px 44px}
.tl::before{
  content:"";position:absolute;left:4px;top:7px;width:16px;height:16px;border-radius:50%;
  background:var(--panel);border:2px solid var(--line-2);
}
.tl.now::before{border-color:var(--green);background:rgba(78,168,107,.25)}
.tl.next::before{border-color:var(--gold);background:rgba(216,164,74,.25)}
.tl h3{margin-bottom:4px}
.tl .when{color:var(--gold);font-size:12px;letter-spacing:.2em;text-transform:uppercase;
          font-weight:700;margin-bottom:6px}
.tl p{margin:0;color:var(--dim);font-size:14.5px;max-width:76ch}
.tl ul{margin:10px 0 0;padding-left:20px;color:var(--dim);font-size:14.5px}
.tl li{margin-bottom:6px}

/* ── Media strip ─────────────────────────────────────────────────────────── */
.shots{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));gap:14px}
figure{margin:0;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
       overflow:hidden}
figure img{width:100%;display:block}
figcaption{padding:12px 16px;color:var(--faint);font-size:13px}

/* A grid for DRAWINGS rather than photographs — the floor plans and the gallery's key
   plans. It is .shots with a wider minimum, and the width is the whole point: at the
   300px minimum a 1300px-wide floor plan lands three-up on a desktop and its room
   names render at about four pixels, which is a texture rather than a plan. 460px puts
   it two-up on a laptop and still collapses to a single column on a phone.
   Photographs read fine three-up; a drawing does not. */
.plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(460px,100%),1fr));gap:14px}
/* A drawing carries its own dark ground, and the panel showing through around it makes
   the sheet look like it failed to load. */
.plans figure img{background:var(--bg-2)}

/* ── Media surface: learn cards, responsive stills, clips ─────────────────────
   The media page is the heaviest page on the site by an order of magnitude, so
   every rule here is about weight or about layout stability rather than about
   decoration.

   ⚠⚠ THE ASPECT-RATIO BOX IS NOT COSMETIC, AND ITS ABSENCE WAS A LIVE DEFECT.
   `figure img` below is width:100%;height:auto, so until the file arrives the
   browser knows the width and nothing about the height — every image on this page
   occupied ZERO pixels and the whole document collapsed and then jumped as
   seventeen frames landed one by one. The repair is `width`/`height` ATTRIBUTES on
   every <img> (the browser derives an aspect ratio from the pair and reserves the
   box), and this rule is the belt to that pair's braces: it also holds for a
   <picture> whose sources have not been chosen yet.
   ⛔ Do not "simplify" this by deleting the width/height attributes in the markup
   because a CSS rule appears to cover it. The attributes are what a browser with
   images disabled, or a browser mid-download, actually uses. */
.mediafig{margin:0;background:var(--panel);border:1px solid var(--line);
          border-radius:var(--radius);overflow:hidden}
.mediafig > img,
.mediafig > picture > img,
.mediafig > video{display:block;width:100%;height:auto;background:#0a0e13}
.mediafig figcaption{padding:12px 16px;color:var(--faint);font-size:13px}
.mediafig figcaption b{color:var(--dim)}

/* A clip and a still sit in the same grid, so the clip's controls must not make
   its box a different height from its neighbour's. The video is the same
   width:100%;height:auto box; the controls draw inside it. */
.mediafig video{max-width:100%}

/* The technical line under a clip — duration, resolution, "no sound". It answers
   "is this worth 8 MB of my data" BEFORE the reader presses play, which is the
   only moment the answer is useful. */
.medmeta{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
  display:flex;gap:14px;flex-wrap:wrap;padding:0 16px 12px;margin:0;
  color:var(--faint);font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;
  font-weight:600;
}
.medmeta span{white-space:nowrap}

/* ── Learn: one subject per row, picture beside the explanation ───────────────
   Not a grid of equal cards. A tutorial is a picture and the paragraph that
   explains it, and the two belong side by side at reading width — three of them
   abreast would give each 400 px and turn the explanation into a caption.
   ⚠ MEASURED at 320 px: `minmax(0,…)` on both tracks is load-bearing for the same
   reason the .g2 comment 300 lines up gives — a bare 1fr track has an automatic
   minimum of its CONTENT's width, so a wide frame pushed the whole document
   sideways before this was written. */
.learn{display:grid;gap:22px}
.learnrow{
  display:grid;gap:20px;align-items:start;
  grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
}
.learnrow:nth-child(even) .learnbody{order:-1}
/* ⚠ A VERY WIDE FRAME MUST NOT SIT IN A HALF-WIDTH COLUMN, and this was visible in
   a screenshot and in nothing else. The destruction strip is 2560x480 — 5.33:1. In
   a 1.15fr column it renders about 120 px tall beside a 340 px column of text, and
   `align-items:start` leaves the difference as a hole under the picture that reads
   as a missing image rather than as a short one. Full width is also simply where a
   strip of four frames belongs: at 1320 px it is legible, and at half that it is a
   smear. Applied per row, because the other two rows are 16:10 and pair correctly. */
.learnrow.wide{grid-template-columns:minmax(0,1fr)}
.learnrow.wide .learnbody{max-width:none}
.learnrow.wide .learnbody p{max-width:78ch}
.learnbody h3{margin-bottom:10px}
.learnbody p{margin:0 0 11px;color:var(--dim);font-size:14.5px;max-width:62ch}
.learnbody p:last-child{margin-bottom:0}
.learnbody ol,.learnbody ul{margin:0 0 11px;padding-left:20px;color:var(--dim);font-size:14.5px}
.learnbody li{margin-bottom:6px}
.learnstep{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
  color:var(--gold);font-size:11.5px;letter-spacing:.24em;text-transform:uppercase;
  font-weight:600;margin:0 0 8px;
}
@media (max-width:820px){
  /* Stacked, the alternating order would put a picture below its own text on one
     row and above it on the next, which reads as a mistake. Picture first, always. */
  .learnrow{grid-template-columns:minmax(0,1fr)}
  .learnrow:nth-child(even) .learnbody{order:0}
}

/* ── Search (support) ────────────────────────────────────────────────────── */
.searchbox{position:relative;margin:26px 0 8px}
.searchbox input{
  width:100%;padding:16px 18px 16px 46px;font-size:16px;color:var(--text);
  background:var(--panel);border:1px solid var(--line-2);border-radius:8px;
  font-family:inherit;
}
.searchbox input:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(216,164,74,.14)}
.searchbox svg{position:absolute;left:16px;top:50%;transform:translateY(-50%);opacity:.55}
.searchmeta{color:var(--faint);font-size:13px;margin:10px 0 22px;min-height:20px}
.kb article{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:22px 24px;margin-bottom:16px;
}
.kb article[hidden]{display:none}
.kb article h3{margin-bottom:6px;color:var(--text)}
.kb article .meta{color:var(--faint);font-size:11.5px;letter-spacing:.16em;
                  text-transform:uppercase;font-weight:700;margin-bottom:10px}
.kb article p{margin:0 0 12px;color:var(--dim);font-size:15px}
.kb article p:last-child{margin-bottom:0}
.kb article ol,.kb article ul{color:var(--dim);font-size:15px;margin:0 0 12px;padding-left:22px}
.kb article li{margin-bottom:7px}
.kb article code{background:#0a0e13;border:1px solid var(--line);border-radius:4px;
                 padding:1px 7px;font-size:13.5px;color:var(--gold)}
/* The rule above is for a code span inside a sentence. `pre` already draws the
   box, and at (0,1,2) that rule beats a bare `pre code` — so a command block
   would otherwise get a second border and an inline pill's padding inside its
   own frame. Scoped here it goes back to being plain text in a block. */
.kb article pre{margin:0 0 12px}
.kb article pre code{background:none;border:0;padding:0;color:var(--text)}
.noresults{color:var(--dim);background:var(--panel);border:1px dashed var(--line-2);
           border-radius:var(--radius);padding:26px;text-align:center}

/* ── Q&A ─────────────────────────────────────────────────────────────────── */
details.qa{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:0;margin-bottom:10px;
}
details.qa summary{
  cursor:pointer;padding:16px 20px;font-weight:600;color:var(--text);list-style:none;
  display:flex;justify-content:space-between;gap:14px;align-items:center;font-size:15.5px;
}
details.qa summary::-webkit-details-marker{display:none}
details.qa summary::after{content:"+";color:var(--gold);font-size:22px;line-height:1;flex:0 0 auto}
details.qa[open] summary::after{content:"–"}
details.qa .ans{padding:0 20px 18px;color:var(--dim);font-size:15px}
details.qa .ans p{margin:0 0 11px}
details.qa .ans p:last-child{margin-bottom:0}

/* ── Legal prose ─────────────────────────────────────────────────────────── */
.legal{max-width:80ch}
.legal h2{margin:38px 0 12px;font-size:19px;color:var(--gold)}
.legal h3{margin:24px 0 8px;font-size:15.5px}
.legal p,.legal li{color:var(--dim);font-size:15px}
.legal ul,.legal ol{padding-left:22px}
.legal li{margin-bottom:8px}

/* ── Footer ──────────────────────────────────────────────────────────────── */
footer{border-top:1px solid var(--line);background:var(--bg-2);padding:48px 0 40px;margin-top:20px}
.fgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:30px}
.fcol h4{margin:0 0 12px;font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
         color:var(--faint);font-weight:700}
.fcol a{display:block;color:var(--dim);font-size:14px;padding:4px 0}
.fcol a:hover{color:var(--gold)}
.fbase{margin-top:36px;padding-top:22px;border-top:1px solid var(--line);
       color:var(--faint);font-size:13px;display:flex;gap:18px;flex-wrap:wrap;
       justify-content:space-between}
.attrib{max-width:74ch;color:var(--faint);font-size:13px;line-height:1.7}

/* ── Agent ID panel ──────────────────────────────────────────────────────────
   The site's own drawing of a handle and the key beside it. It is DRAWN and not
   photographed, and that is the whole point of it rather than a shortcut:

     This site only publishes a capture whose caption is true of the frame, and
     no verified Godot capture has a Name#TAG legible in it — the Barracks
     identity header carries the name on its own and the clan-tag tile beside it
     is an empty placeholder. Under a headline about names, a frame with no tag
     in it is the exact mismatch that took a previous set of images off this
     site. A drawing cannot falsify a caption, because it never claims to be the
     game: it carries no HUD, no build stamp and no menu chrome, and it is built
     out of this stylesheet's own type and tokens so it reads as page furniture.

   ⚠ If a capture ever shows a handle legibly, that capture replaces this panel
   in the news lead. Nothing else depends on it being there — every block below
   degrades to an ordinary card with no image.

   ⛔ The example handle is a shape, not a real player, and it is a shape this
   build can actually mint — the tag alphabet leaves out the characters people
   misread for one another, so not every string is a possible tag. Check
   `Identity.TAG_ALPHABET` in the game repo before writing a new example.
   ⛔ Do NOT write the alphabet, the length or the size of the space into this
   file or into any page. That analysis was taken off services/stats.html
   deliberately, and a comment ships to the browser exactly like the markup
   does. */
.idpanel{
  position:relative;overflow:hidden;
  display:flex;align-items:center;gap:clamp(18px,3.4vw,44px);flex-wrap:wrap;
  padding:clamp(24px,3.6vw,44px) clamp(20px,3.4vw,42px);
  border-bottom:1px solid var(--line);
  background:
    radial-gradient(115% 150% at 8% 0%,rgba(216,164,74,.11),rgba(216,164,74,0) 62%),
    linear-gradient(180deg,#131a23 0%,#0a0f15 100%);
}
/* A hairline rule grid, drawn in gradients so the panel stays a document and
   never becomes a request. It sits under the content and above the ground. */
.idpanel::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    repeating-linear-gradient(90deg,rgba(255,255,255,.028) 0 1px,transparent 1px 46px),
    repeating-linear-gradient(0deg,rgba(255,255,255,.028) 0 1px,transparent 1px 46px);
  mask-image:linear-gradient(105deg,#000 0%,rgba(0,0,0,.25) 62%,transparent 100%);
  -webkit-mask-image:linear-gradient(105deg,#000 0%,rgba(0,0,0,.25) 62%,transparent 100%);
}
/* ⚠ MEASURED at 320 px. Every direct child is a FLEX ITEM, and in the .mini
   column below `align-items:center` replaces the default stretch — so a child
   is shrink-to-fit and a `max-width` in `ch` is free to resolve WIDER than the
   panel. `.idcap` did exactly that and was clipped by the overflow:hidden above,
   which hides the symptom and keeps the caption cut off. Cap every child at the
   box as well as at its own measure. */
.idpanel > *{position:relative;max-width:100%}

/* ⚠⚠ EVERY RULE BELOW IS SCOPED `.idpanel …`, AND IT HAS TO BE. This panel sits
   INSIDE a .card, and `.card p` (0,1,1) beats a bare `.handle` (0,1,0) — so the
   unscoped version of these rules lost, silently, and the handle that is the
   whole subject of the panel rendered at .card p's 14.5px in a box sized for
   62px. Nothing failed: the gate was green, no request 404'd, no box
   overflowed. It was only visible in a screenshot. Scoping every one of them to
   .idpanel takes them to 0,2,0 and puts them back in front. */
.idpanel .idhalf{flex:1 1 300px;min-width:0}
.idpanel .idlabel{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
  color:var(--gold);font-size:11.5px;letter-spacing:.28em;text-transform:uppercase;
  font-weight:600;margin:0 0 12px;line-height:1.2;
}
.idpanel .handle{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
  font-size:clamp(34px,5.4vw,60px);line-height:1;letter-spacing:.04em;
  text-transform:uppercase;color:var(--text);margin:0;font-weight:600;
  /* A tag is dropped whole or not at all, never broken mid-string, so the
     handle may wrap at the separator but a name is never cut in half. */
  overflow-wrap:break-word;
}
.idpanel .handle .sep{color:var(--gold-dim)}
.idpanel .handle .tg{color:var(--gold)}
.idpanel .idkeyline{display:flex;align-items:center;gap:15px;margin:0;flex-wrap:wrap}
.idpanel .idkey{flex:0 0 auto;color:var(--gold);opacity:.95}
.idpanel .idkeytext{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
  font-size:clamp(24px,3.1vw,38px);line-height:1.05;letter-spacing:.04em;
  text-transform:uppercase;color:var(--dim);font-weight:600;
}
.idpanel .idnote{margin:16px 0 0;color:var(--faint);font-size:13.5px;line-height:1.6;max-width:34ch}
.idpanel .idrule{
  flex:0 0 1px;align-self:stretch;min-height:74px;
  background:linear-gradient(180deg,transparent,var(--line-2) 22%,var(--line-2) 78%,transparent);
}
@media (max-width:720px){
  /* Stacked, the vertical rule between the two halves is a 1px column with
     nothing either side of it. It becomes the divider it actually is. */
  .idpanel .idrule{flex:1 1 100%;min-height:0;height:1px;
          background:linear-gradient(90deg,transparent,var(--line-2) 20%,var(--line-2) 80%,transparent)}
}

/* Card-thumbnail variant: fills a .thumb-sized box in a news grid. 16/9 to match
   .thumb, so a row of cards lines up whether its picture is a capture or this.

   ⚠⚠ THE FAILURE MODE THIS GUARDS. .idpanel above sets flex-wrap:wrap, which is
   right for the two-column lead panel and dangerous here: this variant is
   `flex-direction:column` inside a box whose height is FIXED by aspect-ratio, so
   content one pixel too tall does not overflow downward — it wraps into a SECOND
   COLUMN laid out to the right, off the end of the panel. At a 320 px viewport
   the caption did exactly that and landed at x=217..397 inside a panel spanning
   23..311: entirely outside its own box, and invisible because of the
   overflow:hidden above. Vertical overflow would have been visible; sideways
   flight was silent.

   ⚠⚠ CORRECTION, AND IT IS THE OPPOSITE OF WHAT THIS COMMENT FIRST CLAIMED.
   `flex-wrap:nowrap` was written here as "the fix" and it is NOT. Red-proved by
   reverting it in a staged copy and re-rendering: reverting `nowrap` alone does
   not reproduce the defect, reverting `max-width:min(30ch,100%)` alone does not
   reproduce it, and reverting BOTH does not reproduce it. What actually removed
   the trigger was the key glyph: it was a 38x38 square and is now 56x29, so the
   column lost ~9px of height and now fits.

   So the honest statement is: THE PANEL FITS ITS 16/9 BOX WITH ABOUT NINE PIXELS
   TO SPARE, and `nowrap` is defence in depth, not the repair. It converts a
   future overflow from "a child flies out sideways and disappears" into "the
   column overruns the bottom edge and is clipped there" — still a defect, but
   one somebody can see. A longer caption, a taller glyph or a larger type step
   will spend that headroom. ⚠ site/tools/check_overflow.mjs measures HORIZONTAL
   clipping only, so with `nowrap` in place it will NOT catch the downward
   version. An eye on a screenshot is still the check for that. */
.idpanel.mini{
  aspect-ratio:16/9;padding:16px 18px;
  flex-direction:column;flex-wrap:nowrap;align-items:center;justify-content:center;
  gap:12px;text-align:center;
}
.idpanel.mini .handle{font-size:clamp(26px,4.1vw,40px)}
.idpanel.mini .idkey{width:56px;height:29px}
.idpanel.mini .idkeyline{flex-direction:column;gap:11px}
.idpanel.mini .idkeytext{font-size:clamp(16px,2.2vw,22px);letter-spacing:.12em}
.idpanel.mini .idcap{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
  margin:0;color:var(--faint);font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;line-height:1.65;max-width:min(30ch,100%);font-weight:600;
}

/* ── Download cards ──────────────────────────────────────────────────────────
   The two platform choices on services/playtest.html. One card per operating
   system, and the card has to answer four questions before the player clicks:
   which OS is this, what am I getting, is it the real file, and why might my
   machine warn me about it.

   ⛔ THE GLYPHS ARE DRAWN HERE AND IN THE PAGE, AND THEY ARE NOT ANYBODY'S MARK.
   Microsoft's logo and the Linux penguin are both other people's property, and
   this project ships original assets only. What the cards carry instead is a
   FOUR-PANE SASH WINDOW (a frame, with an off-centre mullion) and a TERMINAL
   PROMPT (a chrome bar, a chevron and a cursor). Neither is a trademark: one is
   a window, the other is a command line. They are line art in the same weight as
   the masthead hexagon and the key glyph, so the pair reads as this site's
   furniture rather than as borrowed badges. The heading and the button name the
   platform in words — the glyph is orientation, never the identification.

   ⚠ EVERY RULE BELOW IS SCOPED UNDER `.dlcard`, for the reason written at the
   .idpanel block: these boxes sit INSIDE a .card, and `.card p` (0,1,1) beats a
   bare class selector (0,1,0). An unscoped rule here would lose silently. */
.dlcard .body{display:flex;flex-direction:column;gap:14px;height:100%}
/* .card p + p adds a top margin that would stack on top of the flex gap.
   ⚠ THE CHILD COMBINATOR IS THE WHOLE RULE. Written as `.dlcard .body p + p` it
   also matched the paragraphs INSIDE .dlnote, which are not flex items and had
   nothing but that margin holding them apart — the SmartScreen explainer and the
   Linux instructions both rendered as one unbroken slab of text. Nothing
   overflowed and no gate could see it; it was visible in a screenshot and
   nowhere else. Only the flex items need the margin removed. */
.dlcard .body > p + p{margin-top:0}

.dlcard .dlhead{display:flex;align-items:center;gap:15px}
.dlcard .dlglyph{flex:0 0 auto;color:var(--gold)}
.dlcard .dlhead h3{margin-bottom:0;font-size:22px}
.dlcard .dlfor{margin:3px 0 0;color:var(--faint);font-size:13px}

.dlcard .dlbtn{width:100%;text-align:center;padding-inline:14px}
.dlcard .dlfacts{color:var(--dim);font-size:13.5px}
.dlcard .dlfacts b{color:var(--text)}
/* A file name is one long unbreakable token. At 320 px it is wider than the
   card, and a card has no scroller, so it has to be allowed to break. */
.dlcard .dlfacts code{
  font-family:ui-monospace,"Cascadia Mono",Consolas,"DejaVu Sans Mono",monospace;
  font-size:12.5px;color:var(--text);overflow-wrap:anywhere;
}

.dlcard .dllabel{
  font-family:"Barlow Condensed","Oswald","Segoe UI Semibold",
              "Helvetica Neue Condensed",Impact,system-ui,sans-serif;
  display:block;color:var(--faint);font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;font-weight:700;margin-bottom:6px;
}
/* 64 hex characters do not fit on one line in a 330 px card at any readable
   size, so they wrap rather than scroll: a hash is compared character by
   character and a hidden tail is the one part a reader would not notice was
   missing. break-all, not break-word — there are no word boundaries in a hash. */
.dlcard .dlhash code{
  display:block;background:#0a0e13;border:1px solid var(--line);border-radius:6px;
  padding:9px 11px;color:var(--dim);
  font-family:ui-monospace,"Cascadia Mono",Consolas,"DejaVu Sans Mono",monospace;
  font-size:12.5px;line-height:1.7;word-break:break-all;
}

/* The explainer at the foot of each card.
   ⚠ NOT `margin-top:auto`. Pinning it to the bottom was the first version, on the
   theory that the two notes should line up — but the Linux instructions are three
   times the length of the Windows ones, so all it did was open 200 px of empty
   card between the hash and the note on the Windows side. A reader sees a hole,
   not an alignment. The note follows the thing it is about, and the cards end at
   different heights; the panel behind them stretches, which is what the grid is
   for. Mixed content lengths, not a defect.
   The paragraphs inside it space themselves — see the child-combinator note
   above for why they cannot rely on .card p + p. */
.dlcard .dlnote{font-size:13.5px;padding:14px 16px}
.dlcard .dlnote p{font-size:13.5px}
.dlcard .dlnote > * + *{margin-top:10px}
.dlcard .dlnote code{
  font-family:ui-monospace,"Cascadia Mono",Consolas,"DejaVu Sans Mono",monospace;
  font-size:12.5px;color:var(--gold);overflow-wrap:anywhere;
}
/* The box, the wrap rules and the monospace come from the global `pre` rule.
   Two properties have to be restated here, both for the same reason:
   `.dlcard .dlnote code` above is (0,3,1) and beats `pre code` at (0,0,2), so
   without these a command block renders in inline-code gold and inherits
   `overflow-wrap:anywhere` — which is right for a file name in a sentence and
   wrong for a command. */
.dlcard .dlnote pre code{color:var(--text);overflow-wrap:normal}

/* ── Utility ─────────────────────────────────────────────────────────────── */
.center{text-align:center}
.mt0{margin-top:0}.mt8{margin-top:8px}.mt16{margin-top:16px}.mt24{margin-top:24px}
.mt32{margin-top:32px}.mt40{margin-top:40px}
.mb0{margin-bottom:0}.mb16{margin-bottom:16px}.mb24{margin-bottom:24px}
.hide{display:none}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{transition:none!important;animation:none!important}
}
