/* ============================================================
   mothyfamily hub — hub.css (the modernized single-page hub)
   Hand-written. No frameworks, no build step, no internet needed:
   open index.html in any browser and it works from a USB stick.

   Two things this file is responsible for:
   1. PALETTE. Every colour a page paints comes from a token, so a theme is one
      attribute on <html> and nothing is hard-coded. The six palettes and their
      values are the house palettes, copied from mothyfamily-site/assets/base.css
      — they were measured with tools/theme-contrast.js, not eyeballed.
   2. THE PHONE. The rules at the end quote the measurement that made them
      necessary. Check them with node tools/mobile-probe.js 390 844.
   ============================================================ */

/* ---------- 1. tokens ----------
   Named by what they DO, not by their colour. `--amber` is the accent (links,
   pills, focus ring) even in the purple themes, where it is purple: keeping the
   role name means a rule never has to know which palette it is in.
   `--on-amber` is the text that sits ON the accent — near-black on dark themes,
   near-white on light ones. That is why it is a variable and not a hex.
   `--svc-*` are the service accents (the colour strip on a card). A bright
   accent that glows on dark ink turns to mud on a white card, so every light
   palette re-states them darker; tools/theme-contrast.js proves all of them. */
:root {
  --ink: #14110d;        /* the page ground */
  --ink-2: #1c1813;      /* a lifted slab */
  --ink-3: #26211a;      /* a tile inside a card */
  --panel: #201b15;      /* a card */
  --panel-2: #2a241c;    /* a card that is pressed/hovered */
  --line: #3a3227;       /* hairline border */
  --line-soft: #2e281f;
  --text: #f3ece1;       /* body copy */
  --text-dim: #c3b7a5;   /* secondary copy */
  --text-mute: #9a8e7d;  /* muted copy — the pair that always fails on light */
  --amber: #f0a344;      /* the accent */
  --amber-deep: #c97f22;
  --lamp: #ffd9a0;       /* link hover */
  --teal: #57c1b3;
  --rose: #e8788f;
  --green: #7fc46f;
  --violet: #a98fd8;
  --on-amber: #1a1208;   /* text ON the accent */
  --code-bg: var(--ink-3);

  /* service accents: strip + tile + the word-colour inside the card */
  --svc-media:  #57c1b3;  /* films, TV, music */
  --svc-people: #7fc46f;  /* the doors a person uses: login, status board */
  --svc-ai:     #a98fd8;  /* chat with our own AI */
  --svc-games:  #f0a344;  /* game servers */
  --svc-books:  #57c1b3;  /* books read aloud */
  --svc-photos: #e8788f;  /* family photos */

  /* The page wash, first layer paints on top. The probe proves the stylesheet
     loaded by checking that body has a background-image, so every palette ships
     a gradient. This replaces the twinkling particles: a wash cannot animate, so
     it never costs a frame and never needs a reduced-motion switch. */
  --bg:
    radial-gradient(1100px 520px at 82% -8%, rgba(240, 163, 68, .16), transparent 62%),
    radial-gradient(760px 420px at 8% 4%, rgba(87, 193, 179, .10), transparent 60%),
    var(--ink);
  --shadow: 0 18px 40px -22px rgba(0, 0, 0, .85);
  --radius: 14px;
  --radius-sm: 9px;
  --maxw: 1060px;
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;
}

/* Light — a cream page. Every accent drops to a burnt, darkened version, because
   a pastel background is a bright background. */
[data-theme="light"] {
  --ink: #f6f1e8;
  --ink-2: #efe8dc;
  --ink-3: #e6ddce;
  --panel: #fffdf8;
  --panel-2: #f4ecdf;
  --line: #d8ccb8;
  --line-soft: #e4dbc9;
  --text: #241d13;
  --text-dim: #55483a;
  --text-mute: #7a6b58;
  --amber: #9a570c;
  --amber-deep: #8c4f08;
  --lamp: #7a4a05;
  --teal: #14766a;
  --rose: #b23c56;
  --green: #3d7d2c;
  --violet: #6a4a9c;
  --on-amber: #fff9ef;
  --code-bg: #ece3d3;
  --svc-media: #14766a;
  --svc-people: #3d7d2c;
  --svc-ai: #6a4a9c;
  --svc-games: #9a570c;
  --svc-books: #14766a;
  --svc-photos: #b23c56;
  --bg: radial-gradient(1100px 520px at 82% -8%, rgba(240, 163, 68, .22), transparent 62%), radial-gradient(760px 420px at 8% 4%, rgba(87, 193, 179, .16), transparent 60%), linear-gradient(172deg, #faf6ef 0%, #f4efe4 60%, #efe7d9 100%);
  --shadow: 0 14px 34px -20px rgba(60, 40, 10, .35);
}
/* Grape — a purple page, dark. */
[data-theme="grape"] {
  --ink: #191026;
  --ink-2: #221534;
  --ink-3: #2b1b41;
  --panel: #241738;
  --panel-2: #2f1f48;
  --line: #45305f;
  --line-soft: #382750;
  --text: #f2ecff;
  --text-dim: #c8bce6;
  --text-mute: #a294c4;
  --amber: #f4b877;
  --amber-deep: #d9924a;
  --lamp: #ffdcae;
  --teal: #6fd0c2;
  --rose: #ff92b4;
  --green: #92d97f;
  --violet: #c9a9ff;
  --on-amber: #24120a;
  --svc-media: #6fd0c2;
  --svc-people: #92d97f;
  --svc-ai: #c9a9ff;
  --svc-games: #f4b877;
  --svc-books: #6fd0c2;
  --svc-photos: #ff92b4;
  --bg: radial-gradient(900px 480px at 84% -6%, rgba(201, 169, 255, .22), transparent 60%), radial-gradient(720px 420px at 6% 8%, rgba(111, 208, 194, .10), transparent 58%), linear-gradient(168deg, #2a1741 0%, #1c1029 42%, #24102f 72%, #170d22 100%);
  --shadow: 0 18px 40px -22px rgba(20, 0, 40, .9);
}
/* Noir — a black page with purple light in it. In Noir the accent IS the purple. */
[data-theme="noir"] {
  --ink: #0a060d;
  --ink-2: #120b18;
  --ink-3: #191021;
  --panel: #120c17;
  --panel-2: #1a1122;
  --line: #33203f;
  --line-soft: #261733;
  --text: #f3eefc;
  --text-dim: #c6b8dc;
  --text-mute: #9b8bb0;
  --amber: #b98cff;
  --amber-deep: #8b5cf6;
  --lamp: #dcc9ff;
  --teal: #6fd0c2;
  --rose: #ff8fc6;
  --green: #8fd98a;
  --violet: #c9a9ff;
  --on-amber: #12061c;
  --svc-media: #6fd0c2;
  --svc-people: #8fd98a;
  --svc-ai: #c9a9ff;
  --svc-games: #f0a344;
  --svc-books: #6fd0c2;
  --svc-photos: #ff8fc6;
  --bg: radial-gradient(900px 480px at 82% -8%, rgba(139, 92, 246, .26), transparent 62%), radial-gradient(680px 400px at 4% 10%, rgba(185, 140, 255, .09), transparent 58%), linear-gradient(170deg, #0d0714 0%, #070409 45%, #0b0512 75%, #050308 100%);
  --shadow: 0 18px 40px -22px rgba(0, 0, 0, .95);
}
/* Sky — a light pastel weighted to blue. */
[data-theme="pastel"] {
  --ink: #eaf2fb;
  --ink-2: #e0ebf7;
  --ink-3: #d5e4f3;
  --panel: #fbfdff;
  --panel-2: #eaf3fc;
  --line: #b9d0e8;
  --line-soft: #d3e3f3;
  --text: #1e2c3b;
  --text-dim: #46586d;
  --text-mute: #5b6f86;
  --amber: #9a5f17;
  --amber-deep: #7c4a0d;
  --lamp: #6b3f0a;
  --teal: #0e6f78;
  --rose: #ab3a63;
  --green: #2e7a41;
  --violet: #5a3fa2;
  --on-amber: #fffaf0;
  --code-bg: #d7e6f7;
  --svc-media: #0e6f78;
  --svc-people: #2e7a41;
  --svc-ai: #5a3fa2;
  --svc-games: #9a5f17;
  --svc-books: #0e6f78;
  --svc-photos: #ab3a63;
  --bg: radial-gradient(1000px 520px at 84% -8%, rgba(120, 190, 240, .38), transparent 62%), radial-gradient(760px 420px at 6% 6%, rgba(150, 220, 230, .30), transparent 60%), linear-gradient(172deg, #f4f9ff 0%, #e8f1fb 45%, #dbe8f7 100%);
  --shadow: 0 14px 34px -20px rgba(30, 60, 100, .35);
}
/* Lilac — the mothyfamily Discord server icon, read from pixels. A WHITE page
   with a lilac ring. This is the default, so the family opens the site in its
   own colours. Every pair here was measured against white before writing. */
[data-theme="lilac"] {
  --ink: #f7f4fb;
  --ink-2: #efeaf6;
  --ink-3: #e6dff1;
  --panel: #ffffff;
  --panel-2: #f2ecf9;
  --line: #d8cbec;
  --line-soft: #e9e2f4;
  --text: #2c2138;
  --text-dim: #4a3d5c;
  --text-mute: #625476;
  --amber: #6f4a86;
  --amber-deep: #5a3c6e;
  --lamp: #4f3368;
  --teal: #146978;
  --rose: #a0426e;
  --green: #2f7a52;
  --violet: #6a4a9c;
  --on-amber: #ffffff;
  --code-bg: #efeaf6;
  --svc-media: #146978;
  --svc-people: #2f7a52;
  --svc-ai: #6a4a9c;
  --svc-games: #6f4a86;
  --svc-books: #146978;
  --svc-photos: #a0426e;
  --bg: radial-gradient(1000px 520px at 84% -8%, rgba(178, 132, 200, .20), transparent 62%), radial-gradient(760px 420px at 6% 6%, rgba(143, 167, 205, .16), transparent 60%), linear-gradient(172deg, #fbf9ff 0%, #f3eefa 45%, #eadff6 100%);
  --shadow: 0 14px 34px -20px rgba(70, 40, 100, .35);
}
/* ---------- 2. reset + base ---------- */
*, *::before, *::after { box-sizing: border-box }
html { scroll-behavior: smooth; overflow-x: clip; -webkit-text-size-adjust: 100% }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto }
  *, *::before, *::after { animation-duration: .001s !important; transition-duration: .001s !important }
}
body {
  margin: 0;
  background: var(--bg);
  background-color: var(--ink);   /* the paint under the wash, so a swap mid-scroll never flashes */
  color: var(--text);
  font-family: var(--font-body);
  font-size: 18px; line-height: 1.68;
  -webkit-font-smoothing: antialiased;
}
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 22px }

/* The skip link: 1px wide on purpose, so it never widens the page it lives on. */
.sr { position: absolute; left: -9999px; top: 0 }
.sr:focus {
  left: 12px; top: 12px; z-index: 100; width: auto;
  padding: 10px 16px; background: var(--panel); color: var(--text);
  border: 1px solid var(--amber); border-radius: 10px; font-size: 15px;
}

/* Every control that a keyboard lands on gets a visible ring, in the accent colour. */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--amber); outline-offset: 2px; border-radius: 6px;
}

/* ---------- 3. header ---------- */
header.site {
  position: sticky; top: 0; z-index: 40;
  backdrop-filter: blur(10px);
  background: color-mix(in srgb, var(--ink) 84%, transparent);
  border-bottom: 1px solid var(--line-soft);
}
.brand-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 10px 0 8px }
.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: inherit; min-width: 0 }
.brand img { width: 40px; height: 40px; flex: 0 0 40px; border-radius: 11px; display: block }
.brand .who { display: flex; flex-direction: column; line-height: 1.15; min-width: 0 }
.brand .who b { font-family: var(--font-display); font-size: 19px; letter-spacing: .2px }
.brand .who span { font-size: 11.5px; color: var(--text-mute); letter-spacing: .16em; text-transform: uppercase }
.spacer { flex: 1 }

/* ---------- 4. the theme control ----------
   One button, not a row of them, and the word + dot on the button are painted by CSS from
   [data-theme] alone — so the button can never disagree with the theme you are in.
   role=menu + menuitemradio: aria-checked is the attribute that means "you are on this one". */
.theme-ctl { position: relative; display: inline-flex; margin-left: auto }
.theme-btn {
  display: inline-flex; align-items: center; gap: 9px; min-height: 44px; min-width: 44px;
  padding: 0 12px; background: var(--panel); color: var(--text-dim);
  border: 1px solid var(--line); border-radius: 11px; cursor: pointer;
  font-family: inherit; font-size: 14px; white-space: nowrap;
  transition: .18s color, .18s border-color, .18s background;
}
.theme-btn:hover, .theme-btn[aria-expanded="true"] {
  color: var(--text); border-color: var(--amber); background: var(--panel-2);
}
.theme-btn .chev { opacity: .65 }
.theme-menu {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  display: flex; flex-direction: column; gap: 2px; min-width: 190px; padding: 6px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 20px 44px -20px rgba(0, 0, 0, .8);
}
.theme-menu[hidden] { display: none }   /* [hidden] must be stated: display:flex beats the browser rule */
.titem {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; padding: 0 10px;
  background: transparent; border: 0; border-radius: 10px; cursor: pointer;
  font-family: inherit; font-size: 15px; text-align: left; color: var(--text-dim);
}
.titem:hover, .titem:focus-visible { background: var(--panel-2); color: var(--text) }
.titem[aria-checked="true"] { color: var(--text) }
.titem[aria-checked="true"]::after { content: "\2713"; margin-left: auto; color: var(--amber) }
.dot {
  width: 19px; height: 19px; flex: 0 0 19px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(140, 140, 140, .5), 0 2px 6px -2px rgba(0, 0, 0, .55);
}
.titem .dot { width: 21px; height: 21px; flex: 0 0 21px }
/* Each row paints the theme it SELECTS, never the theme you are in, so these gradients are
   deliberately hard-coded and must track the palette blocks above. */
.t-dark   .dot { background: linear-gradient(150deg, #26211a 0%, #14110d 55%, #f0a344 100%) }
.t-light  .dot { background: linear-gradient(150deg, #fffdf8 0%, #efe8dc 55%, #b4670f 100%) }
.t-grape  .dot { background: linear-gradient(150deg, #c9a9ff 0%, #2b1b41 52%, #f4b877 100%) }
.t-noir   .dot { background: linear-gradient(150deg, #b98cff 0%, #0a060d 55%, #8b5cf6 100%) }
.t-pastel .dot { background: linear-gradient(150deg, #bfe0f7 0%, #f4f9ff 48%, #7fb8e8 100%) }
.t-lilac  .dot { background: linear-gradient(150deg, #d5bed6 0%, #ffffff 46%, #b284c8 100%) }
[data-theme="dark"]   .theme-btn .dot { background: linear-gradient(150deg, #26211a 0%, #14110d 55%, #f0a344 100%) }
[data-theme="light"]  .theme-btn .dot { background: linear-gradient(150deg, #fffdf8 0%, #efe8dc 55%, #b4670f 100%) }
[data-theme="grape"]  .theme-btn .dot { background: linear-gradient(150deg, #c9a9ff 0%, #2b1b41 52%, #f4b877 100%) }
[data-theme="noir"]   .theme-btn .dot { background: linear-gradient(150deg, #b98cff 0%, #0a060d 55%, #8b5cf6 100%) }
[data-theme="pastel"] .theme-btn .dot { background: linear-gradient(150deg, #bfe0f7 0%, #f4f9ff 48%, #7fb8e8 100%) }
[data-theme="lilac"]  .theme-btn .dot { background: linear-gradient(150deg, #d5bed6 0%, #ffffff 46%, #b284c8 100%) }
[data-theme="dark"]   .theme-btn .lbl::after { content: "Dark" }
[data-theme="light"]  .theme-btn .lbl::after { content: "Light" }
[data-theme="grape"]  .theme-btn .lbl::after { content: "Grape" }
[data-theme="noir"]   .theme-btn .lbl::after { content: "Noir" }
[data-theme="pastel"] .theme-btn .lbl::after { content: "Pastel" }
[data-theme="lilac"]  .theme-btn .lbl::after { content: "Lilac" }

/* ---------- 5. hero ---------- */
.hero { padding: 52px 0 20px }
.kicker {
  font-size: 12.5px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--amber); font-weight: 700; margin: 0 0 10px;
}
h1 {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(32px, 5.2vw, 52px); line-height: 1.08;
  margin: 0 0 14px; letter-spacing: -.5px;
}
h1 .glow { color: var(--amber) }        /* one accented word, in a REAL colour: a background-clip
   gradient on text is unmeasurable by the contrast gate and renders as flat grey on a phone. */
.lede { font-size: clamp(19px, 2.1vw, 23px); color: var(--text-dim); max-width: 62ch; margin: 0 0 20px }

/* The two things to press today. 44px min-height is the phone rule, not a decoration.
   `on-amber` ON `amber` is a pair proved by tools/theme-contrast.js in every palette. */
.cta-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 4px }
a.cta {
  display: inline-flex; align-items: center; min-height: 44px; padding: 12px 20px;
  border-radius: 12px; text-decoration: none; font-weight: 650; font-size: 16.5px;
  background: var(--amber); color: var(--on-amber); border: 1px solid transparent;
  transition: .2s transform, .2s border-color;
}
a.cta:hover { transform: translateY(-2px); color: var(--on-amber) }
a.cta.ghost { background: transparent; color: var(--amber); border-color: var(--line) }
a.cta.ghost:hover { color: var(--lamp); border-color: color-mix(in srgb, var(--amber) 55%, var(--line)) }
[data-mode="light"] a.cta.ghost { color: var(--amber-deep) }

/* ---------- 6. sections ---------- */
main { padding-bottom: 36px }
section { margin: 44px 0 }
section > h2 {
  font-family: var(--font-display); font-size: clamp(24px, 3vw, 33px);
  margin: 0 0 6px; letter-spacing: -.2px;
}
section > h2 .n {
  font-family: var(--font-mono); font-size: 13px; color: var(--amber);
  display: block; letter-spacing: .18em; margin-bottom: 6px; font-weight: 600;
}
.sub { color: var(--text-mute); margin: 0 0 20px; max-width: 66ch }
/* The status legend: one row per pill. On a phone an inline legend wrapped mid-definition
   ("Being built running, with a piece / missing ·"), so each pair gets its own line and the
   pill keeps company with its own words. */
.legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 0 0 20px; font-size: 14.5px; color: var(--text-mute) }
.legend p { margin: 0 }
.body-sm { font-size: 15.5px; color: var(--text-dim); margin: 8px 0 }
.body-sm b { color: var(--text) }

/* ---------- 7. status pills ----------
   The pill words are fixed (house rule): Live — Jellyfin / Running / Working today /
   In testing / Being built / Planned / Undecided. A pill is a LABEL, not a target,
   so the mobile probe does not count it against the 44px rule. */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 700; letter-spacing: .04em;
  padding: 3px 10px; border-radius: 999px; border: 1px solid; white-space: nowrap;
}
.pill.live   { color: var(--green);  border-color: color-mix(in srgb, var(--green) 45%, transparent);  background: color-mix(in srgb, var(--green) 12%, transparent) }
.pill.build  { color: var(--amber);  border-color: color-mix(in srgb, var(--amber) 45%, transparent);  background: color-mix(in srgb, var(--amber) 12%, transparent) }
.pill.plan   { color: var(--teal);   border-color: color-mix(in srgb, var(--teal) 45%, transparent);   background: color-mix(in srgb, var(--teal) 12%, transparent) }
.pill.decide { color: var(--rose);   border-color: color-mix(in srgb, var(--rose) 45%, transparent);   background: color-mix(in srgb, var(--rose) 12%, transparent) }

/* ---------- 8. cards ----------
   The whole card is the link (a.card), so the tap target is the card itself, not a
   small button inside it. The service colour rides in a 4px strip on the left edge:
   a strip is decoration, and each card's words carry its identification, so the strip
   never has to clear a contrast ratio on its own. */
/* Four cards in a row of three leaves one card alone on the second row, which reads as a
   mistake. A 2x2 grid is the tidy shape for four doors, and `min(100%, …)` is the guard: a
   minmax(440px,1fr) track is 440px MINIMUM, so on a 358px card container it would force the
   page sideways. min(100%,430px) lets the track shrink below 430 when the container is
   smaller, so the phone stays single-column with 0px overflow. */
.grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 430px), 1fr)) }
@media (max-width: 690px) { .grid { grid-template-columns: minmax(0, 1fr) } }
a.card, div.card {
  border: 1px solid var(--line); border-left: 4px solid var(--amber);
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border-radius: var(--radius); padding: 20px; position: relative;
  box-shadow: var(--shadow); text-decoration: none; color: inherit;
  transition: .2s transform, .2s border-color;
}
a.card:hover { transform: translateY(-3px); border-color: color-mix(in srgb, var(--amber) 55%, var(--line)) }
.card h3, .card h3:first-child {
  font-family: var(--font-display); font-size: 20px; margin: 0 0 6px;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.card .tile {
  width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center;
  font-size: 22px; line-height: 1; margin-bottom: 10px;
  background: color-mix(in srgb, var(--svc) 16%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--svc) 45%, var(--line));
}
.card .svc-word { color: var(--svc) }
.card .go {
  display: inline-flex; align-items: center; min-height: 44px; margin-top: 10px;
  color: var(--amber); font-weight: 650; font-size: 15px;
}
a.card:hover .go { color: var(--lamp) }
[data-mode="light"] a.card:hover .go { color: var(--amber-deep) }
/* The accent for this card. One variable per card means the strip, the tile, and the
   word colour all change together when the palette changes. */
.a-media  { --svc: var(--svc-media)  }
.a-people { --svc: var(--svc-people) }
.a-ai     { --svc: var(--svc-ai)     }
.a-games  { --svc: var(--svc-games)  }
.a-books  { --svc: var(--svc-books)  }
.a-photos { --svc: var(--svc-photos) }
.a-media, .a-people, .a-ai, .a-games, .a-books, .a-photos { border-left-color: var(--svc) }

/* chips: a service's plain-language labels. Neutral on purpose — 6 colours of
   chip in a 6-card grid reads as a rainbow, not as information. */
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 2px }
.tag {
  font-size: 13px; padding: 4px 10px; border-radius: 999px;
  background: var(--ink-3); color: var(--text-dim); border: 1px solid var(--line-soft);
}

/* ---------- 9. the "coming soon" strip ---------- */
.plain {
  border: 1px solid var(--line); border-left: 4px solid var(--amber);
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border-radius: var(--radius); padding: 18px 22px; margin: 22px 0 8px; box-shadow: var(--shadow);
}
.plain b.tag-label {
  display: block; font-size: 11.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--amber); margin-bottom: 6px;
}
.plain p { margin: 6px 0 }

/* ---------- 10. footer ---------- */
footer.site {
  border-top: 1px solid var(--line-soft); margin-top: 30px; padding: 26px 0 40px;
  color: var(--text-mute); font-size: 14.5px;
}
footer.site .disc { max-width: 70ch }
footer.site a { color: var(--amber) }
/* The Discord button is gone (2026-11-01): the page is public and a public invite is an open door.
   When a gated invite exists it comes back as a real button with a 44px target. */

/* ---------- 11. the phone ----------
   Each rule quotes the measurement that made it necessary. Check with
   node tools/mobile-probe.js 390 844  (and 320 844). */
@media (max-width: 720px), (pointer: coarse) {
  /* Tap targets measured 29px tall; the comfortable guideline is 44px. */
  .icon-btn, a.cta, .card .go { min-height: 44px }
  .brand { min-height: 44px }
  /* The sticky header measured 109px = 13% of the screen, permanently in the way. */
  .brand .who span { display: none }
  .brand img { width: 34px; height: 34px; flex-basis: 34px }
  .brand .who b { font-size: 17px }
  .brand-row { padding: 6px 0 2px; gap: 10px }
  /* The hero measured 936px tall on a phone: the first screen showed a headline and
     nothing pressable. */
  .hero { padding: 16px 0 10px }
  .hero h1 { font-size: clamp(27px, 7.5vw, 38px) }
  .lede { font-size: 17.5px }
  section { margin: 26px 0 }
  .wrap { padding-left: max(16px, env(safe-area-inset-left)); padding-right: max(16px, env(safe-area-inset-right)) }
  header.site { padding-top: env(safe-area-inset-top) }
}

/* No hover effects on touch: a card that lifts on :hover stays lifted after a tap, because
   a phone has no mouse-out. Gated on the capability, not the width. */
@media (hover: none) {
  a.card:hover, a.cta:hover { transform: none }
}

/* Touch scrolling: momentum on the strips, no rubber-band into the page behind, and no
   300ms double-tap-zoom delay on controls. */
a, button { touch-action: manipulation }

/* A text link inside a paragraph measured 22px tall at 320px — a thumb lands on 22px and
   hits the words, not the target. Every text link in a prose block gets its own band. */
.plain a, .body-sm a, .sub a, footer.site a {
  display: inline-block; min-height: 22px; padding: 12px 2px; line-height: 1.35;
}

/* ---------- 12. print ----------
   So a grandparent can have the hub on paper: the controls drop out, the links print.
   Measured with --print-to-pdf: the first pass ran to 6 pages because the on-screen spacing
   (a 452px hero, 44px section margins) carried onto paper. Tighten the sheet, keep the
   cards whole, and print the target of every link so a paper reader can type it in. */
@media print {
  header.site, .theme-ctl, .cta-row, .tag, .tile, nav { display: none !important }
  body { background: #fff; color: #111; font-size: 11pt; line-height: 1.4 }
  .wrap { max-width: 100%; padding: 0 }
  .hero { padding: 0 0 6pt }
  h1 { font-size: 22pt }
  .lede { font-size: 11pt; color: #333 }
  section { margin: 14pt 0 }
  section > h2 { font-size: 16pt }
  .sub, .legend, .body-sm { font-size: 10pt; color: #333 }
  .legend { gap: 2pt 10pt }
  a.card, div.card { box-shadow: none; border-color: #999; break-inside: avoid; padding: 10pt; margin-bottom: 8pt }
  .grid { gap: 8pt; grid-template-columns: minmax(0, 1fr) }
  .card h3 { font-size: 13pt }
  .card .go { color: #111 }
  /* The paper reader has no mouse: print the address the card points at. */
  a.card::after { content: " — " attr(href); font-size: 9pt; color: #555 }
  .pill { border-color: #999; color: #111; background: #fff }
  footer.site { border-top: 1px solid #999 }
  footer.site .disc { max-width: 100% }
}
