/* ==========================================================================
   SEQUIcompany — design system
   Art direction: "Two Registers" (warm editorial layer for services,
   dark technical layer for software) executed with editorial restraint.
   No framework. No build step. No third-party CSS.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Reset (minimal, intentional)
   -------------------------------------------------------------------------- */

*, *::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 {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ul, ol {
  margin: 0;
  padding: 0;
}

ul[class], ol[class], nav ul, footer ul, .navdrawer ul, .footgrid ul { list-style: none; }

img, svg, video { display: block; max-width: 100%; height: auto; }

input, button, textarea, select { font: inherit; color: inherit; }

/* --------------------------------------------------------------------------
   2. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Palette — sampled from the logo itself (see tools/build_images.py and
     assets/img/logo-master.png). Deep navy lettering on warm bone, with the
     logo's lighter steel-blue as the single accent. No third colour: the
     restraint is the identity. */
  --ink:            #122438;  /* the logo's navy — body text */
  --ink-soft:       #3E5470;
  --muted:          #6E8098;
  --paper:          #F7F4EE;  /* lifted slightly from the logo bone for screen */
  --paper-deep:     #E9E5DC;  /* the logo's exact background */
  --paper-card:     #FCFAF6;

  --brand:          #2B435A;  /* the logo's mid slate — rules, links, accents */
  --brand-ink:      #16273A;
  --steel:          #58728A;  /* the logo's lighter blue — secondary accent */

  --line:           #DAD4C7;
  --line-strong:    #C2C2BC;

  /* Dark register */
  --dark:           #0B1520;
  --dark-raised:    #122438;
  --dark-line:      #24374B;
  --dark-text:      #EDEAE2;
  --dark-muted:     #93A0AE;
  --dark-accent:    #8FAECB;

  /* Type */
  --font-display: "Source Serif 4", Georgia, "Times New Roman", serif;
  --font-text:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Fluid type scale */
  --step--1: clamp(0.84rem, 0.80rem + 0.18 * var(--vu), 0.94rem);
  --step-0:  clamp(1.00rem, 0.95rem + 0.25 * var(--vu), 1.12rem);
  --step-1:  clamp(1.20rem, 1.11rem + 0.45 * var(--vu), 1.42rem);
  --step-2:  clamp(1.45rem, 1.29rem + 0.80 * var(--vu), 1.90rem);
  --step-3:  clamp(1.75rem, 1.48rem + 1.35 * var(--vu), 2.55rem);
  --step-4:  clamp(2.10rem, 1.62rem + 2.40 * var(--vu), 3.50rem);
  --step-5:  clamp(2.50rem, 1.72rem + 3.90 * var(--vu), 4.75rem);
  --step-6:  clamp(3.00rem, 1.70rem + 6.50 * var(--vu), 6.50rem);

  /* Space */
  --gutter:   clamp(1.15rem, 0.6rem + 2.2 * var(--vu), 3rem);
  --section-y: clamp(3.5rem, 2rem + 6 * var(--vu), 7.5rem);
  --measure:  64ch;
  /* The page is 1000px wide and stops there. Up to that point it widens with
     the window; past it the text stays where it is, the nav stays at its
     maximum, and the only thing that grows is background. A real page. */
  --page-w:   1000px;
  /* One viewport-scaled unit, and it stops at the page. Everything fluid on
     the site -- the type scale, the gutters, the section rhythm, the seal --
     is expressed in --vu instead of vw, so the page grows with the window
     exactly until it reaches --page-w (where 1vw == 10px) and then holds
     still: past that point the text is fixed and only background is added. */
  --vu:       min(1vw, calc(var(--page-w) / 100));
  --spine-w:  0rem;
}

@media (min-width: 1080px) {
  :root { --spine-w: 5rem; }
}

/* --------------------------------------------------------------------------
   3. Base typography
   -------------------------------------------------------------------------- */

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--step-0);
  line-height: 1.65;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.018em;
  text-wrap: balance;
}

h1 { font-size: var(--step-6); font-weight: 500; letter-spacing: -0.028em; }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-2); line-height: 1.2; }
h4 { font-size: var(--step-1); line-height: 1.3; }

p { text-wrap: pretty; }

a { color: var(--brand-ink); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 1px;
}

/* A single, disciplined eyebrow: monospace, small, letterspaced.
   Used once per section — never stacked above every heading. */
.eyebrow {
  font-family: var(--font-text);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
}

.lead {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.42;
  font-weight: 400;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}

.prose { max-width: var(--measure); }
.prose p + p { margin-top: 1.1em; }
.prose h2 { margin-top: 2.2em; margin-bottom: 0.6em; }
.prose h3 { margin-top: 1.8em; margin-bottom: 0.5em; }
.prose ul, .prose ol { margin: 1.1em 0 1.1em 1.15em; }
.prose li + li { margin-top: 0.45em; }

/* --------------------------------------------------------------------------
   4. Layout
   -------------------------------------------------------------------------- */

.shell {
  margin-left: var(--spine-w);
  padding-inline: var(--gutter);
  /* The spine eats into the viewport, so the cap has to account for it --
     otherwise margin-left + max-width overflow the page and the right edge
     of the nav gets clipped. */
  max-width: min(var(--page-w), calc(100% - var(--spine-w)));
  width: 100%;
}

/* The header bar and the mobile drawer carry this class as well. They get the
   same page as the text, never a wider one of their own: the nav stays inside
   the page, so enlarging the window adds background around it and nothing
   else -- no stretched row, no items drifting away from the wordmark. */
.shell--wide { max-width: min(var(--page-w), calc(100% - var(--spine-w))); }

.band {
  padding-block: var(--section-y);
  background: var(--paper);
  color: var(--ink);
}

.band--tight { padding-block: clamp(2.5rem, 1.5rem + 3.5 * var(--vu), 4.5rem); }

/* A band that ends on its heading is a band waiting for what comes next: the
   heading's own margin is the whole gap, and the band boundary must not add two
   more paddings on top of it. This is the spacing the Open source page gets by
   keeping its heading and its text in one band, made the rule everywhere -- so
   the air after a tagline is the same on every page.

   With the padding gone the heading's margin collapses out of the band, so what
   shows in the gap is the page background; a band that follows on a different
   background still shows its own colour change, just without the double air. */
.band:has(> .shell > .sechead:last-child) { padding-bottom: 0; }
.band:has(> .shell > .sechead:last-child) + .band { padding-top: 0; }

/* Same idea on the front page: the hero already ends with air of its own. */
.hero + .band { padding-top: 0; }

/* THE register inversion. Deliberate, once per page: the site steps from
   the warm editorial layer into the dark technical layer. */
.band--dark {
  background: var(--dark);
  color: var(--dark-text);
  --line: var(--dark-line);
  --muted: var(--dark-muted);
  --ink: var(--dark-text);
  --brand-ink: var(--dark-accent);
}
.band--dark h1, .band--dark h2, .band--dark h3, .band--dark h4 { color: var(--dark-text); }
.band--dark a { color: var(--dark-accent); }
.band--dark a:hover { color: #fff; }
.band--dark .eyebrow { color: var(--dark-muted); }

.band--deep { background: var(--paper-deep); }
.band--raised { background: var(--paper-card); }

.rule { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* Two-column editorial split: label rail + content. */
.split {
  display: grid;
  gap: clamp(1.25rem, 0.5rem + 3 * var(--vu), 4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .split { grid-template-columns: minmax(0, 20%) minmax(0, 1fr); }
}

.grid {
  display: grid;
  gap: clamp(1.25rem, 0.6rem + 2 * var(--vu), 2.5rem);
  grid-template-columns: 1fr;
}
@media (min-width: 720px) { .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 960px) { .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* --------------------------------------------------------------------------
   5. The spine — persistent monospace rail
   -------------------------------------------------------------------------- */

.spine {
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--spine-w);
  border-inline-end: 1px solid var(--line);
  display: none;
  z-index: 20;
  background: var(--paper);
}

@media (min-width: 1080px) { .spine { display: block; } }

.spine__inner {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-block: 1.75rem;
}

.spine__label {
  font-family: var(--font-text);
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  writing-mode: vertical-rl;
  transform: rotate(180deg);
}

/* --------------------------------------------------------------------------
   6. Header / navigation
   -------------------------------------------------------------------------- */

.site-header {
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  background: var(--paper);
  position: sticky;
  top: 0;
  z-index: 30;
  backdrop-filter: saturate(1.4) blur(8px);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4.25rem;
}

/* The wordmark is written `sequicompany`: lowercase, unspaced, one word.
   In running text the company is "Sequi Company", but as a brand it is the
   attached lowercase form -- so the header and footer carry that, not a
   two-line lockup. Set in the display serif so it reads as a logotype and
   stays crisp at any zoom, instead of shipping the wordmark as a raster. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}

.brand__mark {
  width: 2.35rem;
  height: auto;
  flex: none;
}

/* Sans, not the serif: the wordmark is a logotype, and the serif is reserved
   for headings. Inter at a heavier weight, tightened. */
.brand__word {
  font-family: var(--font-text);
  font-weight: 600;
  font-size: 1.36rem;
  letter-spacing: -0.005em;
  line-height: 1;
}

.nav { display: none; }
@media (min-width: 900px) {
  .nav { display: block; }
  /* The flex belongs on the list, not on <nav>: <nav> now wraps a single <ul>,
     so putting the flex on the wrapper stacks the items vertically.
     Baseline, not centre: the language picker is set smaller than the links, so
     centring the boxes leaves its type sitting visibly high. Baselines are what
     the eye actually reads mixed sizes against. */
  .nav > ul { display: flex; align-items: baseline; gap: 1.65rem; }
}

.nav a {
  font-family: var(--font-text);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  padding-block: 0.35rem;
  border-bottom: 1px solid transparent;
}
.nav a:hover { color: var(--ink); border-bottom-color: var(--brand); }
.nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }

.langpick {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-text);
  font-size: 0.76rem;
  letter-spacing: 0.06em;
}
.langpick a { color: var(--muted); text-decoration: none; padding: 0 0.3rem; }
.langpick a:hover { color: var(--ink); }
.langpick a[aria-current="true"] { color: var(--ink); font-weight: 700; }
.langpick .sep { color: var(--line-strong); }

.navtoggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  padding: 0.45rem 0.7rem;
  font-family: var(--font-text);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
}
@media (min-width: 900px) { .navtoggle { display: none; } }

/* Mobile drawer */
.navdrawer {
  display: none;
  border-top: 1px solid var(--line);
  padding-block: 1rem 1.5rem;
}
.navdrawer[data-open="true"] { display: block; }
.navdrawer ul { list-style: none; }
.navdrawer li + li { border-top: 1px solid var(--line); }
.navdrawer a {
  display: block;
  padding-block: 0.85rem;
  font-family: var(--font-text);
  font-size: 1.05rem;
  color: var(--ink);
  text-decoration: none;
}
@media (min-width: 900px) { .navdrawer { display: none !important; } }

/* --------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */

.hero { padding-block: clamp(3rem, 2rem + 5 * var(--vu), 6.5rem) clamp(2.5rem, 1.5rem + 4 * var(--vu), 5rem); }

.hero__kicker {
  font-family: var(--font-text);
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(1.5rem, 1rem + 2 * var(--vu), 2.75rem);
  display: block;
}

.hero h1 { max-width: 20ch; }

/* The seal is stamped INTO the page, with the headline printed over it: the
   ink multiplies into the paper, the type sits on top and stays the thing you
   read first. It never disappears -- at every width it keeps a size worth
   looking at and only moves to where the text leaves it room: beside the
   headline on wide screens, behind it on a phone. */
.hero .shell { position: relative; }

.hero__lower { margin-top: clamp(1.35rem, 1rem + 1.6 * var(--vu), 2.25rem); }

.hero__kicker,
.hero h1,
.hero__copy {
  position: relative;
  z-index: 1;
}

.hero__emblem {
  position: absolute;
  z-index: 0;
  pointer-events: none;
  top: 4.5rem;
  left: 50%;
  width: min(80 * var(--vu), 22rem);
  transform: translateX(-50%) rotate(-6deg);
  opacity: 0.2;
}

.hero__emblem img {
  width: 100%;
  height: auto;
  mix-blend-mode: multiply;
}

/* Tablet: the headline still runs wide, so the seal moves off to the right
   edge and stops sitting under the middle of the text. */
@media (min-width: 620px) {
  .hero__emblem {
    top: 3rem;
    left: auto;
    right: 0;
    width: clamp(15rem, 40 * var(--vu), 21rem);
    transform: rotate(-6deg);
    opacity: 0.26;
  }
}

/* Desktop: the text column is capped, so the seal takes the slack beside it
   at full size and the headline overlaps only its left edge. */
@media (min-width: 900px) {
  .hero__emblem {
    top: 0.5rem;
    right: calc(var(--gutter) + 9rem);
    width: clamp(19rem, 30 * var(--vu), 29rem);
    opacity: 0.3;
  }
  .hero__copy { max-width: 54ch; }
}

/* The wide-screen placement belongs to the page, not to the window: the seal
   takes its final size and position at exactly --page-w, the point where the
   page stops widening. Any breakpoint further out (this one used to be 1340px)
   would move the watermark on a page that is standing still -- it would walk as
   the window grows. Media queries cannot read a custom property, so the number
   here has to be kept in step with --page-w by hand. */
@media (min-width: 1000px) {
  .hero__emblem {
    top: -0.5rem;
    right: calc(var(--gutter) + 6rem);
    width: clamp(24rem, 32 * var(--vu), 34rem);
  }
}

.hero__sub {
  margin-top: 0;
  max-width: 56ch;
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--ink-soft);
}

.hero__cta {
  margin-top: clamp(1.75rem, 1.25rem + 1.6 * var(--vu), 2.75rem);
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* --------------------------------------------------------------------------
   8. Section header
   -------------------------------------------------------------------------- */

.sechead { margin-bottom: clamp(2rem, 1.5rem + 2.5 * var(--vu), 3.5rem); }

/* The seal on an inner page, treated exactly as it is in the hero: stamped
   into the paper with the title printed over it, rather than parked in a
   reserved column to the right. It keeps its size at every width instead of
   being dropped on narrow screens -- the type simply passes over it. */
.sechead--with-emblem { position: relative; }
.sechead--with-emblem > :not(.sechead__emblem) { position: relative; z-index: 1; }

.sechead__emblem {
  position: absolute;
  z-index: 0;
  pointer-events: none;
  top: -1.25rem;
  right: -1rem;
  width: clamp(10rem, 34 * var(--vu), 15rem);
  height: auto;
  opacity: 0.22;
  mix-blend-mode: multiply;
  transform: rotate(-6deg);
}

@media (min-width: 1000px) {
  .sechead__emblem {
    top: -2rem;
    right: 6%;
    width: clamp(15rem, 22 * var(--vu), 19rem);
    opacity: 0.26;
  }
}
.sechead h2 { max-width: 22ch; margin-top: 0.9rem; }
.sechead p {
  margin-top: 1.1rem;
  max-width: 58ch;
  color: var(--ink-soft);
}

/* --------------------------------------------------------------------------
   9. Service cards — container-query driven, no shadows, hairline rules
   -------------------------------------------------------------------------- */

.cards { display: grid; gap: 1px; background: var(--line); border-block: 1px solid var(--line); }
@media (min-width: 760px) { .cards { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1120px) { .cards { grid-template-columns: 1fr 1fr 1fr; } }

/* An area with four services reads better as 2x2 than as 3+1, which leaves an
   orphan card and a hole beside it. */
@media (min-width: 760px) { .cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1120px) { .cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.card {
  container-type: inline-size;
  background: var(--paper);
  padding: clamp(1.4rem, 1rem + 1.6 * var(--vu), 2.25rem);
  position: relative;
  transition: background-color 180ms ease;
}
.card::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 2px;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 260ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.card:hover::before { transform: scaleX(1); }
.card:hover { background: var(--paper-card); }

.card__no {
  font-family: var(--font-text);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  color: var(--muted);
}
.card h3 { margin: 0.85rem 0 0.7rem; font-size: var(--step-1); }
.card p { color: var(--ink-soft); font-size: var(--step--1); line-height: 1.6; }

@container (min-width: 22rem) {
  .card p { font-size: var(--step-0); }
}

/* Technical register cards (software half) */
.band--dark .cards { background: var(--dark-line); border-color: var(--dark-line); }
.band--dark .card { background: var(--dark); }
.band--dark .card:hover { background: var(--dark-raised); }
.band--dark .card p { color: var(--dark-muted); }
.band--dark .card h3 { font-family: var(--font-text); font-weight: 600; letter-spacing: -0.01em; }
.band--dark .card__no { color: var(--dark-accent); }

/* --------------------------------------------------------------------------
   10. Credentials / proof
   -------------------------------------------------------------------------- */

.creds { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (min-width: 760px) {
  .creds { grid-template-columns: repeat(2, 1fr); }
  /* An odd number of credentials would otherwise leave an empty cell, which is
     no reason to go and write another credential: the last one spans instead. */
  .creds > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}

.cred { background: var(--paper); padding: clamp(1.35rem, 1rem + 1.5 * var(--vu), 2rem); }
.cred dt {
  font-family: var(--font-text);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.7rem;
}
.cred dd { font-family: var(--font-display); font-size: var(--step-1); line-height: 1.35; }
.cred dd small { display: block; font-family: var(--font-text); font-size: var(--step--1); color: var(--ink-soft); margin-top: 0.5rem; line-height: 1.55; }

/* Credentials on the dark register: the one deliberate inversion on the home page. */
.band--dark .creds { background: var(--dark-line); border-color: var(--dark-line); }
.band--dark .cred { background: var(--dark-raised); }
.band--dark .cred dt { color: var(--dark-accent); }
.band--dark .cred dd { color: var(--dark-text); }
.band--dark .cred dd small { color: var(--dark-muted); }

/* --------------------------------------------------------------------------
   10b. Signals — one numbered statement, standing on its own
   -------------------------------------------------------------------------- */

/* A breather between two sections: a number, a line of display type, nothing
   else. The number is the link back to the full list on the company page, so
   it is set loud enough to be read as an index rather than decoration. */
.signal {
  margin: 0;
  display: grid;
  gap: clamp(0.9rem, 0.6rem + 1 * var(--vu), 1.35rem);
  justify-items: start;
}

.signal__text {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 400;
  line-height: 1.22;
  letter-spacing: -0.015em;
  max-width: 26ch;
  text-wrap: balance;
}

.signal__label {
  font-family: var(--font-text);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.signal__label a { color: inherit; text-underline-offset: 0.3em; }
.signal__label a:hover { color: var(--ink); }

/* A position: a claim you could disagree with, then the reasoning. The number
   is a hanging indent on wide screens so the claims line up as a column of
   argument, with the count running down the margin like a page reference. */
.credo { display: grid; gap: 0; }

.credo__item {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem 0;
  padding-block: clamp(1.6rem, 1.2rem + 1.6 * var(--vu), 2.6rem);
  border-bottom: 1px solid var(--line);
}
.credo__item:first-child { border-top: 1px solid var(--line); }

@media (min-width: 760px) {
  .credo__item {
    grid-template-columns: 4.5rem minmax(0, 1fr);
    column-gap: clamp(1.5rem, 3 * var(--vu), 3rem);
  }
}

.credo__no {
  font-family: var(--font-text);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  color: var(--muted);
  line-height: 1;
  padding-top: 0.45rem;
}

.credo__item h3 {
  font-size: var(--step-2);
  line-height: 1.16;
  max-width: 24ch;
  text-wrap: balance;
}

.credo__item p {
  margin-top: 0.85rem;
  max-width: 62ch;
  color: var(--ink-soft);
  line-height: 1.62;
}

/* Every position is set the same. The order carries the emphasis: the first
   one is first, which is enough -- sizing it up made it read as a different
   kind of thing instead of as the opening argument. */

/* The full set, one line each. Hairline rules and nothing else. */
.signals {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0;
  grid-template-columns: 1fr;
  border-top: 1px solid var(--line);
}
@media (min-width: 860px) {
  .signals { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(2rem, 5 * var(--vu), 4.5rem); }
}

.signals li {
  padding-block: clamp(0.9rem, 0.7rem + 0.6 * var(--vu), 1.3rem);
  border-bottom: 1px solid var(--line);
}

.signals li p {
  margin: 0;
  max-width: 40ch;
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.3;
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   10c. Public repositories — links, and what GitHub says about them
   -------------------------------------------------------------------------- */

/* The list is written into the HTML and rewritten in the browser from GitHub's
   public API, so the markup has to hold under both: a link, an optional line of
   small print, an optional aside, and no assumption about how many there are. */
/* The link that stands in for the list when the fetch never happens. */
.repos__fallback {
  max-width: 62ch;
  color: var(--ink-soft);
}

.repos__list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}

.repos__list li {
  padding-block: clamp(1.1rem, 0.9rem + 1 * var(--vu), 1.75rem);
  border-bottom: 1px solid var(--line);
}

.repos__list a {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.2;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.repos__list a:hover { border-bottom-color: var(--brand); }

.repos__list p {
  margin-top: 0.55rem;
  max-width: 62ch;
  color: var(--ink-soft);
}

/* The facts GitHub knows: licence, when it was last pushed, stars if any. */
.repos__list .repos__meta {
  display: block;
  margin-top: 0.5rem;
  font-family: var(--font-text);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

/* A fork, or something archived: said plainly, not hidden. */
.repos__list .repos__note {
  margin-top: 0.4rem;
  font-family: var(--font-text);
  font-size: var(--step--1);
  color: var(--muted);
}

.repos__stamp { margin-top: 1.5rem; }

/* --------------------------------------------------------------------------
   11. Buttons / links
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-text);
  font-size: 0.92rem;
  font-weight: 500;
  padding: 0.72rem 1.3rem;
  border: 1px solid var(--ink);
  border-radius: 2px;
  background: var(--ink);
  color: var(--paper);
  text-decoration: none;
  transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease;
}
.btn:hover { background: var(--brand); border-color: var(--brand); color: #fff; }

.btn--ghost { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn--ghost:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }

.band--dark .btn { background: var(--dark-text); color: var(--dark); border-color: var(--dark-text); }
.band--dark .btn:hover { background: var(--dark-accent); border-color: var(--dark-accent); color: var(--dark); }
.band--dark .btn--ghost { background: transparent; color: var(--dark-text); border-color: var(--dark-line); }
.band--dark .btn--ghost:hover { background: var(--dark-text); color: var(--dark); }

.arrowlink {
  font-family: var(--font-text);
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
}
.arrowlink::after { content: " →"; }

/* --------------------------------------------------------------------------
   12. Contact
   -------------------------------------------------------------------------- */

.contactgrid {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
@media (min-width: 760px) { .contactgrid { grid-template-columns: repeat(3, 1fr); } }
.contactgrid > div { background: var(--paper); padding: clamp(1.35rem, 1rem + 1.5 * var(--vu), 2rem); }
.contactgrid dt {
  font-family: var(--font-text);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.6rem;
}
.contactgrid dd { font-size: var(--step-0); }
.band--dark .contactgrid { background: var(--dark-line); border-color: var(--dark-line); }
.band--dark .contactgrid > div { background: var(--dark); }

/* The old practice name, mentioned once and never advertised. */
.footnote {
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--dark-line);
  max-width: 38ch;
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--dark-muted);
}
.footnote strong { color: var(--dark-text); font-weight: 500; }

/* --------------------------------------------------------------------------
   14. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--dark);
  color: var(--dark-muted);
  padding-block: clamp(2.5rem, 2rem + 2 * var(--vu), 4rem) 2rem;
  font-size: var(--step--1);
}
.site-footer a { color: var(--dark-text); text-decoration: none; }
.site-footer a:hover { color: var(--dark-accent); }

.footgrid {
  display: grid;
  gap: 2rem;
  grid-template-columns: 1fr;
}
@media (min-width: 760px) { .footgrid { grid-template-columns: 2fr 1fr 1fr; } }

.footgrid h3 {
  font-family: var(--font-text);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dark-muted);
  margin-bottom: 0.9rem;
}
.footgrid ul { list-style: none; }
.footgrid li + li { margin-top: 0.5rem; }

.footbrand {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
}
.footbrand img { width: 2.6rem; height: auto; }
.footbrand .brand__word { color: var(--dark-text); font-size: 1.28rem; }

.footlegal {
  margin-top: 3rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--dark-line);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  font-family: var(--font-text);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: var(--dark-muted);
}

/* --------------------------------------------------------------------------
   15. Cookie banner — first-party, no trackers behind it by default
   -------------------------------------------------------------------------- */

.cookiebar {
  position: fixed;
  inset-inline: var(--spine-w) 0;
  bottom: 0;
  z-index: 50;
  background: var(--dark);
  color: var(--dark-text);
  border-top: 1px solid var(--dark-line);
  padding: 1rem var(--gutter);
  display: none;
}
.cookiebar[data-visible="true"] { display: block; }

/* A fixed bar at the bottom hides whatever is under it. Rather than let it
   cover the last section, reserve the space while a bar is on screen. */
body.has-banner { padding-bottom: 7.5rem; }
.cookiebar__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.9rem 1.5rem;
  max-width: var(--page-w);
}
.cookiebar p { font-size: var(--step--1); max-width: 60ch; color: var(--dark-muted); }
.cookiebar p a { color: var(--dark-text); }
.cookiebar__actions { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.cookiebar button {
  font-family: var(--font-text);
  font-size: 0.86rem;
  font-weight: 500;
  padding: 0.55rem 1.1rem;
  border-radius: 2px;
  border: 1px solid var(--dark-line);
  background: transparent;
  color: var(--dark-text);
  cursor: pointer;
}
.cookiebar button[data-choice="accept"] {
  background: var(--dark-text);
  color: var(--dark);
  border-color: var(--dark-text);
}
.cookiebar button:hover { border-color: var(--dark-accent); color: var(--dark-accent); }
.cookiebar button[data-choice="accept"]:hover { background: var(--dark-accent); border-color: var(--dark-accent); color: var(--dark); }

/* --------------------------------------------------------------------------
   15b. Language suggestion — offers, never redirects
   -------------------------------------------------------------------------- */

.langsuggest {
  position: fixed;
  inset-inline: var(--spine-w) 0;
  bottom: 0;
  z-index: 55;
  background: var(--paper-card);
  border-top: 1px solid var(--line-strong);
  padding: 0.85rem var(--gutter);
}
.langsuggest[data-hidden="true"] { display: none; }
.langsuggest__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  max-width: var(--page-w);
}
.langsuggest p { font-family: var(--font-text); font-size: var(--step--1); color: var(--ink-soft); }
.langsuggest__actions { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.langsuggest__go {
  font-family: var(--font-text);
  font-size: 0.88rem;
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.langsuggest button {
  background: none;
  border: 0;
  padding: 0;
  font-family: var(--font-text);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  cursor: pointer;
  border-bottom: 1px solid transparent;
}
.langsuggest button:hover { color: var(--ink); border-bottom-color: var(--line-strong); }

/* --------------------------------------------------------------------------
   16. Motion — progressive enhancement only
   -------------------------------------------------------------------------- */

.reveal { opacity: 1; transform: none; }

html.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 620ms cubic-bezier(0.2, 0.7, 0.3, 1),
              transform 620ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
html.js .reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.js .reveal { opacity: 1; transform: none; transition: none; }
}

/* --------------------------------------------------------------------------
   17. Small print / utilities
   -------------------------------------------------------------------------- */

.prose--legal { font-size: var(--step--1); line-height: 1.7; }
.prose--legal h2 { font-size: var(--step-2); }
.prose--legal h3 { font-size: var(--step-1); }

/* Cookie names and identifiers, quoted exactly as they appear on the wire. */
.prose code {
  font-family: var(--font-text);
  font-size: 0.92em;
  background: var(--paper-deep);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 0.06em 0.34em;
}
.band--dark .prose code { background: var(--dark-raised); border-color: var(--dark-line); }

.updated {
  font-family: var(--font-text);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.crumbs {
  font-family: var(--font-text);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--muted);
  padding-block: 1.25rem 0;
}
.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--ink); }
.crumbs span[aria-hidden] { padding-inline: 0.45rem; color: var(--line-strong); }

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--ink);
  color: var(--paper);
  padding: 0.75rem 1.25rem;
  z-index: 100;
  font-family: var(--font-text);
  font-size: 0.9rem;
}
.skip:focus { left: 0; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.notfound { padding-block: clamp(4rem, 3rem + 6 * var(--vu), 9rem); }
.notfound h1 { font-size: var(--step-5); }

/* --------------------------------------------------------------------------
   18. Print
   -------------------------------------------------------------------------- */

@media print {
  .site-header, .spine, .cookiebar, .navdrawer { display: none !important; }
  .shell { margin-left: 0; }
  body { background: #fff; color: #000; }
  a { color: #000; text-decoration: underline; }
}
