/* ==========================================================================
   Simple — a calm, conventional landing page in Omarchy's skin.
   Tokyo Night palette (themes/tokyo-night/colors.toml), JetBrains Mono only.
   One column. Big type. Air. One picture per idea.
   ========================================================================== */
:root {
  --bg: #1a1b26; --fg: #a9b1d6; --accent: #7aa2f7; --green: #9ece6a;
  --wall: url('wallpapers/tokyo-night.webp');
  --bg-2:    color-mix(in srgb, var(--bg), #000 22%);
  --surface: color-mix(in srgb, var(--bg), var(--fg) 6%);
  --border:  color-mix(in srgb, var(--bg), var(--fg) 14%);
  --strong:  color-mix(in srgb, var(--fg), #fff 30%);
  --muted:   color-mix(in srgb, var(--fg), var(--bg) 45%);

  --font: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --wrap: 72rem;
  --text: 46rem;
  --radius: 12px;
  --shadow: 0 40px 90px -40px rgba(0, 0, 0, 0.8);
  --section: clamp(4rem, 9vw, 7.5rem);
  --ease: 0.2s cubic-bezier(0.33, 1, 0.68, 1);
}

:root[data-light="1"] { --strong: var(--fg); --bg-2: color-mix(in srgb, var(--bg), #000 4%); }
* { box-sizing: border-box; }
body, .nav, .btn, .theme-chip { transition: background-color 0.35s ease, color 0.35s ease, border-color 0.35s ease; }
html { font-size: 16px; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover, a:focus-visible { text-decoration: underline; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
::selection { background: var(--accent); color: var(--bg); }
strong, b { font-weight: 700; color: var(--strong); }
em, i { font-style: italic; }
img { max-width: 100%; height: auto; display: block; }
kbd {
  font: inherit; font-weight: 500; font-size: 0.85em;
  color: var(--strong);
  background: var(--surface);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: 0.05em 0.45em;
  white-space: nowrap;
}
.dim { color: var(--muted); }
.eyebrow { margin: 0 0 1rem; color: var(--muted); font-size: 0.85rem; font-weight: 500; letter-spacing: 0.04em; }
.eyebrow a { color: inherit; }

.wrap { width: min(100% - 3rem, var(--wrap)); margin-inline: auto; }
.wrap--text { max-width: var(--text); text-align: center; }
.wrap--text p, .wrap--text ol { margin-inline: auto; }

h1, h2, h3 { color: var(--strong); font-weight: 700; letter-spacing: -0.02em; text-wrap: balance; margin: 0; }
h2 { font-size: clamp(1.6rem, 1rem + 2.2vw, 2.5rem); line-height: 1.15; }
h3 { font-size: 1.05rem; letter-spacing: 0; }
.lede { font-size: clamp(1.05rem, 0.95rem + 0.5vw, 1.25rem); line-height: 1.55; color: var(--fg); margin: 1.5rem auto 0; max-width: 38rem; text-wrap: pretty; }
.lede a { color: var(--strong); font-weight: 500; }
.more { display: inline-block; margin-top: 1.25rem; font-weight: 500; }

/* ------------------------------------------------------------------ nav -- */
.nav {
  position: sticky; top: 0; z-index: 10;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(18px) saturate(1.3);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
}
.nav__inner {
  width: min(100% - 3rem, var(--wrap)); margin-inline: auto;
  height: 3.5rem;
  display: flex; align-items: center; gap: 2rem;
}
.nav__brand { display: block; line-height: 0; }
.nav__brand .logo { height: 1.05rem; width: auto; fill: var(--green); }
.nav__links { display: flex; gap: 1.6rem; margin-left: auto; font-size: 0.9rem; font-weight: 500; }
.nav__links a { color: var(--fg); }
.nav__links a:hover { color: var(--strong); text-decoration: none; }
.nav__cta {
  font-size: 0.85rem; font-weight: 700;
  color: var(--bg); background: var(--accent);
  padding: 0.4em 0.95em; border-radius: 999px;
}
.nav__cta:hover { text-decoration: none; filter: brightness(1.1); }
@media (max-width: 48em) { .nav__links { display: none; } .nav__cta { margin-left: auto; } }

/* --------------------------------------------------------------- buttons -- */
.actions { display: flex; flex-wrap: wrap; gap: 0.9rem; justify-content: inherit; margin-top: 2rem; }
.wrap--text .actions { justify-content: center; }
.btn {
  display: inline-flex; align-items: baseline; gap: 0.7ch;
  font: inherit; font-weight: 700; font-size: 0.95rem;
  padding: 0.8em 1.4em;
  border-radius: 999px;
  border: 1px solid transparent;
  transition: filter var(--ease), border-color var(--ease);
}
.btn:hover { text-decoration: none; }
.btn small { font-weight: 400; opacity: 0.7; }
.btn--primary { background: var(--accent); color: var(--bg); }
.btn--primary:hover { filter: brightness(1.1); }
.btn--quiet { color: var(--strong); border-color: var(--border); }
.btn--quiet:hover { border-color: var(--accent); }

/* ----------------------------------------------------------------- hero -- */
.hero {
  position: relative;
  padding: calc(var(--section) * 1.15) 0 0;
  background-image:
    linear-gradient(to bottom,
      color-mix(in srgb, var(--bg) 35%, transparent) 0%,
      color-mix(in srgb, var(--bg) 70%, transparent) 55%,
      var(--bg) 100%),
    var(--wall);
  background-size: cover, cover;
  background-position: center, center 30%;
  background-repeat: no-repeat;
}
.hero .eyebrow, .hero .lede { text-shadow: 0 1px 12px color-mix(in srgb, var(--bg) 80%, transparent); }
.hero__h1 { text-shadow: 0 2px 24px color-mix(in srgb, var(--bg) 90%, transparent); }
.hero .btn--quiet { background: color-mix(in srgb, var(--bg) 55%, transparent); backdrop-filter: blur(8px); }
.shot img { box-shadow: 0 50px 120px -30px rgba(0,0,0,0.85); }
.hero__h1 {
  font-size: clamp(2rem, 1.1rem + 3.6vw, 4rem);
  line-height: 1.08;
  max-width: 16ch;
  margin-inline: auto;
}
.hero__h1 a { color: var(--accent); }
.shot { margin: clamp(3rem, 6vw, 5rem) auto 0; }
.shot img {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.shot figcaption { text-align: center; color: var(--muted); font-size: 0.85rem; margin-top: 1rem; }

/* -------------------------------------------------------------- mission -- */
.mission { padding: var(--section) 0; }
.mission__line {
  margin: 0;
  font-size: clamp(1.8rem, 1.2rem + 3vw, 3.4rem);
  font-weight: 700; letter-spacing: -0.02em; line-height: 1.1;
  color: var(--green);
}
.mission__sub { margin: 1rem 0 0; color: var(--muted); font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; font-size: 0.85rem; }

/* -------------------------------------------------------------- feature -- */
.feature {
  display: grid; gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
  padding: calc(var(--section) * 0.6) 0;
}
@media (min-width: 60em) {
  .feature { grid-template-columns: 1fr 1.2fr; }
  .feature--flip .feature__text { order: 2; }
}
.feature__text p { margin: 1.25rem 0 0; max-width: 40ch; text-wrap: pretty; }
.feature__img, .collage img {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.collage { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.collage img { border-radius: 8px; box-shadow: none; }

.keys { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: 0.55rem; max-width: 26rem; font-size: 0.92rem; }
.keys li { display: flex; justify-content: space-between; gap: 1rem; align-items: baseline; border-bottom: 1px solid var(--border); padding-bottom: 0.55rem; }
.keys li span:last-child { color: var(--muted); }

.term {
  margin: 0;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.6rem 1.8rem;
  font-size: 0.95rem;
  line-height: 1.9;
  color: var(--strong);
  overflow-x: auto;
}
.term .p { color: var(--green); }
.term .c { color: var(--muted); }
.cursor { display: inline-block; width: 0.6em; height: 1.1em; background: var(--accent); vertical-align: -0.2em; animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

/* ---------------------------------------------------------------- stats -- */
.stats {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 2rem;
  padding: 3rem 0;
  margin-top: calc(var(--section) * 0.5);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  text-align: center;
}
@media (min-width: 48em) { .stats { grid-template-columns: repeat(4, 1fr); } }
.stats strong { display: block; font-size: clamp(1.8rem, 1.2rem + 2vw, 2.6rem); letter-spacing: -0.02em; line-height: 1; }
.stats span { display: block; margin-top: 0.5rem; color: var(--muted); font-size: 0.9rem; }

/* -------------------------------------------------------------- patrons -- */
.patrons { padding: var(--section) 0 0; text-align: center; }
.patrons__list {
  list-style: none; margin: 2rem 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 1.5rem 1rem;
}
@media (max-width: 48em) { .patrons__list { grid-template-columns: repeat(2, 1fr); } }
.patrons__list li { display: grid; justify-items: center; gap: 0.15rem; font-size: 0.9rem; }
.patrons__list img { width: 4.5rem; border-radius: 999px; filter: grayscale(1) contrast(1.05); margin-bottom: 0.5rem; transition: filter var(--ease); }
.patrons__list li:hover img { filter: none; }
.patrons__list span { color: var(--strong); font-weight: 500; }
.patrons__list small { color: var(--muted); font-size: 0.8rem; }
.patrons__line { margin: 2.5rem 0 0; color: var(--muted); }

/* ---------------------------------------------------------------- watch -- */
.watch { padding: var(--section) 0 0; text-align: center; }
.videos { display: grid; gap: 1rem; margin-top: 2.5rem; }
.video { min-width: 0; }
.video--grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
@media (min-width: 48em) { .video--grid { grid-template-columns: repeat(4, 1fr); } }
.video__facade {
  position: relative; display: block; width: 100%;
  aspect-ratio: 16 / 9; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-2); padding: 0; cursor: pointer;
}
.video__facade img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--ease); }
.video__facade:hover img { transform: scale(1.02); }
.video__play { position: absolute; inset: 0; display: grid; place-items: center; }
.video__play svg { width: min(14%, 4.5rem); filter: drop-shadow(0 4px 14px rgba(0, 0, 0, 0.5)); }
.video--grid .video__facade { border-radius: 8px; }

/* -------------------------------------------------------------- install -- */
.install { padding: var(--section) 0 0; }
.install__text { max-width: var(--text); margin-inline: auto; }
.steps { margin: 2rem 0 0; padding: 0; list-style: none; counter-reset: step; display: grid; gap: 1.4rem; }
.steps li { counter-increment: step; display: grid; grid-template-columns: 2.5rem 1fr; gap: 1rem; align-items: baseline; }
.steps li::before {
  content: counter(step);
  font-weight: 700; color: var(--accent);
  border: 1px solid var(--border); border-radius: 999px;
  width: 2rem; height: 2rem; display: grid; place-items: center;
  font-size: 0.9rem;
}
.install .dim { margin-top: 1.25rem; font-size: 0.9rem; }

/* ----------------------------------------------------------------- news -- */
.news { padding: var(--section) 0; }
.post-list { list-style: none; margin: 2rem 0 0; padding: 0; text-align: left; }
.post-list li { display: grid; grid-template-columns: 6ch 1fr; gap: 1.25rem; padding: 0.8rem 0; border-top: 1px solid var(--border); }
.post-list li:last-child { border-bottom: 1px solid var(--border); }
.post-list time { color: var(--muted); font-size: 0.9rem; padding-top: 0.1em; }
.post-list a { color: var(--strong); font-weight: 500; }

/* --------------------------------------------------------------- footer -- */
.footer { border-top: 1px solid var(--border); padding: 4rem 0 5rem; margin-top: var(--section); font-size: 0.9rem; }
.footer__inner { width: min(100% - 3rem, var(--wrap)); margin-inline: auto; }
.footer__cols { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2.5rem 2rem; }
@media (min-width: 48em) { .footer__cols { grid-template-columns: repeat(4, 1fr); } }
.footer h3 { color: var(--muted); font-size: 0.75rem; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.9rem; }
.footer__cols a { display: block; color: var(--fg); padding: 0.2rem 0; }
.footer__cols a:hover { color: var(--strong); }
.footer__line { color: var(--muted); margin: 3rem 0 0; max-width: 70ch; }
.footer__line a { color: var(--fg); }

/* ------------------------------------------------------------ doc pages -- */
.doc { padding: calc(var(--section) * 0.7) 0 0; }
.doc__head { margin-bottom: 2.5rem; }
.doc__head h1, .prose h1 { font-size: clamp(1.8rem, 1.2rem + 2.4vw, 3rem); line-height: 1.12; }
.doc__head .dim { margin: 0.9rem 0 0; }
.header__subtext { font-style: italic; color: var(--fg); margin: 1rem 0 0; max-width: 60ch; }
.wrap--text .header__subtext { margin-inline: auto; }
.doc.wrap--text { text-align: left; }
.doc.wrap--text .doc__head { text-align: center; }

.manual { display: grid; gap: 3rem; align-items: start; padding: calc(var(--section) * 0.5) 0 0; }
@media (min-width: 64em) {
  .manual { grid-template-columns: 15rem 1fr; gap: 4rem; }
  .manual__side { position: sticky; top: 4.5rem; max-height: calc(100dvh - 5.5rem); overflow: auto; }
}
.manual__side .eyebrow { margin-bottom: 0.75rem; }
.manual__toc ol { list-style: none; margin: 0; padding: 0; font-size: 0.85rem; }
.manual__toc a { display: block; color: var(--muted); padding: 0.22rem 0.6rem; border-left: 2px solid transparent; }
.manual__toc a:hover { color: var(--strong); text-decoration: none; }
.manual__toc a[aria-current="page"] { color: var(--strong); border-left-color: var(--accent); }
.manual .doc { padding-top: 0; max-width: 46rem; }

/* ---------------------------------------------------------------- prose -- */
.prose { max-width: var(--text); }
body[data-type="page"] .prose, body[data-type="news-index"] .prose, body[data-type="manual-toc"] .prose { max-width: none; }
.prose > h1:first-child { margin-bottom: 1rem; }
.prose h2 { font-size: 1.35rem; margin: 2.2em 0 0.6em; }
.prose h3 { margin: 1.8em 0 0.4em; }
.prose p { margin: 0.9em 0; text-wrap: pretty; }
.prose ul, .prose ol { margin: 0.9em 0; padding-left: 1.4em; }
.prose li { margin: 0.3em 0; }
.prose li::marker { color: var(--muted); }
.prose hr { border: 0; border-top: 1px solid var(--border); margin: 2em 0; }
.prose blockquote { margin: 1.2em 0; padding: 0.2em 1.2em; border-left: 2px solid var(--accent); color: var(--fg); }
.prose img { border: 1px solid var(--border); border-radius: 8px; }
.prose figure { margin: 1.5em 0; }
.prose figcaption { color: var(--muted); font-size: 0.85em; margin-top: 0.5em; }
.prose code { font-family: inherit; font-size: 0.92em; color: var(--strong); background: var(--surface); border-radius: 5px; padding: 0.1em 0.4em; }
.prose pre {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.2rem;
  overflow-x: auto;
  line-height: 1.55;
  margin: 1.2em 0;
}
.prose pre code { background: none; padding: 0; color: var(--fg); }
.prose table { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 0.92em; display: block; overflow-x: auto; }
.prose th, .prose td { border-bottom: 1px solid var(--border); padding: 0.55em 0.8em; text-align: left; vertical-align: top; }
.prose th { color: var(--muted); font-weight: 500; font-size: 0.8em; letter-spacing: 0.06em; text-transform: uppercase; }
.prose iframe, .prose video { max-width: 100%; border-radius: 8px; }

.manual__pagination {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.5rem 1.5rem;
  border-top: 1px solid var(--border);
  margin-top: 2.5em; padding-top: 1.2em;
  font-size: 0.9em; font-weight: 500;
}
.prose > .manual__pagination:first-of-type { display: none; }  /* one set is enough: the bottom */
.manual__pagination-contents { color: var(--muted); }

/* ------------------------------------------ original content families ---- */
.news-card { border-top: 1px solid var(--border); padding: 1.4rem 0; }
.news-card:first-child { border-top: 0; padding-top: 0; }
.news-card__title { margin: 0 0 0.3em; font-size: 1.15rem; }
.news-card__title a { color: var(--strong); }
.news-meta, .news-date, .news-byline { color: var(--muted); font-size: 0.85em; }

.themes__intro { max-width: 60ch; }
.themes__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 1.5rem; margin-top: 2rem; }
.themes__theme { margin: 0; }
.themes__theme img { border-radius: 8px; box-shadow: none; transition: transform var(--ease); }
.themes__theme a:hover img { transform: translateY(-2px); }
.themes__theme figcaption { font-size: 0.9em; font-weight: 500; margin-top: 0.6rem; }

.workstations__images { display: grid; grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); gap: 1.25rem; }
.workstations__image { border: 0; background: none; padding: 0; cursor: zoom-in; }
.workstations__image figure { margin: 0; }
.workstations__image img { border-radius: 8px; width: 100%; }

.team { margin: 0 0 3rem; }
.team__members { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 1.25rem; margin-top: 1.5rem; }
.member { display: grid; gap: 0.3rem; font-size: 0.9em; }
.member img { border-radius: 999px; width: 100%; }
.member h3, .member strong { color: var(--strong); font-size: 1em; margin: 0.6rem 0 0; }

.air__lede { font-style: italic; font-size: 1.1em; max-width: 60ch; }
.resident { display: grid; grid-template-columns: 5.5rem 1fr; gap: 0.4rem 1.5rem; align-items: start; margin: 2rem 0; }
.resident > * { grid-column: 2; margin: 0; }
.resident__avatar { grid-column: 1; grid-row: 1 / span 4; border-radius: 999px; width: 100%; }
@media (max-width: 40em) { .resident { grid-template-columns: 1fr; } .resident__avatar { max-width: 6rem; } }

.sponsorship { border-top: 1px solid var(--border); padding: 2rem 0; max-width: 60ch; }
.sponsorship:first-child { border-top: 0; padding-top: 0; }
.sponsorship__logo img { max-height: 3.2rem; width: auto; max-width: 14rem; }
.sponsorship__name { margin: 1em 0 0; }
.sponsorship__terms { color: var(--green); font-weight: 700; font-size: 0.8em; letter-spacing: 0.08em; text-transform: uppercase; margin: 0.2em 0 0; }

.brand__section { margin: 0 0 3rem; }
.brand__figure { background: #fff; border-radius: var(--radius); padding: 2.5rem; display: grid; place-items: center; }
.brand__figure img { max-width: 24rem; border: 0; }
.brand__files { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 1.5rem; font-size: 0.9em; }
.brand__hint { color: var(--muted); }

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

/* ==========================================================================
   Omarchy Text: the wordmark's grid, stems trimmed 25 units a side for reading.
   Caps only. Cap height is 80% of the em, so sizes run a little smaller.
   ========================================================================== */
@font-face {
  font-family: 'Omarchy Light';
  src: url('fonts/OmarchyLight.woff2?v=1788390373') format('woff2');
  font-weight: 400; font-style: normal; font-display: block;
}
:root { --display: 'Omarchy Light', 'JetBrains Mono', monospace; --small: 'Omarchy Small', 'JetBrains Mono', monospace; }
@font-face {
  font-family: 'Omarchy Small';
  src: url('fonts/OmarchySmall.woff2?v=1788390373') format('woff2');
  font-weight: 400; font-style: normal; font-display: block;
}

h1, h2, .mission__line, .stats strong, .doc__head h1, .prose h1, .prose h2 {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}
.hero__h1 { font-size: clamp(1.5rem, 0.8rem + 3vw, 3.3rem); line-height: 1.18; max-width: 18ch; }
h2 { font-size: clamp(1.25rem, 0.8rem + 1.7vw, 2rem); line-height: 1.22; }
.mission__line { font-size: clamp(1.5rem, 1rem + 2.6vw, 3rem); line-height: 1.2; }
.stats strong { font-size: clamp(1.5rem, 1rem + 1.7vw, 2.2rem); }
.doc__head h1, .prose h1 { font-size: clamp(1.4rem, 1rem + 1.9vw, 2.4rem); line-height: 1.2; }
.prose h2 { font-size: 0.92rem; letter-spacing: 0.04em; }

.nav__brand { font-family: var(--display); font-size: 1.05rem; color: var(--green); letter-spacing: 0.02em; }
.nav__brand:hover { text-decoration: none; color: var(--strong); }
.footer h3 { font-family: var(--display); font-size: 0.7rem; letter-spacing: 0.08em; }

/* Text cut is light enough to carry more than headings. */
.nav__links, .nav__cta, .btn, .eyebrow, .stats span, .steps li::before, .footer__cols a, .more, .footer h3, .prose h2 {
  font-family: var(--small); font-weight: 400; text-transform: uppercase;
}
.nav__links { font-size: 0.62rem; letter-spacing: 0.1em; gap: 2rem; }
.nav__cta { font-size: 0.55rem; letter-spacing: 0.1em; padding: 1.05em 1.6em 0.95em; }
.btn { font-size: 0.6rem; letter-spacing: 0.1em; padding: 1.6em 2.4em 1.5em; line-height: 1; }
.eyebrow { font-size: 0.62rem; letter-spacing: 0.12em; }
.stats span { font-size: 0.62rem; letter-spacing: 0.08em; }
.footer__cols a { font-size: 0.68rem; letter-spacing: 0.04em; }
.more { font-size: 0.7rem; letter-spacing: 0.05em; }
.hero__h1 { line-height: 1.24; }
h2 { line-height: 1.28; }
.doc__head h1, .prose h1 { line-height: 1.26; }

/* Theme chip in the nav. */
.theme-chip {
  display: inline-flex; align-items: center; gap: 0.7ch;
  font-family: var(--small); font-size: 0.55rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--strong); background: color-mix(in srgb, var(--surface) 70%, transparent);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 1.05em 1.3em 0.95em; cursor: pointer; margin-left: 1.5rem;
}
.theme-chip:hover { border-color: var(--accent); }
.theme-chip i { width: 0.7em; height: 0.7em; border-radius: 50%; background: var(--accent); display: inline-block; }
@media (max-width: 48em) { .theme-chip span { display: none; } .theme-chip { margin-left: auto; } }

/* Theme grid replaces the collage in the themes feature. */
.themes-grid { list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); gap: 0.6rem; }
.theme-btn {
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 0.7rem;
  width: 100%; text-align: left;
  font-family: var(--font); font-weight: 500; font-size: 0.82rem;
  color: var(--tfg); background: var(--tbg);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 0.6rem 0.75rem; cursor: pointer;
  transition: border-color var(--ease), transform var(--ease);
}
.theme-btn:hover { border-color: var(--accent); transform: translateY(-1px); }
.theme-btn[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.theme-btn .dots { display: grid; grid-template-columns: repeat(2, 0.65em); gap: 2px; }
.theme-btn .dots i { width: 0.65em; height: 0.65em; display: block; border-radius: 2px; }
.theme-btn .name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* GitHub Invertocat, monochrome per GitHub's logo guidelines. */
.nav__gh { display: inline-flex; align-items: center; color: var(--strong); margin-left: 0.25rem; }
.nav__gh svg { width: 1.15rem; height: 1.15rem; }
.nav__gh:hover { color: var(--accent); text-decoration: none; }

/* One line box for everything in the nav, centered on the same axis. */
.nav__inner { align-items: center; }
.nav__links { align-items: center; }
.nav__links a, .nav__cta, .theme-chip, .nav__gh { display: inline-flex; align-items: center; line-height: 1; }
.nav__gh svg { display: block; }

/* Mobile: a hamburger opens the links as a panel under the bar. */
.nav__toggle { display: none; margin-left: 0.75rem; width: 2.4rem; height: 2.4rem; padding: 0; border: 1px solid var(--border); border-radius: 8px; background: none; cursor: pointer; flex-direction: column; align-items: center; justify-content: center; gap: 5px; }
.nav__toggle span { display: block; width: 1.05rem; height: 2px; background: var(--strong); border-radius: 1px; transition: transform var(--ease), opacity var(--ease); }
.nav.is-open .nav__toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav.is-open .nav__toggle span:nth-child(2) { opacity: 0; }
.nav.is-open .nav__toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (max-width: 48em) {
  .nav { position: sticky; }
  .nav__toggle { display: inline-flex; }
  .nav__links { display: none; }
  .nav.is-open .nav__links {
    display: flex; flex-direction: column; align-items: flex-start; gap: 1.1rem;
    position: absolute; top: 100%; left: 0; right: 0;
    padding: 1.25rem 1.5rem 1.5rem;
    background: color-mix(in srgb, var(--bg) 96%, transparent);
    border-bottom: 1px solid var(--border);
    font-size: 1rem;
  }
  .nav.is-open .nav__links a { font-size: 1rem; }
  .nav__gh { margin-left: 0; }
}

/* Fixed-width chip so a longer theme name never shifts the other links. */
.theme-chip { width: 12.6rem; justify-content: center; }
.theme-chip span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 48em) { .theme-chip { width: auto; } }

/* Mobile bar: tighter so brand, chip, Download and the menu button all fit. */
@media (max-width: 48em) {
  .nav__inner { gap: 0.6rem; width: min(100% - 2rem, var(--wrap)); }
  .nav__brand { font-size: 0.85rem; }
  .nav__brand .logo { height: 0.9rem; }
  .nav__cta { padding-inline: 1.1em; margin-left: auto; }
  .theme-chip { margin-left: auto; padding-inline: 0.8em; }
  .theme-chip + .nav__cta { margin-left: 0; }
  .nav__toggle { margin-left: 0.25rem; flex: none; }
}

/* Mid widths (48-72em): the bar carries too much. Swap the wordmark for the
   square mark and collapse the theme chip to its dot. Links and Download stay. */
.brand-mark { display: none; line-height: 0; }
.brand-mark .mark { height: 1.35rem; width: auto; fill: var(--green); display: block; }
@media (min-width: 48em) and (max-width: 72em) {
  .brand-word { display: none; }
  .brand-mark { display: block; }
  .nav__inner { gap: 1.25rem; }
  .nav__links { gap: 1.25rem; }
  .theme-chip { width: auto; padding-inline: 0.9em; margin-left: 0.5rem; }
  .theme-chip span { display: none; }
}

/* Site notice: the thin banner the current site runs above everything. */
.notice {
  display: block; text-align: center;
  padding: 0.55rem 1.5rem 0.5rem;
  background: var(--accent); color: var(--bg);
  font-size: 0.85rem; font-weight: 500;
}

/* Etch reveal for the wordmark (see site.js). */
.logo.etch rect { opacity: 0; animation: etch-in 0.45s ease-out forwards; }
@keyframes etch-in { 0% { opacity: 0; fill: #fff; } 30% { opacity: 1; fill: #fff; } 100% { opacity: 1; fill: var(--green); } }
.etch-beam {
  position: absolute; top: -12%; bottom: -12%; left: 0; width: 3px;
  background: #fff; box-shadow: 0 0 14px 4px color-mix(in srgb, var(--green) 70%, #fff), 0 0 40px 10px color-mix(in srgb, var(--green) 45%, transparent);
  pointer-events: none; opacity: 0.95;
  animation: etch-beam linear forwards;
}
@keyframes etch-beam { 0% { left: 0; opacity: 0.95; } 85% { opacity: 0.95; } 100% { left: 100%; opacity: 0; } }


/* ------------------------------------------------------- subpage hero ---- */
.subhero {
  text-align: center;
  padding: calc(var(--section) * 0.75) 0 calc(var(--section) * 0.55);
  border-bottom: 1px solid var(--border);
  margin-bottom: calc(var(--section) * 0.55);
}
.subhero h1 { font-size: clamp(1.8rem, 1.2rem + 2.4vw, 3rem); line-height: 1.15; margin-inline: auto; max-width: 20ch; }
.subhero .eyebrow { margin-bottom: 1.1rem; }
.subhero .dim { margin: 1rem 0 0; }
.subhero .header__subtext { margin: 1.25rem auto 0; font-style: normal; color: var(--fg); font-size: 1.05rem; max-width: 46rem; }
.doc { padding-top: 0; }
.doc.wrap--text { text-align: left; }

/* Shared .button markup that arrives inside content (e.g. the Luma link). */
.prose .button {
  display: inline-flex; align-items: center; gap: 0.7ch;
  font-weight: 700; font-size: 0.95rem;
  background: var(--accent); color: var(--bg);
  padding: 0.75em 1.4em; border-radius: 999px;
}
.prose .button:hover { text-decoration: none; filter: brightness(1.1); }
.prose .button svg { width: 1.1em; height: 1.1em; fill: currentColor; flex: none; }

/* Meetups: Luma embed + the rules list. */
.meetups { display: grid; gap: 3rem; max-width: 46rem; margin: 0 auto; }
.meetups__calendar { display: grid; gap: 1.25rem; justify-items: center; text-align: center; }
.meetups__embed { width: 100%; height: 450px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-2); }
.rules { border-top: 1px solid var(--border); padding-top: 2.5rem; display: grid; gap: 1.5rem; }
.rules__header { text-align: center; }
.rules__title { margin: 0; font-size: 0.9rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--strong); }
.rules ol { list-style: none; margin: 0; padding: 0; counter-reset: rule; display: grid; gap: 1.1rem; }
.rules .rule { position: relative; padding-left: 3.25rem; margin: 0; }
.rules .rule::before { counter-increment: rule; content: counter(rule); position: absolute; left: 0; top: -0.15rem; font-weight: 700; color: var(--accent); border: 1px solid var(--border); border-radius: 999px; width: 2rem; height: 2rem; display: grid; place-items: center; font-size: 0.9rem; }
.rule__name { display: block; margin-bottom: 0.25rem; }
.rule__name { color: var(--strong); font-weight: 700; }
.rules__note { border-top: 1px solid var(--border); padding-top: 1.5rem; color: var(--muted); text-align: center; }

/* Wallpaper behind the subpage hero too, more heavily veiled than on home. */
.subhero {
  background-image:
    linear-gradient(to bottom, color-mix(in srgb, var(--bg) 60%, transparent), color-mix(in srgb, var(--bg) 88%, transparent) 70%, var(--bg)),
    var(--wall);
  background-size: cover, cover; background-position: center, center 35%;
  border-bottom: 0;
}
.subhero h1 { text-shadow: 0 2px 24px color-mix(in srgb, var(--bg) 90%, transparent); }

/* Dismissable notice. */
.notice { position: relative; padding-inline: 3rem; }
.notice__link { color: inherit; display: block; }
.notice__link:hover { text-decoration: underline; }
.notice__close {
  position: absolute; right: 0.75rem; top: 50%; transform: translateY(-50%);
  width: 1.7rem; height: 1.7rem; border: 0; border-radius: 999px;
  background: transparent; color: inherit; opacity: 0.6;
  font: inherit; font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.notice__close:hover { opacity: 1; background: color-mix(in srgb, var(--bg) 18%, transparent); }
.notice[hidden] { display: none; }

/* Text etch (hero headline). */
.etch-text .etch-ch { display: inline-block; opacity: 0; animation: etch-ch 0.32s ease-out forwards; }
@keyframes etch-ch { 0% { opacity: 0; color: #fff; text-shadow: 0 0 14px #fff; } 40% { opacity: 1; color: #fff; text-shadow: 0 0 8px #fff; } 100% { opacity: 1; color: inherit; text-shadow: none; } }
.etch-text .etch-beam { top: -10%; bottom: -10%; }
.etch-text .etch-word { display: inline-block; white-space: nowrap; }

/* Brand hover etch: the small nav wordmark/text uses the same keyframes. */
.nav__brand .etch-text, .nav__brand .logo.etch { cursor: pointer; }
.brand-word.etch-text .etch-ch { display: inline-block; }
.etch-beam { display: none; }

/* ---- Laseretch headline (see etch.js) ------------------------------------
   The <pre> is the layout box and the fallback; the canvas etches over it. */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.hero__h1--etch { max-width: none; line-height: 0; }
.etchbox { display: block; position: relative; width: fit-content; max-width: 100%; margin: 0 auto; overflow: hidden; }
.etchart {
  margin: 0; color: var(--strong);
  font-family: var(--font); font-weight: 400;
  font-size: clamp(0.28rem, 0.72vw, 0.56rem); line-height: 1.09; letter-spacing: -0.04em;
  white-space: pre; text-align: left; display: inline-block;
}
.etchbox--pending .etchart { visibility: hidden; animation: etch-fallback 0s 2.5s forwards; }
@keyframes etch-fallback { to { visibility: visible; } }
.etchbox--live .etchart { visibility: hidden; animation: none; }
.etchbox canvas { position: absolute; left: 0; top: 0; transform-origin: 0 0; mix-blend-mode: screen; pointer-events: none; }
:root[data-light="1"] .etchbox canvas { mix-blend-mode: multiply; }

/* Settled state: the same art as an SVG in the theme colour. The canvas
   fades out over it when the effect finishes. */
.etchfinal { position: absolute; inset: 0; display: block; opacity: 0; transition: opacity 0.7s ease; }
.etchfinal__svg { display: block; width: 100%; height: 100%; fill: var(--strong); }
.etchbox canvas { transition: opacity 0.7s ease; }
.etchbox--done .etchfinal { opacity: 1; }
.etchbox--done canvas { opacity: 0; }
.etchbox--pending .etchfinal, .etchbox--static .etchfinal { opacity: 1; transition: none; }
.etchbox--static .etchart { visibility: hidden; }

/* Lead paragraph under a centered subpage hero: centered too. */
body[data-type="page"] .doc .prose > p:first-child,
.doc .prose .themes__intro, .doc .prose .air__lede, .doc .prose .meetups__calendar > p {
  display: block; max-width: 60ch; margin: 0 auto 2.5rem; text-align: center; text-wrap: balance;
}

/* ==========================================================================
   Stage: features that use the screen. Text sits in the column; the
   screenshot is big and runs off the viewport edge.
   ========================================================================== */
.stage { position: relative; overflow: hidden; padding: calc(var(--section) * 0.7) 0; }
.stage__inner {
  width: min(100% - 3rem, var(--wrap)); margin-inline: auto;
  display: grid; align-items: center; gap: clamp(2rem, 4vw, 4rem);
}
.stage__text p { margin: 1.25rem 0 0; max-width: 40ch; text-wrap: pretty; }
.stage__text .keys { margin-top: 1.5rem; }
.stage__img, .stage__term {
  width: 100%;
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 60px 120px -40px rgba(0, 0, 0, 0.85);
}
@media (min-width: 60em) {
  .stage__inner { grid-template-columns: 26rem minmax(0, 1fr); }
  .stage--left .stage__inner { grid-template-columns: minmax(0, 1fr) 26rem; }
  .stage__text { min-width: 0; }
  /* 60vw of screenshot, cropped by the viewport edge. */
  .stage--right .stage__img, .stage--right .stage__term { width: 60vw; max-width: none; justify-self: start; }
  .stage--left .stage__img { width: 60vw; max-width: none; justify-self: end; }
  .stage--right .stage__term { width: 52vw; }
}
/* Fanned stack of three desktops. */
.stage__stack { position: relative; aspect-ratio: 16 / 10; }
.stage__stack img {
  position: absolute; width: 78%; left: 0; top: 0;
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.85);
  transition: transform 0.6s cubic-bezier(0.33, 1, 0.68, 1);
}
.stage__stack img:nth-child(1) { transform: translate(-14%, 4%) rotate(-3deg); z-index: 1; }
.stage__stack img:nth-child(2) { transform: translate(4%, 18%) rotate(1.5deg); z-index: 2; }
.stage__stack img:nth-child(3) { transform: translate(22%, 32%) rotate(4deg); z-index: 3; }
.stage--stack:hover .stage__stack img:nth-child(1) { transform: translate(-20%, 0%) rotate(-5deg); }
.stage--stack:hover .stage__stack img:nth-child(3) { transform: translate(28%, 36%) rotate(6deg); }
@media (min-width: 60em) { .stage--stack .stage__stack { width: 52vw; max-width: none; justify-self: end; } }
.stage .themes-grid { margin-top: 1.5rem; grid-template-columns: repeat(auto-fill, minmax(7.2rem, 1fr)); gap: 0.4rem; }
.stage .theme-btn { font-size: 0.72rem; padding: 0.45rem 0.55rem; }

/* + buttons and modals, Apple product-page style. */
.plus {
  display: inline-flex; align-items: center; gap: 0.7rem; margin-top: 1.5rem;
  font: inherit; font-weight: 500; font-size: 0.9rem; color: var(--strong);
  background: none; border: 0; padding: 0; cursor: pointer;
}
.plus__ring {
  display: grid; place-items: center; width: 1.9rem; height: 1.9rem; border-radius: 999px;
  background: var(--accent); color: var(--bg); font-size: 1.3rem; line-height: 1; font-weight: 500;
  transition: transform var(--ease);
}
.plus:hover .plus__ring { transform: scale(1.08); }
.plus:hover { text-decoration: underline; }

.modal { border: 0; padding: 0; background: none; max-width: none; max-height: none; width: 100%; height: 100%; }
.modal::backdrop { background: color-mix(in srgb, #000 60%, transparent); backdrop-filter: blur(10px); }
.modal[open] { display: grid; place-items: center; }
.modal__box {
  position: relative; width: min(60rem, 92vw); max-height: 88vh; overflow: auto;
  background: var(--bg); color: var(--fg); border: 1px solid var(--border); border-radius: 20px;
  padding: clamp(1.5rem, 4vw, 3.5rem);
  box-shadow: 0 60px 120px -30px rgba(0, 0, 0, 0.9);
  animation: modal-in 0.35s cubic-bezier(0.33, 1, 0.68, 1);
}
@keyframes modal-in { from { opacity: 0; transform: translateY(18px) scale(0.98); } to { opacity: 1; transform: none; } }
.modal__box h2 { margin: 0.25rem 0 1rem; }
.modal__box p { margin: 0.9em 0; max-width: 62ch; }
.modal__box .keys { max-width: 34rem; margin: 1.25rem 0; }
.modal__box img { width: 100%; border-radius: 12px; border: 1px solid var(--border); margin-top: 1.5rem; }
.modal__collage { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-top: 1.5rem; }
.modal__collage img { margin: 0; border-radius: 8px; }
.modal__close {
  position: absolute; top: 1rem; right: 1rem; width: 2.4rem; height: 2.4rem; border-radius: 999px;
  border: 0; background: var(--surface); color: var(--strong); font: inherit; font-size: 1.5rem; line-height: 1; cursor: pointer;
}
.modal__close:hover { background: var(--border); }
body.modal-open { overflow: hidden; }
@media (prefers-reduced-motion: reduce) { .modal__box { animation: none; } .stage__stack img { transition: none; } }

/* ==========================================================================
   Docs layout for the manual: grouped chapters | chapter | on this page.
   Same chrome and hero band as every other page.
   ========================================================================== */
.subhero--docs { padding-bottom: calc(var(--section) * 0.35); margin-bottom: 0; }
.subhero--docs h1 { font-size: clamp(1.6rem, 1.1rem + 2vw, 2.6rem); }
.docs { display: grid; gap: 3rem; align-items: start; padding: 2.5rem 0 4rem; }
@media (min-width: 64em) { .docs { grid-template-columns: 16rem minmax(0, 1fr); gap: 4rem; } }
@media (min-width: 84em) { .docs { grid-template-columns: 16rem minmax(0, 1fr) 13rem; } }

/* Sidebar */
.docs__side { position: sticky; top: 4.5rem; max-height: calc(100dvh - 5.5rem); overflow: auto; padding-right: 0.5rem; font-size: 0.85rem; }
@media (max-width: 64em) { .docs__side { position: static; max-height: none; } }
.docs__search { position: relative; display: block; margin-bottom: 1.25rem; }
.docs__search input {
  width: 100%; font: inherit; color: var(--strong);
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  padding: 0.55rem 2.4rem 0.55rem 0.8rem;
}
.docs__search kbd { position: absolute; right: 0.6rem; top: 50%; transform: translateY(-50%); font-size: 0.75rem; }
.toc-group { border-top: 1px solid var(--border); }
.toc-group:first-of-type { border-top: 0; }
.toc-group summary {
  list-style: none; cursor: pointer;
  font-family: var(--small); font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); padding: 0.85rem 0.35rem 0.6rem; display: flex; justify-content: space-between; align-items: center;
}
.toc-group summary::-webkit-details-marker { display: none; }
.toc-group summary::after { content: "+"; font-family: var(--font); font-size: 1rem; color: var(--muted); }
.toc-group[open] summary::after { content: "–"; }
.toc-group summary:hover { color: var(--strong); }
.toc-group ol { list-style: none; margin: 0 0 0.75rem; padding: 0; }
.manual__toc--grouped a { display: block; color: var(--fg); padding: 0.28rem 0.6rem; border-left: 2px solid var(--border); margin-left: 0.35rem; }
.manual__toc--grouped a:hover { color: var(--strong); border-left-color: var(--muted); text-decoration: none; }
.manual__toc--grouped a[aria-current="page"] { color: var(--strong); border-left-color: var(--accent); font-weight: 500; }
.manual__toc--grouped li[hidden] { display: none; }
.toc-group.is-filtered summary { display: none; }

/* Chapter */
.docs__main { min-width: 0; }
.docs__main .prose { max-width: 46rem; }
.docs__main .prose > h1:first-child { display: none; }          /* the hero band shows it */
.docs__main .prose > .manual__pagination:first-of-type { display: none; }
.docs__main .prose h2 { scroll-margin-top: 5rem; padding-top: 0.5rem; }
.docs__main .prose h2 a.anchor { color: var(--muted); opacity: 0; margin-left: 0.4ch; font-weight: 400; text-decoration: none; }
.docs__main .prose h2:hover a.anchor { opacity: 1; }
.docs__main .prose pre { border-radius: 12px; }
/* prev / next as two cards */
.docs__main .manual__pagination {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; border-top: 0; margin-top: 3rem; padding-top: 0;
  font-family: var(--font); font-size: 0.95rem;
}
.docs__main .manual__pagination a { display: block; border: 1px solid var(--border); border-radius: 12px; padding: 1rem 1.2rem; color: var(--strong); font-weight: 500; }
.docs__main .manual__pagination a:hover { border-color: var(--accent); text-decoration: none; }
.docs__main .manual__pagination-prev, .docs__main .manual__pagination-previous { text-align: left; }
.docs__main .manual__pagination-next { text-align: right; }
.docs__main .manual__pagination-contents { display: none; }
.docs__main .manual__pagination a::before { display: block; font-family: var(--small); font-size: 0.55rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin-bottom: 0.4rem; }
.docs__main .manual__pagination-previous::before, .docs__main .manual__pagination-prev::before { content: "Previous"; }
.docs__main .manual__pagination-next::before { content: "Next"; }

/* Section cards on the manual's front page */
.doc-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1rem; margin-top: 3rem; }
.doc-card { border: 1px solid var(--border); border-radius: 14px; padding: 1.25rem 1.4rem; background: var(--surface); }
.doc-card h3 { margin: 0 0 0.75rem; font-family: var(--small); font-weight: 400; font-size: 0.65rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); }
.doc-card ul { list-style: none; margin: 0; padding: 0; font-size: 0.9rem; }
.doc-card li { padding: 0.22rem 0; }
.doc-card a { color: var(--strong); }
.doc-card .more-count { color: var(--muted); font-size: 0.8rem; padding-top: 0.4rem; }

/* On this page */
.docs__onpage { position: sticky; top: 4.5rem; font-size: 0.82rem; display: none; }
@media (min-width: 84em) { .docs__onpage:not([hidden]) { display: block; } }
.docs__onpage .eyebrow { margin-bottom: 0.75rem; }
.docs__onpage a { display: block; color: var(--muted); padding: 0.22rem 0.75rem; border-left: 2px solid var(--border); }
.docs__onpage a:hover { color: var(--strong); text-decoration: none; }
.docs__onpage a.is-active { color: var(--strong); border-left-color: var(--accent); }

/* Form fields: focus is an accent border plus a soft ring, no offset gap. */
input:focus-visible, select:focus-visible, textarea:focus-visible, .docs__search input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
}

/* The hero H1 is etched letter by letter (spans), which disables kerning during the
   animation. Keep kerning off permanently so the text does not shift when the spans go. */
.hero__h1 { font-kerning: none; font-feature-settings: 'kern' 0; }

/* ==========================================================================
   The Omarch — mascot drawn from the square logo's 15x15 grid.
   Lives in the footer, cropped below the waist; hover and he peeks up.
   ========================================================================== */
.footer { position: relative; overflow: hidden; }
.mascot {
  --px: 7px;
  position: absolute; left: 0; bottom: 0;
  width: calc(var(--px) * 17); height: calc(var(--px) * 17);
  font-size: var(--px); line-height: 0;
  pointer-events: auto; cursor: pointer;
  transition: bottom 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
  animation: mascot-bob 3.2s ease-in-out infinite;
}
.mascot > i { position: absolute; left: 1em; top: 0; width: 1em; height: 1em; display: block; }
.mascot__body { background: transparent; box-shadow:
    0em 0em 0 0 var(--green),
    1em 0em 0 0 var(--green),
    2em 0em 0 0 var(--green),
    3em 0em 0 0 var(--green),
    4em 0em 0 0 var(--green),
    5em 0em 0 0 var(--green),
    6em 0em 0 0 var(--green),
    7em 0em 0 0 var(--green),
    8em 0em 0 0 var(--green),
    9em 0em 0 0 var(--green),
    10em 0em 0 0 var(--green),
    11em 0em 0 0 var(--green),
    12em 0em 0 0 var(--green),
    13em 0em 0 0 var(--green),
    14em 0em 0 0 var(--green),
    0em 1em 0 0 var(--green),
    7em 1em 0 0 var(--green),
    14em 1em 0 0 var(--green),
    0em 2em 0 0 var(--green),
    2em 2em 0 0 var(--green),
    3em 2em 0 0 var(--green),
    4em 2em 0 0 var(--green),
    5em 2em 0 0 var(--green),
    6em 2em 0 0 var(--green),
    7em 2em 0 0 var(--green),
    11em 2em 0 0 var(--green),
    12em 2em 0 0 var(--green),
    14em 2em 0 0 var(--green),
    0em 3em 0 0 var(--green),
    2em 3em 0 0 var(--green),
    12em 3em 0 0 var(--green),
    14em 3em 0 0 var(--green),
    0em 4em 0 0 var(--green),
    2em 4em 0 0 var(--green),
    12em 4em 0 0 var(--green),
    14em 4em 0 0 var(--green),
    0em 5em 0 0 var(--green),
    2em 5em 0 0 var(--green),
    12em 5em 0 0 var(--green),
    14em 5em 0 0 var(--green),
    0em 6em 0 0 var(--green),
    2em 6em 0 0 var(--green),
    12em 6em 0 0 var(--green),
    14em 6em 0 0 var(--green),
    0em 7em 0 0 var(--green),
    1em 7em 0 0 var(--green),
    2em 7em 0 0 var(--green),
    12em 7em 0 0 var(--green),
    14em 7em 0 0 var(--green),
    0em 8em 0 0 var(--green),
    2em 8em 0 0 var(--green),
    12em 8em 0 0 var(--green),
    14em 8em 0 0 var(--green),
    0em 9em 0 0 var(--green),
    2em 9em 0 0 var(--green),
    12em 9em 0 0 var(--green),
    14em 9em 0 0 var(--green),
    0em 10em 0 0 var(--green),
    2em 10em 0 0 var(--green),
    12em 10em 0 0 var(--green),
    14em 10em 0 0 var(--green),
    0em 11em 0 0 var(--green),
    2em 11em 0 0 var(--green),
    12em 11em 0 0 var(--green),
    14em 11em 0 0 var(--green),
    0em 12em 0 0 var(--green),
    2em 12em 0 0 var(--green),
    3em 12em 0 0 var(--green),
    4em 12em 0 0 var(--green),
    5em 12em 0 0 var(--green),
    6em 12em 0 0 var(--green),
    7em 12em 0 0 var(--green),
    8em 12em 0 0 var(--green),
    9em 12em 0 0 var(--green),
    10em 12em 0 0 var(--green),
    11em 12em 0 0 var(--green),
    12em 12em 0 0 var(--green),
    14em 12em 0 0 var(--green),
    0em 13em 0 0 var(--green),
    7em 13em 0 0 var(--green),
    14em 13em 0 0 var(--green),
    0em 14em 0 0 var(--green),
    1em 14em 0 0 var(--green),
    2em 14em 0 0 var(--green),
    3em 14em 0 0 var(--green),
    4em 14em 0 0 var(--green),
    5em 14em 0 0 var(--green),
    6em 14em 0 0 var(--green),
    7em 14em 0 0 var(--green),
    9em 14em 0 0 var(--green),
    10em 14em 0 0 var(--green),
    11em 14em 0 0 var(--green),
    12em 14em 0 0 var(--green),
    13em 14em 0 0 var(--green),
    14em 14em 0 0 var(--green); }
.mascot__eyes { background: transparent; transform-origin: 0 6em; transition: transform 0.25s ease;
  animation: mascot-blink 5s steps(1) infinite; box-shadow:
    5em 5em 0 0 var(--green),
    5em 6em 0 0 var(--green),
    9em 5em 0 0 var(--green),
    9em 6em 0 0 var(--green); }
.mascot__mouth { background: transparent; transition: box-shadow 0.25s ease; box-shadow:
    6em 9em 0 0 var(--green),
    6em 9em 0 0 var(--green),
    6em 9em 0 0 var(--green),
    7em 9em 0 0 var(--green),
    8em 9em 0 0 var(--green),
    8em 9em 0 0 var(--green),
    8em 9em 0 0 var(--green); }
.mascot__arms { background: transparent; transition: transform 0.25s ease; box-shadow:
    -1em 7em 0 0 var(--green),
    -1em 8em 0 0 var(--green),
    15em 7em 0 0 var(--green),
    15em 8em 0 0 var(--green); }
.mascot__legs { background: transparent; box-shadow:
    3em 15em 0 0 var(--green),
    3em 16em 0 0 var(--green),
    5em 15em 0 0 var(--green),
    5em 16em 0 0 var(--green),
    9em 15em 0 0 var(--green),
    9em 16em 0 0 var(--green),
    11em 15em 0 0 var(--green),
    11em 16em 0 0 var(--green); }

.mascot:hover { bottom: calc(var(--px) * 1); animation: mascot-jump 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) 0.15s 1; }
.mascot:hover .mascot__eyes { transform: none; animation: mascot-wink 2.4s ease-in-out 0.6s infinite; box-shadow:
    5em 4em 0 0 var(--green),
    5em 5em 0 0 var(--green),
    9em 4em 0 0 var(--green),
    9em 5em 0 0 var(--green); }
.mascot:hover .mascot__mouth { animation: mascot-grin 2.4s ease-in-out 0.6s infinite; box-shadow:
    5em 8em 0 0 var(--green),
    5em 8em 0 0 var(--green),
    6em 9em 0 0 var(--green),
    7em 9em 0 0 var(--green),
    8em 9em 0 0 var(--green),
    9em 8em 0 0 var(--green),
    9em 8em 0 0 var(--green); }
.mascot:hover .mascot__arms { animation: mascot-wave 0.5s ease-in-out infinite alternate; }
.mascot:hover .mascot__legs { animation: mascot-legs 0.35s steps(2) infinite; }

@keyframes mascot-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-0.4em); } }
@keyframes mascot-blink { 0%, 92%, 100% { transform: scaleY(1); } 94%, 98% { transform: scaleY(0.15); } }
@keyframes mascot-wave { from { transform: translateY(0); } to { transform: translateY(-2em); } }
@keyframes mascot-legs { from { transform: translateY(0); } to { transform: translateY(-1em); } }
@keyframes mascot-jump { 0% { transform: translateY(0); } 35% { transform: translateY(-1.8em) scaleY(1.06); } 70% { transform: translateY(0) scaleY(0.92); } 100% { transform: translateY(0); } }
@keyframes mascot-wink {
  0%, 30%, 62%, 100% { box-shadow: 5em 4em 0 0 var(--green),
    5em 5em 0 0 var(--green),
    9em 4em 0 0 var(--green),
    9em 5em 0 0 var(--green); }
  40%, 54% { box-shadow: 5em 4em 0 0 var(--green),
    5em 5em 0 0 var(--green),
    9em 5em 0 0 var(--green),
    9em 5em 0 0 var(--green); }
}
@keyframes mascot-grin {
  0%, 42%, 100% { box-shadow: 5em 8em 0 0 var(--green),
    5em 8em 0 0 var(--green),
    6em 9em 0 0 var(--green),
    7em 9em 0 0 var(--green),
    8em 9em 0 0 var(--green),
    9em 8em 0 0 var(--green),
    9em 8em 0 0 var(--green); }
  55%, 86% { box-shadow: 4em 7em 0 0 var(--green),
    5em 8em 0 0 var(--green),
    6em 9em 0 0 var(--green),
    7em 9em 0 0 var(--green),
    8em 9em 0 0 var(--green),
    9em 8em 0 0 var(--green),
    10em 7em 0 0 var(--green); }
}
@media (prefers-reduced-motion: reduce) { .mascot, .mascot * { animation: none !important; transition: none !important; } }
@media (max-width: 48em) { .mascot { --px: 5px; } }

/* ==========================================================================
   Pixel draw: the headline art, one half-cell pixel at a time, in draw
   order (letter -> column -> row). JS sizes the box to a whole number of
   device pixels per cell, so the grid renders crisp with no seams.
   ========================================================================== */
.hero__h1--px { max-width: none; line-height: 0; }
.pxdraw { display: block; position: relative; width: min(100%, 62rem); margin: 0 auto; --dur: 1600ms; }
.pxdraw__svg, .pxfinal__svg { display: block; width: 100%; height: 100%; fill: var(--strong); }
.pxdraw__svg rect { opacity: 1; }
.pxdraw--run .pxdraw__svg rect {
  opacity: 0;
  animation: px-in 180ms steps(2, end) forwards;
  animation-delay: calc(var(--i) * (var(--dur) / var(--n)));
}
@keyframes px-in {
  0%   { opacity: 0; }
  1%   { opacity: 1; fill: #fff; }
  100% { opacity: 1; fill: var(--strong); }
}
.pxdraw__pen {
  position: absolute; display: none; width: 0; height: 0;
  box-shadow: 0 0 0 2px #fff, 0 0 10px 4px color-mix(in srgb, var(--accent) 80%, #fff), 0 0 26px 10px color-mix(in srgb, var(--accent) 45%, transparent);
  pointer-events: none;
}
.pxdraw--run .pxdraw__pen { display: block; }
.pxdraw__final { position: absolute; inset: 0; display: block; opacity: 0; transition: opacity 0.4s ease; }
.pxdraw--done .pxdraw__final { opacity: 1; }
.pxdraw--done .pxdraw__svg { opacity: 0; transition: opacity 0.4s ease; }
.pxdraw--run:not(.pxdraw--done) .pxdraw__final { opacity: 0; }
.hero .pxdraw { filter: drop-shadow(0 2px 24px color-mix(in srgb, var(--bg) 90%, transparent)); }

/* Ambient pixel embers behind the headline: one element per ember, its
   box-shadow list keyframed (the campfire trick). */
.hero__embers { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.hero__embers i {
  position: absolute; left: 50%; bottom: 20%; width: 4px; height: 4px; background: transparent;
  opacity: 0; animation: ember 9s linear infinite;
  box-shadow:
    -22vw 0 0 0 var(--accent), -9vw 6vh 0 0 var(--green), 8vw -4vh 0 0 var(--accent),
    19vw 3vh 0 0 var(--green), 27vw -8vh 0 0 var(--accent), -31vw -6vh 0 0 var(--green);
}
.hero__embers i:nth-child(2) { animation-delay: -3s; left: 46%; }
.hero__embers i:nth-child(3) { animation-delay: -6s; left: 54%; }
@keyframes ember {
  0%   { transform: translateY(0); opacity: 0; }
  10%  { opacity: 0.55; }
  70%  { opacity: 0.35; }
  100% { transform: translateY(-46vh); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .hero__embers { display: none; } .pxdraw--run .pxdraw__svg rect { animation: none; opacity: 1; } .pxdraw__pen { display: none !important; } }

/* ==========================================================================
   Omarchy menu (walker-style), keybindings sheet, and the mark button in the
   bar — the way you get around in Omarchy itself.
   ========================================================================== */
.nav__omenu {
  display: inline-grid; place-items: center; width: 2.2rem; height: 2.2rem; margin-right: 0.25rem;
  background: none; border: 1px solid transparent; border-radius: 8px; cursor: pointer; padding: 0;
}
.nav__omenu .mark { width: 1.3rem; height: 1.3rem; fill: var(--green); display: block; transition: transform var(--ease); }
.nav__omenu:hover { border-color: var(--border); background: var(--surface); }
.nav__omenu:hover .mark { transform: scale(1.08); }
.hero__key { margin-top: 1.25rem; }
.hero__key kbd { font-size: 0.8em; }

.omenu, .okeys { border: 0; padding: 0; background: none; max-width: none; max-height: none; width: 100%; height: 100%; }
.omenu::backdrop, .okeys::backdrop { background: color-mix(in srgb, #000 55%, transparent); backdrop-filter: blur(8px); }
.omenu[open], .okeys[open] { display: grid; place-items: start center; padding-top: 12vh; }
.omenu__box, .okeys__box {
  width: min(40rem, 92vw);
  background: color-mix(in srgb, var(--bg) 96%, transparent); color: var(--fg);
  border: 1px solid var(--accent); border-radius: 12px;
  box-shadow: 0 40px 100px -20px rgba(0, 0, 0, 0.9);
  overflow: hidden;
  animation: modal-in 0.22s cubic-bezier(0.33, 1, 0.68, 1);
}
.okeys__box { width: min(60rem, 92vw); padding: 0 0 1rem; }
.omenu__head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.8rem 1rem; border-bottom: 1px solid var(--border); font-size: 0.75rem; color: var(--muted); }
.omenu__title { font-family: var(--small); letter-spacing: 0.1em; text-transform: uppercase; color: var(--strong); }
.omenu__hint kbd { font-size: 0.75rem; margin-right: 0.2rem; }
.omenu__input { width: 100%; font: inherit; font-size: 1.05rem; color: var(--strong); background: none; border: 0; padding: 0.9rem 1rem; outline: none; }
.omenu__input::placeholder { color: var(--muted); }
.omenu__list { list-style: none; margin: 0; padding: 0.4rem; max-height: 50vh; overflow: auto; border-top: 1px solid var(--border); }
.omenu__group { padding: 0.75rem 0.7rem 0.3rem; font-family: var(--small); font-size: 0.55rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.omenu__item { display: flex; justify-content: flex-start; align-items: center; padding: 0.5rem 0.7rem; border-radius: 6px; cursor: pointer; color: var(--fg); }
/* The label sits next to its swatch. `space-between` was pushing it to the
   far right of the row, which read as right-aligned. The note, where there is
   one, still keeps to the right. */
.omenu__item > span { margin-right: auto; }
.omenu__item small { margin-left: 1rem; }
.omenu__item small { color: var(--muted); font-size: 0.75rem; }
.omenu__item.is-active { background: var(--accent); color: var(--bg); }
.omenu__item.is-active small { color: color-mix(in srgb, var(--bg) 70%, var(--accent)); }
.omenu__item .swatch { width: 0.8rem; height: 0.8rem; border-radius: 3px; border: 1px solid var(--border); flex: none; margin-right: 0.6rem; }
.omenu__empty { padding: 1rem 0.7rem; color: var(--muted); }
.okeys__cols { display: grid; gap: 1rem 2rem; padding: 0.5rem 1.25rem 0.5rem; }
@media (min-width: 48em) { .okeys__cols { grid-template-columns: 1fr 1fr; } }
.okeys h3 { margin: 0.75rem 0 0.5rem; font-family: var(--small); font-weight: 400; font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); }
.okeys .keys { max-width: none; }

/* Notice on narrow screens: wrap on two lines at most, keep the × clear of the text. */
@media (max-width: 40em) {
  .notice { font-size: 0.78rem; line-height: 1.35; padding: 0.5rem 2.4rem 0.5rem 0.9rem; text-align: left; }
  .notice__close { right: 0.4rem; }
}

/* Pixel headline only where it has room; phones get the type version. */
.hero__h1-text { display: none; }
@media (max-width: 48em) {
  .hero__h1--px { line-height: 1.22; max-width: 16ch; }
  .hero__h1--px .pxdraw { display: none; }
  .hero__h1--px .hero__h1-text { display: inline; }
}
@media (min-width: 48.01em) {
  .hero__h1--px .hero__h1-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

/* No Super key on a phone. */
@media (max-width: 48em) { .hero__key, .stage__key, .stage__fine { display: none; } .nav__omenu { display: none; } }

/* Phones: the chapter list folds behind a "Chapters" toggle. Desktop: always open, no toggle. */
.docs__fold-summary { display: none; }
@media (max-width: 64em) {
  .docs__fold-summary {
    display: flex; justify-content: space-between; align-items: center; cursor: pointer; list-style: none;
    font-family: var(--small); font-size: 0.65rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--strong);
    border: 1px solid var(--border); border-radius: 8px; padding: 0.75rem 0.9rem; background: var(--surface);
  }
  .docs__fold-summary::-webkit-details-marker { display: none; }
  .docs__fold-summary::after { content: "+"; font-family: var(--font); font-size: 1rem; color: var(--muted); }
  .docs__fold[open] .docs__fold-summary::after { content: "–"; }
  .docs__fold[open] .docs__fold-summary { margin-bottom: 1rem; }
}

.stage__key { margin-top: 1.25rem; max-width: 40ch; }
.stage__key kbd { font-size: 0.8em; }

/* Tighten the mark-to-wordmark gap in the bar (the flex gap is 2rem / 1.25rem). */
@media (min-width: 72.01em) { .nav__omenu + .nav__brand { margin-left: -1.4rem; } }
@media (min-width: 48em) and (max-width: 72em) { .nav__omenu + .nav__brand { margin-left: -0.65rem; } }

/* News: left-aligned, same column as the install steps. */
.news__inner { max-width: var(--text); margin-inline: auto; text-align: left; }
.news__inner .post-list { margin-top: 1.75rem; }

.stage__key { color: var(--fg); font-size: 0.9rem; }
.stage__fine { margin-top: 0.5rem; max-width: 40ch; color: var(--muted); font-size: 0.72rem; line-height: 1.5; }
.stage__fine kbd { font-size: 0.9em; }

/* Super key icon inside <kbd>Super</kbd>. */
kbd .kbd-ico { display: inline-block; width: 0.95em; height: 0.95em; margin-right: 0.35em; vertical-align: -0.1em; line-height: 1; font-size: 1em; opacity: 0.85; }
kbd span.kbd-ico { width: auto; }

/* Clickable key combos. */
.keycombo { background: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer; display: inline; }
.keycombo kbd { transition: border-color var(--ease), transform var(--ease), color var(--ease); }
.keycombo:hover kbd { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }
.keycombo:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

/* Key combos never wrap; the description does. */
.keys li > span:first-child { white-space: nowrap; flex: none; }
.keys li > span:last-child { text-align: right; }

/* News index cards: the whole card is the link (the accessible "Read more"
   link is stretched over it), one visible "Read more" pill, lift on hover. */
.news-list { display: grid; gap: 1rem; }
.news-card {
  position: relative; display: grid; gap: 0.6rem;
  border: 1px solid var(--border); border-radius: 14px; background: var(--surface);
  padding: 1.5rem 1.6rem 1.4rem; margin: 0;
  transition: transform 0.25s cubic-bezier(0.33, 1, 0.68, 1), border-color 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
}
.news-card:first-child { border-top: 1px solid var(--border); padding-top: 1.5rem; }
.news-card header { display: grid; gap: 0.35rem; }
.news-card .news-meta { margin: 0; font-size: 0.8rem; }
.news-card__title { margin: 0; font-size: 1.15rem; line-height: 1.3; color: var(--strong); transition: color 0.25s ease; }
.news-card__excerpt { color: var(--fg); max-width: 62ch; }
.news-card__link { position: absolute; inset: 0; z-index: 1; border-radius: inherit; color: transparent; font-size: 0; text-decoration: none; }
.news-card__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.news-card__more { margin-top: 0.4rem; }
.news-card__button {
  display: inline-flex; align-items: center; gap: 0.6ch;
  font-size: 0.8rem; font-weight: 500; color: var(--accent);
  border: 1px solid var(--border); border-radius: 999px; padding: 0.35em 0.9em;
  transition: border-color 0.25s ease, background 0.25s ease, color 0.25s ease;
}
.news-card__button::after { content: "→"; display: inline-block; transition: transform 0.25s cubic-bezier(0.33, 1, 0.68, 1); }
.news-card:hover, .news-card:focus-within {
  transform: translateY(-3px);
  border-color: var(--accent);
  box-shadow: 0 18px 40px -22px color-mix(in srgb, var(--accent) 60%, transparent), 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
  background: color-mix(in srgb, var(--surface) 85%, var(--accent) 15%);
}
.news-card:hover .news-card__title { color: var(--accent); }
.news-card:hover .news-card__button { background: var(--accent); color: var(--bg); border-color: var(--accent); }
.news-card:hover .news-card__button::after { transform: translateX(4px); }
.news-card .news-byline a { position: relative; z-index: 2; }   /* the author link stays clickable */
@media (prefers-reduced-motion: reduce) { .news-card, .news-card * { transition: none !important; } .news-card:hover { transform: none; } }

/* Pixel confetti layer. */
.confetti { position: fixed; inset: 0; pointer-events: none; z-index: 10000; overflow: hidden; }
.confetti i { position: absolute; left: 0; top: 0; display: block; will-change: transform, opacity; }

/* Live hotkey rows: click one and the screenshot beside it changes. */
.keyrow { cursor: pointer; border-radius: 6px; transition: background 0.2s ease; }
.keyrow:hover, .keyrow:focus-visible { background: color-mix(in srgb, var(--surface) 70%, var(--accent) 12%); }
.keyrow:hover kbd, .keyrow.is-active kbd { border-color: var(--accent); color: var(--accent); }
.keyrow.is-active > span:last-child { color: var(--strong); }
.keyrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#f-keys .stage__ghost { transition: opacity 0.6s ease; z-index: 1; }

/* Live hotkey rows: inset padding so the hover/focus box has air on both sides. */
.keyrow { position: relative; padding: 0.5rem; margin-inline: -0.5rem; border-bottom: 0; }
/* Absolutely positioned: as an ::after in a flex row it became a third
   flex item, and space-between pushed the label off the right edge. */
.keyrow::after { content: ""; position: absolute; left: 0.5rem; right: 0.5rem; bottom: 0; height: 1px; background: var(--border); }
.keyrow:hover::after, .keyrow.is-active::after { opacity: 0; }
.keys--live { max-width: 27.4rem; }

/* Hotkey screenshots come in different shapes; hold the box steady and crop. */
#f-keys .stage__img, #f-keys .stage__ghost { aspect-ratio: 16 / 9; height: auto; object-fit: cover; object-position: center top; background: var(--bg-2); }

/* Looping video layer for a hotkey row (the Omarchy menu opening). */
#f-keys .stage__video { position: absolute; object-fit: cover; object-position: center top; border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 60px 120px -40px rgba(0, 0, 0, 0.85); opacity: 0; transition: opacity 0.6s ease; z-index: 2; pointer-events: none; background: var(--bg-2); }
#f-keys .stage__video.is-on { opacity: 1; }

/* Patron avatars are links; hover brings the colour back and lifts them. */
.patrons__list li { display: block; }
.patron { display: grid; justify-items: center; gap: 0.15rem; color: inherit; text-decoration: none; border-radius: 12px; padding: 0.6rem 0.4rem; transition: background 0.25s ease; }
.patron img { width: 4.5rem; height: 4.5rem; border-radius: 999px; filter: grayscale(1) contrast(1.05); margin-bottom: 0.5rem;
  transition: filter 0.35s ease, transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.35s ease; box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }
.patron span { color: var(--strong); font-weight: 500; transition: color 0.25s ease; }
.patron small { color: var(--muted); font-size: 0.8rem; }
.patron:hover, .patron:focus-visible { text-decoration: none; background: color-mix(in srgb, var(--surface) 70%, transparent); }
.patron:hover img, .patron:focus-visible img { filter: none; transform: translateY(-4px) scale(1.08) rotate(-3deg); box-shadow: 0 0 0 3px var(--accent), 0 14px 30px -14px color-mix(in srgb, var(--accent) 70%, transparent); }
.patron:hover span { color: var(--accent); }

/* Team and patron cards on their pages: the avatar is a link too, with the same lift. */
.member { transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); }
.member img { cursor: pointer; transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.35s ease, filter 0.35s ease; filter: grayscale(0.15); }
.member:hover img { transform: translateY(-4px) scale(1.04) rotate(-2deg); box-shadow: 0 0 0 3px var(--accent), 0 16px 30px -14px color-mix(in srgb, var(--accent) 70%, transparent); filter: none; }
.member:hover .member__name a { color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .patron img, .member img, .member { transition: none; } .patron:hover img, .member:hover img { transform: none; } }

/* Banner dismissed: decided in <head>, so nothing shifts. */
.notice-off .notice { display: none; }

.pxdraw__pen { left: 0; top: 0; will-change: transform; }

/* With the menu button carrying the mark, the brand keeps its wordmark at mid widths. */
@media (min-width: 48em) and (max-width: 72em) {
  .nav__omenu ~ .nav__brand .brand-word { display: inline; }
  .nav__omenu ~ .nav__brand .brand-mark { display: none; }
  .nav__omenu + .nav__brand { margin-left: -0.65rem; }
}

/* Footer music player: pixel waveform driven by the Web Audio analyser. */
.player { display: flex; align-items: center; gap: 0.9rem; margin: 2.5rem 0 0; flex-wrap: wrap; }
.player__btn {
  display: grid; place-items: center; width: 2.4rem; height: 2.4rem; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface); color: var(--strong); cursor: pointer; padding: 0;
  transition: border-color 0.2s ease, background 0.2s ease, transform 0.2s ease;
}
.player__btn:hover { border-color: var(--accent); transform: scale(1.06); }
.player__btn svg { width: 0.9rem; height: 0.9rem; }
.player__btn .player__pause { display: none; }
.player.is-playing .player__btn { background: var(--accent); color: var(--bg); border-color: var(--accent); }
.player.is-playing .player__btn .player__play { display: none; }
.player.is-playing .player__btn .player__pause { display: block; }
.player__wave { width: 288px; height: 32px; image-rendering: pixelated; }
.player__credit { color: var(--muted); font-size: 0.8rem; }
.player__credit a { color: var(--fg); }
.player__credit a:hover { color: var(--accent); }
@media (max-width: 40em) { .player__wave { width: 100%; } }

/* ==========================================================================
   Mobile audit fixes: legible type, thumb-sized targets, sane avatars.
   Measured at 390px; the Small cut runs tiny by design and needs a floor
   on a phone, and several controls were under the 44px touch minimum.
   ========================================================================== */
@media (max-width: 48em) {
  /* --- type floors --- */
  .nav__cta { font-size: 0.68rem; padding: 0.95em 1.2em; }
  .eyebrow { font-size: 0.76rem; letter-spacing: 0.08em; }
  .btn { font-size: 0.74rem; padding: 1.15em 1.5em; }
  .stats span, .more, .patron small, .patrons__line { font-size: 0.8rem; }
  .footer h3 { font-size: 0.74rem; }
  .footer__cols a { font-size: 0.85rem; }
  .stage__text p, .news-card__excerpt { font-size: 0.95rem; }
  .player__credit { font-size: 0.85rem; }
  kbd { font-size: 0.88em; }

  /* --- touch targets: 44px minimum --- */
  .notice { padding-right: 3.2rem; }
  .notice__close { width: 44px; height: 44px; right: 0.15rem; font-size: 1.2rem; }
  .theme-chip { min-height: 44px; min-width: 44px; justify-content: center; }
  .nav__toggle { width: 44px; height: 44px; }
  .nav__brand { display: inline-flex; align-items: center; min-height: 44px; }
  .nav__gh { min-width: 44px; min-height: 44px; justify-content: center; }
  .plus { min-height: 44px; }
  .plus__ring { width: 2.2rem; height: 2.2rem; }
  .theme-btn { min-height: 44px; }
  .keyrow { min-height: 44px; align-items: center; }
  .footer__cols a { padding: 0.4rem 0; }
  .links a, .post-list a { display: inline-block; padding: 0.25rem 0; }
  .player__btn { width: 3rem; height: 3rem; }
  .modal__close { width: 3rem; height: 3rem; }

  /* Heading anchors are a hover affordance; useless on touch. */
  .manual__heading-link, .prose h2 a.anchor { display: none; }

  /* Avatars were rendering one per row at the full column width. */
  .team__members { grid-template-columns: repeat(2, 1fr); gap: 1.25rem 1rem; }
  .member { justify-items: center; text-align: center; }
  .member img { max-width: 6.5rem; margin-inline: auto; }
  .resident__avatar { max-width: 5.5rem; }

  /* Footer columns were 1fr tracks refusing to shrink below their content,
     which pushed the second column past the viewport. */
  .footer__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem 1.25rem; }
  .footer__cols a, .footer h3 { overflow-wrap: anywhere; }
  .nav__cta { font-size: 0.73rem; }
  .btn small { font-size: 0.78rem; }
  .notice__link { display: block; padding: 0.3rem 0; }
}

/* Modal: one measure for everything. The paragraph (62ch), the key table
   (34rem) and the image (full box) were three different widths, which read
   as ragged. Narrow the box so its content column is the single measure. */
.modal__box { width: min(50rem, 92vw); }
.modal__box p,
.modal__box .keys,
.modal__box img,
.modal__collage { max-width: none; }
.modal__box > * { margin-inline: 0; }

/* The agents terminal has short lines; at 52vw most of it was empty air.
   Size it to its content, with a floor so it still balances the text column. */
@media (min-width: 60em) {
  .stage--right .stage__term { width: max-content; min-width: 28rem; max-width: 52vw; }
}

/* ==========================================================================
   Laser etch: the headline is a canvas over a static SVG of the same art,
   so there is always something to read if the canvas never starts.
   ========================================================================== */
.hero__h1--etch { max-width: none; line-height: 0; }
.etchbox { display: block; position: relative; width: min(100%, 62rem); margin: 0 auto; }
.etchbox__still { position: absolute; inset: 0; display: block; transition: opacity 0.3s ease; }
.etchbox__still svg { display: block; width: 100%; height: 100%; fill: var(--strong); }
.etchbox__canvas { display: block; width: 100%; height: 100%; opacity: 0; transition: opacity 0.2s ease; }
.etchbox.is-live .etchbox__canvas { opacity: 1; }
.etchbox.is-live .etchbox__still { opacity: 0; }

/* The nav wordmark re-cuts on hover; the canvas sits over the word. */
.nav__brand { position: relative; }
/* Collapsed until a hover sizes it; otherwise the canvas lays out at its
   backing width (480px) and pushes the page sideways on a phone. */
.brand-etch { position: absolute; left: 0; top: 0; width: 0; height: 0; max-width: 100%;
  pointer-events: none; opacity: 0; }
.nav__brand.is-etching .brand-etch { opacity: 1; }
/* opacity, not visibility: a hidden child stops the anchor hit-testing,
   which killed the link home exactly while you were hovering it. */
.nav__brand.is-etching .brand-word { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .etchbox__canvas, .brand-etch { display: none; } .etchbox__still { opacity: 1; } }

/* The canvas sits over a wallpaper, so it needs the same lift the SVG had. */
.hero .etchbox { filter: drop-shadow(0 2px 24px color-mix(in srgb, var(--bg) 92%, transparent)); }

/* Over a wallpaper the muted eyebrow disappeared. Lift it and give it a
   shadow so it holds on both busy and light backgrounds. */
.hero .eyebrow {
  color: color-mix(in srgb, var(--strong) 88%, transparent);
  text-shadow: 0 1px 10px color-mix(in srgb, var(--bg) 92%, transparent),
               0 0 2px color-mix(in srgb, var(--bg) 70%, transparent);
}
.hero .lede { text-shadow: 0 1px 12px color-mix(in srgb, var(--bg) 85%, transparent); }

/* On a phone the "+ More about…" button sat between the hotkeys and the demo
   it was offering more about. Flatten the text block into the section so the
   order can be: read, watch, then dig deeper. */
@media (max-width: 60em) {
  /* `align-items: center` is right for the two-column desktop layout, but
     once this becomes a single column it makes every child size to its own
     content instead of filling the width. That is what left the hotkey rows
     and the theme grid floating narrow, with the video full width beneath
     them. Stretching here fixes both, at every width below 60em, so phones
     and tablets get the same treatment from one rule. */
  .stage__inner { display: flex; flex-direction: column; gap: 0; align-items: stretch; }
  .keys { max-width: none; }
  .stage__text { display: contents; }
  .stage__text > * { order: 1; }
  .stage__img, .stage__term, .stage__stack { order: 2; margin-top: 2rem; }
  .stage__text > .plus { order: 3; margin-top: 1.75rem; }
}

/* ==========================================================================
   Hero screenshot: reclined in perspective, rising flat as you scroll to it.
   The card carries the transform; the figure gives it somewhere to sit.
   ========================================================================== */
.shot { perspective: 1400px; perspective-origin: 50% 0%; }
.shot__card {
  transform-origin: 50% 0%;
  transform: perspective(1400px) rotateX(22deg) scale(0.9) translateY(26px);
  will-change: transform;
}
.shot__card img { display: block; width: 100%; border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
/* The figure already styled the image directly; the card owns it now. */
.shot > img { border: 0; box-shadow: none; }
@media (prefers-reduced-motion: reduce) { .shot__card { transform: none; } }

/* ==========================================================================
   Pixelated portraits. The canvas sits over the photograph and hover
   dissolves it away, so the blocks resolve into the person.
   ========================================================================== */
.patron, .member { position: relative; }
/* The overlay is an <img> too, so it has to be excluded here. `.patron img`
   outranks `.pixelate` on specificity, which dropped the sprite back into
   normal flow and stacked it under the photograph: two of each person. */
.patron img:not(.pixelate), .member__avatar:not(.pixelate) { position: relative; }
.pixelate {
  position: absolute; left: 0; top: 0; z-index: 1;
  border-radius: 999px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.35s ease;
}
.pixelate.is-on { opacity: 1; }
.patron:hover canvas.pixelate, .member:hover .pixelate { opacity: 0; }
/* The photograph underneath no longer needs the greyscale trick. */
.patron img { filter: none; }
@media (prefers-reduced-motion: reduce) { .pixelate { transition: none; } }

/* ==========================================================================
   The playfield.

   A generated ASCII landscape across the full width of the footer, with the
   Omarch loose in it. The scene is painted with a gradient clipped to the
   glyphs, so it fades up out of the page background at the top and warms
   towards the accent at the horizon. It is scenery, not content: low
   contrast, aria-hidden, and it never competes with the fine print.

   Hover or focus the band and the arrow keys are his.
   ========================================================================== */
.playfield {
  position: relative;
  margin: 3.5rem 0 0;
  overflow: hidden;
  user-select: none;
  outline: none;
  cursor: default;
}
.playfield__scene {
  margin: 0;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.06;
  white-space: pre;
  letter-spacing: 0;
  color: transparent;
  background-image: linear-gradient(
    180deg,
    color-mix(in srgb, var(--fg) 0%, transparent) 0%,
    color-mix(in srgb, var(--fg) 9%,  transparent) 26%,
    color-mix(in srgb, var(--accent) 46%, transparent) 58%,
    color-mix(in srgb, var(--fg) 40%, transparent) 74%,
    color-mix(in srgb, var(--fg) 12%, transparent) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  transition: filter 0.4s ease;
  pointer-events: none;
}
/* The sun rides on its own layer, in the accent, so it reads as the light
   source instead of blending into the scenery. It shares the scene's metrics
   exactly, so the two grids stay in register. */
.playfield__sun {
  position: absolute; inset: 0;
  margin: 0;
  font: inherit;
  font-family: var(--mono); font-size: 13px; line-height: 1.06;
  white-space: pre; letter-spacing: 0;
  color: transparent;
  background-image: linear-gradient(
    180deg,
    color-mix(in srgb, var(--accent) 70%, white) 0%,
    var(--accent) 45%,
    color-mix(in srgb, var(--accent) 62%, transparent) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  opacity: 0.75;
  transition: opacity 0.4s ease;
  pointer-events: none;
}
.playfield.is-active .playfield__sun { opacity: 1; }

/* The scene lifts a little when you take the controls. */
.playfield.is-active .playfield__scene { filter: brightness(1.45) saturate(1.15); }

/* The wrapper carries the position; the Omarch inside keeps his own bob,
   blink and leg animations, which would otherwise fight the transform. */
.playfield__actor { position: absolute; left: 0; bottom: 0; display: block; pointer-events: none; }
.playfield .mascot {
  --px: 6px;
  display: block;
  position: relative; left: auto; right: auto; bottom: auto;
  transition: none; pointer-events: none; cursor: default;
}

.playfield.is-walking .mascot__legs { animation: mascot-legs 0.26s steps(2) infinite; }
.playfield.is-walking .mascot__eyes { transform: none; }
.playfield.is-airborne .mascot__arms { transform: translateY(calc(var(--px) * -1.2)); }
.playfield.is-airborne .mascot__legs { transform: translateY(calc(var(--px) * 0.5)); }
.playfield.is-active .mascot__eyes { transform: none; }
.playfield.is-active .mascot__mouth { box-shadow:
  5em 10em 0 0 var(--fg), 6em 10em 0 0 var(--fg), 7em 10em 0 0 var(--fg),
  8em 10em 0 0 var(--fg), 9em 10em 0 0 var(--fg),
  4em 9em 0 0 var(--fg), 10em 9em 0 0 var(--fg); }

.playfield__hint {
  position: absolute; right: 1.25rem; top: 0.5rem;
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.06em;
  color: var(--muted);
  opacity: 0; transition: opacity 0.3s ease;
  pointer-events: none;
}
.playfield__hint b { color: var(--strong); font-weight: 500; }
.playfield__hint span { opacity: 0.5; }
.playfield.is-active .playfield__hint { opacity: 1; }
.playfield:focus-visible { box-shadow: inset 0 0 0 1px var(--accent); }
/* Clicked in rather than tabbed in: no ring. See playfield.js for why. */
.playfield.no-ring:focus-visible { box-shadow: none; }

@media (max-width: 48em) {
  .playfield { margin-top: 2.5rem; }
  .playfield .mascot { --px: 5px; }
  .playfield__scene, .playfield__sun { font-size: 10px; }
  .playfield__hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .playfield.is-walking .mascot__legs { animation: none; }
}

/* The mark is line art, so out here he was see-through and the mountains
   showed straight through his face. Fill the 15x15 grid behind the pixels,
   in his own green over the page ground, so he reads as a body. */
.playfield .mascot::before {
  content: '';
  position: absolute; left: 1em; top: 0; width: 15em; height: 15em;
  background: color-mix(in srgb, var(--green) 30%, var(--bg));
  z-index: -1;
}

/* A shadow on the boardwalk. It holds its place on the ground while he
   jumps, and shrinks as he rises, which is what sells the jump. */
.playfield__shadow {
  position: absolute; left: 0; bottom: 0;
  width: 60px; height: 9px;
  margin-left: -30px;
  background: radial-gradient(ellipse at 50% 50%,
    color-mix(in srgb, black 60%, transparent) 0%, transparent 70%);
  pointer-events: none;
  will-change: transform, opacity;
}

/* An Omarchy USB drive, thrown. Built from three boxes rather than an image
   so it takes the theme's colours like everything else here: green shell,
   metal connector, and the square mark stamped on the side. */
.usb {
  position: absolute; left: 0; bottom: 0;
  font-size: var(--px, 5px);
  width: 14em; height: 6em;
  margin-left: -7em;
  pointer-events: none;
  will-change: transform, opacity;
}
.usb__body {
  position: absolute; left: 0; top: 0; width: 10em; height: 6em;
  background: var(--green);
  border-radius: 0.6em;
  display: block;
}
.usb__cap {
  position: absolute; right: 0; top: 1.5em; width: 3.6em; height: 3em;
  background: color-mix(in srgb, var(--fg) 65%, var(--bg));
  border-radius: 0.2em;
  display: block;
}
/* Printed on the shell, the way it would be on a real drive. */
.usb__mark {
  position: absolute; left: 1.1em; top: 1em;
  width: 4em; height: 4em;
  display: block;
  fill: color-mix(in srgb, var(--green) 10%, black);
}
/* He winds up as one leaves his hand. */
.playfield.is-throwing .mascot__arms { transform: translateY(calc(var(--px) * -1.6)); }
@media (prefers-reduced-motion: reduce) { .usb { display: none; } }

/* ==========================================================================
   Wallpaper cross-fade.

   `transition: background-image` does nothing, because background-image is
   not an animatable property, so switching themes used to snap the wallpaper
   in the moment it finished downloading. Instead the incoming wallpaper is
   painted on a pseudo-element that carries the same veiling gradient, and
   faded up over the outgoing one. Once it is fully in, the base layer is
   committed and the overlay is cleared with transitions off, so there is no
   second flash. The script only starts the fade after the image has decoded.
   ========================================================================== */
.hero::after, .subhero::after {
  content: '';
  position: absolute; inset: 0; z-index: 0;
  background-image:
    linear-gradient(to bottom,
      color-mix(in srgb, var(--bg) 35%, transparent) 0%,
      color-mix(in srgb, var(--bg) 70%, transparent) 55%,
      var(--bg) 100%),
    var(--wall-next, none);
  background-size: cover, cover;
  background-position: center, center 30%;
  background-repeat: no-repeat;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.75s ease;
}
.subhero::after {
  background-image:
    linear-gradient(to bottom, color-mix(in srgb, var(--bg) 60%, transparent), color-mix(in srgb, var(--bg) 88%, transparent) 70%, var(--bg)),
    var(--wall-next, none);
  background-position: center, center 35%;
}
.hero.is-swapping::after, .subhero.is-swapping::after { opacity: 1; }
.hero.is-instant::after, .subhero.is-instant::after { transition: none; }

/* The overlay is positioned, so the hero's own children have to be lifted
   above it. The embers layer is already absolute and only needs the stacking. */
.subhero { position: relative; }
.hero > *, .subhero > * { position: relative; z-index: 1; }
.hero > .hero__embers { position: absolute; }

@media (prefers-reduced-motion: reduce) {
  .hero::after, .subhero::after { transition: none; }
}

/* The tilted hero card is projected in perspective, so its near edge is wider
   than the element itself and pushed the document 27px past the viewport.
   `overflow-x: clip` on main removes the sideways scroll without creating a
   scroll container, so the sticky nav and the dialogs are unaffected. */
main { overflow-x: clip; }

/* ==========================================================================
   The crowd.

   Square-edged so they sit in a scene made of blocks, but built from boxes
   rather than pixel sprites. A sprite version looked right and read wrong:
   at eleven pixels across there is no room for a face, and a 3x3 mark cannot
   say "Apple" or "Windows" — which is the entire joke. So the shapes are
   hard-edged and the marks stay as SVG, drawn large enough to recognise.
   ========================================================================== */
.npc {
  --npc-px: 5.5px;
  position: absolute; left: 0; bottom: 0;
  font-size: var(--npc-px);
  width: 12em; height: 16em;
  margin-left: -6em;
  z-index: 1;
  pointer-events: none;
  opacity: 0.92;
}
.npc__wrap { position: absolute; inset: 0; display: block; }

.npc__head {
  position: absolute; left: 2.5em; top: 0; width: 7em; height: 5.5em;
  display: block;
  background: color-mix(in srgb, var(--fg) 62%, var(--bg));
  transform: translateY(0.6em);                /* slumped */
  transition: transform 0.35s ease;
}
.npc__eye {
  position: absolute; top: 1.9em; width: 1em; height: 1em; display: block;
  background: color-mix(in srgb, var(--bg) 62%, black);
}
.npc__eye--l { left: 1.6em; }
.npc__eye--r { left: 4.4em; }
/* The mouth is one pixel; the rest is box-shadow copies of it, which is how
   the Omarch is drawn too. It has to be a single cell: a shadow repeats the
   whole element, so a wide bar with "corner" shadows produced two more wide
   bars set diagonally — which read as tusks.

   Frown drops the ends a row, smile lifts them. No curves anywhere. */
/* The mouth is one cell, repeated by box-shadow — a shadow copies the whole
   element, so it has to start as a single pixel or the copies come out as
   full-width bars.

   It is deliberately shorter than it is wide. At full cell height the line
   was as thick as an eye, which read as a grille rather than a mouth. The
   smile lifts its ends by that same half-height, so the curve is shallow
   instead of a zigzag. */
.npc__mouth {
  position: absolute; left: 2.2em; top: 3.7em; width: 0.9em; height: 0.5em;
  display: block;
  background: currentColor;
  color: color-mix(in srgb, var(--bg) 62%, black);
  box-shadow:
    0.9em 0 0 0 currentColor,
    1.8em 0 0 0 currentColor;
}

.npc__shirt {
  position: absolute; left: 1.2em; top: 6.2em; width: 9.6em; height: 6.6em;
  display: block;
  background: color-mix(in srgb, var(--fg) 40%, var(--bg));
}
.npc__shirt svg {
  /* One cell higher than centred: the shirt runs behind the arms and the legs
     start right under it, so an optically centred mark sits low. */
  position: absolute; left: 2.3em; top: 0.3em; width: 5em; height: 5em;
  display: block;
  fill: color-mix(in srgb, var(--fg) 92%, white);
}
.npc__arm {
  position: absolute; top: 6.6em; width: 1.2em; height: 5em;
  display: block;
  background: color-mix(in srgb, var(--fg) 50%, var(--bg));
}
.npc__arm--l { left: 0; }
.npc__arm--r { right: 0; }
.npc__leg {
  position: absolute; top: 12.8em; width: 2.4em; height: 3.2em;
  display: block;
  background: color-mix(in srgb, var(--fg) 50%, var(--bg));
  animation: npc-step 0.9s steps(1, end) infinite;
}
.npc__leg--l { left: 2.6em; }
.npc__leg--r { left: 7em; animation-delay: -0.45s; }
@keyframes npc-step { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-0.7em); } }

/* Converted: head up, real smile, Omarchy green, dark mark, quicker step. */
.npc.is-omarchy { opacity: 1; }
.npc.is-omarchy .npc__head { transform: translateY(0); background: color-mix(in srgb, var(--fg) 82%, var(--bg)); }
.npc.is-omarchy .npc__mouth {
  box-shadow:
    0.9em 0 0 0 currentColor,
    1.8em 0 0 0 currentColor,
    -0.9em -0.5em 0 0 currentColor,
    2.7em -0.5em 0 0 currentColor;
}
.npc.is-omarchy .npc__shirt { background: var(--green); }
.npc.is-omarchy .npc__shirt svg { fill: color-mix(in srgb, var(--green) 10%, black); }
.npc.is-omarchy .npc__arm,
.npc.is-omarchy .npc__leg { background: color-mix(in srgb, var(--fg) 66%, var(--bg)); }
.npc.is-omarchy .npc__leg { animation-duration: 0.42s; }

/* Cut, not swapped: the laser etch's own fire palette. */
@keyframes npc-pop { 0% { transform: scale(1); } 35% { transform: scale(1.4); } 100% { transform: scale(1); } }
@keyframes npc-cut {
  0%   { background: #ffffff; box-shadow: 0 0 16px 5px rgba(255,255,255,0.85); }
  14%  { background: #ffe680; box-shadow: 0 0 14px 4px rgba(255,230,128,0.8); }
  38%  { background: #ff7b00; box-shadow: 0 0 10px 2px rgba(255,123,0,0.6); }
  100% { background: var(--green); box-shadow: 0 0 0 0 transparent; }
}
@keyframes npc-flash {
  0%   { filter: brightness(2.1) drop-shadow(0 0 9px #ffffff); }
  55%  { filter: brightness(1.2) drop-shadow(0 0 4px #ff7b00); }
  100% { filter: none; }
}
.npc.is-converting { animation: npc-flash 0.9s ease-out 1; }
.npc.is-converting .npc__shirt { animation: npc-cut 0.9s ease-out 1, npc-pop 0.45s ease-out 1; }

.sparks { position: absolute; left: 50%; top: 46%; width: 0; height: 0; }
.sparks i {
  position: absolute; width: 2px; height: 2px;
  background: #ffe680;
  animation: npc-spark 0.6s ease-out forwards;
}
@keyframes npc-spark {
  0%   { transform: translate(0, 0); background: #ffe680; opacity: 1; }
  60%  { background: #ff7b00; opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)); background: #1a0900; opacity: 0; }
}

/* Dancing happens on the spot, so it rides the wrapper: the outer element is
   carrying the walk position. */
.npc.is-dancing .npc__wrap { animation: npc-dance 0.5s ease-in-out infinite; }
.npc.is-dancing .npc__leg { animation-duration: 0.25s; }
.npc.is-dancing .npc__arm { animation: npc-arms 0.5s ease-in-out infinite alternate; }
.npc.is-dancing .npc__arm--r { animation-delay: -0.25s; }
@keyframes npc-dance {
  0%   { transform: translateY(0) rotate(-6deg); }
  25%  { transform: translateY(-1.3em) rotate(0deg); }
  50%  { transform: translateY(0) rotate(6deg); }
  75%  { transform: translateY(-1.3em) rotate(0deg); }
  100% { transform: translateY(0) rotate(-6deg); }
}
@keyframes npc-arms { from { transform: translateY(0); } to { transform: translateY(-1.6em); } }

/* He is the hero, so he walks in front, and the drives in front of everyone. */
.playfield__shadow { z-index: 0; }
.playfield__actor { z-index: 3; }
.usb { z-index: 4; }

@media (max-width: 48em) { .npc { --npc-px: 4.5px; } }
@media (prefers-reduced-motion: reduce) {
  .npc__leg, .npc.is-dancing .npc__wrap, .npc.is-dancing .npc__arm, .npc.is-converting { animation: none; }
}

/* ==========================================================================
   The control pad.

   Touch has no hover and no arrow keys, so on a coarse pointer the strip
   grows a band at the bottom and puts real buttons in it: walk on the left,
   jump and throw on the right, laid out like a gamepad. Targets are 44px,
   which is the smallest a thumb should have to hit.
   ========================================================================== */
.playfield__pad { display: none; }

@media (pointer: coarse) {
  .playfield { padding-bottom: 3.6rem; }
  .playfield__hint { display: none; }
  .playfield__pad {
    position: absolute; left: 0; right: 0; bottom: 0;
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.35rem 0.75rem 0.5rem;
    gap: 0.75rem;
  }
  .playfield__dpad, .playfield__acts { display: flex; gap: 0.5rem; }
  .padbtn {
    /* Holding a button on iOS otherwise selects it and raises the callout
       menu (copy / look up / share), which both interrupts the game and
       leaves the button stuck down because the pointerup never arrives.
       `touch-action` alone does not stop it: the callout and the selection
       are separate behaviours and each needs turning off by name. */
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    width: 44px; height: 44px;
    display: grid; place-items: center;
    font-family: var(--mono); font-size: 1rem; line-height: 1;
    color: var(--fg);
    background: color-mix(in srgb, var(--bg) 62%, transparent);
    border: 1px solid var(--border);
    border-radius: 10px;
    backdrop-filter: blur(6px);
    touch-action: none;                 /* so a held button never scrolls the page */
    -webkit-tap-highlight-color: transparent;
    cursor: pointer;
    padding: 0;
  }
  .padbtn.is-down { background: var(--accent); color: var(--bg); border-color: var(--accent); }
  /* A drive on the tilt, matching the ones he throws. The old flat bar plus
     a square read as a film strip, not a USB stick. */
  .padbtn--throw svg { width: 24px; height: 24px; }
  .padbtn--throw .padbtn__shell { fill: var(--green); }
  .padbtn--throw .padbtn__cap { fill: color-mix(in srgb, var(--fg) 65%, var(--bg)); }
  .padbtn--throw.is-down .padbtn__shell,
  .padbtn--throw.is-down .padbtn__cap { fill: var(--bg); }
}

/* ==========================================================================
   Conversion: the shirt is cut, not swapped.

   The ramp is the laser etch's own fire palette, so the footer and the
   headline read as the same machine at work: white hot, down through #ffe680
   and #ff7b00, and out at Omarchy green. Sparks fly off and cool to #1a0900
   on the way, which is what the etch does to its own cut edge.
   ========================================================================== */
@keyframes npc-cut {
  0%   { background: #ffffff; box-shadow: 0 0 16px 5px rgba(255, 255, 255, 0.85); }
  14%  { background: #ffe680; box-shadow: 0 0 14px 4px rgba(255, 230, 128, 0.8); }
  38%  { background: #ff7b00; box-shadow: 0 0 10px 2px rgba(255, 123, 0, 0.6); }
  70%  { background: color-mix(in srgb, var(--green) 55%, #ff7b00); box-shadow: 0 0 5px 1px rgba(255, 123, 0, 0.3); }
  100% { background: var(--green); box-shadow: 0 0 0 0 transparent; }
}
@keyframes npc-flash {
  0%   { filter: brightness(2.1) drop-shadow(0 0 9px #ffffff); }
  22%  { filter: brightness(1.6) drop-shadow(0 0 7px #ffe680); }
  55%  { filter: brightness(1.2) drop-shadow(0 0 4px #ff7b00); }
  100% { filter: brightness(1) drop-shadow(0 0 0 transparent); }
}
.npc.is-converting { animation: npc-flash 0.9s ease-out 1; }
.npc.is-converting .npc__shirt { animation: npc-cut 0.9s ease-out 1, npc-pop 0.45s ease-out 1; }

.sparks { position: absolute; left: 50%; top: 46%; width: 0; height: 0; }
.sparks i {
  position: absolute; width: 2px; height: 2px; border-radius: 50%;
  background: #ffe680;
  animation: npc-spark 0.6s ease-out forwards;
}
@keyframes npc-spark {
  0%   { transform: translate(0, 0) scale(1.2); background: #ffe680; opacity: 1; }
  60%  { background: #ff7b00; opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(0.4); background: #1a0900; opacity: 0; }
}

/* Converted people are brighter than the ones still trudging: the whole
   figure lifts, not just the shirt. */
.npc.is-omarchy .npc__head { background: color-mix(in srgb, var(--fg) 84%, var(--bg)); }
.npc.is-omarchy .npc__arm,
.npc.is-omarchy .npc__leg { background: color-mix(in srgb, var(--fg) 68%, var(--bg)); }

@media (prefers-reduced-motion: reduce) {
  .npc.is-converting, .npc.is-converting .npc__shirt { animation: none; }
  .sparks { display: none; }
}

/* ==========================================================================
   Mobile pass.

   From a narrated walkthrough on a real phone. Buttons and footer links were
   set at desktop sizes, two grids left dead space at the edges, the agent
   list scrolled sideways, and a couple of lines of copy told a phone user to
   press a key they do not have.
   ========================================================================== */

/* Copy that only makes sense with a keyboard, or only fits on a wide screen.
   One class, so anything else of the same kind can join it later. */
@media (max-width: 48em) {
  .opt-sm { display: none !important; }

  /* Buttons were reading at desktop scale on a 390px screen. */
  .btn { font-size: 0.52rem; padding: 1.5em 2em 1.4em; }
  .nav__cta { font-size: 0.52rem; padding: 1em 1.4em; }

  /* Footer links had grown to button size. Bring them back under it. */
  .footer__cols a { font-size: 0.6rem; }
  .footer h3 { font-size: 0.62rem; }

  /* Two even columns on a phone; wider screens keep auto-fill, which now has
     the full width to work with. */
  .themes-grid,
  .stage .themes-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* The agent list ran off the right and grew a sideways scrollbar. It fits
     once the padding and type come down, so there is nothing to scroll. */
  .term {
    padding: 1rem 0.9rem;
    font-size: 0.68rem;
    line-height: 1.75;
    overflow-x: hidden;
  }
}

/* ==========================================================================
   The bar on a narrow phone.

   At 332px the bar wanted 362px: wordmark 109, theme dot 44, Download 105,
   menu 44, plus gaps. The menu button was pushed 18px off the right edge and
   clipped. Swapping the wordmark for the square mark buys back about 87px,
   which is more than enough. That swap already existed but was scoped to
   48-72em, so it never ran where space is tightest.

   The four controls are also given one height. Download had shrunk to 25px
   next to 44px neighbours, which is what made the row look wrong.
   ========================================================================== */
/* Measured rather than guessed: with the wordmark the bar needs 327px of
   content, and the bar is the viewport less 32px of padding. So the wordmark
   fits down to about 359px. 23em (368px) keeps it on every iPhone from the SE
   up, with 16px to spare, and only falls back to the square mark on the
   narrow Androids below that. The old cutoff was 30em, which dropped the
   wordmark on every phone for no reason. */
@media (max-width: 23em) {
  .brand-word { display: none; }
  .brand-mark { display: block; }
}

@media (max-width: 48em) {
  .nav__cta {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px;
    padding: 0 1.2em;
  }
  .theme-chip, .nav__toggle { width: 44px; height: 44px; flex: none; }
}

/* The outgoing screenshots, held over the incoming ones while they dissolve.
   Opacity only: the fan transform is already set inline to match the slot it
   is covering, and must not animate. */
.stage__stack img.stack-ghost {
  transition: opacity 0.45s ease;
  pointer-events: none;
}
.stage__stack img.stack-ghost.is-out { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .stage__stack img.stack-ghost { transition: none; }
}

/* ==========================================================================
   A steady subpage hero.

   The subhero was sized entirely by its content, so a page with no lede, or
   the shorter docs variant, gave `background-size: cover` a different box to
   fill. The wallpaper then cropped at a different scale on each page and
   visibly jumped as you moved between them.

   A floor height fixes the crop, and centring the content means a short
   heading sits in the same place as a tall one rather than riding up. The
   docs variant inherits both, so the manual matches the rest of the site.
   ========================================================================== */
.subhero {
  min-height: clamp(14rem, 12rem + 8vw, 19rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* ==========================================================================
   Cross-document view transitions.

   Four lines, no JavaScript, and it degrades to today's hard cut where the
   browser does not support it. The nav is given its own name so it holds
   still while the page underneath changes, which is what makes it read as
   one site rather than a slideshow.
   ========================================================================== */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.26s;
  animation-timing-function: ease;
}

.nav { view-transition-name: site-nav; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* ==========================================================================
   The sound toggle.

   Every sound here is triggered by something you did, so it starts on. The
   toggle exists anyway, sits quietly in the corner of the playfield, and
   remembers your choice.
   ========================================================================== */
.playfield__sound {
  position: absolute; right: 1.25rem; bottom: 0.75rem;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  padding: 0;
  color: var(--muted);
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  border: 1px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.3s ease, color 0.2s ease, border-color 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
.playfield__sound svg { width: 16px; height: 16px; display: block; }
.playfield__sound .slash { opacity: 0; transition: opacity 0.15s ease; }
.playfield__sound.is-off .wave1,
.playfield__sound.is-off .wave2 { opacity: 0; }
.playfield__sound.is-off .slash { opacity: 1; }
.playfield.is-active .playfield__sound { opacity: 1; }
.playfield__sound:hover { color: var(--strong); border-color: var(--border); }
.playfield__sound:focus-visible { opacity: 1; outline: 2px solid var(--accent); outline-offset: 2px; }

/* On touch there is no hover, so it is always there; it moves above the pad. */
@media (pointer: coarse) {
  .playfield__sound { opacity: 1; bottom: auto; top: 0.5rem; right: 0.75rem; }
}

/* ==========================================================================
   Omarchy Radio.

   The footer player now carries the live stream instead of a single track,
   and a compact version floats on wide screens once you have scrolled past
   the hero. The floater hides itself whenever the footer player is on screen,
   so you never see two of the same control.
   ========================================================================== */

/* The live dot, shared by both players. */
.player__live {
  display: inline-flex; align-items: center; gap: 0.35em;
  color: var(--green); font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.85em;
}
.player__live i {
  width: 0.45em; height: 0.45em; border-radius: 50%;
  background: currentColor;
  animation: radio-pulse 2s ease-in-out infinite;
}
@keyframes radio-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* --- the floater --- */
.radio {
  position: fixed;
  right: 1.5rem; bottom: 1.5rem;
  z-index: 60;
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.6rem 0.9rem 0.6rem 0.7rem;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(10px);
  animation: radio-in 0.35s ease both;
}
@keyframes radio-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.radio[hidden] { display: none; }

.radio__btn {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%; padding: 0;
  color: var(--fg);
  background: transparent;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.radio__btn svg { width: 0.75rem; height: 0.75rem; }
.radio__btn:hover { border-color: var(--accent); color: var(--accent); }
.radio__btn .radio__pause { display: none; }
.radio.is-playing .radio__btn { background: var(--accent); color: var(--bg); border-color: var(--accent); }
.radio.is-playing .radio__btn .radio__play { display: none; }
.radio.is-playing .radio__btn .radio__pause { display: block; }

.radio__body { display: grid; gap: 0.2rem; }
.radio__name {
  display: flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.62rem;
  color: var(--muted); white-space: nowrap;
}
.radio__wave { width: 120px; height: 18px; display: block; image-rendering: pixelated; }

.radio__close {
  width: 20px; height: 20px; flex: none;
  display: grid; place-items: center;
  padding: 0; margin-left: 0.15rem;
  font-size: 0.95rem; line-height: 1;
  color: var(--muted);
  background: transparent; border: 0; border-radius: 50%;
  cursor: pointer; opacity: 0.6;
  transition: opacity 0.2s ease, color 0.2s ease;
}
.radio__close:hover { opacity: 1; color: var(--strong); }

/* Only where there is genuinely room beside the content. The page column is
   about 1200px, so below this the floater would sit on top of the words. */
@media (max-width: 87.5em) { .radio { display: none !important; } }
@media (prefers-reduced-motion: reduce) {
  .radio { animation: none; }
  .player__live i { animation: none; }
}

/* ==========================================================================
   Quotes.

   Rotating, attributed, each with the speaker's pixel portrait. Three things
   worth knowing:

   1. The slides share one grid cell, so the block is as tall as the longest
      quote and nothing shifts when it changes. Each slide centres itself in
      that cell, or a short quote would sit high with a hole beneath it.
   2. Type size steps down as the quote gets longer, set per slide, so a long
      one does not turn into a wall of display type.
   3. No typographic quote marks. The display face has no curly quotes and
      falls back to something that reads as a diaeresis. The portrait and the
      attribution already say "someone said this".
   ========================================================================== */
.quotes { margin: 0; }
.quotes__stack { display: grid; }

.quote {
  grid-area: 1 / 1;
  /* A grid item's automatic minimum size is its content size, so one long
     unbreakable word (EVERYTHING., COMPUTER) pushed this item wider than its
     cell and the text ran off the screen. `main { overflow-x: clip }` then
     hid the evidence, and because the blockquote inherited the widened box,
     the script's own overflow check measured against it and saw no problem. */
  min-width: 0;
  margin: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 2rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
.quote.is-on {
  opacity: 1;
  visibility: visible;
  /* Delayed in, so the outgoing quote has cleared before this one arrives.
     Two sets of large type dissolving through each other is unreadable. */
  transition: opacity 0.35s ease 0.22s;
}

.quote blockquote {
  margin: 0;
  /* Bounded, not shrink-to-fit. As a centred flex item this sized itself to
     its own text, so clientWidth grew with the content and the script's
     overflow check could never fail — a long word ran off the screen while
     the measurement said everything fitted. */
  width: 100%;
  min-width: 0;
  font-family: var(--display);
  color: var(--green);
  line-height: 1.2;
  text-wrap: balance;
  /* The script measures each quote and sets this so every one fills the same
     box: a short line stays big, a long one shrinks only as far as it must.
     The value here is the fallback if the script never runs. */
  font-size: var(--quote-size, clamp(1.2rem, 0.9rem + 1.7vw, 2.1rem));
}
/* A definite height, not a minimum. The script fits each quote into this box,
   so it has to be fixed: with min-height the box grows to fit the text, and
   the text is then measured against a box it just resized. Nothing ever
   shrinks and every quote comes out at the maximum size. */
.quotes__stack { height: clamp(13rem, 26vh, 18rem); }

.quote figcaption { display: flex; align-items: center; gap: 0.85rem; }
.quote__face {
  width: 2.75rem; height: 2.75rem;
  border-radius: 999px;
  display: block;
  image-rendering: pixelated;
}
.quote__who { display: grid; text-align: left; line-height: 1.3; }
.quote__who b {
  font-family: var(--mono); font-weight: 500;
  font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--strong);
}
.quote__who small { font-size: 0.72rem; color: var(--muted); }

.quotes__dots { display: flex; justify-content: center; gap: 0.5rem; margin-top: 2rem; }
.quotes__dots button {
  width: 7px; height: 7px; padding: 0;
  border: 0; border-radius: 50%;
  background: var(--border);
  cursor: pointer;
  transition: background 0.25s ease, transform 0.25s ease;
}
.quotes__dots button:hover { background: var(--muted); }
.quotes__dots button[aria-selected="true"] { background: var(--green); transform: scale(1.3); }
.quotes__dots button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.mission__tag {
  margin: 3rem 0 0;
  color: var(--muted); font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; font-size: 0.85rem;
}

@media (prefers-reduced-motion: reduce) { .quote { transition: none; } }

/* ==========================================================================
   The playfield, taller.

   Nineteen rows instead of fourteen, so there is sky above the ridgeline and
   room for the parallax to read. The layers move at different rates as the
   strip crosses the viewport: sun furthest, scenery in front of it, the
   boardwalk and everyone on it nearest and still.
   ========================================================================== */
.playfield__sun,
.playfield__scene { will-change: transform; }
.playfield__actor,
.playfield__shadow,
.npc,
.usb { transform-box: fill-box; }

/* --- the tally --- */
.playfield__score {
  position: absolute; left: 1.25rem; top: 0.6rem;
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-family: var(--mono); font-size: 0.66rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.35s ease, transform 0.35s ease;
  pointer-events: none;
}
.playfield__score.is-on { opacity: 1; transform: none; }
.playfield__score i {
  width: 0.45em; height: 0.45em; border-radius: 50%;
  background: var(--green);
}
.playfield__score b { color: var(--strong); font-weight: 500; }
.playfield__score.is-bump b { animation: score-bump 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes score-bump {
  0% { transform: scale(1); }
  40% { transform: scale(1.5); color: var(--green); }
  100% { transform: scale(1); }
}

/* Everyone converted. The whole strip lifts, briefly. */
.playfield.is-cleared .playfield__scene { filter: brightness(1.7) saturate(1.25); }
.playfield.is-cleared .playfield__score i { animation: score-bump 0.9s ease-in-out infinite; }

@media (max-width: 48em) {
  .playfield__score { font-size: 0.6rem; left: 0.75rem; }
}
@media (prefers-reduced-motion: reduce) {
  .playfield__sun, .playfield__scene { transform: none !important; }
  .playfield__score.is-bump b { animation: none; }
}

/* ==========================================================================
   Quote controls.

   Arrows where there is room beside the text, swipe where there is not, dots
   in both. All three do the same thing and all three stop the auto-advance.
   ========================================================================== */
.quotes { position: relative; }
.quotes__arrow {
  position: absolute; top: 50%;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  margin-top: -2.5rem;                 /* sit against the quote, not the dots */
  padding: 0;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 50%;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.25s ease, color 0.2s ease, border-color 0.2s ease;
}
.quotes__arrow svg { width: 15px; height: 15px; display: block; }
.quotes__arrow--prev { left: -3.5rem; transform: translateY(-50%); }
.quotes__arrow--next { right: -3.5rem; transform: translateY(-50%); }
.quotes:hover .quotes__arrow { opacity: 1; }
.quotes__arrow:hover { color: var(--strong); border-color: var(--border); }
.quotes__arrow:focus-visible { opacity: 1; outline: 2px solid var(--accent); outline-offset: 2px; }

/* No room beside the text, and no hover to reveal them: swipe instead. */
@media (max-width: 68em) {
  .quotes__arrow { display: none; }
  .quotes__stack { touch-action: pan-y; }
}

/* The attribution links to the speaker. The whole thing is the target, not
   just the name, so it is an easy hit on a phone. */
.quote__link {
  display: flex; align-items: center; gap: 0.85rem;
  text-decoration: none; color: inherit;
  border-radius: 999px;
  transition: opacity 0.2s ease;
}
.quote__link:hover { text-decoration: none; }
.quote__link .quote__face {
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.25s ease;
}
.quote__link:hover .quote__face,
.quote__link:focus-visible .quote__face {
  transform: scale(1.08);
  box-shadow: 0 0 0 2px var(--green);
}
.quote__link:hover .quote__who b { color: var(--green); }
.quote__link .quote__who b { transition: color 0.2s ease; }
.quote__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* The track title, read out of the stream itself. Hidden until there is one,
   so the player never shows an empty slot. */
.player__track {
  display: none;
  color: var(--fg);
  max-width: 22rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.player__track.is-on { display: block; }
.player__credit .player__track.is-on::before { content: "\00b7\00a0"; color: var(--muted); }
.player__track.is-new { animation: track-in 0.45s ease both; }
@keyframes track-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.radio__name .player__track { max-width: 11rem; font-size: 0.62rem; }
@media (max-width: 48em) { .player__track { max-width: 12rem; } }
@media (prefers-reduced-motion: reduce) { .player__track.is-new { animation: none; } }

/* ==========================================================================
   Player controls: skip, live, volume.

   The live badge doubles as the way back to the broadcast, so it is a button
   rather than a label. It only looks pressable once you have left.
   ========================================================================== */
.player__skip { display: flex; gap: 0.25rem; }
.player__nav, .radio__nav {
  width: 26px; height: 26px; flex: none;
  display: grid; place-items: center;
  padding: 0;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 50%;
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.player__nav svg, .radio__nav svg { width: 11px; height: 11px; display: block; }
.player__nav:hover, .radio__nav:hover { color: var(--strong); border-color: var(--border); }
.player__nav:focus-visible, .radio__nav:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The live badge, as a control. */
button.player__live {
  padding: 0; border: 0; background: transparent;
  font: inherit; cursor: default;
  color: var(--green);
}
.player.is-live button.player__live { cursor: default; }
.player:not(.is-live) button.player__live {
  cursor: pointer;
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.player:not(.is-live) button.player__live i { background: var(--muted); animation: none; }
.player:not(.is-live) button.player__live:hover { color: var(--green); }

/* Volume. Deliberately small: it is a footer, not a mixing desk. */
.player__vol { display: flex; align-items: center; }
.player__vol input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 68px; height: 3px;
  background: var(--border);
  border-radius: 999px;
  cursor: pointer;
}
.player__vol input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--fg);
  transition: background 0.2s ease, transform 0.2s ease;
}
.player__vol input[type="range"]:hover::-webkit-slider-thumb { background: var(--green); transform: scale(1.2); }
.player__vol input[type="range"]::-moz-range-thumb {
  width: 10px; height: 10px; border: 0; border-radius: 50%; background: var(--fg);
}
.player__vol input[type="range"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

@media (max-width: 48em) {
  .player__vol { display: none; }        /* phones have hardware volume */
  .player__skip { order: 3; }
}

/* ==========================================================================
   The banner on a phone.

   "Omacom Foundation launches with $12.6 million" is 44 characters. At 12px
   in a monospace face that needs about 317px, and after the padding for the
   close button there are only 310px — so it wrapped to two lines by seven
   pixels. Truncating would cut the number, which is the whole point of the
   sentence, so the type comes down instead and the padding tightens.
   ========================================================================== */
@media (max-width: 48em) {
  .notice { padding-inline: 0.8rem 2.6rem; }
  .notice__link, .notice { font-size: 0.66rem; letter-spacing: 0; }
  .notice__close { right: 0.35rem; }
}

/* Below this even that will not fit on one line. Wrapping is fine, but the
   two lines should look deliberate rather than like an accident. */
@media (max-width: 22em) {
  .notice__link { text-wrap: balance; }
}

/* The credit line was an inline-flex badge, an inline anchor and an
   inline-block title with a vertical-align override — three different
   alignment rules, so nothing shared a baseline and "LIVE" sat high. One flex
   row puts them all on a common centre. */
.player__credit {
  display: flex;
  align-items: center;
  gap: 0.45em;
  min-width: 0;
}
.player__credit > * { flex: none; }
.player__credit .player__track { flex: 0 1 auto; min-width: 0; }
