:root {
  --tg-bg: #ffffff;
  --tg-fg: #14181f;
  --tg-muted: #5b6675;
  --tg-accent: #1f6feb;
  --tg-border: #e3e8ef;
  --tg-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  --tg-surface: #f6f8fa;
  /* The reading column. Everything that has to line up with it is
     derived from this, so the two cannot drift apart. */
  --tg-measure: 46rem;
}

body {
  color: var(--tg-fg);
  background: var(--tg-bg);
  font-size: 17px;
  line-height: 1.7;
}

.entry-content { max-width: var(--tg-measure); }

/* Capping the text and leaving its container alone is what put 424px of empty
   card to the right of every paragraph: GeneratePress stretches .inside-article
   to the full 1200px grid, and only the words inside it stopped at the measure.
   The guide template appeared to escape this and did not -- it was 820px because
   it was still in the sidebar layout, 70% of the grid, with an empty column
   beside it. Two different mistakes landing on nearly the same number is why
   neither was visible next to the other.

   +80px is GeneratePress's 40px of horizontal padding on each side, which the
   padding override further down deliberately leaves in place. Below 768px GP
   drops that padding to 30px and this cap stops binding altogether: at every
   width where the two numbers differ, the card is already narrower than the
   cap. So there is no second breakpoint to keep in step.

   .page-header is in the list because the guides archive puts its heading and
   intro there, outside the cards. Capping the cards alone moved them inward and
   left the heading above them at the old width: one column of text starting in
   two different places on one page. */
.separate-containers .inside-article,
.separate-containers .page-header {
  max-width: calc(var(--tg-measure) + 80px);
  /* Left, not centred. Centring the capped card split the difference and put
     192px of nothing on each side of it, which left the text starting 192px
     inside the wordmark above it -- the page had two left edges and neither
     was the one the eye had already been given by the header. Flush left is
     one edge: .main-title and the first character of every paragraph both
     land on the container's padding, at 66px in a 1200px container. The
     slack all moves to the right, where a reading column is supposed to end
     and nothing is claiming alignment. */
  margin-inline: 0;
}

/* Headings carried the same weight and colour as body text at 24px against
   17px, so a page had no visible skeleton -- every page read as one block of
   grey and therefore as the same page. Weight is what makes a document
   scannable; the rule under it was doing that job alone and doing it weakly. */
.entry-content h2 {
  margin-top: 2.8rem;
  padding-bottom: .35rem;
  border-bottom: 1px solid var(--tg-border);
  font-size: 1.55rem;
  font-weight: 600;
  letter-spacing: -.01em;
}

.entry-content h3 {
  margin-top: 1.9rem;
  font-size: 1.15rem;
  font-weight: 600;
}

.entry-content a { color: var(--tg-accent); }

.entry-content pre {
  padding: 1rem 1.1rem;
  overflow-x: auto;
  border: 1px solid var(--tg-border);
  border-radius: 6px;
  background: var(--tg-surface);
  font-family: var(--tg-mono);
  font-size: .88rem;
  line-height: 1.55;
}

/* Horizontal padding stays under the width of a space (~4.4px at this size).
   At .4em it measured 6px, wider than a space, so `code`. read as `code` .
   -- the punctuation after inline code looked detached on every page. */
.entry-content :not(pre) > code {
  padding: .1em .18em;
  border-radius: 4px;
  background: var(--tg-surface);
  font-family: var(--tg-mono);
  font-size: .88em;
}

.entry-content table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.4rem 0;
  font-size: .95rem;
}

.entry-content th,
.entry-content td {
  padding: .55rem .7rem;
  border: 1px solid var(--tg-border);
  text-align: left;
}

.entry-content th { background: var(--tg-surface); font-weight: 600; }

/* Archive entry titles are links, and on an index they are the only way in.
   The theme styles them as plain dark headings with a hover colour shift --
   which says nothing at all on a touch screen, where there is no hover. On
   /guides/ that is nine headings a reader has no reason to tap. */
.entry-title a {
  color: var(--tg-accent);
}

.entry-title a:hover,
.entry-title a:focus-visible {
  text-decoration: underline;
  text-underline-offset: .12em;
}

/* Not on a single page: there the title is the page, not a link to it. */
.single .entry-title a,
.page .entry-title a {
  color: var(--tg-fg);
}

/* Wide tables scroll inside this rather than widening the page. See the
   wrapper filter in functions.php. */
.tg-scroll {
  overflow-x: auto;
  margin: 1.4rem 0;
  -webkit-overflow-scrolling: touch;
}

.tg-scroll > table { margin: 0; }

.entry-content caption {
  caption-side: bottom;
  margin-top: .5rem;
  color: var(--tg-muted);
  font-size: .86rem;
  text-align: left;
}

.entry-content img { max-width: 100%; height: auto; }

/* ===== Media =====
 *
 * Every slot reserves its space through aspect-ratio before anything loads.
 * CLS is currently 0 and images are the usual way that gets lost: a picture
 * that arrives after first paint and pushes the text down is exactly what the
 * metric measures. Placeholders use the same ratios as the images that will
 * replace them, so filling them in changes nothing about the layout.
 */

.tg-figure {
  margin: 1.75rem 0;
}

.tg-figure img,
.tg-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--tg-border);
  border-radius: 8px;
  background: var(--tg-surface);
}

.tg-figure figcaption,
.tg-shot figcaption {
  margin-top: .55rem;
  color: var(--tg-muted);
  font-size: .86rem;
  line-height: 1.5;
}

.tg-figure figcaption strong,
.tg-shot figcaption strong { color: var(--tg-fg); }

/* Gallery grid. Collapses to one column on narrow screens. */
.tg-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.4rem;
  margin: 1.75rem 0;
}

.tg-shot { margin: 0; }

/* Placeholder media must never be mistaken for a real TerraGear render. */
.tg-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 16 / 9;
  margin: 1.5rem 0;
  padding: 1.5rem;
  border: 2px dashed var(--tg-border);
  border-radius: 8px;
  background: repeating-linear-gradient(
    45deg, var(--tg-surface), var(--tg-surface) 10px,
    #eef1f5 10px, #eef1f5 20px
  );
  color: var(--tg-muted);
  font-family: var(--tg-mono);
  font-size: .85rem;
  line-height: 1.6;
  text-align: center;
}

/* Inside a figure or a gallery cell the wrapper already spaces things. */
.tg-figure .tg-placeholder,
.tg-shot .tg-placeholder { margin: 0; }

.tg-gallery .tg-placeholder {
  aspect-ratio: 4 / 3;
  padding: 1rem;
  font-size: .78rem;
}

/* A squarer slot for portrait or diagram content. */
.tg-placeholder--square { aspect-ratio: 1 / 1; }
/* A wide slot for panoramic terrain shots. */
.tg-placeholder--wide { aspect-ratio: 21 / 9; }

.tg-note {
  margin: 1.5rem 0;
  padding: .9rem 1.1rem;
  border-left: 3px solid var(--tg-accent);
  background: var(--tg-surface);
  color: var(--tg-muted);
  font-size: .94rem;
}

.tg-note strong { color: var(--tg-fg); }

/* GeneratePress pads .inside-article 40px and .site-main another 20 above it.
   Content did not start until 331px on a 1000px screen -- a third of the first
   view was furniture. */
/* Two classes, because GeneratePress sets these as
   `.separate-containers .inside-article { padding: 40px }` and a single-class
   rule loses on specificity no matter where it sits in the cascade. Only the
   top is reclaimed; the horizontal padding is doing real work. */
.separate-containers .inside-article { padding-top: 1.4rem; }
.separate-containers .site-main { margin-top: .5rem; }

.tg-breadcrumbs {
  margin-bottom: .9rem;
  color: var(--tg-muted);
  font-size: .85rem;
}

.tg-breadcrumbs a { color: var(--tg-muted); }
.tg-breadcrumbs a:hover { color: var(--tg-accent); }
.tg-breadcrumbs .tg-sep { padding: 0 .35rem; opacity: .55; }

.tg-updated {
  margin: -.4rem 0 1.6rem;
  color: var(--tg-muted);
  font-size: .85rem;
}

/* The singular variant pulls itself up under the h1 with a negative margin.
   In a listing the title above it is smaller and the pull overlaps it, so this
   has to come after that rule rather than before it. */
.tg-updated--listing {
  margin-top: .35rem;
  margin-bottom: .9rem;
}

.tg-updated a { color: var(--tg-muted); text-decoration: underline; }
.tg-updated a:hover { color: var(--tg-accent); }

/* Previous/next under a guide: two links, a label over each, pushed apart. */
.tg-guide-nav {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--tg-border);
  font-size: .95rem;
}

.tg-guide-nav a { color: var(--tg-accent); text-decoration: none; }
.tg-guide-nav a:hover { text-decoration: underline; }
.tg-guide-nav-next { margin-left: auto; text-align: right; }

.tg-guide-nav-label {
  display: block;
  color: var(--tg-muted);
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.tg-colophon p {
  margin: 0 0 .35rem;
  font-size: .85rem;
  line-height: 1.6;
}

.tg-colophon p:last-child { margin-bottom: 0; }

/*
 * Focus rings for keyboard users only.
 *
 * GeneratePress does this with an inline script that toggles a `using-mouse`
 * class on <body> from pointer and key events. The site's CSP allows no
 * inline scripts, so the script is switched off in functions.php and
 * :focus-visible -- which every current browser implements with the same
 * heuristic -- does the job without JavaScript.
 */
:focus:not(:focus-visible) { outline: 0; }

/* The header mark, if a file was ever put in assets/img/. Sized from the
   wordmark rather than in absolute pixels so the two stay in proportion at
   every breakpoint, and given optical spacing rather than a full space: a mark
   and the word it sits beside read as one lockup or as two things, and the gap
   is what decides which. */
.main-title a { display: inline-flex; align-items: center; gap: 0.45em; }
.tg-mark { width: 1.05em; height: 1.05em; flex: none; }

/* --- Home page components -------------------------------------------------
   Three small layouts, all of them lists. The home page was 445 words of
   consecutive paragraphs with one image at the top, which is the right content
   in the wrong shape: a reader deciding whether this toolchain is worth an
   afternoon had to read prose to find the four numbers that answer it.

   Nothing here introduces a claim. Every figure and every tool name already had
   a page proving it, and each one links to that page: the layout's job is to
   make the evidence visible from the front door, not to add to it. */

/* Measured figures from the recorded build. Grid rather than flex so the cells
   share a width and the numbers line up down the page; auto-fit so it collapses
   to two and then one without a breakpoint of its own. 9rem is the widest a
   cell can be and still fit four across inside the reading measure. */
.tg-figures {
  list-style: none;
  margin: 1.75rem 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.75rem;
}

.tg-figures a {
  display: block;
  height: 100%;
  padding: 0.85rem 0.9rem;
  border: 1px solid var(--tg-border);
  border-radius: 6px;
  text-decoration: none;
  color: inherit;
  background: var(--tg-surface);
}

.tg-figures a:hover,
.tg-figures a:focus-visible { border-color: var(--tg-accent); }

.tg-figures strong {
  display: block;
  font-size: 1.35rem;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;   /* so 37 and 115,989 share a baseline grid */
  color: var(--tg-accent);
}

.tg-figures span {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--tg-muted);
}

/* The four stages, in order. Numbered because the order is the whole point: run
   tg-construct before the others and it has nothing to assemble. The counter is
   the list's own, not the marker, so the number can sit in the border. */
.tg-pipeline {
  list-style: none;
  counter-reset: tg-stage;
  margin: 1.5rem 0;
  padding: 0;
}

.tg-pipeline li {
  counter-increment: tg-stage;
  position: relative;
  padding: 0.55rem 0 0.55rem 2.5rem;
  border-left: 2px solid var(--tg-border);
}

.tg-pipeline li::before {
  content: counter(tg-stage);
  position: absolute;
  left: -0.85rem;
  top: 0.55rem;
  width: 1.6rem;
  height: 1.6rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--tg-accent);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.tg-pipeline span,
.tg-steps span {
  display: block;
  margin-top: 0.15rem;
  color: var(--tg-muted);
  font-size: 0.95rem;
}

/* The three steps a newcomer takes. Same idea as the pipeline and a different
   shape on purpose: the pipeline describes what the software does in an order
   fixed by the tools, this is advice about what to read, and a reader should
   not have to work out which kind of list they are looking at. */
.tg-steps {
  list-style: none;
  counter-reset: tg-step;
  margin: 1.5rem 0;
  padding: 0;
  display: grid;
  gap: 0.75rem;
}

.tg-steps li {
  counter-increment: tg-step;
  padding: 0.9rem 1rem;
  border: 1px solid var(--tg-border);
  border-radius: 6px;
}

.tg-steps li::before {
  content: "Step " counter(tg-step);
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--tg-muted);
}

/* --- Footer navigation ----------------------------------------------------
   Four columns of links under the content. The navigation bar carries seven
   items and wraps at eight, so this is where the other twenty pages become
   reachable without reading the prose that happens to mention them.

   Grid rather than flex: the columns hold different numbers of links and the
   headings have to line up across them, which is a row alignment problem and
   not a wrapping one. auto-fit collapses four to two to one without a
   breakpoint of its own. */
/* GeneratePress puts the footer inside a flex row as `flex: 0 1 auto`, so the
   bar sizes to its content: 624px of a 1200px container, which was right for
   one line of copyright and leaves four columns nowhere to go. They collapsed
   to three and the fourth wrapped underneath, which is the same ragged shape
   the gallery had before it went to four images. */
.copyright-bar { flex: 1 1 100%; }

/* The footer is dark, so it reads as the end of the page rather than more of
   it. Every colour below was measured against the #14181f ground rather than
   picked by eye, because inverting a palette is where contrast quietly fails:
   the muted grey that is correct on white is 2.4:1 on this, and the link blue
   the rest of the site uses is worse. Headings 6.8:1, links 8.4:1, colophon
   11.1:1, all above the 4.5:1 the rest of this site is held to. */
.site-footer,
.site-footer .site-info,
.site-footer .copyright-bar,
.site-footer .inside-site-info {
  background-color: #14181f;
  color: #c3cdd9;
}

/* .site-info is the one that had to be named. .site-footer was already dark and
   already spanned the viewport, but GeneratePress paints .site-info white
   inside it, and .site-info is full width while the container it holds stops at
   1200px. The dark only reached as far as that container, so the footer sat in
   a white frame that grew wider the wider the window got. */

.site-footer .tg-footer-col h2 { color: #93a1b1; }
.site-footer .tg-footer-col a,
.site-footer .tg-colophon a { color: #8ab4f8; }
.site-footer .tg-colophon,
.site-footer .tg-colophon p { color: #c3cdd9; }

/* The rule between the links and the colophon. A divider is not text, so it is
   judged on being visible rather than on 4.5:1; the border token from the light
   palette is invisible here. */
.site-footer .tg-footer-nav { border-bottom-color: rgba(255, 255, 255, 0.14); }

.tg-footer-nav {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1.5rem 2rem;
  margin-bottom: 1.75rem;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--tg-border);
  text-align: left;
}

.tg-footer-col h2 {
  margin: 0 0 0.5rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--tg-muted);
}

.tg-footer-col ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.tg-footer-col li { margin-bottom: 0.3rem; }

.tg-footer-col a {
  font-size: 0.9rem;
  line-height: 1.5;
  text-decoration: none;
}

.tg-footer-col a:hover,
.tg-footer-col a:focus-visible { text-decoration: underline; }

/* The colophon is attribution, not navigation, and reads as a note rather than
   a fifth column. Left with the columns above it so the footer has one edge. */
.tg-colophon { text-align: left; }

