/* ==================================================================
   anyvm.org

   Direction: "Coverage".
   The subject is a tool that makes 17 operating systems boot on 7 CPU
   architectures. The most characteristic artifact in that world is the
   coverage matrix itself, so it is the hero, not a table further down.

   Palette rule: colour carries meaning and nothing else. The four hues
   encode operating-system lineage (BSD / illumos / Linux / research).
   Buttons, links and focus rings stay neutral so that a coloured cell
   always means exactly one thing.

   No build step, no external resources, no framework. Pure 7-bit ASCII.
   ================================================================== */

/* ---------- 1. Tokens ---------- */

:root {
  /* Ground: blueprint ink, never neutral black. */
  --ink:    #0a1922;
  --ink-2:  #122a38;
  --ink-3:  #16323f;
  --rule:   #1e4055;
  --chalk:  #e9f1f5;
  --haze:   #86a3b4;

  /* Lineage hues. Still used for the accents outside the matrix. */
  --fam-bsd:      #ff7a59;
  --fam-illumos:  #35c4e0;
  --fam-linux:    #f5c451;
  --fam-research: #b693f0;

  /* ---- Per-guest brand colours ----------------------------------------
     Each one was sampled from that project's OWN site or logo, not from
     memory. The comment records where, so a future edit can re-check it.

     Several are lifted in luminance from the published value: the source
     colour was chosen for a white page and would sit at 2:1 or less against
     this ink ground, which is under the 3:1 that non-text UI needs. The hue
     is kept; only the lightness moves.

     Four projects publish no palette at all -- MidnightBSD's logo is a plain
     outline, NextBSD's site is greyscale, the Hurd logo is monochrome, and
     9front uses the stock werc theme. Those are marked DERIVED and are not
     presented anywhere as official. */

  --os-freebsd:     #e2504a;  /* freebsd.org main.min.css #ab2b28, lifted */
  --os-openbsd:     #e05434;  /* openbsd.org --red, dark-theme value, as-is */
  --os-netbsd:      #f2551b;  /* netbsd.org global.css #d43900, lifted */
  --os-dragonfly:   #cfff22;  /* logo disc, small_logo.png, as-is */
  --os-midnightbsd: #7d88de;  /* DERIVED -- no published palette */
  --os-ghostbsd:    #22bcd4;  /* site logo ghostbsd.png #009cb5, lifted */
  --os-nextbsd:     #93a0b8;  /* DERIVED -- site is greyscale */
  --os-solaris:     #e05a48;  /* oracle.com #c74634, lifted */
  --os-omnios:      #ff8f00;  /* omnios.org app.css, as-is */
  --os-openindiana: #95d834;  /* oibird.svg, as-is */
  --os-tribblix:    #3fae3f;  /* tribblix.css #006600, lifted hard */
  --os-ubuntu:      #e95420;  /* ubuntu.com styles.css, as-is */
  --os-openeuler:   #5b8cf0;  /* official logo png #204bb9, lifted */
  --os-blissos:     #0080ff;  /* blissos.org neon.css, as-is */
  --os-haiku:       #ff9c00;  /* haiku-os.org accent, as-is */
  --os-hurd:        #a48fd0;  /* DERIVED -- logo is monochrome */
  --os-plan9:       #ffd324;  /* 9front.org style.css, as-is */

  /* Page surfaces (light is the default document). */
  --bg:      #ffffff;
  --bg-2:    #f2f6f8;
  --bg-3:    #e7eef2;
  --line:    #d8e3e9;
  --line-2:  #bccbd4;
  --fg:      #0a1922;
  --fg-2:    #4f6b7a;
  --fg-3:    #5d7a89;   /* 4.56:1 on white -- the lightest text allowed */

  /* Lineage hues, darkened for the paper ground. */
  --fam-bsd-p:      #d1492a;
  --fam-illumos-p:  #10798f;
  --fam-linux-p:    #96700a;
  --fam-research-p: #6f45b8;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;

  --r:    6px;
  --r-lg: 10px;
  --wrap: 1140px;
  /* Cell pitch of the hero matrix. Sized so the figure stands as tall as the
     headline column beside it -- it is the hero's other half, not a footnote
     to it. Reduced on narrow screens where it stacks underneath instead. */
  --cell: 33px;
}

/* Dark surfaces. Applied on two paths that must stay in step:
     1. the system asks for dark AND the reader has not forced light;
     2. the reader explicitly chose dark.
   The block is duplicated rather than shared because a media query cannot be
   combined with an attribute selector in one rule. If you edit one, edit the
   other -- they are the same palette. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:     #0a1922;
    --bg-2:   #0e222d;
    --bg-3:   #122a38;
    --line:   #1b3a4b;
    --line-2: #27546b;
    --fg:     #e9f1f5;
    --fg-2:   #9ab5c4;
    --fg-3:   #6d8b9c;

    --fam-bsd-p:      #ff7a59;
    --fam-illumos-p:  #35c4e0;
    --fam-linux-p:    #f5c451;
    --fam-research-p: #b693f0;
  }
}

:root[data-theme="dark"] {
  --bg:     #0a1922;
  --bg-2:   #0e222d;
  --bg-3:   #122a38;
  --line:   #1b3a4b;
  --line-2: #27546b;
  --fg:     #e9f1f5;
  --fg-2:   #9ab5c4;
  --fg-3:   #6d8b9c;

  --fam-bsd-p:      #ff7a59;
  --fam-illumos-p:  #35c4e0;
  --fam-linux-p:    #f5c451;
  --fam-research-p: #b693f0;
}

/* ---------- 2. Base ---------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 76px;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0 0 0.5em; line-height: 1.2; font-weight: 640; }

h1 {
  font-size: clamp(2.3rem, 1.5rem + 3vw, 3.7rem);
  letter-spacing: -0.038em;
}
h2 { font-size: clamp(1.45rem, 1.2rem + 1vw, 1.95rem); letter-spacing: -0.025em; }
h3 { font-size: 1.06rem; letter-spacing: -0.012em; }

p { margin: 0 0 1rem; }

/* Links stay neutral. Colour is reserved for lineage. */
a { color: inherit; text-decoration: underline; text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    text-decoration-color: var(--line-2); }
a:hover { text-decoration-color: currentColor; }

code, kbd, samp, pre { font-family: var(--mono); }

:not(pre) > code {
  background: var(--bg-3);
  border-radius: 4px;
  padding: 0.12em 0.36em;
  font-size: 0.84em;
  white-space: nowrap;
}

:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 3px; }

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

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: 12px; top: 12px; z-index: 100;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--line-2); border-radius: var(--r);
  padding: 8px 14px; text-decoration: none;
}

/* The utility face: monospace carries every label, count and axis. */
.mono, .eyebrow, .axis, .cov-os, .tag, .crumbs, .pill, .copy, .term-title {
  font-family: var(--mono);
}

/* ---------- 3. Nav ---------- */

.nav {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--line);
}
.nav-in {
  max-width: var(--wrap); margin: 0 auto; padding: 0 24px;
  height: 56px; display: flex; align-items: center; gap: 22px;
}
.brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 640; letter-spacing: -0.02em; flex: none;
  text-decoration: none;
}
.brand svg { display: block; }
/* The wordmark has to be ONE flex item. Left as a bare text node, the
   brand's flex gap would land inside the name and split it in half. */
.brand .wordmark { white-space: nowrap; }
.nav-links {
  display: flex; align-items: center; gap: 20px;
  margin-left: auto; font-size: 0.9rem;
}
.nav-links a { color: var(--fg-2); text-decoration: none; }
.nav-links a:hover { color: var(--fg); }
.nav-links a.on { color: var(--fg); font-weight: 550; }

/* ---- Bilingual copy ------------------------------------------------
   Both languages sit in the markup and CSS picks one. The alternative --
   swapping strings in from a JS dictionary -- makes the copy unreadable in
   the file it belongs to and leaves a JS-less visitor with an empty page.
   This way the source reads as prose in both languages, and with scripting
   off the page is still a complete document in the default language.

   Cost, stated plainly: every string ships twice, so the HTML is roughly
   double the size. For a static page with no images that is a few KB.

   The doubled [lang][lang] is deliberate. A single attribute selector scores
   the same as a class, so component rules further down the file -- .eyebrow
   and .tag both set display -- were winning on source order and leaking five
   Chinese nodes into the English page. Doubling it outranks them. */
[lang="zh"][lang] { display: none; }
:root[data-lang="zh"] [lang="zh"][lang] { display: revert; }
:root[data-lang="zh"] [lang="en"][lang] { display: none; }

/* The switch shows the language you would move TO, not the current one. */
.lang-toggle .when-zh { display: none; }
:root[data-lang="zh"] .lang-toggle .when-en { display: none; }
:root[data-lang="zh"] .lang-toggle .when-zh { display: inline; }

.lang-toggle { display: none; }
.js .lang-toggle {
  display: inline-flex;
  align-items: center; justify-content: center;
  height: 32px; min-width: 32px; padding: 0 8px; flex: none;
  appearance: none; cursor: pointer;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--fg-2);
  font-family: var(--mono);
  font-size: 0.78rem;
  line-height: 1;
}
.lang-toggle:hover { color: var(--fg); border-color: var(--line-2); }

/* ---- Theme switch -------------------------------------------------
   Hidden until the inline head script adds .js: without JS the control
   cannot do anything, and a dead button is worse than no button. The page
   still follows the system preference in that case. */
.theme-toggle { display: none; }
.js .theme-toggle {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 32px; height: 32px; flex: none;
  appearance: none; cursor: pointer;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--fg-2);
}
.theme-toggle:hover { color: var(--fg); border-color: var(--line-2); }
.theme-toggle svg { display: block; }

/* Show the icon for the mode you would switch TO. Light page -> moon. */
.theme-toggle .sun { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .moon { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .sun  { display: block; }
}
:root[data-theme="dark"] .theme-toggle .moon { display: none; }
:root[data-theme="dark"] .theme-toggle .sun  { display: block; }
:root[data-theme="light"] .theme-toggle .moon { display: block; }
:root[data-theme="light"] .theme-toggle .sun  { display: none; }

@media (max-width: 720px) {
  .nav-links { gap: 14px; font-size: 0.84rem; }
  .nav-links .opt { display: none; }
}

/* Under ~440px the nav cannot hold four items beside the wordmark without
   pushing the whole page into horizontal scroll. Drop the two in-page jumps
   -- they only target sections of the landing page -- and keep Docs and
   GitHub, which are the actual destinations. */
@media (max-width: 440px) {
  .nav-links { gap: 12px; }
  .nav-links a:nth-child(1),
  .nav-links a:nth-child(2) { display: none; }
}

/* ---------- 4. Buttons: neutral by design ---------- */

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 18px;
  border: 1px solid var(--line-2); border-radius: var(--r);
  font-weight: 550; font-size: 0.94rem;
  color: var(--fg); background: var(--bg);
  text-decoration: none;
  transition: border-color .14s, background .14s;
}
.btn:hover { border-color: var(--fg); }
.btn-solid { background: var(--fg); border-color: var(--fg); color: var(--bg); }
.btn-solid:hover { filter: brightness(1.15); border-color: var(--fg); }

/* ---------- 5. Hero ---------- */

.hero {
  background: var(--ink);
  color: var(--chalk);
  border-bottom: 1px solid var(--rule);
  position: relative;
  overflow: hidden;
}

/* Drafting grid. Quiet enough to read as paper texture, not decoration. */
.hero::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, rgba(134, 163, 180, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(134, 163, 180, 0.05) 1px, transparent 1px);
  background-size: 28px 28px;
  mask-image: radial-gradient(120ch 60ch at 30% 0%, #000 35%, transparent 78%);
  pointer-events: none;
}

/* ---------- 5a. The guest roll ----------
   The 17 guest names scattered across the hero ground. Placed by hand rather
   than randomly: real randomness collides and reads as noise. Sizes are in em
   so one font-size on the container rescales the whole field for small
   screens. Deliberately colourless -- hue stays reserved for lineage. */

.hero-names {
  position: absolute; inset: 0;
  overflow: hidden;
  pointer-events: none;
  user-select: none;
  font-family: var(--mono);
  font-size: 1rem;
  color: var(--haze);
  letter-spacing: -0.02em;
  white-space: nowrap;
}
/* POSITIONS COME FROM site.js, NOT FROM HERE, and that is deliberate.

   The foreground is a fixed-width centred column; this layer spans the full
   bleed. The two respond to a viewport change differently, so any percentage
   layout that clears the text at one width slides underneath it at another
   (verified: a set solved at 1440px put six names under the type at 1280px).
   site.js measures the real foreground boxes and solves the placement on
   load and on resize, which is the only way to hold "never overlaps" across
   every width. The scatter is re-randomised per page load but stable within
   one, so a reload rearranges the field while a resize does not.

   Size and weight stay here because they are design decisions. Opacity runs
   INVERSE to size: a big name covers a lot of ground, so it has to be
   fainter than a small one for the field to read evenly. The .18 ceiling is
   the accessibility limit -- body text sitting directly on a name still
   measures 5.0:1 there, and 0.20 would drop it to 4.79, under AA.

   Without JS the layer stays hidden. It is pure decoration, so an absent
   background costs nothing; a background sitting on top of the headline
   would cost plenty. */
.hero-names {
  opacity: 0;
  transition: opacity .5s ease;
}
.hero-names.ready { opacity: 1; }

.hero-names span { position: absolute; top: -9999px; opacity: .16; }

.hero-names span:nth-child(1)  { font-size: 3.10em; opacity: .13; } /* FreeBSD */
.hero-names span:nth-child(2)  { font-size: 1.50em; opacity: .18; } /* OmniOS */
.hero-names span:nth-child(3)  { font-size: 2.30em; opacity: .14; } /* Plan 9 */
.hero-names span:nth-child(4)  { font-size: 1.40em; opacity: .18; } /* Tribblix */
.hero-names span:nth-child(5)  { font-size: 2.10em; opacity: .15; } /* NetBSD */
.hero-names span:nth-child(6)  { font-size: 1.45em; opacity: .18; } /* GNU Hurd */
.hero-names span:nth-child(7)  { font-size: 3.40em; opacity: .13; } /* Haiku */
.hero-names span:nth-child(8)  { font-size: 1.75em; opacity: .17; } /* OpenBSD */
.hero-names span:nth-child(9)  { font-size: 2.50em; opacity: .14; } /* BlissOS */
.hero-names span:nth-child(10) { font-size: 1.60em; opacity: .17; } /* MidnightBSD */
.hero-names span:nth-child(11) { font-size: 2.70em; opacity: .14; } /* Solaris */
.hero-names span:nth-child(12) { font-size: 1.95em; opacity: .15; } /* DragonFly */
.hero-names span:nth-child(13) { font-size: 2.20em; opacity: .14; } /* OpenEuler */
.hero-names span:nth-child(14) { font-size: 1.70em; opacity: .17; } /* GhostBSD */
.hero-names span:nth-child(15) { font-size: 2.35em; opacity: .14; } /* OpenIndiana */
.hero-names span:nth-child(16) { font-size: 1.80em; opacity: .17; } /* NextBSD */
.hero-names span:nth-child(17) { font-size: 2.85em; opacity: .13; } /* Ubuntu */

/* Architectures: a second, quieter layer. Held well below the guest sizes so
   the two read as foreground and background of the same field rather than as
   one flat list of words. */
.hero-names span:nth-child(18) { font-size: 1.35em; opacity: .18; } /* x86_64 */
.hero-names span:nth-child(19) { font-size: 1.50em; opacity: .17; } /* aarch64 */
.hero-names span:nth-child(20) { font-size: 1.20em; opacity: .18; } /* riscv64 */
.hero-names span:nth-child(21) { font-size: 1.10em; opacity: .18; } /* arm64 */
.hero-names span:nth-child(22) { font-size: 1.40em; opacity: .17; } /* sparc64 */
.hero-names span:nth-child(23) { font-size: 1.00em; opacity: .18; } /* s390x */
.hero-names span:nth-child(24) { font-size: 1.25em; opacity: .18; } /* loongarch64 */
.hero-names span:nth-child(25) { font-size: 1.15em; opacity: .18; } /* ppc64le */
.hero-names span:nth-child(26) { font-size: 1.05em; opacity: .18; } /* amd64 */
.hero-names span:nth-child(27) { font-size: 1.30em; opacity: .17; } /* powerpc64 */
.hero-names span:nth-child(28) { font-size: 0.95em; opacity: .18; } /* i386 */

@media (max-width: 1000px) { .hero-names { font-size: 0.8rem; } }
@media (max-width: 640px)  { .hero-names { font-size: 0.6rem; } }

.hero-in {
  position: relative;
  max-width: var(--wrap); margin: 0 auto; padding: 20px 24px 52px;
  display: grid;
  /* max-content, not auto: an auto track absorbs leftover space and leaves the
     matrix floating short of the right edge. max-content pins it to its own
     width so the figure sits flush and the slack all goes to the headline. */
  grid-template-columns: minmax(0, 1fr) max-content;
  gap: 56px; align-items: start;
}

.hero h1 { color: var(--chalk); margin-bottom: 18px; }

/* The two rotating slots are the whole argument of the product -- any guest,
   any host -- so they get the type moment: monospace, as if entered at a
   prompt.

   Each slot holds a min-width equal to its longest word, so the headline
   never reflows while typing. Content is LEFT-aligned in that reserved
   width: the four slots already share a left edge, so centring made the four
   words start at four different x positions and the block read as ragged.
   Left-aligned, every word begins on the same column and the slack falls to
   the right of the cursor -- which is where a line being typed has its slack
   anyway. */
/* Three lines: guest, architecture, host. The leads are held to one width so
   the three slots start on a common left edge -- the headline then reads like
   aligned terminal output rather than three ragged phrases. */
.hero h1 .line {
  display: flex;
  align-items: baseline;
  gap: 0.4em;
}
.hero h1 .lead { flex: none; min-width: 2.3em; }

.hero h1 .typer {
  display: inline-block;
  text-align: left;
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.78em;
  letter-spacing: -0.02em;
  white-space: nowrap;
  box-shadow: inset 0 -0.13em 0 var(--fam-illumos);
}
.hero h1 .typer       { min-width: 12.4ch; }  /* DragonFlyBSD */
.hero h1 .typer-arch  { min-width: 11.4ch; }  /* loongarch64 */
.hero h1 .typer-host  { min-width:  7.4ch; }  /* Windows */
.hero h1 .typer-accel { min-width:  5.4ch; }  /* WHPX */

/* All four lines type independently, so all four carry a cursor. They blink
   in step on purpose: the typing is already staggered, and letting the
   cursors drift as well would read as four unrelated widgets. The caret only
   appears once JS marks the slot active, so the no-JS headline is clean. */
.hero h1 .caret {
  display: none;
  width: 0.09em;
  height: 0.88em;
  margin-left: 0.05em;
  vertical-align: -0.1em;
  background: var(--fam-illumos);
}
.hero h1 .typer.active .caret {
  display: inline-block;
  animation: caret 1.05s steps(1) infinite;
}
@keyframes caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

.eyebrow {
  display: inline-block;
  font-size: 0.73rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--haze);
  border-top: 1px solid var(--rule);
  padding-top: 9px; margin-bottom: 20px;
}

.hero-cmd {
  border: 1px solid var(--rule);
  border-radius: var(--r);
  background: rgba(0, 0, 0, 0.28);
  padding: 13px 16px;
  margin: 0 0 24px;          /* it is a <pre>: reset the UA margin */
  /* Wide enough for the longest line (47 chars) plus the padding, so the
     block never grows a scrollbar on desktop. */
  max-width: 54ch;
  font-family: var(--mono);
  font-size: 0.84rem;
  line-height: 1.9;
  overflow-x: auto;
}
.hero-cmd .s { color: var(--fam-illumos); }
.hero-cmd .o { color: var(--haze); }

.hero .cta { display: flex; flex-wrap: wrap; gap: 11px; }
.hero .btn { background: transparent; border-color: var(--rule); color: var(--chalk); }
.hero .btn:hover { border-color: var(--haze); }
.hero .btn-solid { background: var(--chalk); border-color: var(--chalk); color: var(--ink); }
.hero .btn-solid:hover { filter: brightness(0.94); }

.hero-foot {
  margin: 26px 0 0;
  font-size: 0.8rem; color: var(--haze);
}
.hero-foot a { text-decoration-color: var(--rule); }

@media (max-width: 1000px) {
  /* minmax(0, ...) not 1fr: a grid item defaults to min-width:auto, so a
     plain 1fr track refuses to shrink below its content's min-content width
     and the column gets pushed wider than the viewport. */
  .hero-in { grid-template-columns: minmax(0, 1fr); gap: 44px; padding: 18px 24px 44px; }
}

/* Phone widths: lead + gap + an 11.4ch slot outgrows the content box, and the
   hero's overflow clip would silently cut the headline off rather than
   scroll. Scale the type AND pull the reserved slot widths in -- the slots
   only need to be wide enough to stop the line reflowing mid-word. */
@media (max-width: 480px) {
  .hero h1 { font-size: 1.85rem; }
  .hero h1 .lead { min-width: 2.1em; }
  .hero h1 .typer { font-size: 0.72em; }
  .hero h1 .typer       { min-width: 11ch; }
  .hero h1 .typer-arch  { min-width: 10ch; }
  .hero h1 .typer-host  { min-width: 6.6ch; }
  .hero h1 .typer-accel { min-width: 4.6ch; }
}

@media (max-width: 340px) {
  .hero h1 { font-size: 1.6rem; }
  .hero h1 .typer { font-size: 0.7em; }
}

/* Shrink the command block rather than let it grow a scrollbar on a phone. */
@media (max-width: 520px) { .hero-cmd { font-size: 0.72rem; } }
@media (max-width: 400px) { .hero-cmd { font-size: 0.64rem; } }

/* ---------- 6. Signature: the coverage matrix ---------- */

/* margin:0 is load-bearing -- <figure> carries a UA default of "1em 40px",
   which widened this grid track by 80px and left the matrix floating short
   of the right edge. */
.cov { --dot: var(--haze); margin: 0; }

.cov-title {
  font-family: var(--mono);
  font-size: 0.8rem; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--haze);
  border-bottom: 1px solid var(--rule);
  padding-bottom: 10px; margin-bottom: 16px;
  display: flex; justify-content: space-between; gap: 20px;
}

.cov-grid {
  display: grid;
  grid-template-columns: auto repeat(7, var(--cell));
  align-items: center;
  column-gap: 3px;
}

.axis {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  color: var(--haze);
  justify-self: center;
  /* The grid centres its items; these labels differ in length, so centring
     leaves their baselines ragged. Pin them to the bottom so every label
     ends on the same line just above the first row of cells. */
  align-self: end;
  /* padding-TOP, deliberately. rotate(180deg) flips the box, so the physical
     top edge is what ends up visually nearest the cells -- padding-bottom
     here lands above the label instead and lets the text sit flush on the
     first row. */
  padding-top: 14px;
  white-space: nowrap;
}

.cov-os {
  font-size: 0.85rem;
  color: var(--haze);
  text-align: right;
  padding-right: 13px;
  white-space: nowrap;
  line-height: calc(var(--cell) - 3px);
}

.cov-cell {
  width: var(--cell); height: calc(var(--cell) - 3px);
  border-radius: 2px;
  background: rgba(134, 163, 180, 0.08);
  box-shadow: inset 0 0 0 1px rgba(134, 163, 180, 0.1);
}
.cov-cell.on { background: var(--dot); box-shadow: none; }

/* Guest identity, resolved ONCE here and consumed by both the hero matrix
   and the readable table below it. Adding a guest means adding its colour
   above and one line here -- nowhere else. */
[data-os="freebsd"]     { --os-color: var(--os-freebsd); }
[data-os="openbsd"]     { --os-color: var(--os-openbsd); }
[data-os="netbsd"]      { --os-color: var(--os-netbsd); }
[data-os="dragonfly"]   { --os-color: var(--os-dragonfly); }
[data-os="midnightbsd"] { --os-color: var(--os-midnightbsd); }
[data-os="ghostbsd"]    { --os-color: var(--os-ghostbsd); }
[data-os="nextbsd"]     { --os-color: var(--os-nextbsd); }
[data-os="solaris"]     { --os-color: var(--os-solaris); }
[data-os="omnios"]      { --os-color: var(--os-omnios); }
[data-os="openindiana"] { --os-color: var(--os-openindiana); }
[data-os="tribblix"]    { --os-color: var(--os-tribblix); }
[data-os="ubuntu"]      { --os-color: var(--os-ubuntu); }
[data-os="openeuler"]   { --os-color: var(--os-openeuler); }
[data-os="blissos"]     { --os-color: var(--os-blissos); }
[data-os="haiku"]       { --os-color: var(--os-haiku); }
[data-os="hurd"]        { --os-color: var(--os-hurd); }
[data-os="plan9"]       { --os-color: var(--os-plan9); }

/* One band per guest. Lineage grouping is still legible -- the gaps do that
   job -- but the colour now names the system itself, which is why there is
   no legend: the label sits directly beside its own row. */
.cov-band { display: contents; --dot: var(--os-color); }

.cov-gap { grid-column: 1 / -1; height: 11px; }

.cov-key {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin-top: 20px; padding-top: 15px;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.78rem; color: var(--haze);
}
.cov-key span { display: inline-flex; align-items: center; gap: 7px; }
.cov-key i {
  width: 11px; height: 11px; border-radius: 2px; display: block;
}

@media (max-width: 1000px) {
  .cov { --cell: 19px; }
}
@media (max-width: 420px) {
  .cov { --cell: 15px; }
  .cov-os { font-size: 0.63rem; padding-right: 7px; }
}

/* ---------- 7. Sections ---------- */

.section { padding: 74px 0; border-bottom: 1px solid var(--line); }
.section-2 { background: var(--bg-2); }
.section-head { max-width: 52ch; margin-bottom: 38px; }
.section-head p { color: var(--fg-2); margin: 0 0 0.85rem; }
.section-head p:last-child { margin-bottom: 0; }
.section-head p strong { color: var(--fg); font-weight: 600; }

.tag {
  display: block;
  font-size: 0.71rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--fg-3); margin-bottom: 10px;
}

@media (max-width: 720px) { .section { padding: 52px 0; } }

/* ---------- 8. Code ---------- */

.code {
  position: relative;
  background: var(--ink);
  border: 1px solid var(--rule);
  border-radius: var(--r);
  overflow: hidden;
}
.code pre {
  margin: 0; padding: 15px 62px 15px 17px;
  overflow-x: auto;
  color: var(--chalk);
  font-size: 0.83rem; line-height: 1.75;
}
.code .s { color: var(--fam-illumos); }
.code .cm { color: var(--haze); }
.code .o { color: var(--haze); }

.copy {
  position: absolute; top: 8px; right: 8px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--haze);
  border-radius: 4px; padding: 3px 8px;
  font-size: 0.68rem; cursor: pointer;
  transition: color .14s, border-color .14s;
}
.copy:hover { color: var(--chalk); border-color: var(--haze); }
.copy.done { color: var(--fam-illumos); border-color: var(--fam-illumos); }

/* ---------- 9. Terminal ---------- */

.term {
  background: var(--ink);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.term-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--rule);
  color: var(--haze);
}
.term-title { font-size: 0.71rem; }
.term pre {
  margin: 0; padding: 16px 18px 18px;
  overflow-x: auto; color: var(--chalk);
  font-size: 0.81rem; line-height: 1.8;
}
.term .s { color: var(--fam-illumos); }
.term .o { color: var(--haze); }

/* ---------- 10. Tabs ---------- */

.tabs {
  display: flex; gap: 2px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
  margin-bottom: 18px;
}
.tab {
  appearance: none; border: 0; background: none; font: inherit;
  font-family: var(--mono);
  font-size: 0.83rem; color: var(--fg-2);
  padding: 8px 14px;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  cursor: pointer;
}
.tab:hover { color: var(--fg); }
.tab[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--fg); }
.panel[hidden] { display: none; }
.panel-note { margin: 12px 0 0; font-size: 0.86rem; color: var(--fg-2); }

/* ---------- 11. Cards ---------- */

.cards {
  display: grid;
  /* min() guards the track floor: a bare minmax(272px, 1fr) is wider than a
     290px viewport's content box and forces the whole page to scroll. */
  grid-template-columns: repeat(auto-fit, minmax(min(272px, 100%), 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.card { background: var(--bg); padding: 24px 22px; }
.section-2 .card { background: var(--bg-2); }
.card h3 { margin: 0 0 7px; }
.card p { margin: 0; color: var(--fg-2); font-size: 0.9rem; }
.card .n {
  font-family: var(--mono);
  font-size: 0.7rem; color: var(--fg-3);
  display: block; margin-bottom: 12px;
}

/* ---------- 12. Tables ---------- */

.tablewrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
table { border-collapse: collapse; width: 100%; font-size: 0.89rem; }
th, td {
  padding: 9px 14px; text-align: left;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
thead th {
  background: var(--bg-2);
  font-family: var(--mono);
  font-size: 0.7rem; font-weight: 500;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--fg-2);
}
.section-2 .tablewrap thead th { background: var(--bg-3); }
tbody tr:last-child td, tbody tr:last-child th { border-bottom: 0; }
td.mark, th.mark { text-align: center; }

.mk { display: inline-block; width: 9px; height: 9px; border-radius: 2px; }
.mk-on  { background: var(--fg); }
.mk-off { background: var(--line-2); opacity: 0.55; border-radius: 50%; width: 5px; height: 5px; }

.row-os { font-weight: 550; }
.row-os .sub {
  display: block; font-weight: 400;
  font-family: var(--mono); font-size: 0.71rem; color: var(--fg-3);
}
.legend { margin-top: 14px; font-size: 0.85rem; color: var(--fg-2); }

/* Brand stripe on the readable table, same source of truth as the matrix.
   The colours were picked to sit on the dark hero; on the light page they
   are darkened so a pale one (DragonFly's chartreuse, Plan 9's yellow) does
   not vanish against white. */
/* Darkened by default because the light page is the default document; the
   dark paths below restore the published colour. A few of the brighter hues
   (DragonFly's chartreuse, Plan 9's yellow) still land near 2.5:1 on white --
   acceptable here because the stripe is an identifying accent, not the thing
   that tells you which row you are on. That is the label's job. */
tbody tr[data-os] th[scope="row"] {
  border-left: 3px solid color-mix(in srgb, var(--os-color) 72%, #10222c);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) tbody tr[data-os] th[scope="row"] {
    border-left-color: var(--os-color);
  }
}
:root[data-theme="dark"] tbody tr[data-os] th[scope="row"] {
  border-left-color: var(--os-color);
}

/* ---------- 13. Ecosystem ---------- */

.eco {
  display: grid;
  /* Same floor guard as .cards -- see the note there. */
  grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr));
  gap: 24px;
}
.eco-item { border-top: 1px solid var(--line-2); padding-top: 18px; }
.eco-item h3 { margin: 0 0 7px; }
.eco-item p { margin: 0 0 12px; color: var(--fg-2); font-size: 0.9rem; }
.eco-links { font-family: var(--mono); font-size: 0.82rem; }
.eco-links a { margin-right: 14px; display: inline-block; }

.pills { display: flex; flex-wrap: wrap; gap: 6px; }
.pill {
  font-size: 0.73rem;
  border: 1px solid var(--line); border-radius: 3px;
  color: var(--fg-2); padding: 2px 8px;
  text-decoration: none;
}
.pill:hover { color: var(--fg); border-color: var(--fg-3); }
.pill[data-fam="bsd"]      { border-left: 2px solid var(--fam-bsd-p); }
.pill[data-fam="illumos"]  { border-left: 2px solid var(--fam-illumos-p); }
.pill[data-fam="linux"]    { border-left: 2px solid var(--fam-linux-p); }
.pill[data-fam="research"] { border-left: 2px solid var(--fam-research-p); }

/* ---------- 14. Footer ---------- */

.footer { padding: 46px 0 54px; color: var(--fg-2); font-size: 0.89rem; }
.footer-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 26px; margin-bottom: 32px;
}
.footer h4 {
  font-family: var(--mono);
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--fg-3); margin: 0 0 10px; font-weight: 500;
}
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { margin-bottom: 5px; }
.footer a { text-decoration-color: transparent; }
.footer a:hover { text-decoration-color: currentColor; }
.footer-base {
  border-top: 1px solid var(--line); padding-top: 20px;
  display: flex; flex-wrap: wrap; gap: 8px 20px;
  font-size: 0.82rem; color: var(--fg-3);
}

/* ---------- 15. Docs ---------- */

.docs {
  display: grid; grid-template-columns: 218px minmax(0, 1fr);
  gap: 48px; align-items: start; padding: 40px 0 76px;
}
.side { position: sticky; top: 78px; font-size: 0.89rem; }
.side h4 {
  font-family: var(--mono);
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--fg-3); margin: 22px 0 8px; font-weight: 500;
}
.side h4:first-child { margin-top: 0; }
.side ul { list-style: none; margin: 0; padding: 0; }
.side a {
  display: block; padding: 4px 12px;
  border-left: 1px solid var(--line);
  color: var(--fg-2); text-decoration: none;
}
.side a:hover { color: var(--fg); border-left-color: var(--line-2); }
.side a.on { color: var(--fg); border-left-color: var(--fg); font-weight: 550; }

@media (max-width: 900px) {
  .docs { grid-template-columns: 1fr; gap: 26px; padding-top: 26px; }
  .side {
    position: static; background: var(--bg-2);
    border: 1px solid var(--line); border-radius: var(--r-lg);
    padding: 16px 18px;
  }
}

.doc { min-width: 0; }
.doc h2 { margin-top: 2.6rem; scroll-margin-top: 74px; }
.doc h2:first-of-type { margin-top: 1rem; }
.doc h3 { margin-top: 1.7rem; scroll-margin-top: 74px; }
.doc ul, .doc ol { padding-left: 1.25em; margin: 0 0 1rem; }
.doc li { margin-bottom: 0.3rem; }
.doc .code, .doc .tablewrap { margin: 0 0 1.2rem; }
.doc table td { white-space: normal; }
.doc table td:first-child, .doc table th[scope="row"] { white-space: nowrap; }

.crumbs { font-size: 0.78rem; color: var(--fg-3); margin-bottom: 8px;
          letter-spacing: 0.06em; text-transform: uppercase; }
.lede { font-size: 1.04rem; color: var(--fg-2); margin-bottom: 1.6rem; }

.note {
  border-left: 2px solid var(--fg-3);
  background: var(--bg-2);
  border-radius: 0 var(--r) var(--r) 0;
  padding: 13px 17px; margin: 0 0 1.2rem;
  font-size: 0.92rem;
}
.section-2 .note { background: var(--bg-3); }
.note strong { color: var(--fg); }
.note > :last-child { margin-bottom: 0; }

.pagenav {
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  margin-top: 3rem; padding-top: 1.5rem;
  border-top: 1px solid var(--line); font-size: 0.9rem;
}

/* Per-guest heading rule, coloured by lineage. */
.doc h2[data-fam] { border-left: 3px solid var(--line-2); padding-left: 12px; }
.doc h2[data-fam="bsd"]      { border-left-color: var(--fam-bsd-p); }
.doc h2[data-fam="illumos"]  { border-left-color: var(--fam-illumos-p); }
.doc h2[data-fam="linux"]    { border-left-color: var(--fam-linux-p); }
.doc h2[data-fam="research"] { border-left-color: var(--fam-research-p); }

.meta {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  font-family: var(--mono); font-size: 0.76rem; color: var(--fg-3);
  margin: -0.3rem 0 1rem;
}

/* Option lists in the CLI reference. */
.dl { margin: 0 0 1.7rem; }
.dl dt {
  font-family: var(--mono); font-size: 0.86rem; font-weight: 600;
  color: var(--fg); margin-top: 1.4rem; scroll-margin-top: 74px;
  padding-bottom: 2px; border-bottom: 1px solid var(--line);
}
.dl dt:first-child { margin-top: 0; }
.dl dd { margin: 7px 0 0; color: var(--fg-2); font-size: 0.93rem; }
.dl dd .code { margin: 8px 0 0; }
.dl dd > :last-child { margin-bottom: 0; }
.dl dd + dd { margin-top: 6px; }

/* ---------- 16. 404 ---------- */

.center-page {
  min-height: 60vh; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center; gap: 4px;
}

/* ---------- 17. Motion ---------- */

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