/* app.css — generic components. Colour and type tokens live in theme.css;
   the page layout (the centred column, the bar, figures, the article head,
   the project list) lives in layout.css. This file holds the pieces that do
   not care which layout wraps them: base type, the skip link, media,
   figures, tables and code highlighting. */

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

:root {
  --pad: clamp(1.25rem, 4vw, 3rem);

  --s-1: .5rem; --s-2: .875rem; --s-3: 1.5rem;
  --s-4: 2.5rem; --s-5: 4rem; --s-6: 6.5rem;

  --t--2: .72rem;
  --t--1: clamp(.8rem, .78rem + .1vw, .86rem);
  --t-0:  var(--body-size);
  --t-1:  clamp(1.16rem, 1.1rem + .3vw, 1.35rem);
  --t-2:  clamp(1.45rem, 1.3rem + .7vw, 1.9rem);
  --t-3:  clamp(1.85rem, 1.55rem + 1.4vw, 2.8rem);
  --t-4:  clamp(2.4rem, 1.8rem + 3vw, 4.2rem);

  --lh-body: 1.68;
  --lh-tight: 1.08;
  --ls-display: -.018em;
  --radius: 6px;
  --hair: 1px;
}

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body, html { overflow-x: clip; max-width: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-0);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  font-synthesis-weight: none;
  transition: background .2s ease, color .2s ease;
}
@media (prefers-reduced-motion: reduce) { body { transition: none; } }

img, svg, video { display: block; max-width: 100%; }
a { color: inherit; }
::selection { background: var(--accent); color: var(--bg); }

/* skip link: off-screen until focused, then a mono label on the page bg */
.skip {
  position: absolute; top: -999px; left: 0;
  background: var(--bg); color: var(--accent);
  font-family: var(--font-mono); font-size: var(--t--1);
  letter-spacing: .04em; text-decoration: none;
  padding: var(--s-1) var(--s-2); z-index: 100;
}
.skip:focus, .skip:focus-visible {
  top: var(--s-1); left: var(--s-1);
  outline: 2px solid var(--accent); outline-offset: 2px;
}
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px;
}

/* ---------- media ---------- */

.media { position: relative; background: var(--surface); border-radius: var(--radius); overflow: hidden; }
.media video, .media img { width: 100%; height: auto; }
.media--screen { border-radius: 0; }

/* hero video: crop to a cinematic band and blend into the page, so a bright
   render does not fight the surface it sits on */
.media--hero { border-radius: 0; }
.media--hero video {
  width: 100%; height: clamp(320px, 52vh, 560px);
  object-fit: cover; object-position: center 42%;
}
.hero--over { margin-top: calc(var(--s-5) * -1); position: relative; z-index: 1; }

/* two-up: the sim against the rig — the thematic component of this blog */
.duo { display: grid; gap: var(--s-2); }
@media (min-width: 560px) { .duo { grid-template-columns: 1fr 1fr; } }
.duo__cap {
  font-family: var(--font-mono); font-size: var(--t--2);
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-dim); margin-bottom: .5rem;
}
.duo__cap b { color: var(--accent); font-weight: 400; }

.ph {
  aspect-ratio: 16/9; display: grid; place-content: center; gap: .3rem;
  border: var(--hair) dashed var(--rule); border-radius: var(--radius);
  text-align: center; font-family: var(--font-mono);
  font-size: var(--t--2); color: var(--ink-faint); letter-spacing: .1em;
}

/* ---------- figures: unframed, on the page background ---------- */

figure { margin-block: var(--s-5); }
figcaption {
  font-family: var(--font-mono); font-size: var(--t--1);
  line-height: 1.6; color: var(--ink-dim);
  margin-top: var(--s-2); padding-top: var(--s-2);
  border-top: var(--hair) solid var(--rule);
}
figcaption b { color: var(--ink); font-weight: 500; }

/* the plot SVGs carry their own colours as CSS variables (--fig-*), set in
   theme.css, so the same figure reads correctly in both themes. */
[data-fig] svg { width: 100%; height: auto; display: block; }
.plot-hint {
  display: none; font-family: var(--font-mono); font-size: var(--t--2);
  color: var(--ink-faint); letter-spacing: .1em; margin-top: .5rem;
}

/* Migrated posts bring light-background figures — notebook plots, CAD renders,
   Gazebo captures. Giving them a plate makes them read as printed plates
   rather than as a hole in the page. Scoped to .rowfig img: the site's own
   figures are inline SVG, and the owner-app screenshots already carry their
   own frame. */
.rowfig img {
  background: #F4F5F7;
  padding: .7rem;
  border-radius: var(--radius);
  box-shadow: 0 1px 0 var(--rule-hi);
}

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

.tw { overflow-x: auto; margin-block: var(--s-4); }
table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: .55rem .9rem .55rem 0; border-bottom: var(--hair) solid var(--rule); }
th {
  font-family: var(--font-mono); font-size: var(--t--2);
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint);
  font-weight: 400; border-bottom-color: var(--rule-hi);
}
td { font-size: var(--t--1); }
td.n, th.n { text-align: right; font-family: var(--font-mono); }
td b { color: var(--accent); font-weight: 500; }

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

/* Blocks are highlighted at build time by site/tools/highlight.py, which wraps
   tokens in short classes. NOTHING is left bare: an unrecognised block still
   falls through to `generic`, so every block on the site reads as a terminal.
   Inline <code> is deliberately NOT highlighted -- a coloured word mid-sentence
   reads as a link. */
code { font: .88em var(--font-mono); background: var(--surface); padding: .1em .35em; border-radius: 4px; }
pre code { color: var(--ink); background: none; padding: 0; }
pre .c  { color: var(--code-com); font-style: italic; }   /* comment */
pre .s  { color: var(--code-str); }                       /* string  */
pre .k  { color: var(--code-key); font-weight: 500; }     /* keyword / command */
pre .f  { color: var(--code-fn); }                        /* call    */
pre .n  { color: var(--code-num); }                       /* number  */
pre .o  { color: var(--code-op); }                        /* flag    */
pre .u  { color: var(--code-fn); text-decoration: none; } /* path / url */
pre .mg { color: var(--code-op); font-weight: 500; }      /* notebook magic */
pre .pr { color: var(--accent); font-weight: 700; }       /* shell prompt */
pre .tr { color: var(--rule-hi); }                        /* tree rules */
pre .d  { color: var(--code-fn); }                        /* directory */

/* Trace output is a table pretending to be text: dim everything except the
   numbers, so the columns read at a glance. */
pre .lang-data { color: var(--ink-faint); }
pre .lang-data .n { color: var(--ink); }

/* Tree listings: the box characters are structure, not content. */
pre .lang-tree { color: var(--ink-dim); }

pre {
  background: var(--surface);
  border: var(--hair) solid var(--rule);
  border-left: 2px solid var(--rule-hi);
  border-radius: var(--radius);
  padding: var(--s-3) var(--s-3);
  margin-block: var(--s-4);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--t--1);
  line-height: 1.62;
  tab-size: 4;
}
pre::-webkit-scrollbar { height: 6px; }
pre::-webkit-scrollbar-thumb { background: var(--rule-hi); border-radius: 4px; }

/* long single lines scroll rather than pushing the page sideways */
@media (max-width: 820px) {
  pre { margin-inline: calc(var(--pad) * -1); padding-inline: var(--pad); border-left: 0; }
}

/* ---------- stats — hairline dividers, no cards ---------- */

.stats {
  display: grid; gap: var(--s-3); margin-block: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  border-top: var(--hair) solid var(--rule); padding-top: var(--s-3);
}
.stat__v {
  font-family: var(--font-display); font-weight: var(--w-display);
  font-size: var(--t-2); line-height: 1; letter-spacing: var(--ls-display);
  font-variant-numeric: tabular-nums; color: var(--ink-hi);
}
.stat__k {
  font-family: var(--font-mono); font-size: var(--t--2);
  color: var(--ink-faint); margin-top: .4rem;
  letter-spacing: .1em; text-transform: uppercase;
}

/* pull quote — a rule, not a box */
.pull {
  margin-block: var(--s-5); padding-block: var(--s-3);
  border-block: var(--hair) solid var(--rule);
  font-family: var(--font-display); font-weight: var(--w-display);
  font-size: var(--t-2); line-height: 1.25; letter-spacing: var(--ls-display);
  color: var(--ink-hi);
}
.pull p { margin: 0; }

/* note — a hanging label, no background fill */
.note { margin-block: var(--s-4); padding-left: var(--s-3); border-left: 2px solid var(--accent); }
.note p:last-child { margin-bottom: 0; }
.note__t {
  font-family: var(--font-mono); font-size: var(--t--2);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--accent); margin-bottom: .4rem;
}
