/* The site stylesheet. One file, no framework, no build step.
 *
 * The palette is the digital one — the dark field and terracotta accent the
 * video series and the knowledge-base pages already use. Marketing/NAMING.md's
 * navy and blue is the product-and-print brand; see docs/WEBSITE_PLAN.md §8 for
 * why the two differ on purpose.
 *
 * WHAT WAS WRONG WITH THE FIRST VERSION OF THIS FILE, since it was not the
 * colours and not the typeface: there was one shape on the site. Every page,
 * including the one a visitor lands on, was a 38rem column of paragraphs with a
 * hairline above it. That is a fine stylesheet for an essay and it is not a
 * website — no page could begin, nothing could be a figure, a grid or an action,
 * and twenty-one captures of the running product sat unused in media/ because
 * prose has nowhere to put them.
 *
 * So there are now two shapes. A DOCUMENT (`main.prose`) is the reading column,
 * unchanged, because an 1,800-word article on roughness wants exactly that. A
 * PAGE (`main.landing`) is a stack of bands, each one full-bleed with its
 * content held in `.inner` at the frame width. Which one a page gets is
 * declared in the register, not guessed from its content.
 */

:root {
  --bg:#1b1b1f; --surface:#232328; --card:#2a2a30; --raise:#32323a;
  --fg:#f0ede7; --body:#c4c0b7; --muted:#a5a199; --dim:#8e8a83;
  --accent:#c47046; --accent-hi:#dd8456; --accent-soft:rgba(196,112,70,.14);
  --cool:#7ba8b8;
  --border:rgba(240,237,231,.11); --border-hi:rgba(240,237,231,.2);
  --sans:'Sora', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono:ui-monospace, 'DejaVu Sans Mono', Menlo, monospace;

  /* Two widths, and the difference between them is the whole layout. */
  --measure:38rem;          /* a column of text, at a length that is readable */
  --frame:74rem;            /* the page itself */
  --gutter:1.5rem;
  --radius:14px;
  --shadow:0 1px 2px rgba(0,0,0,.3), 0 12px 32px -12px rgba(0,0,0,.55);
}

*, *::before, *::after { box-sizing:border-box; }
html { -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior:auto; }
  *, *::before, *::after { transition-duration:0s !important; animation-duration:0s !important; }
}

/* --body is for reading and --muted for chrome. They were one token, and the
   result was 5.4:1 body copy — legal, and not generous for 900 words. */
body {
  margin:0; background:var(--bg); color:var(--body);
  font-family:var(--sans); font-size:clamp(16px, 15.2px + .25vw, 18px); line-height:1.7;
  text-rendering:optimizeLegibility; -webkit-font-smoothing:antialiased;
}

a { color:var(--accent); text-decoration:none; border-bottom:1px solid rgba(196,112,70,.35); }
a:hover, a:focus-visible { color:var(--fg); border-bottom-color:var(--fg); }
:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }

/* Keyboard users reach the content without walking the nav. */
.skip { position:absolute; left:-9999px; }
.skip:focus { left:1rem; top:1rem; z-index:20; background:var(--card); color:var(--fg);
              padding:.6rem 1rem; border-radius:8px; border:1px solid var(--border-hi); }

/* ── the masthead ─────────────────────────────────────────────────────────
   Full width, because the page under it is now full width; the earlier version
   was clamped to the reading measure so that the wordmark lined up with the
   first word of the prose, which was the right call when prose was all there
   was. It is sticky and translucent, and it carries the one thing that was
   missing from every page of this site: a link into the application. */
header.site {
  position:sticky; top:0; z-index:10;
  background:rgba(27,27,31,.82);
  -webkit-backdrop-filter:saturate(140%) blur(14px);
  backdrop-filter:saturate(140%) blur(14px);
  border-bottom:1px solid var(--border);
}
header.site .bar {
  max-width:var(--frame); margin:0 auto; padding:.85rem var(--gutter);
  display:flex; align-items:center; gap:1.25rem;
}
.wordmark {
  font-weight:700; font-size:1.22rem; letter-spacing:-.035em; color:var(--fg);
  border:0; white-space:nowrap; flex:none;
}
.wordmark b { color:var(--accent); font-weight:700; }
header.site nav {
  display:flex; align-items:center; gap:1.15rem; flex:1 1 auto; min-width:0;
  font-size:.875rem; line-height:1.4; overflow-x:auto; scrollbar-width:none;
  /* One line that scrolls, not two lines that wrap: eight items wrapping onto
     a second row on a phone pushes the first sentence of every page below the
     fold. The full set is in the footer, which is where completeness belongs. */
  mask-image:linear-gradient(90deg, #000 0, #000 calc(100% - 1.5rem), transparent 100%);
}
header.site nav::-webkit-scrollbar { display:none; }
header.site nav a { color:var(--muted); border:0; white-space:nowrap; padding:.2rem 0; }
header.site nav a:hover { color:var(--fg); }
header.site nav a[aria-current="page"] { color:var(--fg); box-shadow:inset 0 -2px 0 var(--accent); }
header.site .btn { flex:none; }

/* ── actions ─────────────────────────────────────────────────────────────── */
.btn {
  display:inline-flex; align-items:center; gap:.4rem;
  background:var(--accent); color:#fff; border:1px solid var(--accent);
  padding:.72rem 1.15rem; border-radius:9px;
  font-size:.95rem; font-weight:600; line-height:1.2; letter-spacing:-.005em;
  transition:background .15s, border-color .15s, color .15s, transform .15s;
}
.btn:hover, .btn:focus-visible { background:var(--accent-hi); border-color:var(--accent-hi);
                                 color:#fff; transform:translateY(-1px); }
.btn.ghost { background:transparent; color:var(--fg); border-color:var(--border-hi); }
.btn.ghost:hover, .btn.ghost:focus-visible { background:var(--accent-soft); border-color:var(--accent);
                                             color:var(--fg); }
.btn.small { padding:.5rem .85rem; font-size:.85rem; border-radius:8px; }
.actions { display:flex; flex-wrap:wrap; gap:.7rem; margin:1.6rem 0 0; }
.actions:empty { display:none; }

/* ── type ─────────────────────────────────────────────────────────────────
   Fluid, so a 1,500px laptop and a 390px phone each get a scale rather than
   one scale and a breakpoint that corrects it. Sora is a variable face capped
   at 700, so hierarchy comes from size and tracking, not from a heavier cut. */
h1, h2, h3, h4 { color:var(--fg); font-weight:700; line-height:1.15; letter-spacing:-.025em; }
h1 { font-size:clamp(2.1rem, 1.6rem + 2.1vw, 3.1rem); margin:0 0 1.4rem; }
h2 { font-size:clamp(1.5rem, 1.3rem + .8vw, 2rem); margin:3.2rem 0 1rem; letter-spacing:-.022em; }
h3 { font-size:1.14rem; font-weight:600; margin:2rem 0 .6rem; letter-spacing:-.012em; }
h4 { font-size:1rem; font-weight:600; margin:1.5rem 0 .5rem; letter-spacing:-.005em; }
p  { margin:0 0 1.15rem; }
strong { color:var(--fg); font-weight:600; }
em { font-style:italic; }

/* An article's H1 does not need the hero's size: it sits over a 38rem column,
   where 3rem wraps a headline onto four lines. */
main.prose h1 { font-size:clamp(2rem, 1.65rem + 1.4vw, 2.65rem); }

/* Where the reader is, and when this was written — on a site whose argument is
   that a figure without its year is not a figure. */
.kicker {
  max-width:var(--measure); margin:0 auto; padding:2.5rem var(--gutter) 0;
  display:flex; flex-wrap:wrap; gap:.6rem 1rem; align-items:baseline;
  font-size:.82rem; letter-spacing:.06em; text-transform:uppercase;
}
.kicker a { color:var(--accent); border:0; font-weight:600; }
.kicker a:hover { color:var(--fg); }
.kicker time { color:var(--dim); }
main.prose.article { padding-top:1.25rem; }

/* The lede: the first paragraph of an article, which its markdown italicises. */
.article > p:first-of-type { font-size:1.18rem; line-height:1.6; color:var(--fg); }
.article > p:first-of-type em { font-style:normal; }

ul, ol { margin:0 0 1.15rem; padding-left:1.4rem; }
li { margin:0 0 .5rem; }
li::marker { color:var(--dim); }

blockquote {
  margin:1.75rem 0; padding:.2rem 0 .2rem 1.25rem;
  border-left:3px solid var(--accent); color:var(--fg);
}
blockquote p:last-child { margin-bottom:0; }

hr { border:0; border-top:1px solid var(--border); margin:3rem 0; }

code { font-family:var(--mono); font-size:.88em; background:var(--accent-soft);
       color:var(--fg); padding:.12em .35em; border-radius:4px; }

/* ── a document ───────────────────────────────────────────────────────────
   Unchanged in substance: one column at a readable length. An article is not
   improved by being made into a dashboard. */
main.prose { max-width:var(--measure); margin:0 auto; padding:3rem var(--gutter) 4.5rem; }

/* ── a page ───────────────────────────────────────────────────────────────
   A stack of bands. Each is full-bleed so a tint or a rule can run edge to
   edge; `.inner` holds its content at the frame width. */
main.landing { padding:0 0 1rem; }
.band { padding:clamp(3rem, 6vw, 5.5rem) 0; }
.band > .inner { max-width:var(--frame); margin:0 auto; padding:0 var(--gutter); }
.band > .inner.prose { max-width:calc(var(--measure) + var(--gutter) * 2); }
.band h2:first-child, .band h3:first-child, .band h1:first-child { margin-top:0; }

/* The hero. The product's own screen beside the argument for it, because a
   council officer deciding whether to read on is asking whether this is real,
   and a picture of the running software answers that faster than a paragraph. */
.band.hero {
  padding-top:clamp(2.75rem, 5vw, 4.5rem); padding-bottom:clamp(3rem, 5vw, 4.5rem);
  background:
    radial-gradient(60rem 28rem at 15% -10%, rgba(196,112,70,.17), transparent 70%),
    radial-gradient(44rem 26rem at 92% 8%, rgba(123,168,184,.10), transparent 70%);
}
.band.hero .inner { display:grid; gap:clamp(2rem, 4vw, 3.5rem); align-items:center; }
.band.hero .copy > :first-child { margin-top:0; }
.band.hero h1 { letter-spacing:-.035em; }
.band.hero .copy p { font-size:clamp(1.05rem, 1rem + .35vw, 1.22rem); line-height:1.6; max-width:34rem; }
.band.hero .copy p:first-of-type { color:var(--fg); }
.band.hero .shot figure { margin:0; }
@media (min-width:62rem) {
  .band.hero .inner { grid-template-columns:minmax(0,1fr) minmax(0,1.08fr); }
}

/* The figures, read from the registries. Big numerals, because the point of the
   band is that they are small numbers somebody can hold. */
.band.stats { padding:0; }
.band.stats > .inner { padding-top:0; padding-bottom:0; }
.band.stats ul {
  display:grid; gap:0; margin:0; padding:0; list-style:none;
  border-top:1px solid var(--border); border-bottom:1px solid var(--border);
  grid-template-columns:repeat(auto-fit, minmax(13rem, 1fr));
}
.band.stats li {
  margin:0; padding:1.6rem 1.5rem 1.7rem; border-left:1px solid var(--border);
  display:flex; flex-direction:column; gap:.3rem;
}
.band.stats li:first-child { border-left:0; }
.band.stats b {
  font-size:clamp(2rem, 1.6rem + 1.4vw, 2.7rem); font-weight:700;
  letter-spacing:-.04em; line-height:1; color:var(--fg);
  font-variant-numeric:tabular-nums;
}
.band.stats span { font-size:.9rem; line-height:1.5; color:var(--muted); }

/* A grid of things. `auto-fit` rather than a fixed count, because the registry
   decides how many capabilities there are and the stylesheet does not get a
   vote. */
.band.cards .lead { max-width:46rem; margin-bottom:2.5rem; }
.band.cards .lead > :last-child { margin-bottom:0; }
.band.cards .grid { display:grid; gap:1.1rem; grid-template-columns:repeat(auto-fit, minmax(17rem, 1fr)); }
.card {
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius); padding:1.5rem 1.5rem 1.35rem;
  transition:border-color .15s, background .15s, transform .15s;
}
.card:hover { border-color:var(--border-hi); background:var(--card); transform:translateY(-2px); }
.card h3 { margin:0 0 .55rem; font-size:1.05rem; }
.card h3 a { color:var(--fg); border:0; }
.card:hover h3 a { color:var(--accent); }
.card p { margin:0; font-size:.95rem; line-height:1.62; color:var(--body); }
.card p + p { margin-top:.7rem; }
.band.cards .actions { margin-top:2.25rem; }

/* Prose beside a figure. The figure is the evidence for the paragraph, so they
   belong on the same screen rather than one above the other. */
.band.split { border-top:1px solid var(--border); }
.band.split .inner { display:grid; gap:clamp(2rem, 4vw, 3.5rem); align-items:center; }
.band.split .copy { max-width:38rem; }
.band.split .copy > :last-child { margin-bottom:0; }
.band.split .shot figure { margin:0; }
@media (min-width:62rem) {
  .band.split .inner { grid-template-columns:minmax(0,1fr) minmax(0,1.15fr); }
  /* Alternate, so two splits in a row do not read as one long column. Which
     one flips is counted in the renderer; a :nth-of-type here would count
     every <section> on the page and flip both or neither. */
  .band.split.flip .inner { grid-template-columns:minmax(0,1.15fr) minmax(0,1fr); }
  .band.split.flip .copy { order:2; }
}

/* The callout. On this site it carries the sentence the whole argument rests
   on — that nobody uses this yet — so it is the one band that is tinted. */
.band.note > .inner {
  max-width:calc(var(--frame) - 8rem);
  background:var(--surface); border:1px solid var(--border);
  border-left:3px solid var(--accent);
  border-radius:var(--radius); padding:2rem clamp(1.5rem, 3vw, 2.5rem);
}
.band.note .inner > :last-child { margin-bottom:0; }
.band.note p { max-width:44rem; }

/* The close. One action, centred, with nothing competing with it. */
.band.close { border-top:1px solid var(--border); text-align:center; }
.band.close > .inner { max-width:46rem; }
.band.close p { max-width:40rem; margin-left:auto; margin-right:auto; }
.band.close .actions { justify-content:center; }
.band.close p:last-child { margin-top:1.75rem; margin-bottom:0; font-size:.875rem; color:var(--dim); }

/* ── tables ───────────────────────────────────────────────────────────────
   Tables are the one thing that genuinely needs more width than prose should
   have. Rather than widen the measure for everything, a table in a DOCUMENT
   breaks out of it, centred, up to the viewport — and below that falls back to
   scrolling. A three-column comparison clipped at the text edge is the table
   nobody reads. Inside a band it is already at the frame width and needs no
   breakout, which is why the rule is scoped. */
.table-wrap { overflow-x:auto; margin:1.75rem 0; }
@media (min-width:52rem) {
  main.prose > .table-wrap, .band > .inner.prose > .table-wrap {
    width:min(54rem, calc(100vw - 3rem)); margin-left:50%; transform:translateX(-50%);
  }
}
table { border-collapse:collapse; width:100%; font-size:.93rem; }
th, td { text-align:left; padding:.65rem .85rem; border-bottom:1px solid var(--border);
         vertical-align:top; }
th { color:var(--fg); font-weight:600; font-size:.78rem; letter-spacing:.07em;
     text-transform:uppercase; white-space:nowrap; }
tbody tr:last-child td { border-bottom:0; }

/* ── figures ──────────────────────────────────────────────────────────────
   A capture of the running product is the site's main evidence, so it is
   framed rather than dropped in: a border so it reads as a screen, a radius so
   it does not fight the cards, and a shadow so it sits on the field instead of
   in it. In a document it breaks out of the measure, as a table does — a
   screenshot of a works programme at 38rem is a picture of a table nobody can
   read. In a band it fills its column. */
figure { margin:2.25rem 0; }
figure img, figure video {
  display:block; width:100%; height:auto; border-radius:12px;
  border:1px solid var(--border-hi); background:var(--card); box-shadow:var(--shadow);
}
figcaption { margin-top:.7rem; font-size:.875rem; line-height:1.5; color:var(--dim); }
@media (min-width:52rem) {
  main.prose > figure, .band > .inner.prose > figure {
    width:min(54rem, calc(100vw - 3rem)); margin-left:50%; transform:translateX(-50%);
  }
  main.prose > figure figcaption, .band > .inner.prose > figure figcaption {
    max-width:38rem; margin-left:auto; margin-right:auto;
  }
}
figure.video video { aspect-ratio:16/9; }

/* ── the footer ───────────────────────────────────────────────────────────
   In columns, because a flat row of the same links as the header tells a
   reader nothing — and because it let /changelog become a page reachable only
   from a sentence in the middle of another one. */
footer.site {
  border-top:1px solid var(--border); background:var(--surface);
  padding:clamp(2.75rem, 5vw, 4rem) 0 2.5rem; font-size:.9rem;
}
footer.site .cols, footer.site .fine {
  max-width:var(--frame); margin:0 auto; padding:0 var(--gutter);
}
footer.site .cols {
  display:grid; gap:2.25rem 2rem;
  grid-template-columns:repeat(auto-fit, minmax(11rem, 1fr));
}
@media (min-width:58rem) {
  footer.site .cols { grid-template-columns:2fr 1fr 1fr 1fr 1fr; }
}
footer.site .who { max-width:24rem; }
footer.site .who .wordmark { display:inline-block; margin-bottom:.85rem; }
footer.site .who p { font-size:.875rem; line-height:1.6; }
/* The one sentence on this site that must never be skimmed past sits in the
   footer, and the fine-print colour is not where you put it. */
footer.site .who .meta { color:var(--muted); font-size:.875rem; }
footer.site nav { display:flex; flex-direction:column; gap:.55rem; align-items:flex-start; }
footer.site nav h2 {
  margin:0 0 .35rem; font-size:.74rem; font-weight:600; letter-spacing:.09em;
  text-transform:uppercase; color:var(--dim);
}
footer.site nav a { color:var(--muted); border:0; font-size:.875rem; line-height:1.4; }
footer.site nav a:hover { color:var(--fg); }
footer.site .meta { color:var(--dim); font-size:.82rem; }
footer.site .fine {
  margin-top:2.75rem; padding-top:1.5rem; border-top:1px solid var(--border);
  display:flex; flex-wrap:wrap; gap:.5rem 1.5rem; justify-content:space-between;
}
footer.site .fine p { margin:0; }
footer.site .fine a { color:var(--dim); border-bottom-color:transparent; }
footer.site .fine a:hover { color:var(--fg); }

/* ── narrow ───────────────────────────────────────────────────────────────── */
@media (max-width:40rem) {
  :root { --gutter:1.15rem; }
  main.prose { padding-top:2.25rem; }
  .band.stats li { padding:1.25rem 1.15rem 1.35rem; border-left:0; border-top:1px solid var(--border); }
  .band.stats li:first-child { border-top:0; }
  .band.note > .inner { border-radius:12px; padding:1.5rem 1.25rem; }
  .actions .btn { flex:1 1 auto; justify-content:center; }
}

/* The site is dark by design. A reader who has asked for light gets a light
   field rather than an inverted one that nobody checked. */
@media (prefers-color-scheme: light) {
  :root {
    --bg:#fbf9f6; --surface:#fff; --card:#fff; --raise:#f3efe9;
    --fg:#1b1b1e; --body:#3a382f; --muted:#56534b; --dim:#67625a;
    --accent:#a2532c; --accent-hi:#8c4524; --accent-soft:rgba(162,83,44,.1);
    --border:rgba(27,27,30,.13); --border-hi:rgba(27,27,30,.22);
    --shadow:0 1px 2px rgba(27,27,30,.05), 0 14px 34px -14px rgba(27,27,30,.22);
  }
  a { border-bottom-color:rgba(162,83,44,.4); }
  header.site { background:rgba(251,249,246,.85); }
  .band.hero {
    background:
      radial-gradient(60rem 28rem at 15% -10%, rgba(162,83,44,.09), transparent 70%),
      radial-gradient(44rem 26rem at 92% 8%, rgba(60,120,140,.07), transparent 70%);
  }
  .card:hover { background:var(--raise); }
  footer.site { background:var(--raise); }
}

@media print {
  body { background:#fff; color:#000; font-size:11pt; }
  header.site, footer.site nav, footer.site .fine, .skip, .actions { display:none; }
  header.site { position:static; }
  .band { padding:1rem 0; }
  figure img { box-shadow:none; }
}
