:root{--bg:#17191d;--fg:#eaecef;--text:#b7bdc6;--muted:#707a8a;--border:#2f353d;
--accent:#fcd535;--card:#21242a;--code-bg:#1d1f24;--code-fg:#f0b90b;--add:#0ecb81;--del:#f6465d;
--warn:#f0b90b;--info:oklch(.79 .12 250);
/* Kind hues. Xenon stores exactly five kinds and they were all the same grey
   pill, so the one genuinely categorical axis in the product was invisible.
   One hue each, spaced around the wheel and kept clear of the three colours
   that already mean something here: yellow = action/selection, green = success,
   red = danger. They appear on the kind chip and its filter only — never on a
   card, a heading, or a border at size — so the page gains a legend, not a
   coat of paint. OKLCH because equal lightness reads equal: every one of these
   lands at L .78-.82 and clears 7:1 on the canvas. */
--k-artifact:oklch(.82 .11 195);
--k-review:oklch(.78 .13 300);
--k-analysis:oklch(.78 .14 340);
--k-doc:oklch(.80 .11 250);
--k-attention:oklch(.80 .13 55);
--k:var(--accent);
--sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Helvetica,Arial,sans-serif;
--mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace}
.k--artifact{--k:var(--k-artifact)}
.k--review{--k:var(--k-review)}
.k--analysis{--k:var(--k-analysis)}
.k--doc{--k:var(--k-doc)}
.k--attention{--k:var(--k-attention)}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);font:14px/1.5 var(--sans)}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
/* Keyboard focus was invisible on every control. Yellow is the interaction
   colour everywhere else on this surface, so it is the ring too. */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}
.wrap{max-width:1100px;margin:0 auto;padding:24px 20px 64px}
header.top{display:flex;align-items:baseline;gap:16px;border-bottom:1px solid var(--border);
padding-bottom:12px;margin-bottom:20px}
header.top h1{font:600 15px/1 var(--mono);letter-spacing:.04em;margin:0;color:var(--accent)}
header.top nav{margin-left:auto;display:flex;gap:14px;font:11px/1 var(--mono);letter-spacing:.04em}
header.top nav a{color:var(--muted)}
header.top nav a:hover{color:var(--accent)}
header.top nav .top__who{color:var(--fg)}
/* sign out has to be a form button; it reads as the nav link beside it */
header.top nav form{margin:0}
header.top nav button{background:none;border:0;padding:0;color:var(--muted);
font:inherit;letter-spacing:inherit;cursor:pointer}
header.top nav button:hover{color:var(--accent);text-decoration:underline}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
.card{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:13px}
.card h3{margin:0 0 6px;font:600 13px/1.3 var(--sans)}
/* A card title is the content, not an action, so it reads in the text colour
   and lets the kind chip beside it be the coloured thing. Every title in yellow
   was spending the accent on the least surprising element on the page. */
.card h3 a{color:var(--fg)}
.card h3 a:hover{color:var(--accent)}
.meta{font:11px/1.6 var(--mono);color:var(--muted);letter-spacing:.04em;
font-variant-numeric:tabular-nums}
.pill{display:inline-block;background:var(--code-bg);border-radius:5px;padding:2px 7px;
font:10px/1.6 var(--mono);letter-spacing:.04em;color:var(--muted)}
/* The kind chip is the legend for its hue: same colour here, on the filter row,
   and on the resource page, so the mapping is learned once. */
.pill.k{color:var(--k);background:color-mix(in oklab,var(--k) 13%,var(--code-bg));
box-shadow:inset 0 0 0 1px color-mix(in oklab,var(--k) 28%,transparent)}
/* Public is a fact about who can read this, so it gets the success tone;
   private is the quiet default and stays neutral. The word carries it either
   way — the colour is the second signal, never the only one. */
/* The project logo: the name's first letter on a hue hashed from the whole
   slug, so a project keeps the same face on its card, its page, and its usage
   page without anyone drawing or storing anything. Identity, not status — the
   lightness/chroma sit where the kind hues do (L≈.8, tinted ground like
   .pill.k), so a logo that happens to land near green or red reads as a
   colour, not a verdict. --l exists so the letter, tint, and ring stay one
   colour that moves together when --h does. */
.logo{--l:oklch(.8 .12 var(--h));display:inline-flex;flex:none;align-items:center;
justify-content:center;width:34px;height:34px;border-radius:9px;
font:600 15px/1 var(--mono);color:var(--l);
background:color-mix(in oklab,var(--l) 14%,var(--code-bg));
box-shadow:inset 0 0 0 1px color-mix(in oklab,var(--l) 30%,transparent)}
.logo--lg{width:42px;height:42px;border-radius:11px;font-size:19px}
.card--project{display:flex;gap:11px;align-items:center}
.card__body{min-width:0}
.project-head{display:flex;gap:11px;align-items:center;margin-bottom:6px}
.project-head h2{margin:0}
/* The GitHub link is a fact about the project, not an action on this page, so
   it sits quiet in the muted tone until pointed at. */
.project-head__gh{font:11px/1.6 var(--mono);letter-spacing:.04em;color:var(--muted)}
.project-head__gh:hover{color:var(--accent);text-decoration:none}
/* The references section is an index of where the content points, so it reads
   like the meta rows do — mono, quiet — and stays out of the document's way
   behind a border. */
.refs{border-top:1px solid var(--border);margin-top:24px;padding-top:12px}
.refs__title{margin:0 0 8px;font:600 11px/1.6 var(--mono);letter-spacing:.04em;
color:var(--muted);text-transform:lowercase}
.refs__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}
.refs__list li{display:flex;align-items:baseline;gap:8px;min-width:0}
.refs__list a{font:12px/1.5 var(--mono);overflow-wrap:anywhere}
.refs__kind{flex:none}
.state{font:10px/1.6 var(--mono);letter-spacing:.04em}
.state--public{color:var(--add)}
.state--private{color:var(--muted)}
.empty{text-align:center;color:var(--muted);font:12px/2 var(--mono);padding:36px 0}
.footer{border-top:1px solid var(--border);margin-top:28px;padding-top:10px;
font:11px/1.6 var(--mono);color:var(--muted)}
.kinds{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}
.kinds a{background:var(--code-bg);border:1px solid color-mix(in oklab,var(--k) 26%,var(--border));
border-radius:5px;padding:3px 9px;font:10px/1.6 var(--mono);letter-spacing:.04em;color:var(--k);
transition:background 160ms cubic-bezier(.22,1,.36,1),color 160ms cubic-bezier(.22,1,.36,1)}
.kinds a:hover{background:color-mix(in oklab,var(--k) 14%,var(--code-bg));text-decoration:none}
/* The selected filter is the one place a kind hue fills a shape: solid on the
   canvas colour, so "what am I looking at" is answered from across the room. */
.kinds a.on{color:var(--bg);background:var(--k);border-color:var(--k)}
/* The count rides inside its chip rather than beside it: it is an attribute of
   the kind, not a second control. Dimmed against whatever colour the chip is
   currently wearing, so the word stays the thing you read and click and the
   number is the thing you weigh. */
.kinds__n{margin-left:7px;opacity:.6;font-variant-numeric:tabular-nums}
/* A kind with nothing in it keeps its place — the row is a fixed legend, and a
   chip that comes and goes is harder to aim at than one that says zero — but it
   steps back so the row reads as what is actually there. */
.kinds a.is-empty{opacity:.45}
.kinds a.is-empty:hover{opacity:1}
@media (prefers-reduced-motion:reduce){.kinds a{transition:none}}
/* A resource page is a stack: the title, what it is, then which file of it you
   are reading. The meta line carried no bottom margin because on a project card
   it is the last thing in the box — here it is followed by the tab row, and the
   two boxes were touching at exactly 0px, which read as one crowded control. */
.res .meta{margin-bottom:14px}
/* Eleven event kinds is a long filter row, and unlike resource kinds they have
   no hue of their own — left on the default they all came out accent yellow and
   shouted over the feed they are filtering. Muted at rest; the accent means
   "this one is on", which is what it means everywhere else. */
.kinds--events a{color:var(--muted);border-color:var(--border)}
.kinds--events a:hover{color:var(--accent);background:var(--code-bg)}
.kinds--events a.on{color:var(--bg);background:var(--accent);border-color:var(--accent)}

/* Who uploaded this. Two voices in one line: what the server authenticated
   reads in the text colour, what the client merely claimed stays muted, so the
   difference is visible without reading the tooltip. */
.byline{margin:6px 0 0;font:11px/1.6 var(--mono);letter-spacing:.04em;color:var(--muted)}
.byline__who{color:var(--fg)}
.byline__token{color:var(--text)}
.byline__claimed{color:var(--muted)}

/* Activity feed. A row is a sentence, not a card: actor, verb, object, when.
   Cards here would be eleven boxes of chrome around one line of text each, and
   the whole point of the page is that it can be scanned. */
.feed__day{margin:26px 0 8px;font:11px/1.6 var(--mono);letter-spacing:.06em;color:var(--muted);
font-weight:400}
.feed{margin:0;padding:0;list-style:none}
.feed__row{display:flex;align-items:baseline;gap:10px;padding:7px 0;
border-top:1px solid var(--border)}
.feed__row:last-child{border-bottom:1px solid var(--border)}
/* Wide enough for the longest chip there is (`project.create`), so the column
   never truncates the one word that says what a row is. */
.feed__kind{flex:0 0 11.4em;font:10px/1.6 var(--mono);letter-spacing:.04em;color:var(--muted);
text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Only a row about a resource takes the kind hue; account rows stay muted, so
   the security entries read as a different class of thing at a glance. */
.feed__kind--res{color:var(--k)}
.feed__say{flex:1;min-width:0;color:var(--text)}
.feed__actor{color:var(--fg)}
.feed__subject{color:var(--fg)}
.feed__project{font:11px var(--mono);color:var(--muted)}
.feed__project:hover{color:var(--accent)}
.feed__when{flex:0 0 auto;font:11px var(--mono);color:var(--muted);
font-variant-numeric:tabular-nums}
@media (max-width:640px){
  .feed__row{flex-wrap:wrap}
  .feed__kind{flex-basis:auto;text-align:left}
  .feed__when{width:100%}
}
.files{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 18px;padding:0;list-style:none}
.files a{display:block;background:var(--code-bg);border:1px solid var(--border);border-radius:5px;
padding:3px 9px;font:11px/1.6 var(--mono);color:var(--muted)}
/* The open file belongs to a resource of a known kind, so the tab that is open
   is marked in that resource's own hue. */
.files a.on{color:var(--k);border-color:color-mix(in oklab,var(--k) 55%,var(--border))}
article.doc{max-width:820px;font-size:15px;line-height:1.65;color:var(--text)}
article.doc h1{font-size:1.75em;color:var(--accent)}
article.doc h2{font-size:1.35em;border-bottom:1px solid var(--border);padding-bottom:.2em}
article.doc h3{font-size:1.15em;color:var(--accent)}
article.doc code{background:var(--code-bg);color:var(--code-fg);border-radius:3px;padding:1px 4px;
font:.9em var(--mono)}
article.doc pre{background:var(--code-bg);border:1px solid var(--border);border-radius:8px;
padding:12px;overflow:auto}
article.doc pre code{background:none;color:var(--text);padding:0}
article.doc table{border-collapse:collapse;width:100%}
article.doc th,article.doc td{border:1px solid var(--border);padding:6px 9px;text-align:left}
article.doc blockquote{border:1px solid var(--border);border-radius:8px;
background:rgba(112,122,138,.08);margin:1em 0;padding:.6em 1em;color:var(--muted)}
article.doc img{max-width:100%;border-radius:8px}
/* An artifact opens in its own tab (see web.rs render_file), so there is no
   frame to size and nothing nested to scroll. This is just the call to action. */
/* Breadcrumbs: one click back to every level above the current page. The last
   crumb is the page you are on, so it is text — a link to yourself looks live
   and goes nowhere. */
nav.crumbs{display:flex;flex-wrap:wrap;align-items:baseline;gap:7px;
margin:0 0 18px;font:11px var(--mono);letter-spacing:.04em}
nav.crumbs a{color:var(--muted)}
nav.crumbs a:hover{color:var(--accent)}
.crumbs__sep{color:var(--border)}
.crumbs__here{color:var(--fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
max-width:52ch}

/* Move between revisions of the same resource without going back up first. */
nav.revnav{display:flex;gap:16px;flex-wrap:wrap;margin:22px 0 0;padding-top:12px;
border-top:1px solid var(--border);font:11px var(--mono);letter-spacing:.04em}

header.top h1 a{color:var(--accent)}

.artifact-open{margin:1.4em 0 .4em;font:14px var(--mono)}
.artifact-open a{padding:9px 14px;border:1px solid var(--accent);border-radius:8px;
display:inline-block;color:var(--accent)}
.artifact-open a:hover{background:var(--accent);color:var(--bg)}
form.auth{max-width:380px}
form.auth label{display:block;font:10px/2 var(--mono);letter-spacing:.04em;color:var(--muted)}
form.auth input,form.auth select{width:100%;background:var(--code-bg);color:var(--fg);
border:1px solid var(--border);border-radius:6px;padding:8px 10px;font:13px var(--mono);
margin-bottom:12px}
button{background:var(--accent);color:var(--bg);border:0;border-radius:6px;padding:8px 16px;
font:600 12px var(--mono);letter-spacing:.04em;cursor:pointer}
button.ghost{background:var(--code-bg);color:var(--muted);border:1px solid var(--border)}
.msg{font:11px/1.6 var(--mono);margin:10px 0;min-height:1.6em}
.msg.err{color:var(--del)}
.msg.ok{color:var(--add)}
table.data{width:100%;border-collapse:collapse;font:11px/1.6 var(--mono);
font-variant-numeric:tabular-nums}
table.data th{text-align:left;color:var(--muted);font-weight:400;letter-spacing:.04em;
border-bottom:1px solid var(--border);padding:6px 8px}
table.data td{border-bottom:1px solid var(--border);padding:6px 8px;color:var(--text)}

/* Page switch (spec 214). A project's resources and its usage ledger are two
   bodies of data under one project, so they are peers — not a filter of one
   another, which is why this sits above the kind chips and does not borrow
   their pill shape. */
.tabs{display:flex;gap:18px;margin:14px 0 16px;padding-bottom:9px;
border-bottom:1px solid var(--border);font:11px/1 var(--mono);letter-spacing:.04em}
.tabs a{color:var(--muted)}
.tabs a:hover{color:var(--accent);text-decoration:none}
.tabs a.on{color:var(--fg)}

/* A numeric table is read down its columns, so every figure is right-aligned
   and only the cells that NAME a thing stay left. `tabular-nums` on table.data
   is what makes the digits line up once they are. */
table.data--num th,table.data--num td{text-align:right}
table.data--num th.txt,table.data--num td.txt,
table.data--num th:first-child{text-align:left}
table.data--num td.txt{color:var(--fg)}

/* Eight columns here and twelve in the ledger, so on a narrow screen each
   table scrolls inside its own box rather than letting the whole document
   scroll — that would carry the nav and the range chips off with it. Nothing
   wraps: a model id broken across three lines costs more legibility than the
   scrollbar does. */
.scroll{overflow-x:auto}
table.data--num{white-space:nowrap}
table.data--ledger td.txt{color:var(--text)}
table.data--ledger td.txt:first-child{color:var(--fg)}

/* A statement about data that is missing — one flat surface, full border, no
   left accent rail. */
.notice{margin:16px 0 0;padding:9px 12px;border:1px solid var(--border);border-radius:6px;
background:var(--code-bg);font:11px/1.7 var(--mono);color:var(--muted)}
.empty code,.notice code{color:var(--code-fg)}
.secret{background:var(--code-bg);border:1px solid var(--accent);border-radius:8px;padding:12px;
margin:12px 0;font:12px var(--mono);color:var(--accent);word-break:break-all}
.scopes{display:flex;gap:14px;flex-wrap:wrap;margin-bottom:12px;font:11px var(--mono);
color:var(--text)}
.scopes label{display:flex;align-items:center;gap:5px}
.scopes input{width:auto;margin:0}

/* Review Board typed blocks (src/render.rs). Ported from Krypton's archive so a
   Board reads the same in both places. Stage 2 moves this to assets/app.css.
   House rule: never a left accent rail — full border, background tint, or
   heading colour carries the meaning instead. */
ol.rv-steps{list-style:decimal;margin:1em 0;padding:14px 14px 14px 2.4em;
border:1px solid var(--border);border-radius:8px;background:var(--card)}
ol.rv-steps>li{margin:0 0 10px}
ol.rv-steps>li:last-child{margin-bottom:0}
.rv-step__at{display:block;font:12px var(--mono);color:var(--accent);word-break:break-all}
.rv-step__say{display:block;color:var(--text);margin-top:2px}
.rv-steps__title{font:12px var(--mono);color:var(--muted);text-transform:uppercase;
letter-spacing:.04em;margin:1.4em 0 .4em}

/* Severity tints the whole perimeter and the fill, never one edge — a card is
   scannable at a glance without reading the chip, and the chip is still there
   for anyone who cannot see the difference. */
.rv-finding{margin:1em 0;padding:12px 14px;
border:1px solid color-mix(in oklab,var(--sev) 34%,var(--border));
border-radius:8px;background:color-mix(in oklab,var(--sev) 7%,var(--card));
--sev:var(--muted);--sev-ink:var(--sev)}
.rv-finding__head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.rv-finding__sev{font:700 11px var(--mono);letter-spacing:.06em;color:var(--sev-ink)}
.rv-finding__title{color:var(--sev-ink)}
/* `--del` is the alert red: right for the border, too dark for 11px type on a
   surface tinted with itself (measured 4.07:1). The ink is the same red lifted
   until it clears AA, so the card keeps one colour and the text stays legible. */
.rv-finding--blocking{--sev:var(--del);--sev-ink:oklch(.79 .15 22)}
.rv-finding--warn{--sev:var(--warn)}
/* A suggestion is information, not a problem: blue reads as "worth knowing"
   where the old grey read as "ignore me". */
.rv-finding--sugg{--sev:var(--info)}
.rv-finding__title{font-weight:600}
/* The path is the second thing read on a finding, not decoration; muted sat at
   3.3:1 on the tinted fill. */
.rv-finding__at{margin-left:auto;font:11px var(--mono);color:var(--text);word-break:break-all}

ol.rv-options{list-style:decimal;margin:.6em 0 1em;padding-left:1.7em}
ol.rv-options>li{margin:.3em 0}
ol.rv-options>li.is-chosen{color:var(--accent);font-weight:600}
.rv-decision__question{font-weight:600;color:var(--fg);margin:1em 0 0}
.rv-option__rec{font:10px var(--mono);letter-spacing:.06em;color:var(--muted);margin-left:8px}

dl.rv-metrics{display:grid;grid-template-columns:auto 1fr;gap:4px 16px;margin:1em 0;
padding:12px 14px;font-size:13px;background:var(--code-bg);border:1px solid var(--border);
border-radius:6px}
dl.rv-metrics dt{font:600 13px var(--mono);color:var(--muted);white-space:nowrap}
dl.rv-metrics dd{margin:0;color:var(--fg);word-break:break-word}

.rv-chart{margin:1em 0;padding:12px 14px;border:1px solid var(--border);border-radius:8px;
background:var(--card)}
.rv-chart__title{font:12px var(--mono);color:var(--muted);margin-bottom:10px}
.rv-chart__row{display:flex;align-items:center;gap:10px;margin:4px 0}
.rv-chart__label{flex:0 0 34%;font:12px var(--mono);color:var(--text);text-align:right;
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rv-chart__track{flex:1;min-width:0;height:10px;background:var(--code-bg);border-radius:2px}
.rv-chart__bar{display:block;height:100%;background:var(--accent);border-radius:2px}
.rv-chart__value{flex:0 0 auto;font:12px var(--mono);color:var(--muted);min-width:3.5em}

pre.rv-diff{font:12px/1.45 var(--mono);background:var(--code-bg);border:1px solid var(--border);
border-radius:6px;padding:12px 14px;overflow-x:auto;margin:1em 0}
pre.rv-diff span{display:block}
.rv-diff__add{color:var(--add)}
.rv-diff__del{color:var(--del)}
.rv-diff__hunk{color:var(--muted)}

.rv-svg{margin:1em 0;text-align:center}
.rv-svg svg{max-width:100%;height:auto}
.rv-unknown{font:11px var(--mono);color:var(--muted);margin:1em 0 -.6em}

/* Attention flag — a judgement item, whose entire payload is the revision's
   `meta` (no files exist for this kind). Field headings carry the structure;
   the reversibility tier is a text chip AND a colour, never colour alone. Flat
   by house rule: one surface, no card inside a card, no left accent rails. */
.jdg{max-width:820px;margin:1.2em 0}
.jdg__tier{display:inline-block;margin:0 0 1.2em;padding:2px 8px;border-radius:5px;
border:1px solid color-mix(in oklab,var(--tier) 45%,var(--border));
background:color-mix(in oklab,var(--tier) 10%,var(--code-bg));
font:700 11px/1.6 var(--mono);letter-spacing:.06em;color:var(--tier-ink);
--tier:var(--muted);--tier-ink:var(--tier)}
/* Three tiers, three tones, in the order a reader triages them: safe to undo,
   expensive to undo, cannot be undone. Irreversible borrows the finding card's
   lifted red for the same reason: 11px of `--del` on its own tint fails AA. */
.jdg__tier--reversible{--tier:var(--add)}
.jdg__tier--costly{--tier:var(--warn)}
.jdg__tier--irreversible{--tier:var(--del);--tier-ink:oklch(.79 .15 22)}
.jdg__field{margin:0 0 1.4em}
.jdg__field h3{margin:0 0 .35em;font:12px var(--mono);color:var(--muted);
text-transform:uppercase;letter-spacing:.04em}
.jdg__body{color:var(--text);font-size:15px;line-height:1.65}
ul.jdg__list{margin:0;padding-left:1.3em}
ul.jdg__list>li{margin:.25em 0}

/* Whatever the per-kind layout above did not claim. The floor that keeps a
   field from being silently dropped when a producer adds one. */
table.kv{border-collapse:collapse;margin:1.4em 0;max-width:820px;width:100%}
table.kv th,table.kv td{border-top:1px solid var(--border);padding:7px 12px 7px 0;
text-align:left;vertical-align:top}
table.kv th{width:11em;font:12px/1.6 var(--mono);color:var(--muted);font-weight:400;
letter-spacing:.04em}
table.kv td{color:var(--text);word-break:break-word}
pre.kv__json{margin:0;font:12px/1.45 var(--mono);color:var(--code-fg);
background:var(--code-bg);border-radius:6px;padding:10px 12px;overflow-x:auto}

/* A text file read in place — JSON evidence, a log, a config, source. One
   surface with a full border and a header line, flat by house rule: no card
   inside a card, no left accent rail. The body is one <span> per line so the
   gutter number can be generated content, which keeps it out of anything you
   select and copy — the same trick pre.rv-diff uses for diffs. */
.filetext{border:1px solid var(--border);border-radius:8px;background:var(--code-bg);
margin:1em 0;overflow:hidden}
.filetext__bar{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin:0;
padding:8px 12px;border-bottom:1px solid var(--border);font:11px var(--mono);color:var(--muted)}
.filetext__path{color:var(--fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
max-width:46ch}
.filetext__lang{border:1px solid var(--border);border-radius:5px;padding:1px 7px;
letter-spacing:.04em;text-transform:uppercase}
.filetext__bar a{margin-left:auto;color:var(--muted)}
.filetext__bar a:hover{color:var(--accent)}
.filetext__body{margin:0;padding:10px 0;overflow-x:auto;tab-size:4;
font:12px/1.55 var(--mono);color:var(--text);counter-reset:ln}
/* min-width keeps a short line selectable across the full width; max-content
   lets a long one push the scroll rather than wrap. */
.filetext__body span{display:block;counter-increment:ln;width:max-content;min-width:100%;
padding-right:14px}
/* Sticky so the numbering stays put while a long line scrolls under it, and
   raised above its own line — without the z-index the code slides over the
   number rather than under it. */
.filetext__body span::before{content:counter(ln);position:sticky;left:0;z-index:1;
display:inline-block;width:4ch;padding:0 14px 0 12px;text-align:right;
background:var(--code-bg);color:color-mix(in oklab,var(--muted) 72%,var(--code-bg));
user-select:none;-webkit-user-select:none}
