/*
 * Presentation. Tokens come from tokens.css; the patterns and the reasoning are in
 * blueprint/design/patterns.md. Nothing here invents a colour.
 */

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* Motion: 150ms on colour and opacity, and nothing that moves layout. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

/* ---------------------------------------------------------------- chrome --- */

/* The banner: the one place the accent shouts, and it is contrast-safe there. */
.site-banner {
  background: var(--term-bg);
  color: var(--term-ink);
  text-align: center;
  padding: var(--space-2) var(--space-6);
  font-size: var(--text-sm);
  line-height: 1.45;
}
.site-banner strong {
  color: var(--term-yellow);
  font-weight: 600;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-6);
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--ink);
  text-decoration: none;
}
.brand .mark {
  flex: none;
}
.wordmark {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 1.1rem;
  letter-spacing: -0.01em;
}
/* The block cursor. Never blinks — an animated cursor in a header is a
   distraction with no information in it. */
.cursor {
  width: 0.42em;
  height: 1em;
  background: var(--brand-yellow);
  font-size: 1.1rem;
}

.site-header nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  margin-left: auto;
}
.site-header nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: var(--text-sm);
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
  transition: color 0.15s, border-color 0.15s;
}
.site-header nav a:hover {
  color: var(--ink);
  border-bottom-color: var(--brand-yellow);
}
/* Current page: weight is the accessible signal, the yellow rule is the accent. */
.site-header nav a.current {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--brand-yellow);
}

.site-footer {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--space-6);
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--ink-soft);
}
.site-footer .versions {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.site-footer a {
  color: var(--ink-soft);
}
.site-footer a:hover {
  color: var(--ink);
}

/* Skip link — first focusable thing on the page, hidden until focused. */
.skip-link {
  position: absolute;
  left: var(--space-2);
  top: var(--space-2);
  z-index: 20;
  padding: var(--space-2) var(--space-4);
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--radius-sm);
  text-decoration: none;
  transform: translateY(-150%);
  transition: transform 0.15s;
}
.skip-link:focus {
  transform: translateY(0);
}

/* One focus ring everywhere. The dark ring does the contrast work (17:1 on any
   surface here); the yellow band outside it is the accent and carries no meaning. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
details:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px rgba(242, 194, 0, 0.55);
  border-radius: 2px;
}
.terminal a:focus-visible,
.terminal button:focus-visible {
  outline-color: var(--term-ink);
}

/* ---------------------------------------------------------------- layout --- */

.page {
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 var(--space-6);
}
.page.has-sidebar {
  display: grid;
  grid-template-columns: var(--sidebar) minmax(0, 1fr);
  gap: var(--space-12);
  align-items: start;
}

main {
  min-width: 0;
  max-width: var(--content);
  padding: var(--space-4) 0 var(--space-16);
}
/* Prose is capped shorter than the column: a 50rem line of 16px text is too long
   to track. Tables and terminal blocks get the full width. */
main > p,
main > ul,
main > ol,
main > blockquote,
main > details {
  max-width: var(--measure);
}

/* --------------------------------------------------------------- sidebar --- */

.sidebar {
  position: sticky;
  top: var(--space-6);
  padding: var(--space-6) 0;
  font-size: var(--text-sm);
}
.sidebar > summary {
  cursor: pointer;
  font-weight: 600;
  padding: var(--space-2) 0;
}
.sidebar .section {
  margin: var(--space-6) 0 var(--space-2);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  color: var(--ink);
}
.sidebar .section:first-of-type {
  margin-top: var(--space-2);
}
/* The group sits under its section, so it is indented and lighter — the two levels
   have to be told apart at a glance or the extra level buys nothing. */
.sidebar .group {
  margin: var(--space-4) 0 var(--space-2);
  padding-left: var(--space-2);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}
.sidebar ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.sidebar li a {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-code);
  color: var(--ink-soft);
  text-decoration: none;
  padding: 3px var(--space-2);
  border-left: 2px solid var(--line);
  transition: color 0.15s, border-color 0.15s;
}
.sidebar li a:hover {
  color: var(--ink);
  border-left-color: var(--line-strong);
}
/* Current command: weight carries it, the yellow bar accents it. */
.sidebar li a.current {
  color: var(--ink);
  font-weight: 600;
  border-left-color: var(--brand-yellow);
  background: var(--inset);
}

/* Above 900px the sidebar is a permanent column: force it open and drop the
   summary. Below, it is an ordinary <details> disclosure — no JavaScript, and
   nothing that can get stuck in the wrong state. */
@media (min-width: 900px) {
  .sidebar > summary {
    display: none;
  }
}
@media (max-width: 899px) {
  .page.has-sidebar {
    display: block;
  }
  .sidebar {
    position: static;
    padding: var(--space-4) 0 0;
    border-bottom: 1px solid var(--line);
  }
  .sidebar nav {
    padding-bottom: var(--space-4);
  }
}

/* ------------------------------------------------------------------ text --- */

h1,
h2,
h3 {
  line-height: 1.25;
  letter-spacing: -0.015em;
  font-weight: 600;
}
h1 {
  font-size: var(--text-2xl);
  margin: var(--space-6) 0 var(--space-4);
}
h2 {
  font-size: var(--text-xl);
  margin: var(--space-12) 0 var(--space-3);
  padding-top: var(--space-6);
  border-top: 1px solid var(--line);
}
h3 {
  font-size: var(--text-lg);
  margin: var(--space-8) 0 var(--space-2);
}

.command-title {
  font-family: var(--font-mono);
  letter-spacing: -0.02em;
}

.lead {
  font-size: var(--text-lg);
  color: var(--ink-soft);
  margin-top: 0;
}

/* A tagline is the subordinate line under a heading — the heading says what the
   section is, the tagline says it in a few more words. Always --ink-soft, always
   hugging the heading it belongs to, and scaled to that heading: --text-sm under a
   section h3 here, --text-xl under the hero's h1 (which overrides on specificity).
   The heading's own bottom margin is the gap, so there is no negative margin
   holding the pair together. */
.tagline {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin: 0 0 var(--space-4);
  max-width: var(--measure);
}

/* Links: near-black text with a yellow underline. The text does the contrast
   work; the yellow is decoration, and a reader who cannot see it still sees an
   underline (WCAG 1.4.1). */
a {
  color: var(--ink);
}
main a {
  text-decoration: underline;
  text-decoration-color: var(--brand-yellow);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.16em;
  transition: text-decoration-color 0.15s;
}
main a:hover {
  text-decoration-color: var(--brand-yellow-dim);
}

blockquote {
  margin: var(--space-6) 0;
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--brand-yellow);
  background: var(--inset);
  color: var(--ink-soft);
}
blockquote p {
  margin: var(--space-1) 0;
}

/* --------------------------------------------------------------- badges --- */

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-6);
  padding: 0;
}
.badge {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-soft);
  background: var(--inset);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 2px var(--space-2);
}
/* The scope badge carries the accent bar. The word is the signal. */
.badge[class*="scope-"] {
  border-left: 3px solid var(--brand-yellow);
  color: var(--ink);
  font-weight: 600;
}

/* ------------------------------------------------------------------ code --- */

code {
  font-family: var(--font-mono);
  font-size: 0.875em;
  background: var(--inset);
  padding: 0.1em 0.35em;
  border-radius: var(--radius-sm);
}

pre {
  background: var(--term-bg);
  color: var(--term-ink);
  padding: var(--space-4);
  border-radius: var(--radius);
  overflow-x: auto;
  line-height: 1.55;
  font-size: var(--text-code);
  font-family: var(--font-mono);
  margin: var(--space-6) 0;
}
pre code {
  background: none;
  padding: 0;
  color: inherit;
  font-size: inherit;
}

/* The terminal block: command output shown as command output. It scrolls inside
   its own frame, so a long line never makes the page scroll sideways. */
.terminal {
  margin: var(--space-6) 0 var(--space-8);
  background: var(--term-bg);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.terminal-bar {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--term-yellow);
  padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--term-line);
}
.terminal-bar::before {
  content: "$ ";
  color: var(--term-muted);
}
.terminal pre {
  margin: 0;
  border-radius: 0;
  padding: var(--space-4);
}

/* Icon copy button on code blocks (added by assets/copy.js) */
.code-wrap {
  position: relative;
}
.copy-btn {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  color: var(--term-ink);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s, background 0.15s, color 0.15s;
}
.code-wrap:hover .copy-btn,
.copy-btn:focus-visible {
  opacity: 1;
}
.copy-btn:hover {
  background: rgba(255, 255, 255, 0.18);
}
.copy-btn.copied {
  color: var(--term-yellow);
  border-color: var(--term-yellow);
}
/* Touch devices have no hover — keep it visible but subtle. */
@media (hover: none) {
  .copy-btn {
    opacity: 0.6;
  }
}

/* Screen-reader-only (the copy live region). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------- tables --- */

table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-6) 0;
  font-size: var(--text-sm);
  display: block;
  overflow-x: auto;
}
th,
td {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
th {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  font-weight: 600;
}

/* The command index: name column tight, summary takes the rest. */
table.commands td:first-child {
  width: 1%;
  white-space: nowrap;
}
table.commands code {
  background: none;
  padding: 0;
  font-size: var(--text-code);
}

/* --------------------------------------------------------------- details --- */

main > details {
  margin: var(--space-6) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
}
main > details > summary {
  cursor: pointer;
  font-weight: 600;
}

/* ------------------------------------------------------------- home page --- */
/* Four parts, and only the home page uses them: the hero, the two-column split,
   the tool list, and the provisional card. See blueprint/design/patterns.md. */

/* The hero. The only place type gets this big, and the yellow rule is the accent
   doing graphic work — it carries no meaning a reader could miss. The size is a
   clamp rather than a token because it is the one element that should track the
   viewport; every other size on the site is fixed. */
.hero {
  margin: var(--space-8) 0 var(--space-12);
}
/* The one place the site speaks in display type: the name in Bodoni (Parma, 1798),
   the line under it in Cinzel's Roman capitals — Italian for the name, Horace's Rome
   for the steward it comes from. Everything else stays Plex. */
.hero h1 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(3.4rem, 12.5vw, 5.75rem);
  letter-spacing: -0.01em;
  line-height: 1;
  margin: 0;
}
.hero h1::after {
  content: "";
  display: block;
  width: 3.5rem;
  height: 5px;
  margin-top: var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--brand-yellow);
}
/* The tagline at hero scale — the same pattern as the section taglines, sized to the
   heading above it. The yellow rule sits between, so this one is spaced off the h1
   rather than hugging it. */
.hero .tagline {
  font-family: var(--font-inscription);
  font-size: var(--text-xl);
  letter-spacing: 0.04em;
  color: var(--ink);
  margin: var(--space-4) 0 0;
}

/* The split: a figure beside the thing you would actually type. Below 640px it
   stacks, and the figure goes first because it is the smaller half. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 3fr);
  gap: var(--space-8);
  align-items: center;
  margin: var(--space-8) 0;
  padding: var(--space-6);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
/* The mark, and the version badge under it. A column so the badge reads as a caption
   on the mark rather than as the first line of the install instructions. */
.split-figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}
/* The mark is line art on `currentColor`, so it takes the page's ink and needs no
   second copy in another colour. */
.split-figure img {
  width: 100%;
  max-width: 120px;
  height: auto;
  color: var(--ink);
}
.split-do > :first-child {
  margin-top: 0;
}
/* The version badge: the terminal surface shrunk to a pill, because that is the one
   place --brand-yellow is contrast-safe as text. The label is a word, so the number
   is never left to be guessed from its colour. It reads {{version}} from VERSION at
   build time (site/versions.js) — the install command beside it comes from the same
   number, and neither is retyped at release. Spacing is the figure column's gap. */
.version {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  margin: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--term-bg);
  border-radius: var(--radius);
}
/* Label over number, not beside it. The figure column is 180px at the page's full
   width; the two set on one line measure 204px and overhang the card. Stacked they
   are 145px. Measured against the shipped Plex faces, not guessed. */
.version span {
  font-size: var(--text-xs);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--term-muted);
}
.version strong {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  line-height: 1;
  color: var(--term-yellow);
}
.split-do > :last-child {
  margin-bottom: 0;
}
.split-do p {
  max-width: var(--measure);
}

/* The tool list: other people's work, so each line says what the tool is for
   rather than how it compares. Bold name, plain sentence.

   Indented one step, so the run of rows reads as a block belonging to the sentence
   that introduces it rather than as more prose at the same left edge. The indent is
   padding inside `--measure` (box-sizing is border-box), so the block still ends
   where the paragraphs do — it is inset, not pushed out. */
.tools ul {
  list-style: none;
  padding: 0 0 0 var(--space-6);
  margin: var(--space-6) 0;
  max-width: var(--measure);
}
.tools li {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line);
}
.tools li:last-child {
  border-bottom: 0;
}

/* The provisional card. Dashed, because a dashed edge is how scaffolding has read
   since long before the web — and its heading says the same thing in words, so the
   border is never the only carrier. */
.card.provisional {
  margin: var(--space-12) 0 var(--space-8);
  padding: var(--space-4) var(--space-6) var(--space-6);
  background: var(--inset);
  border: 2px dashed var(--line-strong);
  border-radius: var(--radius-lg);
}
.card.provisional > :first-child {
  margin-top: 0;
}
.card.provisional > :last-child {
  margin-bottom: 0;
}
.card.provisional p {
  max-width: var(--measure);
}

/* ------------------------------------------------------- command sections --- */

/* The command index has two levels from the binary: the section (who runs this)
   and the group (how far it reaches). The section is upper-cased and quiet — it
   labels a run of groups rather than competing with them. */
main h2.section {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------------ roles --- */

/* One card per role, because a role is a closed set of two and a reader should be
   able to see both at once and pick. The icon is line art on `currentColor`, like
   every other mark on the site, and it is aria-hidden — the heading is the label. */
.roles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-4);
  margin: var(--space-6) 0;
}
.role {
  padding: var(--space-4) var(--space-6) var(--space-6);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.role h3 {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  margin: var(--space-3) 0 var(--space-2);
}
.role p {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin: 0 0 var(--space-3);
}
.role .role-cmd {
  margin-bottom: 0;
}

/* ------------------------------------------------------------------ small --- */

@media (max-width: 640px) {
  .page,
  .site-header,
  .site-footer {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
  h1 {
    font-size: 1.6rem;
  }
  .hero h1 {
    font-size: clamp(2.25rem, 12vw, 3rem);
  }
  /* A step smaller: 24px of a phone's width is a line break the reader pays for. */
  .tools ul {
    padding-left: var(--space-4);
  }
  .split {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }
  .site-header nav {
    gap: var(--space-4);
    margin-left: 0;
  }
}

/* ------------------------------------------------------------ app library --- */

/* One card per app, drawn like the role cards: the name in mono (it is what you type
   and what the console shows), the description, then the few facts the deploy
   contract cares about. Generated from the manifest the console imports. */
.library {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--space-4);
  margin: var(--space-8) 0;
}
.library-app {
  padding: var(--space-4) var(--space-6) var(--space-6);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  min-width: 0;
}
.library-app h2 {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  margin: 0 0 var(--space-2);
}
.library-app p {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin: 0 0 var(--space-3);
}
.library-app dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-1) var(--space-3);
  margin: 0;
  font-size: var(--text-sm);
}
.library-app dt { color: var(--muted); }
.library-app dd { margin: 0; overflow-wrap: anywhere; }

/* ------------------------------------------------------------------- poem --- */

/* Horace's letter, Latin beside English. Two whole poems rather than a crib — the
   translation rhymes in couplets, so the lines do not pair — and they stack below
   the width where two columns of verse would wrap. */
.poem-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--space-8);
  margin: var(--space-8) 0;
}
.poem h2 {
  font-family: var(--font-inscription);
  font-weight: 400;
  font-size: var(--text-lg);
  letter-spacing: 0.04em;
  margin: 0 0 var(--space-4);
}
.poem-text {
  white-space: pre-line;
  line-height: 1.7;
}
.poem-source {
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin-top: var(--space-6);
}
