/* ═══════════════════════════════════════════════════════════════════════════
   BOKKAPIG — TTY
   The whole site is one terminal. Panels are frames with their title notched
   into the top border, the machine index is an `ls -la` listing rather than a
   stack of cards, and a status bar is pinned to the bottom of the viewport.
   Palette: Slate / Ice — blue-grey ground, cyan accent, periwinkle tags.
   Fonts are loaded via <link> in baseof.html, not @import — @import blocks render.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Chassis ─────────────────────────────────────────────────────────── */
  --bg-deep:       #0f1319;   /* the page itself */
  --bg-main:       #151a22;   /* inside a frame */
  --bg-surface:    #1b222c;   /* raised rows */
  --bg-elevated:   #242e3a;   /* pressed / active */

  --border:        #2a3540;   /* frame edges */
  --border-soft:   #202932;   /* row rules inside a frame */
  --border-focus:  #455565;   /* tree connectors, focus rings */

  --text-primary:  #ccd5df;
  --text-dim:      #93a1ae;
  --text-faint:    #6e7d8b;

  /* ── Accent ──────────────────────────────────────────────────────────────
     Four load-bearing places: the mode block in the status bar, the selected
     row, the active filter chip, and every heading. A hue has to survive all
     four — as a solid fill under dark text and as 11px type — to work here. */
  --accent:        #56b8e0;
  --accent-bright: #8ad9f5;
  --accent-deep:   #173f4e;   /* selected-row wash: the hue at ~18% chroma */

  /* Cursor, counts and keybinding letters. Deliberately *not* the accent —
     two hues so the eye separates "you are here" from "you can press this". */
  --amber:         #d7b070;
  --amber-dim:     #a68a56;

  /* Tags. Periwinkle rather than blue: a cyan accent swallows a blue tag. */
  --blue:          #9aa8e8;
  --blue-dim:      #6f7cb8;

  --red:           #dd8079;
  --red-bright:    #f09b94;
  --purple:        #ac9ad6;

  /* Alternating code lines. Tone A is --bg-main, so it sits flush with the
     block's own surface; B is one step up — enough to tell two wrapped lines
     apart, not enough to read as banding. */
  --code-line-a:   #151a22;
  --code-line-b:   #19202a;

  /* Difficulty is semantic and never borrows the accent — an accent-coloured
     difficulty would make every easy row look selected. */
  --diff-easy:     #7fc98f;
  --diff-medium:   #d7b070;
  --diff-hard:     #dd8079;
  --diff-insane:   #c3ccd6;

  /* Legacy hue names. The reference-set styles further down still speak in
     hues rather than roles; aliasing keeps them correct without a 1,000-line
     find-and-replace. New rules should use --accent. */
  --green:         var(--accent);
  --green-bright:  var(--accent-bright);

  /* One face for everything — a TTY has no second typeface. --font-display
     survives as an alias so older rules keep resolving. */
  --font-mono:     'IBM Plex Mono', 'Menlo', 'Consolas', monospace;
  --font-display:  var(--font-mono);

  --max-width:     880px;
  --wide-width:    1220px;
  --gutter:        clamp(0.85rem, 3vw, 1.6rem);
  --statusbar-h:   2.1rem;
}

/* ── Reset & Base ──────────────────────────────────────────────────────── */

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Percentage, not px — this scales with the reader's browser font-size setting */
html {
  font-size: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 2rem;
}

/* ── Scrollbars ────────────────────────────────────────────────────────────
   The OS default is a light chunky bar that reads as a foreign object against
   the terminal palette. Square, thin, and drawn from the same colours. */

* {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

::-webkit-scrollbar {
  width: 9px;
  height: 9px;
}

::-webkit-scrollbar-track {
  background: var(--bg-deep);
}

::-webkit-scrollbar-thumb {
  background: var(--border);
  border: 2px solid var(--bg-deep);
}

::-webkit-scrollbar-thumb:hover { background: var(--border-focus); }
::-webkit-scrollbar-thumb:active { background: var(--accent); }
::-webkit-scrollbar-corner { background: var(--bg-deep); }

/* Inside code blocks, tables and the TOC the surface is one step lighter,
   so the track follows it rather than punching a dark hole in the box.
   The thumb sits back until you hover the box it belongs to — macOS overlay
   scrollbars ignore ::-webkit-scrollbar-thumb:hover, but they do follow
   scrollbar-color, so the hover state goes on the container. */
.writeup-body pre,
.table-wrap,
.frame,
.toc { scrollbar-color: var(--border) var(--bg-main); }

.writeup-body pre:hover,
.table-wrap:hover,
.toc:hover { scrollbar-color: var(--border-focus) var(--bg-main); }

.writeup-body pre::-webkit-scrollbar-track,
.table-wrap::-webkit-scrollbar-track,
.toc::-webkit-scrollbar-track { background: var(--bg-main); }

.writeup-body pre::-webkit-scrollbar-thumb,
.table-wrap::-webkit-scrollbar-thumb,
.toc::-webkit-scrollbar-thumb {
  background: var(--border);
  border: 2px solid var(--bg-main);
}

.writeup-body pre:hover::-webkit-scrollbar-thumb,
.table-wrap:hover::-webkit-scrollbar-thumb,
.toc:hover::-webkit-scrollbar-thumb { background: var(--border-focus); }

.writeup-body pre::-webkit-scrollbar-thumb:hover,
.table-wrap::-webkit-scrollbar-thumb:hover,
.toc::-webkit-scrollbar-thumb:hover { background: var(--green); }

body {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 0.95rem;
  color: var(--text-primary);
  background: var(--bg-deep);
  line-height: 1.65;
  min-height: 100vh;
  /* The status bar is fixed to the viewport, so the page reserves its height
     rather than running underneath it. */
  padding-bottom: var(--statusbar-h);
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: var(--accent);
  color: var(--bg-deep);
}

a {
  color: var(--green);
  text-decoration: none;
  transition: color 0.2s;
}

a:hover {
  color: var(--green-bright);
}

:focus-visible {
  outline: 1px solid var(--accent-bright);
  outline-offset: 1px;
}

[hidden] { display: none !important; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10000;
  background: var(--accent);
  border: 1px solid var(--accent);
  color: var(--bg-deep);
  padding: 0.4rem 0.9rem;
  font-size: 0.78rem;
}

.skip-link:focus {
  left: 0.5rem;
  top: 0.5rem;
}

/* ── Topbar ───────────────────────────────────────────────────────────────
   One line: the prompt on the left, numbered nav on the right. The numbers are
   not live keybindings — they are there because a TUI menu has them, and they
   give the eye a fixed left edge to run down. */

.site-header {
  border-bottom: 1px solid var(--border);
  background: var(--bg-main);
  padding: 0 var(--gutter);
}

.header-inner {
  max-width: var(--wide-width);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 0.6rem 1.5rem;
  flex-wrap: wrap;
  padding: 0.4rem 0;
}

.site-title {
  font-size: 0.95rem;
  color: var(--accent);
  letter-spacing: 0.06em;
  display: flex;
  align-items: center;
}

.site-title a { color: var(--accent); }
.site-title a:hover { color: var(--accent-bright); }

.prompt-symbol {
  color: var(--amber);
  animation: blink 1.2s step-end infinite;
}

@keyframes blink { 50% { opacity: 0; } }

.site-subtitle {
  font-size: 0.72rem;
  color: var(--text-faint);
  letter-spacing: 0.04em;
}

.site-subtitle::before { content: '· '; }

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.1rem;
  margin-left: auto;
  font-size: 0.78rem;
  letter-spacing: 0.02em;
}

.site-nav a { color: var(--text-faint); }
.site-nav a .k { color: var(--amber); }
.site-nav a:hover { color: var(--text-primary); }
.site-nav a[aria-current="page"],
.site-nav a[aria-current="page"] .k { color: var(--accent-bright); }

/* ── Frame ────────────────────────────────────────────────────────────────
   Every panel on the site. The legend sits astride the top border with the
   page colour behind it, which is what makes it read as a notch cut into the
   rule rather than a label parked on top of one — so a frame only works
   directly against --bg-deep, never nested inside another frame. */

.frame {
  position: relative;
  border: 1px solid var(--border);
  background: var(--bg-main);
  margin-bottom: 1.4rem;
}

.frame > .frame-legend,
.frame > .frame-rlegend {
  position: absolute;
  top: 0;
  transform: translateY(-50%);
  background: var(--bg-deep);
  padding: 0 0.5rem;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  max-width: calc(100% - 3rem);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.frame > .frame-legend { left: 0.9rem; }
.frame > .frame-rlegend { right: 0.9rem; }

.frame > .frame-legend b { color: var(--accent); font-weight: 400; }
.frame > .frame-legend .count { color: var(--amber); }
.frame > .frame-legend a { color: inherit; }
.frame > .frame-legend a:hover { color: var(--accent); }

.frame-body { padding: 1rem 1.1rem; }

/* A frame whose body is a full-bleed list: the rows bring their own padding
   so their rules can run the whole width of the panel. */
/* A frame whose body is a full-bleed list: the rows bring their own padding so
   their rules can run the whole width of the panel. Clearance under the legend
   is the first row's job, not this one's. */
.frame-rows { padding-top: 0; }

/* The legend sits astride the top border and hangs half a line into the panel,
   so the first thing under it has to start below that. */
.frame > .filter-bar .filter-search { padding-top: 0.8rem; }
.frame > .filter-bar > .filter-search { padding-left: 1.1rem; padding-right: 1.1rem; }

/* ── Main Content ──────────────────────────────────────────────────────── */

.site-main {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 1.6rem var(--gutter) 2.5rem;
}

.site-main--section,
.site-main--home,
.site-main--taxonomy,
.site-main--term { max-width: var(--wide-width); }

/* ── Page heading ─────────────────────────────────────────────────────────
   Only the pages that are not a frame still use this — taxonomies and search.
   Everywhere else the heading has moved into the frame legend. */

.index-header {
  margin-bottom: 1.4rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--border);
}

.index-header h1 {
  font-size: 0.95rem;
  font-weight: 400;
  color: var(--text-dim);
  letter-spacing: 0.04em;
}

.index-header .count { color: var(--amber); }
.index-header .writeup-nav { margin-bottom: 0.5rem; }

.no-results {
  margin: 1.4rem 0;
  padding: 1.6rem 1.1rem;
  text-align: center;
  border: 1px dashed var(--border);
  color: var(--text-faint);
  font-size: 0.82rem;
}

/* ── Command line ─────────────────────────────────────────────────────────
   The search box at the top of the machine index and on /search/. It is a
   shell prompt: the label is the command, the input is its argument. */

.filter-bar { border-bottom: 1px solid var(--border-soft); }

.filter-search {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 1.1rem;
  border-bottom: 1px solid var(--border-soft);
  transition: background 0.15s;
}

.filter-search:focus-within { background: var(--bg-surface); }

.filter-prompt {
  color: var(--accent);
  white-space: nowrap;
  cursor: text;
  font-size: 0.85rem;
}

.filter-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--text-primary);
}

.filter-input::placeholder { color: var(--text-faint); }
.filter-input::-webkit-search-cancel-button { filter: grayscale(1) opacity(0.5); }

.filter-kbd {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-faint);
  border: 1px solid var(--border);
  padding: 0 0.35rem;
  line-height: 1.5;
}

.filter-groups {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 1.1rem;
  padding: 0.45rem 1.1rem;
}

.filter-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.filter-label {
  font-size: 0.66rem;
  color: var(--text-faint);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-right: 0.2rem;
}

.filter-chip,
.filter-clear {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.02em;
  background: none;
  border: 1px solid transparent;
  color: var(--text-dim);
  padding: 0 0.4rem;
  cursor: pointer;
  transition: color 0.12s, background 0.12s, border-color 0.12s;
}

.filter-chip:hover,
.filter-clear:hover {
  color: var(--text-primary);
  border-color: var(--border);
}

.filter-chip.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg-deep);
}

.filter-clear {
  margin-left: auto;
  color: var(--amber-dim);
}

.filter-status {
  padding: 0 1.1rem 0.5rem;
  font-size: 0.7rem;
  color: var(--text-faint);
  min-height: 1.2em;
}

/* ── Machine index ────────────────────────────────────────────────────────
   `ls -la` rather than a stack of cards: one grid shared by the column header
   and every row, so the columns line up down the whole listing. Widths are in
   ch because the face is monospaced — 11ch is exactly an ISO date.

   Each machine is a single element so the filter can hide it with one flag;
   the summary is a second grid row inside that element, not a sibling. */

.machine-index { display: flex; flex-direction: column; }

.machine-head,
.machine-card {
  display: grid;
  grid-template-columns:
    30px                     /* avatar / status */
    minmax(10ch, 18ch)       /* name            */
    8ch                      /* difficulty      */
    8ch                      /* os              */
    11ch                     /* date            */
    minmax(0, 1fr);          /* tags            */
  gap: 0 1.1rem;
  padding: 0.34rem 1.1rem;
  /* Centred, not baseline: the avatar is taller than the text it sits beside,
     and baseline alignment would pin the text to the top of the row. */
  align-items: center;
  /* Shared, and it has to stay shared: the columns are sized in ch, which
     resolves against the grid container's own font-size. Sizing the header
     down here instead of on its labels shifts every column under it. */
  font-size: 0.85rem;
}

.machine-head {
  color: var(--text-faint);
  border-bottom: 1px solid var(--border);
  padding-top: 0.7rem;
  padding-bottom: 0.5rem;
}

.machine-head > span {
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.machine-card {
  border-bottom: 1px solid var(--border-soft);
  color: var(--text-primary);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.machine-card:last-child { border-bottom: none; }

/* The whole row lights up, the way a selection bar does in a file manager. */
a.machine-card:hover,
a.machine-card:focus-visible {
  background: var(--accent-deep);
  color: var(--text-primary);
  outline: none;
}

a.machine-card:hover .card-title,
a.machine-card:focus-visible .card-title { color: var(--accent-bright); }

/* Sized to the avatar and centred on the row rather than sitting on its
   baseline, which would hang the image below the text. */
.card-mark {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  display: block;
  width: 30px;
  height: 30px;
}

.card-avatar {
  display: block;
  width: 30px;
  height: 30px;
  object-fit: cover;
}

/* No avatar in the front matter — a framed blank keeps the column true. */
.card-avatar--none {
  border: 1px solid var(--border);
  background: var(--bg-deep);
}

/* Not yet retired: the avatar drops back and a lock sits on top of it. Drawn
   in CSS rather than set as a glyph, so it takes the palette and stays crisp
   at 20px where an emoji padlock would be mush. */
.card-mark.is-locked .card-avatar {
  opacity: 0.45;
  filter: grayscale(0.85);
}

.card-mark.is-locked::before,
.card-mark.is-locked::after {
  content: '';
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

/* shackle */
.card-mark.is-locked::before {
  top: 6px;
  width: 9px;
  height: 7px;
  border: 1.75px solid var(--amber);
  border-bottom: none;
  border-radius: 4.5px 4.5px 0 0;
}

/* Body. The ring is the page colour, so the lock keeps its edge over a busy
   avatar without needing a plate behind the whole thing. */
.card-mark.is-locked::after {
  top: 13px;
  width: 15px;
  height: 12px;
  background: var(--amber);
  box-shadow: 0 0 0 1px var(--bg-deep);
  border-radius: 1px;
}
.card-title { grid-column: 2; grid-row: 1; color: var(--text-primary); }
.card-diff { grid-column: 3; grid-row: 1; }
.card-os   { grid-column: 4; grid-row: 1; color: var(--text-dim); }
.card-date { grid-column: 5; grid-row: 1; color: var(--text-dim); }
.card-tags { grid-column: 6; grid-row: 1; }

/* Indented under the name, so the eye reads it as belonging to that row
   rather than as another entry. */
.card-summary {
  grid-column: 2 / -1;
  grid-row: 2;
  color: var(--text-dim);
  font-size: 0.78rem;
  line-height: 1.5;
  padding-bottom: 0.2rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-diff { text-transform: lowercase; }
.diff-easy    { color: var(--diff-easy); }
.diff-medium  { color: var(--diff-medium); }
.diff-hard    { color: var(--diff-hard); }
.diff-insane  { color: var(--diff-insane); }
.diff-unknown { color: var(--text-faint); }

/* Tags are a run of dot-separated words, not pills — a row of bordered chips
   inside a table row makes the columns impossible to scan. */
.card-tags {
  color: var(--text-faint);
  font-size: 0.75rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-tags .tag-sep { color: var(--border-focus); padding: 0 0.15rem; }
.card-tags .tag-more { color: var(--blue-dim); }

/* Stands in for the tag list on a machine that is still live. */
.card-pending { color: var(--amber-dim); }

.machine-card--locked { color: var(--text-faint); }
.machine-card--locked .card-title { color: var(--text-dim); }


/* Difficulty as a bordered pill, for the pages that are not the index — the
   writeup header and the reference tables. */
.diff-pill {
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.05rem 0.4rem;
  border: 1px solid currentColor;
}

/* ── Tags ─────────────────────────────────────────────────────────────── */

.tag {
  font-size: 0.68rem;
  padding: 0 0.4rem;
  border: 1px solid var(--border);
  color: var(--blue);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.tag-more { color: var(--text-faint); }

a.tag:hover { border-color: var(--blue-dim); color: var(--accent-bright); }

.writeup-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.75rem;
}

/* ── Locked Writeup Page ──────────────────────────────────────────────── */

.writeup-locked {
  text-align: center;
  padding: 3.5rem 1rem;
}

.writeup-locked .locked-icon {
  font-size: 1.8rem;
  color: var(--amber);
  margin-bottom: 0.8rem;
}

.writeup-locked .locked-message {
  font-size: 1rem;
  color: var(--amber);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 0.7rem;
}

.writeup-locked .locked-detail {
  font-size: 0.82rem;
  color: var(--text-dim);
  line-height: 1.6;
  margin-bottom: 1.4rem;
}

.writeup-locked .locked-back { font-size: 0.78rem; color: var(--text-dim); }
.writeup-locked .locked-back:hover { color: var(--accent); }

/* ── Writeup header ───────────────────────────────────────────────────────
   A frame, so the breadcrumb rides in the legend and the metadata reads as a
   key/value dump rather than a run-on line of labels. */

.writeup-nav a {
  font-size: inherit;
  color: inherit;
  letter-spacing: inherit;
}

.writeup-title {
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--accent-bright);
  letter-spacing: 0.04em;
  margin-bottom: 0.6rem;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.writeup-head-grid {
  display: flex;
  gap: 1.2rem;
  align-items: flex-start;
}

.writeup-avatar {
  width: 56px;
  height: 56px;
  flex: none;
  object-fit: cover;
}

/* Two columns, label then value, so the values form a straight edge. */
.writeup-meta {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.05rem 1.2rem;
  font-size: 0.8rem;
  color: var(--text-dim);
  margin: 0;
}

.writeup-meta dt {
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding-top: 0.18rem;
}

.writeup-meta dd { margin: 0; }
.writeup-meta a { color: inherit; }
.writeup-meta a:hover { color: var(--accent-bright); }

/* ── tl;dr ────────────────────────────────────────────────────────────── */

.writeup-summary p {
  font-size: 0.82rem;
  color: var(--text-dim);
  line-height: 1.7;
}

/* ── Pwned Certificate ─────────────────────────────────────────────────── */

/* Capped so the writeup itself isn't pushed a full screen down */
.pwned-certificate { text-align: center; }

.pwned-certificate img {
  max-width: min(100%, 620px);
  height: auto;
  border: 1px solid var(--border);
}

/* ── Contents ─────────────────────────────────────────────────────────────
   Drawn as a directory tree. The connectors are borders and generated content,
   so they never end up in a copied selection and Hugo's own .TableOfContents
   markup passes through untouched. */

.toc { font-size: 0.78rem; }

/* <summary> as the legend: still the disclosure control, so it keeps working
   on narrow screens where the tree stacks above the writeup instead of
   sitting beside it. */
.toc-summary {
  cursor: pointer;
  list-style: none;
}

.toc-summary::-webkit-details-marker { display: none; }
.toc-summary:hover { color: var(--accent); }
.toc[open] > .toc-summary::after { content: ' ▾'; }
.toc:not([open]) > .toc-summary::after { content: ' ▸'; }

.toc #TableOfContents { padding: 0; }

/* The cheatsheet hands its nav straight to the frame rather than through a
   .frame-body, so it supplies the padding itself. */
.toc > #TableOfContents { padding: 1rem 1.1rem; }

.toc ul {
  list-style: none;
  padding-left: 0;
  margin: 0;
}

/* The tree is drawn with borders, not box-drawing characters. A `├──` glyph
   carries its own vertical stroke, which doubled up against the rule on the
   nested list — and it only exists on an item's first line, so anything that
   wrapped broke the trunk. Borders span the whole item however tall it gets.

   Each item's own left border IS the trunk continuing past it to the next
   sibling; the ::before is the elbow reaching out to the text. */
.toc li {
  position: relative;
  padding-left: 1.6ch;
  border-left: 1px solid var(--border-focus);
}

.toc li::before {
  content: '';
  position: absolute;
  left: 0;
  /* Half of one line box, so the elbow meets the first line of the label
     rather than its top edge. Tied to .toc a's line-height below. */
  top: 0.875em;
  /* Spans the whole indent, so the elbow runs up to the label instead of
     stopping halfway and reading as a stray dash. */
  width: 1.6ch;
  border-top: 1px solid var(--border-focus);
}

/* The last item closes the branch: no trunk below it, and a stub above the
   elbow standing in for the part that would otherwise be its border. */
.toc li:last-child { border-left-color: transparent; }

.toc li:last-child::after {
  content: '';
  position: absolute;
  left: -1px;
  top: 0;
  height: 0.875em;
  border-left: 1px solid var(--border-focus);
}

.toc a {
  display: block;
  color: var(--text-dim);
  line-height: 1.75;
  padding-left: 0.3rem;
  overflow-wrap: anywhere;
}

.toc a:hover { color: var(--accent); }

.toc a.is-current {
  color: var(--accent-bright);
  background: var(--accent-deep);
}

/* ── Writeup Body ──────────────────────────────────────────────────────── */

.writeup-body h1,
.writeup-body h2,
.writeup-body h3,
.writeup-body h4 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--text-primary);
  margin-top: 2.5rem;
  margin-bottom: 0.75rem;
  letter-spacing: 0.03em;
  line-height: 1.3;
  scroll-margin-top: 1.5rem;
}

.writeup-body h1 { font-size: 1.35rem; color: var(--accent-bright); }
.writeup-body h2 { font-size: 1.1rem; color: var(--accent); }
.writeup-body h3 { font-size: 0.98rem; color: var(--amber); }
.writeup-body h4 { font-size: 0.88rem; color: var(--blue); }

/* The hashes the heading was written with, put back. Generated content, so a
   copied selection is still the plain heading text. */
.writeup-body h2::before,
.writeup-body h3::before,
.writeup-body h4::before {
  color: var(--text-faint);
  font-weight: 400;
}

.writeup-body h2::before { content: '## '; }
.writeup-body h3::before { content: '### '; }
.writeup-body h4::before { content: '#### '; }

.heading-anchor {
  margin-left: 0.5rem;
  color: var(--text-faint);
  font-size: 0.8em;
  opacity: 0;
  transition: opacity 0.15s;
}

.anchored-heading:hover .heading-anchor,
.heading-anchor:focus-visible { opacity: 1; }

.writeup-body p { margin-bottom: 1rem; }

.writeup-body ul,
.writeup-body ol {
  margin-bottom: 1rem;
  padding-left: 1.5rem;
}

.writeup-body li { margin-bottom: 0.35rem; }
.writeup-body li::marker { color: var(--text-faint); }

.writeup-body strong { font-weight: 600; color: var(--amber); }
.writeup-body em { color: var(--blue); font-style: italic; }

.writeup-body hr {
  border: none;
  border-top: 1px dashed var(--border);
  margin: 2rem 0;
}

.writeup-body a {
  color: var(--green);
  text-decoration: underline;
  text-decoration-color: var(--border-focus);
  text-underline-offset: 0.2em;
  overflow-wrap: anywhere;
}
.writeup-body a:hover { text-decoration-color: var(--green); }

/* Inline code */
.writeup-body code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  padding: 0.1em 0.4em;
  color: var(--amber);
  overflow-wrap: anywhere;
}

/* ── Code blocks ───────────────────────────────────────────────────────────
   Every fence goes through layouts/_markup/render-codeblock.html, so they all
   arrive as .highlight > pre > code > .line > .cl. The raw-<pre> selectors are
   kept for hand-written HTML in content, which the hook never sees. The lines
   themselves are styled further down, alongside the refs pages' blocks. */

.writeup-body .highlight,
.writeup-body > pre,
.writeup-body li > pre,
.writeup-body blockquote > pre {
  margin-bottom: 1.25rem;
  background: var(--bg-main);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-focus);
  overflow: hidden;
}

.writeup-body pre {
  /* Vertical only — the horizontal padding lives on the lines themselves so the
     alternating tones run edge to edge. */
  padding: 0.85rem 0;
  line-height: 1.6;
  margin: 0;
  background: transparent;
  font-size: 0.82rem;
  tab-size: 4;
}

.writeup-body .highlight pre { border: none; }

.writeup-body pre code {
  font-size: inherit;
  background: none;
  border: none;
  padding: 0;
  color: var(--text-primary);
}

/* ── Code lines ────────────────────────────────────────────────────────────
   Shared by the writeups, the mirrored refs entries and the reverse shell
   generator: one line per .line, wrapped rather than scrolled, numbered from a
   CSS counter and striped in two tones.

   The number is generated content on purpose. It cannot be selected, so it
   never lands in a copied command, and Pagefind does not index it — a real
   <span> full of digits would show up in search results. */

pre > code {
  display: block;
  counter-reset: code-line;
}

pre .line {
  display: flex;
  counter-increment: code-line;
  background: var(--code-line-a);
}

pre .line:nth-child(even) { background: var(--code-line-b); }

/* hl_lines on a fence marks lines with .hl — keep that visible over the stripe */
pre .line.hl { background: rgba(212, 191, 114, 0.1); }

pre .line::before {
  content: counter(code-line);
  flex: 0 0 auto;
  min-width: calc(2ch + 1.4rem);
  padding: 0 0.7rem;
  text-align: right;
  color: var(--text-faint);
  border-right: 1px solid var(--border);
  user-select: none;
  -webkit-user-select: none;
}

pre .cl {
  flex: 1 1 auto;
  /* Without this the flex item refuses to shrink below its content and the long
     lines go back to overflowing */
  min-width: 0;
  padding: 0 1rem 0 0.8rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Keep the first line clear of the copy button and language tag, which sit over
   the top-right corner. .code-block is added by main.js, and lands on the
   .highlight wrapper or on the <pre> itself depending on the shape. */
.code-block .line:first-child .cl { padding-right: 5.25rem; }

/* Hand-written <pre> in content has no lines to hang the padding off, so it pays
   for its own — and wraps the same way. Both containers are named so this stays
   ahead of .refs-single pre further down the file. */
.writeup-body pre:not(:has(.line)),
.refs-single pre:not(:has(.line)) {
  padding-left: 1rem;
  padding-right: 1rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  pre .line::before {
    min-width: calc(2ch + 0.9rem);
    padding: 0 0.45rem;
  }
  pre .cl { padding: 0 0.6rem 0 0.55rem; }
}

.code-block { position: relative; }

.code-tools {
  position: absolute;
  top: 6px;
  right: 9px;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.45rem;
}

.copy-btn {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  white-space: normal;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 2px 8px;
  cursor: pointer;
  letter-spacing: 0.06em;
  opacity: 0;
  transition: opacity 0.2s, color 0.2s, border-color 0.2s;
}

.code-block:hover .copy-btn,
.copy-btn:focus-visible { opacity: 1; }

.copy-btn:hover { color: var(--green); border-color: var(--green); }
.copy-btn.is-copied { opacity: 1; color: var(--green-bright); border-color: var(--green-bright); }
.copy-btn.is-failed { opacity: 1; color: var(--red); border-color: var(--red); }

/* Touch devices have no hover — keep the button permanently visible */
@media (hover: none) {
  .copy-btn { opacity: 1; }
}

.code-lang {
  font-size: 0.62rem;
  color: var(--text-faint);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: var(--bg-main);
  padding: 0 0.3rem;
  pointer-events: none;
}

/* Blockquotes */
.writeup-body blockquote {
  border-left: 3px solid var(--amber-dim);
  padding: 0.6rem 1rem;
  margin-bottom: 1rem;
  background: var(--bg-surface);
  color: var(--text-dim);
  font-style: italic;
}

.writeup-body blockquote p { margin-bottom: 0.5rem; }
.writeup-body blockquote p:last-child { margin-bottom: 0; }

/* Images */
.writeup-figure {
  margin: 1.5rem 0;
}

.writeup-body img {
  max-width: 100%;
  height: auto;
  border: 1px solid var(--border);
  display: block;
}

.writeup-figure figcaption {
  font-size: 0.72rem;
  color: var(--text-faint);
  margin-top: 0.4rem;
  letter-spacing: 0.03em;
}

/* Tables — the render hook wraps each one in .table-wrap, which does the scrolling,
   so the table itself keeps normal table layout and full width. */
.table-wrap {
  overflow-x: auto;
  margin-bottom: 1.25rem;
  scrollbar-width: thin;
}

.writeup-body table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

.writeup-body th {
  text-align: left;
  padding: 0.5rem 0.8rem;
  border-bottom: 2px solid var(--border);
  color: var(--amber);
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.writeup-body td {
  padding: 0.45rem 0.8rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.writeup-body tr:hover td { background: var(--bg-surface); }

/* ── Two-column layout ────────────────────────────────────────────────────
   Below the breakpoint the contents frame simply stacks above the body. */

.writeup-layout > .writeup-col { min-width: 0; }

@media (min-width: 1100px) {
  .site-main--page { max-width: var(--wide-width); }

  .writeup-layout:has(> .toc),
  .writeup-layout:has(> .cs-side) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: 1.4rem;
    align-items: start;
  }

  .writeup-layout > .writeup-col { grid-column: 1; grid-row: 1; }

  .writeup-layout > .toc {
    grid-column: 2;
    grid-row: 1;
    position: sticky;
    top: 1.4rem;
  }

  .writeup-layout > .toc > .frame-body {
    max-height: calc(100vh - var(--statusbar-h) - 4rem);
    overflow-y: auto;
  }

  /* The masthead blocks sit outside the two-column split and run the full
     width, so their right edge lands on the contents rail's rather than
     stopping short of it. */
}

/* ── Prev / next ─────────────────────────────────────────────────────── */

.writeup-prevnext {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.4rem;
  border: 1px solid var(--border);
  background: var(--bg-main);
}

.prevnext-link {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.65rem 1.1rem;
  min-width: 0;
  color: var(--text-dim);
}

.prevnext-link.next { text-align: right; margin-left: auto; }
.prevnext-link:hover { background: var(--accent-deep); }
.prevnext-link:hover .prevnext-title { color: var(--accent-bright); }

.prevnext-label {
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.prevnext-title {
  font-size: 0.85rem;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Taxonomy pages ───────────────────────────────────────────────────── */

.term-cloud {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.term-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  border: 1px solid var(--border);
  padding: 0.15rem 0.5rem;
  font-size: 0.78rem;
  color: var(--text-dim);
}

.term-chip:hover {
  border-color: var(--accent);
  background: var(--accent-deep);
  color: var(--accent-bright);
}

.term-count {
  font-size: 0.68rem;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
}

.term-back { margin-top: 1.5rem; font-size: 0.78rem; color: var(--text-dim); }

/* ── Hugo syntax highlight overrides ───────────────────────────────────── */

.chroma { background: transparent; color: var(--text-primary); }
.chroma .c,
.chroma .ch,
.chroma .cm,
.chroma .c1,
.chroma .cs { color: var(--text-dim); font-style: italic; }
.chroma .k,
.chroma .kc,
.chroma .kd,
.chroma .kn,
.chroma .kp,
.chroma .kr { color: var(--green); }
.chroma .kt { color: var(--blue); }
.chroma .s,
.chroma .sa,
.chroma .sb,
.chroma .sc,
.chroma .s2,
.chroma .s1,
.chroma .sh,
.chroma .ss { color: var(--amber); }
.chroma .sr { color: var(--red); }
.chroma .si,
.chroma .sx { color: var(--amber-dim); }
.chroma .nb,
.chroma .bp { color: var(--blue); }
.chroma .nf,
.chroma .fm { color: var(--green-bright); }
.chroma .nc,
.chroma .nn { color: var(--blue); }
.chroma .no { color: var(--amber); }
.chroma .nt { color: var(--green); }
.chroma .na { color: var(--blue); }
.chroma .nv,
.chroma .vc,
.chroma .vg,
.chroma .vi { color: var(--text-primary); }
.chroma .o,
.chroma .ow { color: var(--text-dim); }
.chroma .m,
.chroma .mf,
.chroma .mh,
.chroma .mi,
.chroma .mo { color: var(--purple); }
.chroma .ge { font-style: italic; }

/* ── Status bar ───────────────────────────────────────────────────────────
   Pinned to the viewport. It carries what a stats strip used to take a whole
   band of the page for, plus the keys the site actually listens to. */

.site-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  align-items: stretch;
  height: var(--statusbar-h);
  background: var(--bg-main);
  border-top: 1px solid var(--border);
  font-size: 0.7rem;
  color: var(--text-dim);
  overflow: hidden;
}

.status-mode {
  display: flex;
  align-items: center;
  padding: 0 0.8rem;
  background: var(--accent);
  color: var(--bg-deep);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}

.status-seg {
  display: flex;
  align-items: center;
  padding: 0 0.9rem;
  border-right: 1px solid var(--border-soft);
  white-space: nowrap;
}

.status-seg b { color: var(--text-primary); font-weight: 400; }
.status-push { margin-left: auto; }

.status-keys {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0 0.9rem;
  color: var(--text-faint);
  white-space: nowrap;
}

.status-keys b { color: var(--amber); font-weight: 400; }
.site-footer a { color: inherit; }
.site-footer a:hover { color: var(--accent-bright); }

/* Narrow: the bar stops being fixed and the keybinding hints go — there is no
   keyboard to press them on, and a fixed bar eats a tenth of a phone screen. */
@media (max-width: 760px) {
  body { padding-bottom: 0; }

  .site-footer {
    position: static;
    height: auto;
    flex-wrap: wrap;
    padding: 0.35rem 0;
  }

  .status-seg { border-right: none; padding: 0.15rem 0.75rem; }
  .status-keys { display: none; }
  .status-push { margin-left: 0; }
}

/* ── Responsive ────────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  /* The columns stop earning their width. The row becomes a block and falls
     back to DOM order: name first, then the metadata on one line, then the
     summary and the tags. */
  .machine-head { display: none; }

  .machine-card {
    display: block;
    padding: 0.6rem 1rem;
  }

  .card-mark {
    display: inline-block;
    vertical-align: -0.55em;
    margin-right: 0.55rem;
  }
  .card-title { font-size: 0.95rem; }

  .card-diff,
  .card-os,
  .card-date { font-size: 0.72rem; }

  /* A newline before the metadata, so it starts under the name rather than
     trailing off the end of it. */
  .card-diff::before { content: '\A'; white-space: pre; }

  .card-diff::after,
  .card-os::after { content: ' · '; color: var(--border-focus); }

  .card-summary { margin-top: 0.25rem; }

  .card-tags {
    display: block;
    white-space: normal;
    margin-top: 0.2rem;
  }
}

@media (max-width: 600px) {
  body { font-size: 0.9rem; }
  .writeup-title { font-size: 1.25rem; }
  .filter-kbd { display: none; }
  .site-subtitle { display: none; }
  .writeup-head-grid { flex-direction: column; gap: 0.8rem; }
  .prevnext-link { max-width: 48%; }
}

/* ── Motion & contrast preferences ─────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .prompt-symbol { animation: none; }
}

@media (prefers-contrast: more) {
  :root {
    --text-dim: #d3dbe3;
    --text-faint: #aab6c1;
    --border: #55636f;
    --border-soft: #3c4854;
  }
}

/* ── Print ─────────────────────────────────────────────────────────────── */

@media print {
  body { background: #fff; color: #000; font-size: 11pt; padding-bottom: 0; }
  .site-header, .site-footer, .toc, .filter-bar,
  .writeup-prevnext, .writeup-nav, .copy-btn, .cs-copy-exports,
  .frame > .frame-legend, .frame > .frame-rlegend,
  .skip-link { display: none !important; }
  .site-main { max-width: none; padding: 0; }

  /* The frames are a screen device — on paper they become plain sections. */
  .frame { border: none; background: none; margin-bottom: 1rem; }
  .frame-body { padding: 0; }
  .writeup-layout { display: block !important; }

  .writeup-title, .writeup-body h1, .writeup-body h2,
  .writeup-body h3, .writeup-body h4 { color: #000; }
  .writeup-body h2::before, .writeup-body h3::before,
  .writeup-body h4::before { content: none; }
  .writeup-body pre, .writeup-body .highlight {
    background: #f4f4f4;
    border: 1px solid #ccc;
    white-space: pre-wrap;
    word-break: break-word;
  }
  /* Stripes are screen furniture; on paper they just eat toner. Keep the
     numbered gutter, which is the part that is useful in print. */
  pre .line, pre .line:nth-child(even) { background: transparent; }
  pre .line::before { color: #888; border-right-color: #ccc; }
  .writeup-body a { color: #000; }
  .writeup-body a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.85em; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   REFS — mirrored reference sets (/refs/)
   ═══════════════════════════════════════════════════════════════════════════ */

.refs-title {
  font-size: 1.3rem;
  font-weight: 400;
  color: var(--accent-bright);
  letter-spacing: 0.05em;
}

.refs-title .count { color: var(--amber); }

.refs-intro {
  color: var(--text-dim);
  font-size: 0.85rem;
  line-height: 1.7;
  margin-top: 0.6rem;
}

.refs-intro a { color: var(--green); }
.refs-intro a:hover { color: var(--green-bright); }

.refs-tagline {
  color: var(--text-dim);
  font-size: 0.85rem;
  margin-top: 0.4rem;
}

.refs-footnote {
  margin-top: 1.4rem;
  font-size: 0.72rem;
  color: var(--text-faint);
  line-height: 1.7;
}

.refs-footnote a { color: var(--blue); }

/* ── Hub cards ─────────────────────────────────────────────────────────── */

/* Two fixed columns: standalone lookup databases left, AllTheThings right.
   Collapses to a single stack below the breakpoint. */
.ref-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.9rem;
  align-items: start;
}

.ref-col {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

@media (max-width: 720px) {
  .ref-cards { grid-template-columns: 1fr; }
}

.ref-card-tag { color: var(--blue-dim); font-size: 0.68rem; }
.ref-card-tag:hover { color: var(--green-bright); }

.ref-card {
  position: relative;
  display: block;
  background: var(--bg-main);
  border: 1px solid var(--border);
  padding: 0.85rem 1rem;
  transition: border-color 0.15s, background 0.15s;
}

/* The title link covers the whole card, so the card is one click target —
   except for the scope-tag link, which is lifted back above it. */
.ref-card-name::after {
  content: '';
  position: absolute;
  inset: 0;
}

.ref-card-tag {
  position: relative;
  z-index: 1;
}

.ref-card:hover {
  background: var(--accent-deep);
  border-color: var(--border-focus);
}

.ref-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
}

.ref-card-name {
  font-size: 0.95rem;
  color: var(--accent);
  letter-spacing: 0.02em;
}

.ref-card:hover .ref-card-name { color: var(--green-bright); }

.ref-card-count {
  font-size: 0.72rem;
  color: var(--amber);
  white-space: nowrap;
}

.ref-card-tagline {
  margin-top: 0.45rem;
  font-size: 0.76rem;
  line-height: 1.6;
  color: var(--text-dim);
}

.ref-card-meta {
  margin-top: 0.7rem;
  font-size: 0.68rem;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.ref-card-licence.is-unlicensed,
.ref-source-licence.is-unlicensed { color: var(--red); }

/* ── Attribution banner ────────────────────────────────────────────────── */

.ref-source {
  background: var(--bg-main);
  border: 1px solid var(--border);
  padding: 0.7rem 1.1rem;
  margin-bottom: 1.4rem;
  font-size: 0.72rem;
  line-height: 1.65;
}

.ref-source-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
}

.ref-source-tag {
  color: var(--amber);
  letter-spacing: 0.05em;
}

.ref-source-name a {
  color: var(--green);
  font-weight: 500;
}

.ref-source-name a:hover { color: var(--green-bright); }
.ref-source-by { color: var(--text-faint); }

.ref-source-licence {
  margin-left: auto;
  color: var(--text-dim);
}

.ref-source-licence a { color: var(--text-dim); text-decoration: underline; }
.ref-source-licence a:hover { color: var(--text-primary); }

.ref-source-note {
  margin-top: 0.4rem;
  color: var(--text-faint);
}

.ref-source-note a { color: var(--blue); }

.ref-source-links {
  margin-top: 0.45rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  color: var(--text-faint);
}

.ref-source-links a { color: var(--blue-dim); }
.ref-source-links a:hover { color: var(--blue); }
.ref-sep { color: var(--border-focus); }
.ref-commit { color: var(--text-faint); }

/* ── Browse index (LOLBAS / GTFOBins / WADComs) ────────────────────────── */

.refs-browse { margin-top: 1.4rem; }

.filter-status-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0 1.1rem;
}

.ref-rows {
  list-style: none;
  border-top: 1px solid var(--border);
}

.ref-row {
  border-bottom: 1px solid var(--border-soft);
  padding: 0.45rem 1.1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
}

.ref-row:last-child { border-bottom: none; }
.ref-row:hover { background: var(--accent-deep); }

.ref-row-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.6rem;
  flex: 1 1 22rem;
  min-width: 0;
}

.ref-row-name {
  font-size: 0.85rem;
  color: var(--accent);
  white-space: nowrap;
}

.ref-row:hover .ref-row-name { color: var(--accent-bright); }

.ref-row-desc {
  font-size: 0.72rem;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
}

.ref-row-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-left: auto;
}

/* ── Chips ─────────────────────────────────────────────────────────────── */

.ref-chip {
  font-size: 0.63rem;
  padding: 0.12rem 0.45rem;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  color: var(--text-dim);
  letter-spacing: 0.04em;
  white-space: nowrap;
}

a.ref-chip:hover { border-color: var(--green); color: var(--green-bright); }

.ref-chip.is-key    { color: var(--green); border-color: rgba(143, 184, 126, 0.35); }
.ref-chip.is-mitre  { color: var(--purple); border-color: rgba(160, 144, 192, 0.35); }
.ref-chip.is-os     { color: var(--blue); border-color: rgba(126, 164, 192, 0.35); }
.ref-chip.is-attack { color: var(--amber); border-color: rgba(212, 191, 114, 0.35); }
.ref-chip.is-tool   { color: var(--text-dim); }

/* ── Section contents listing ──────────────────────────────────────────── */

.ref-children { margin-top: 2rem; }

.ref-children-title {
  font-family: var(--font-display);
  font-size: 0.8rem;
  color: var(--text-faint);
  letter-spacing: 0.06em;
  margin-bottom: 0.7rem;
}

.ref-children-title .count { color: var(--amber); }

.ref-children-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 0.3rem;
}

.ref-child a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  font-size: 0.78rem;
  color: var(--text-primary);
}

.ref-child a:hover {
  border-color: var(--green);
  color: var(--green-bright);
}

.ref-child.is-section .ref-child-name { color: var(--blue); }
.ref-child.is-section a:hover .ref-child-name { color: var(--green-bright); }
.ref-child-count { font-size: 0.65rem; color: var(--text-faint); }

/* ── Entry pages: shared blocks ────────────────────────────────────────── */

.refs-single .ref-block { margin-top: 2rem; }

.refs-single .ref-block > h2,
.gtfo-function-name {
  font-family: var(--font-mono);
  font-size: 1.05rem;
  color: var(--green);
  padding-bottom: 0.35rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.9rem;
  scroll-margin-top: 1.5rem;
}

.ref-links { list-style: none; }

.ref-links li {
  font-size: 0.75rem;
  padding: 0.2rem 0;
  overflow-wrap: anywhere;
}

.ref-links a { color: var(--blue); }
.ref-links a:hover { color: var(--green); }

/* Code blocks built by the refs layouts, rather than rendered from markdown.
   Mirrors the .writeup-body treatment so the copy button lands identically. */

.refs-single pre {
  background: var(--bg-main);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-focus);
  /* Horizontal padding is on the lines — see "Code lines" above */
  padding: 0.85rem 0;
  line-height: 1.6;
  font-size: 0.82rem;
  tab-size: 4;
  margin: 0.6rem 0;
  scrollbar-color: var(--border) var(--bg-main);
}

.refs-single pre code {
  font-size: inherit;
  background: none;
  border: none;
  padding: 0;
  color: var(--text-primary);
}

.refs-single :not(pre) > code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  padding: 0.1em 0.4em;
  color: var(--amber);
  overflow-wrap: anywhere;
}

.gtfo-intro { color: var(--text-dim); font-size: 0.85rem; }
.gtfo-intro p { margin-bottom: 0.6rem; }

/* ── GTFOBins ──────────────────────────────────────────────────────────── */

.gtfo-alias {
  font-size: 0.8rem;
  color: var(--text-dim);
  margin-bottom: 1rem;
}

.gtfo-alias a { color: var(--green); }

.gtfo-funcs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-bottom: 1.5rem;
}

.gtfo-function { margin-top: 2.25rem; }

.gtfo-function-desc {
  font-size: 0.8rem;
  color: var(--text-dim);
  margin-bottom: 0.9rem;
}

.gtfo-examples { list-style: none; }

.gtfo-example {
  border-left: 2px solid var(--border);
  padding-left: 0.9rem;
  margin-bottom: 1.5rem;
}

/* Context switcher — radio tabs, no JavaScript. Labels are ordered before the
   panels so a wrapping flex row keeps all tabs on one line. */

.gtfo-contexts {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.25rem;
}

.gtfo-tab-input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

.gtfo-tab {
  order: 1;
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  padding: 0.22rem 0.7rem;
  background: var(--bg-main);
  border: 1px solid var(--border);
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
}

.gtfo-tab:hover { border-color: var(--border-focus); color: var(--text-primary); }

.gtfo-tab-input:checked + .gtfo-tab {
  background: var(--bg-elevated);
  border-color: var(--green);
  color: var(--green-bright);
}

.gtfo-tab-input:focus-visible + .gtfo-tab {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.gtfo-panel {
  order: 2;
  width: 100%;
  display: none;
  margin-top: 0.5rem;
}

.gtfo-tab-input:checked + .gtfo-tab + .gtfo-panel { display: block; }

.gtfo-ctx-desc {
  font-size: 0.72rem;
  color: var(--text-faint);
  line-height: 1.6;
}

.gtfo-ctx-desc p { margin-bottom: 0.4rem; }
.gtfo-ctx-desc code { font-size: 0.9em; }

.gtfo-note {
  border: 1px solid var(--border);
  border-left: 2px solid var(--amber-dim);
  padding: 0.5rem 0.75rem;
  margin: 0.6rem 0;
  font-size: 0.73rem;
  color: var(--text-dim);
  line-height: 1.6;
}

.gtfo-note legend {
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: lowercase;
  color: var(--amber);
  padding: 0 0.35rem;
}

.gtfo-note p { margin-bottom: 0.35rem; }
.gtfo-note p:last-child { margin-bottom: 0; }
.gtfo-note a { color: var(--blue); }

/* ── LOLBAS ────────────────────────────────────────────────────────────── */

.lol-aliases, .lol-ack, .lol-os {
  font-size: 0.75rem;
  color: var(--text-dim);
  margin-top: 0.5rem;
}

.lol-aliases .label, .lol-ack .label, .lol-os .label { color: var(--text-faint); }

.lol-commands { list-style: none; }

.lol-command {
  border-left: 2px solid var(--border);
  padding-left: 0.9rem;
  margin-bottom: 1.6rem;
}

.lol-command-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-bottom: 0.5rem;
}

.lol-usecase {
  font-size: 0.82rem;
  color: var(--text-primary);
  margin-bottom: 0.4rem;
}

.lol-desc {
  font-size: 0.75rem;
  color: var(--text-dim);
  margin-top: 0.5rem;
  line-height: 1.6;
}

.lol-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.5rem;
}

.lol-detection { list-style: none; }

.lol-detection li {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.25rem 0;
  font-size: 0.75rem;
  color: var(--text-dim);
  overflow-wrap: anywhere;
}

.lol-detection a { color: var(--blue); }

/* ── WADComs ───────────────────────────────────────────────────────────── */

.wad-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-bottom: 1.2rem;
}

/* ── Search results (custom UI over the Pagefind JS API) ───────────────── */

.search-box {
  border-top: 1px solid var(--border-soft);
}

.search-box .search-tags {
  padding: 0.45rem 1.1rem;
  margin-top: 0;
}

.search-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.8rem;
}

.search-tags-label {
  font-size: 0.7rem;
  color: var(--text-faint);
  letter-spacing: 0.05em;
  margin-right: 0.15rem;
}

.search-tag { font-size: 0.68rem; }
.search-tag-clear { margin-left: 0.3rem; }

.search-results {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  margin-top: 1.4rem;
}

.search-result {
  border-top: 1px solid var(--border);
  padding-top: 0.9rem;
}

.search-result-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
}

.search-result-title {
  font-size: 0.9rem;
  color: var(--green);
}

.search-result-title:hover { color: var(--green-bright); }

.search-result-excerpt {
  margin-top: 0.3rem;
  font-size: 0.78rem;
  line-height: 1.65;
  color: var(--text-dim);
}

.search-result-excerpt mark,
.search-sub-excerpt mark {
  background: transparent;
  color: var(--amber);
  font-weight: 600;
}

.search-subs {
  margin-top: 0.5rem;
  border-left: 2px solid var(--border);
  padding-left: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.search-sub { display: block; }

.search-sub-title {
  font-size: 0.75rem;
  color: var(--blue);
  margin-right: 0.4rem;
}

.search-sub:hover .search-sub-title { color: var(--green-bright); }

.search-sub-excerpt {
  font-size: 0.72rem;
  color: var(--text-faint);
}

@media (max-width: 640px) {
  .ref-row-tags { margin-left: 0; width: 100%; }
  .ref-source-licence { margin-left: 0; }
}

/* ── Search scope tags ─────────────────────────────────────────────────── */

.search-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  margin-top: 1.25rem;
}

.search-tags-label {
  font-size: 0.7rem;
  color: var(--text-faint);
  letter-spacing: 0.05em;
  margin-right: 0.15rem;
}

.search-tag { font-size: 0.68rem; }
.search-tag-clear { margin-left: 0.3rem; }

/* Inline code in intro/lede paragraphs (e.g. the "#gtfo sudo" example). */
.refs-intro code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  padding: 0.05em 0.35em;
  color: var(--amber);
}

/* Hand-written /refs/ sections: green accent, so "mine" reads differently
   from the amber "mirrored" banner at a glance. */
.ref-source.is-local {
  border-left-color: var(--green);
}

.ref-source.is-local .ref-source-tag { color: var(--green); }
.ref-source.is-local .ref-source-licence a { color: var(--blue-dim); }

.ref-card.is-local { border-color: var(--accent-deep); }
.ref-card.is-local .ref-card-name::before { content: '~/'; color: var(--text-faint); }
.ref-card.is-local .ref-card-licence { color: var(--text-faint); }

/* ── Reverse shell generator ───────────────────────────────────────────── */

.rsg-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--green);
  margin-bottom: 1.5rem;
  position: sticky;
  top: 0;
  z-index: 5;
}

.rsg-field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.rsg-label {
  font-size: 0.65rem;
  color: var(--text-faint);
  letter-spacing: 0.06em;
}

.rsg-field input,
.rsg-field select,
.rsg-listener select {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  color: var(--text-primary);
  padding: 0.3rem 0.5rem;
}

.rsg-field input:focus,
.rsg-field select:focus,
.rsg-listener select:focus {
  border-color: var(--green);
  outline: none;
}

#rsg-ip { width: 11rem; }
#rsg-port { width: 6rem; }

.rsg-controls .filter-clear { margin-left: auto; align-self: center; }

.rsg-listener {
  margin-bottom: 1.75rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--amber-dim);
  padding: 0.75rem 1rem 0.9rem;
  background: var(--bg-main);
}

.rsg-listener-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 0.6rem;
}

.rsg-listener-head h2 {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--amber);
  letter-spacing: 0.06em;
  border: none;
  margin: 0;
  padding: 0;
}

.rsg-filter { margin-bottom: 1.5rem; }

.rsg-group { margin-bottom: 2.25rem; }

.rsg-group-name {
  font-family: var(--font-mono);
  font-size: 1rem;
  color: var(--green);
  padding-bottom: 0.35rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1rem;
  scroll-margin-top: 5rem;
}

.rsg-group-name .count { color: var(--amber); font-size: 0.8rem; }

.rsg-cmd { margin-bottom: 1.1rem; }

.rsg-cmd-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  margin-bottom: 0.35rem;
}

.rsg-cmd-name {
  font-size: 0.82rem;
  color: var(--text-primary);
}

/* These payloads run long — cap the tall ones so the page stays navigable. */
.rsg-cmd pre {
  max-height: 22rem;
  overflow: auto;
}

@media (max-width: 640px) {
  .rsg-controls { position: static; }
  #rsg-ip, #rsg-port { width: 100%; }
  .rsg-field { flex: 1 1 8rem; }
}

/* ── Cheatsheet ────────────────────────────────────────────────────────────
   Variables panel, the export block you paste into a fresh terminal, and the
   command list. The code blocks themselves are the shared .line/.cl shape, so
   only the surrounding furniture is styled here. */

.cs-section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 0.6rem;
}

.cs-section-title {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--green);
  letter-spacing: 0.06em;
  border: none;
  margin: 0;
  padding: 0;
}

.cs-set-count {
  font-size: 0.68rem;
  color: var(--text-faint);
}

.cs-section-head .filter-clear { margin-left: auto; }

.cs-vars {
  border: 1px solid var(--border);
  border-left: 3px solid var(--green);
  background: var(--bg-surface);
  padding: 0.9rem 1rem 1rem;
  margin-bottom: 1.25rem;
}

.cs-hint {
  font-size: 0.72rem;
  color: var(--text-faint);
  line-height: 1.6;
  margin: 0 0 0.9rem;
}

.cs-vargroup {
  border: none;
  border-top: 1px solid var(--border);
  padding: 0.7rem 0 0;
  margin: 0 0 0.5rem;
}

.cs-vargroup:first-of-type { border-top: none; padding-top: 0; }

.cs-vargroup-label {
  font-size: 0.65rem;
  color: var(--amber);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0 0 0.4rem;
}

.cs-vargroup-note {
  font-size: 0.68rem;
  color: var(--text-faint);
  margin: 0 0 0.5rem;
}

/* Four across at full width, then as many as fit. The minimum is wide enough
   for a hash without the field turning into a slit. */
.cs-vargrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.55rem 0.7rem;
}

/* `wide: true` on a vargroup — paths do not fit in an 11rem box */
.cs-vargrid.is-wide { grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); }

/* `cols: 4` — the creds groups read as rows of USER/PASS/HASH/AUTH, so they get
   a fixed count rather than however many auto-fill decides will fit. */
.cs-vargrid.is-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 900px) {
  .cs-vargrid.is-cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.cs-var {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

/* `span: 2` on a var — a path needs more than one 11rem column */
.cs-var.is-span-2 { grid-column: span 2; }

.cs-var-name {
  font-size: 0.63rem;
  color: var(--text-faint);
  letter-spacing: 0.06em;
}

.cs-var-input {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  width: 100%;
  min-width: 0;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  color: var(--text-primary);
  padding: 0.3rem 0.45rem;
}

.cs-var-input:focus {
  border-color: var(--green);
  outline: none;
}

/* A value present is the signal you scan the panel for — mark it on the field
   itself rather than making you read every box. The class comes from the JS
   rather than :placeholder-shown, which never matches on the fields that have
   no placeholder to show and so marked every empty one. */
.cs-var-input.is-set {
  color: var(--green-bright);
  border-color: var(--border-focus);
}

.cs-var-note {
  font-size: 0.62rem;
  color: var(--text-faint);
}

.cs-export {
  border: 1px solid var(--border);
  border-left: 3px solid var(--amber-dim);
  background: var(--bg-main);
  padding: 0.85rem 1rem 0.9rem;
  margin-bottom: 1.75rem;
}

.cs-export .cs-section-title { color: var(--amber); }

.cs-filter { margin-bottom: 1.5rem; }

.cs-group { margin-bottom: 2.25rem; }

.cs-group-name {
  font-family: var(--font-mono);
  font-size: 1rem;
  color: var(--green);
  padding-bottom: 0.35rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1rem;
  scroll-margin-top: 5rem;
  /* The privileges page names its groups SeDelegateSessionUserImpersonatePrivilege;
     at phone width that one word is wider than the screen. */
  overflow-wrap: anywhere;
}

.cs-group-name .count { color: var(--amber); font-size: 0.8rem; }

.cs-group-note {
  font-size: 0.72rem;
  color: var(--text-faint);
  line-height: 1.6;
  margin: -0.5rem 0 1rem;
}

.cs-cmd { margin-bottom: 1.1rem; }

.cs-cmd-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.3rem;
}

.cs-cmd-name {
  font-size: 0.82rem;
  color: var(--text-primary);
  overflow-wrap: anywhere;
}

/* Pointer to the long version of a command — a script on the notes page, an
   upstream reference. Sits on the head row, after the name. */
.cs-cmd-link {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--amber-dim);
  border-bottom: 1px dotted var(--amber-dim);
}

.cs-cmd-link:hover { color: var(--green); border-bottom-color: var(--green); }

/* ── A command entry that is a door, not a block ───────────────────────────
   `button:` in the data. Deliberately looks like the copy-exports button in
   the rail rather than like a code block, because it is the one thing in the
   list you click instead of copy. */

.cs-cmd-button {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  background: var(--bg-main);
  border: 1px solid var(--amber-dim);
  color: var(--amber);
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}

.cs-cmd-button::after {
  content: ' ↗';
  color: var(--text-faint);
}

.cs-cmd-button:hover {
  color: var(--bg-deep);
  background: var(--amber);
  border-color: var(--amber);
}

.cs-cmd-button:hover::after { color: var(--bg-deep); }

/* Which variables this command wants and does not have yet */
.cs-needs {
  font-size: 0.63rem;
  color: var(--amber-dim);
  border: 1px solid var(--amber-dim);
  padding: 1px 6px;
  letter-spacing: 0.04em;
}

.cs-cmd-note {
  font-size: 0.7rem;
  color: var(--text-faint);
  line-height: 1.6;
  margin: 0 0 0.35rem;
}

/* ── Folded command block ──────────────────────────────────────────────────
   For the entries carrying collapsed: true in data/cheatsheet/ — one-off
   setup you run once and then never again. The summary is the only thing on
   the page until you ask for it; main.js opens the fold when a filter matches
   what is inside, so the block stays searchable. */

.cs-fold { margin: 0; }

.cs-fold-summary {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--amber-dim);
  cursor: pointer;
  list-style: none;
  display: inline-block;
  border: 1px solid var(--border);
  padding: 2px 8px;
}

.cs-fold-summary::-webkit-details-marker { display: none; }

.cs-fold-summary::before {
  content: '▸ ';
  color: var(--text-faint);
}

.cs-fold[open] > .cs-fold-summary::before {
  content: '▾ ';
  color: var(--green);
}

.cs-fold-summary:hover {
  color: var(--green);
  border-color: var(--border-focus);
}

.cs-fold[open] > .cs-fold-summary { margin-bottom: 0.35rem; }

/* ── Cheatsheet side nav ───────────────────────────────────────────────────
   Built on .toc, so it inherits the sticky two-column placement. The one thing
   it adds is a tree: a group's commands are revealed by scrolling into that
   group or hovering it, never by clicking, so ~100 links stay scannable. */

.cs-toc .cs-toc-sub {
  display: none;
  padding-left: 0.9rem;
  border-left: 1px solid var(--border);
  margin-left: 0.2rem;
}

/* Only the group you are scrolled into opens. Hover used to open one too, which
   made the list unusable: opening a group pushes everything below it down, so
   moving the cursor down the nav slid the next item out from under it, which
   opened another group, and so on. Nothing here reflows while you aim at it —
   the list only changes when you scroll the page, which is not when you are
   trying to hit a link. */
.cs-toc li.is-current > .cs-toc-sub { display: block; }

/* Filtering is the exception — the nav is pruned to the matches by then, and
   they are spread across groups, so everything opens. */
.cs-toc.is-filtering .cs-toc-sub { display: block; }

.cs-toc .cs-toc-sub a {
  font-size: 0.72rem;
  color: var(--text-faint);
}

.cs-toc .cs-toc-sub a:hover { color: var(--green); }

/* With hover gone, the marker is the only thing saying a group has commands
   under it. :has() is already relied on elsewhere in this file. */
.cs-toc > nav > ul > li:has(.cs-toc-sub) > a::before {
  content: '▸ ';
  color: var(--text-faint);
}

.cs-toc > nav > ul > li.is-current:has(.cs-toc-sub) > a::before,
.cs-toc.is-filtering > nav > ul > li:has(.cs-toc-sub) > a::before {
  content: '▾ ';
  color: var(--green);
}

/* The group heading stays the emphasised line even when a command inside it is
   the current one — otherwise two entries fight for the eye. */
.cs-toc > nav > ul > li > a { color: var(--text-dim); }
.cs-toc > nav > ul > li.is-current > a {
  color: var(--green-bright);
  border-left-color: var(--green);
  background: var(--bg-surface);
}

.cs-toc .cs-toc-sub li.is-current > a {
  color: var(--green);
  border-left-color: var(--border-focus);
}

.cs-group,
.cs-cmd { scroll-margin-top: 1.5rem; }

/* ── Cheatsheet side rail ──────────────────────────────────────────────────
   Wraps the copy-exports button and the nav, and takes over the sticky
   placement from .toc so both ride along. Unlike the .copy-btn on a code block
   this one never fades out — it exists precisely for the point where the export
   block is off screen, so there is nothing to hover to reveal it. */

.cs-copy-exports {
  display: block;
  width: 100%;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-align: left;
  background: var(--bg-main);
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.6rem;
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s;
}

.cs-copy-exports::before {
  content: '⧉ ';
  color: var(--amber);
}

.cs-copy-exports:hover { color: var(--accent); border-color: var(--accent); }
.cs-copy-exports.is-copied { color: var(--accent-bright); border-color: var(--accent-bright); }
.cs-copy-exports.is-failed { color: var(--red); border-color: var(--red); }

/* Nav on the right, same side as the writeups and the mirrored refs entries.
   Three explicit placements rather than the usual two, because the header is
   inside the grid here — that is what lets the nav start level with the title
   rather than below the whole masthead. Below the breakpoint none of this
   applies: the layout is plain block flow in DOM order, so the collapsed
   contents bar sits after the header. */
@media (min-width: 1100px) {
  .cheatsheet .writeup-layout .cs-head { grid-column: 1; grid-row: 1; }
  .cheatsheet .writeup-layout .writeup-col { grid-column: 1; grid-row: 2; }

  /* The rail is the grid item and the sticky one; the nav inside it goes back
     to static and does the internal scrolling, so a long contents list cannot
     push the button off the viewport. */
  .cheatsheet .writeup-layout .cs-side {
    grid-column: 2;
    grid-row: 1 / span 2;
    position: sticky;
    top: 1.4rem;
    max-height: calc(100vh - var(--statusbar-h) - 2.8rem);
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  /* relative, not static: the frame legend is absolutely positioned against
     this box, and a static one hands it up to the sticky rail — which parks
     "contents" on top of the copy button. */
  .cheatsheet .writeup-layout .cs-side .toc {
    position: relative;
    min-height: 0;
    max-height: none;
    margin-bottom: 0;
  }
}

@media (max-width: 640px) {
  .cs-vargrid { grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); }
  /* Two narrow columns is already as wide as the panel gets */
  .cs-var.is-span-2 { grid-column: span 2; }
}

/* ── Cheatsheet phases ─────────────────────────────────────────────────────
   One per file under data/cheatsheet/. The phase is the step of the box you
   are on, so it reads as the loudest heading in the list; groups sit under it. */

.cs-phase { margin-bottom: 3rem; scroll-margin-top: 1.5rem; }

.cs-phase-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.15rem;
  color: var(--amber);
  letter-spacing: 0.04em;
  margin: 0 0 0.35rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--amber);
  background: var(--bg-surface);
}

.cs-phase-name::before { content: '# '; color: var(--text-faint); }

.cs-phase-note {
  font-size: 0.74rem;
  color: var(--text-dim);
  line-height: 1.6;
  margin: 0 0 1.4rem;
}

/* Second level of the nav — the groups inside a phase */
.cs-toc .cs-toc-sub .cs-toc-sub { padding-left: 0.7rem; }
.cs-toc > nav > ul > li > .cs-toc-sub > li > a { font-size: 0.75rem; color: var(--text-dim); }
.cs-toc > nav > ul > li > .cs-toc-sub > li.is-current > a { color: var(--green-bright); }

/* ── OSCP mode ─────────────────────────────────────────────────────────────
   The box in the filter bar, and the tags on the commands it acts on. */

.cs-oscp {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--text-dim);
  cursor: pointer;
}

.cs-oscp input { accent-color: var(--amber); margin: 0; }
.cs-oscp:has(input:checked) { color: var(--amber); }

.cs-oscp-tag {
  font-size: 0.63rem;
  padding: 1px 6px;
  letter-spacing: 0.04em;
  border: 1px solid currentColor;
}

.cs-oscp-tag.is-banned { color: var(--red); }
.cs-oscp-tag.is-limited { color: var(--amber-dim); }

/* ── Exam weight ───────────────────────────────────────────────────────────
   `exam:` on a group in the bloodhound data — how often that edge turns up on
   the OSCP. Sits on the group heading, so the A–Z list still reads as a study
   order: likely is the loud one, none is barely there. */

.cs-exam-tag {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 0.6rem;
  letter-spacing: 0.06em;
  padding: 1px 6px;
  margin-left: 0.6rem;
  border: 1px solid currentColor;
  vertical-align: middle;
}

.cs-exam-tag.is-likely   { color: var(--green-bright); }
.cs-exam-tag.is-possible { color: var(--amber); }
.cs-exam-tag.is-rare     { color: var(--text-dim); }
.cs-exam-tag.is-none     { color: var(--text-faint); border-style: dotted; }

/* ── Acting as ─────────────────────────────────────────────────────────────
   `roles` in a page's vars.yaml — the chip row that points $ME and friends at
   a cred slot. Same chips as the show: toggle. The readout after them says
   who the pick resolves to right now, which is the thing you actually want to
   know before copying a command. */

.cs-roles-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.cs-roles-as {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--green-bright);
  margin-left: 0.5rem;
}

.cs-roles-as.is-empty { color: var(--amber-dim); }

/* ── Cheatsheet nav height ─────────────────────────────────────────────────
   The list changes height as you scroll: a group's commands open and the one
   above closes. Two problems follow from that, and one cap fixes both.

   Below the two-column breakpoint the rail is in normal flow *above* the
   commands, so a height change moves the whole page under the reader — which
   moves what the spy reads as current, which changes the height again. Pinning
   the box to a fixed height and scrolling inside it breaks that loop.

   On wide screens the rail is sticky and cannot move the content, so a cap is
   enough; without one a tall phase spills out past the bottom of the rail with
   no way to reach it. */

.cs-toc > nav {
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

@media (max-width: 1099px) {
  .cs-toc > nav { height: 50vh; }
}

@media (min-width: 1100px) {
  /* Leaves room for the copy button above and the "contents" legend. */
  .cs-toc > nav { max-height: calc(100vh - var(--statusbar-h) - 9rem); }
}

/* ── Exam tracker ──────────────────────────────────────────────────────────
   /refs/notes/exam/ — layouts/refs/tracker.html. Reuses the cheatsheet's
   panel inputs and section heads; the only new shapes are the clock row, the
   score strip and the grid of box cards. */

.tr-clock-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.6rem;
  margin-bottom: 0.8rem;
}

.tr-start { display: flex; flex-direction: column; gap: 0.2rem; }
.tr-start .cs-var-input { width: auto; color-scheme: dark; }
.tr-clock-row .filter-clear { margin-left: auto; }
.tr-times { margin-bottom: 0.6rem; }
.tr-times dd.is-late { color: var(--amber); }
.tr-times dd.is-over { color: var(--red); }
.tr-clock .cs-hint { margin: 0; }

/* The score strip: amber while you are short, the accent once you would pass
   if the exam ended now. */
.tr-score {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 1rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--amber);
  background: var(--bg-surface);
  padding: 0.7rem 1rem;
  margin-bottom: 1.6rem;
  font-size: 0.78rem;
  color: var(--text-dim);
}

.tr-score.is-pass { border-left-color: var(--green); }
.tr-score-points { font-size: 1rem; color: var(--text-primary); }
.tr-score-points b { color: var(--amber); font-weight: 500; font-size: 1.5rem; }
.tr-score.is-pass .tr-score-points b { color: var(--green-bright); }
.tr-score-state { color: var(--text-primary); }
.tr-score-detail { font-size: 0.7rem; color: var(--text-faint); }
.tr-score .tr-copy { margin-left: auto; }
.tr-score .tr-passnote { flex-basis: 100%; margin: 0.2rem 0 0; }

.tr-set { margin-bottom: 2rem; }

.tr-boxes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  gap: 1.2rem 1rem;
  margin-top: 1rem;
}

.tr-box { margin-bottom: 0; }
.tr-box.is-done { border-color: var(--border-focus); }
.tr-box.is-done > .frame-legend { color: var(--green-bright); }
.tr-box .frame-body { padding: 1rem 0.9rem 0.8rem; }
.tr-name { margin-bottom: 0.6rem; }

.tr-steps {
  list-style: none;
  margin: 0 0 0.6rem;
  padding: 0;
  font-size: 0.74rem;
}

.tr-step label {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.22rem 0;
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
  color: var(--text-dim);
}

.tr-step:last-child label { border-bottom: none; }
.tr-step label:hover { color: var(--text-primary); }
.tr-step input { accent-color: var(--green); margin: 0; }
.tr-step.is-done .tr-step-label { color: var(--green-bright); }
.tr-when { font-size: 0.66rem; color: var(--amber-dim); white-space: nowrap; }
.tr-notes { resize: vertical; font-size: 0.72rem; min-height: 2.6rem; }
