/* ==========================================================
   agentcontextsystems.com, the shared stylesheet.

   EXTRACTED FROM THE HUB'S <style> BLOCK, 2026-08-20, when the site went from
   one page to four. The Keyline page's original convention was that every page
   is fully self-contained. That was right for one page and is wrong for four:
   the accent is about to change, and a shared file makes that one edit instead
   of four. It also puts a Content Security Policy back within reach, which
   inline styles had ruled out.

   Load order on every page:
     <link rel="stylesheet" href="/assets/site.css">
     ... page content ...
     <script src="/assets/site.js"></script>

   ========================================================== */

/* ==========================================================
   AGENT CONTEXT SYSTEMS, the hub.

   This page sets the visual language every other page inherits.
   The design contract is WEBSITE-BRIEF.md section 12, "The Anatomy".

   PALETTE. Every value below was re-derived with a WCAG relative
   luminance script at build time, not copied on trust and not chosen by
   eye. Ratios are quoted against the TIGHTEST of the four grounds in
   each theme, so the quoted number is the worst case, not the flattering
   one.

   Dark, on --raised #1d2025          Light, on --well #eef1f4
     primary    13.79  AAA              primary     15.86  AAA
     strong     10.33  AAA              strong      11.58  AAA
     secondary   7.23  AAA              secondary    6.97  AAA
     muted       4.69  AA               muted        5.04  AA
     accent      9.06  AAA              accent ink   4.62  AA
     border      3.08  AA (UI)          border       3.07  AA (UI)

   THREE FINDINGS THAT ARE NOT NEGOTIABLE.

   1. White on amber measures 1.80 and fails outright. Every amber fill
      takes ink text: 10.47 dark, 9.97 light. Do not "fix" the contrast
      of a button by making its label white.
   2. The bright amber cannot be text in light mode. #ffb224 on the light
      ground measures 1.76. Light mode uses the derived #966100 for links
      and accent text while fills stay bright. That is why there are two
      accent tokens rather than one.
   3. The light accent measures 4.24 under deuteranopia, just under AA.
      Links are underlined here for that reason. Do not remove the
      underline later to tidy the design up.
      NOT RE-DERIVED: the deuteranopia figures are carried from the
      design pass. The WCAG figures above were re-computed here.

   THE FIVE PART HUES are for diagram contexts only. Page chrome stays
   amber plus neutrals, or the palette turns carnival. Worst pair
   separation under deuteranopia is 1.02, which means a reader with the
   most common colour vision deficiency cannot tell two slats apart by
   colour at all. So every part always carries three other channels: a
   fixed position 1 to 5, its own glyph shape, and a text label. Never
   ship a part that is identified by colour alone.

   TYPE. Inter and JetBrains Mono, both SIL OFL 1.1, self hosted from
   /assets/fonts/ with the licence text sitting beside them. Google
   serves ONE variable woff2 per family covering the whole weight axis,
   so this ships two files (79.8KB total), not the four the brief
   budgeted for. Mono carries the technical voice only: diagram labels,
   eyebrows, status chips, file paths, the terminal, the wordmark. Prose
   never sets in mono.

   Note for whoever edits this: CSS comments cannot contain the sequence
   that closes them, and this file carries no em dashes anywhere in user
   facing copy, by house convention.
   ========================================================== */

@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/inter-var-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/assets/fonts/jetbrains-mono-var-latin.woff2') format('woff2');
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

/* ---------- tokens ----------
   DARK IS THE DEFAULT, and it is the bare :root block rather than a media
   query, so it holds even with no script and no data-theme attribute. Light is
   an explicit opt-in via the switch in the header, remembered in localStorage.

   This deliberately does not follow prefers-color-scheme. The owner asked for
   dark by default and the design was drawn for it; a visitor whose system is
   set to light gets dark until they say otherwise, and then their choice
   sticks. Reconsider if that ever feels wrong: it is one media query away from
   honouring the system preference as the initial value.
   ---------- */
:root {

  --well: #0a0b0d;
  --ground: #101114;
  --surface: #16181c;
  --raised: #1d2025;
  --hairline: #262a31;
  --rule: #343a42;
  --border: #646c78;
  --muted: #828a97;
  --secondary: #a6adb8;
  --strong: #c9ced6;
  --primary: #e9ecf1;
  --accent: #f5f7fa;
  --accent-ink: #ffffff;
  --on-accent: #0a0b0d;
  --glow: 0.05;

  --spot: #ffb224;
  --spot-fill: #ffb224;
  --on-spot: #101114;
  --spot-wash: rgba(255, 178, 36, 0.09);

  --card-fill: linear-gradient(180deg, #17191d, #0f1013);
  --card-glow: radial-gradient(30% 36% at 0% 60%, rgba(255, 255, 255, 0.055) 0, rgba(255, 255, 255, 0.02) 54%, transparent 100%);
  --card-hi: rgba(255, 255, 255, 0.26);

  /* The catalog column in the Use cases menu. It cannot use --card-fill, which
     is a RAISED card and only reads against a tinted ground. Inside that panel
     the ground is --raised itself, the lightest surface there is, so the column
     has to be RECESSED instead. Dark got away with --card-fill because the dark
     card happens to be darker than the panel; light did not, because the light
     card starts at #ffffff and the panel is #ffffff.
     Measured so both themes recess by the same amount: 1.08 at the top of the
     gradient and 1.17 at the bottom, against their own panel. */
  --menu-aside: radial-gradient(80% 62% at 100% 0%, rgba(255, 255, 255, 0.07) 0, transparent 70%),
    linear-gradient(180deg, #17191d, #0f1013);
  --menu-aside-hover: radial-gradient(80% 62% at 100% 0%, rgba(255, 255, 255, 0.12) 0, transparent 70%),
    linear-gradient(180deg, #17191d, #0f1013);

  --p-rules: #ffb224;
  --p-skills: #c49bff;
  --p-knowledge: #35d0ab;
  --p-scripts: #5ab8ff;
  --p-tests: #a3e635;

  --header-bg: rgba(16, 17, 20, 0.82);
  --shadow-panel: 0 12px 28px rgba(0, 0, 0, 0.5);

  /* Theme independent, and they live here for a reason. These were in the old
     light block, and when dark became the default they were briefly lost with
     it: with no --font-sans the entire site fell back to the browser's serif.
     Anything that is not a colour belongs in this block, never in a theme. */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --shell: 1120px;
  --header-h: 64px;
}

:root[data-theme='light'] {

  --well: #eef1f4;
  --ground: #fbfcfd;
  --surface: #f4f6f8;
  --raised: #ffffff;
  --hairline: #e3e7eb;
  --rule: #ccd2d9;
  --border: #828a96;
  --muted: #5f6773;
  --secondary: #4a525d;
  --strong: #2b3138;
  --primary: #14171b;
  --accent: #14171b;        /* fills: ink in light, near white in dark */
  --accent-ink: #14171b;    /* accent text and links */
  --on-accent: #ffffff;     /* the label sitting on a filled accent */
  --glow: 0;                /* the hero bloom is a dark theme device only */

  /* Card surfaces. The recipe is adapted from the technique Resend uses: a very
     low alpha white radial anchored at one edge, over a vertical fill, with a
     lit hairline along the top edge. In light mode a white glow is a smudge, so
     it becomes a plain surface and the highlight inverts to a faint ink line. */
  /* The one spot colour on an otherwise monochrome page, and it means exactly
     one thing: the human's part. It marks the verb you want in the headline and
     the thing the system never takes. Nothing else may use it. Two tokens
     because the bright amber measures 1.76 as text on the light ground. */
  --spot: #966100;
  --spot-fill: #ffb224;
  --on-spot: #14171b;
  --spot-wash: rgba(255, 178, 36, 0.10);

  --card-fill: linear-gradient(180deg, #ffffff, #f7f9fb);
  --card-glow: none;
  --card-hi: rgba(20, 23, 27, 0.10);

  /* No wash here, for the same reason --card-glow is none: a white bloom on a
     light surface is a smudge. The recess carries it on its own. */
  --menu-aside: linear-gradient(180deg, #f4f6f8, #eaeef2);
  --menu-aside-hover: linear-gradient(180deg, #eef1f4, #e6eaef);

  --p-rules: #966100;
  --p-skills: #8836ff;
  --p-knowledge: #1c7a64;
  --p-scripts: #006ec2;
  --p-tests: #50770f;

  --header-bg: rgba(251, 252, 253, 0.82);
  --shadow-panel: 0 12px 28px rgba(20, 23, 27, 0.12);

}

/* ---------- base ---------- */
.acs-page,
.acs-page *,
.acs-page *::before,
.acs-page *::after { box-sizing: border-box; }

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

.acs-page {
  margin: 0;
  background: var(--ground);
  color: var(--primary);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.65;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* These are resets, so they are written at ZERO specificity with :where().
   Written as `.acs-page p` they outrank every component class that sets a
   margin, which silently swallowed the spacing on eyebrows, ledes, status
   lines and links. Caught by looking at a render. Keep the :where(). */
:where(.acs-page) h1,
:where(.acs-page) h2,
:where(.acs-page) h3 { line-height: 1.15; margin: 0; font-weight: 700; letter-spacing: -0.015em; }
:where(.acs-page) p { margin: 0; }
:where(.acs-page) ul,
:where(.acs-page) ol { margin: 0; padding: 0; list-style: none; }

:where(.acs-page) a { color: var(--accent-ink); }
.acs-page p a,
.acs-page li a.acs-inline { text-decoration: underline; text-underline-offset: 3px; }

.acs-page :focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
  border-radius: 2px;
}

.acs-mono {
  font-family: var(--font-mono);
  line-height: 1.5;
  font-feature-settings: 'liga' 0;
}

.acs-skip {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 20;
  background: var(--accent);
  color: var(--on-accent);
  padding: 10px 16px;
  border-radius: 6px;
  font: 600 15px/1 var(--font-sans);
  text-decoration: none;
}
.acs-skip:focus { left: 20px; }

.acs-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.acs-shell {
  width: 100%;
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 20px;
}
@media (min-width: 720px) {
  .acs-shell { padding: 0 32px; }
}

.acs-section { padding: 64px 0; }
.acs-section + .acs-section { border-top: 1px solid var(--hairline); }
@media (min-width: 960px) {
  .acs-section { padding: 96px 0; }
}
[id] { scroll-margin-top: 88px; }

/* These orient the reader at the top of every section, so they have to be
   readable. At --muted and 12px they measured fine (4.69 dark) and still read
   as barely there, because small uppercase mono with letter-spacing loses far
   more legibility than its contrast ratio suggests. A ratio is a floor, not a
   verdict. */
.acs-eyebrow {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--secondary);
  margin: 0 0 14px;
}

.acs-h2 { font-size: 32px; max-width: 28ch; }
@media (min-width: 720px) { .acs-h2 { font-size: 40px; } }

.acs-lede {
  font-size: 18px;
  color: var(--secondary);
  max-width: 62ch;
  margin-top: 20px;
}

.acs-note {
  font-size: 15px;
  color: var(--muted);
  max-width: 62ch;
}

/* Verification marks. The single best expression of the house rule that a
   limitation stated beats a finding asserted. Use them sparingly: three on
   a page is a discipline, ten is a tic. */
.acs-mark {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 2px 8px;
  white-space: normal;
  max-width: 68ch;
}

/* ---------- the five bar glyph, scale 3 ----------
   Five bars, five emphasis weights, no SVG per system. A card sets
   --w1 to --w5 inline and the mark redraws itself. In page chrome the
   bars are neutral; in diagram contexts they take the part hues. */
.acs-glyph {
  display: inline-grid;
  grid-template-columns: repeat(5, 2px);
  gap: 2px;
  align-items: end;
  height: 18px;
  flex: none;
}
.acs-glyph i {
  display: block;
  background: var(--strong);
  border-radius: 1px;
  min-height: 3px;
}
.acs-glyph i:nth-child(1) { height: calc(var(--w1, 0.6) * 100%); }
.acs-glyph i:nth-child(2) { height: calc(var(--w2, 0.6) * 100%); }
.acs-glyph i:nth-child(3) { height: calc(var(--w3, 0.6) * 100%); }
.acs-glyph i:nth-child(4) { height: calc(var(--w4, 0.6) * 100%); }
.acs-glyph i:nth-child(5) { height: calc(var(--w5, 0.6) * 100%); }
.acs-glyph--brand i { background: var(--accent-ink); }
.acs-glyph--hued i:nth-child(1) { background: var(--p-rules); }
.acs-glyph--hued i:nth-child(2) { background: var(--p-skills); }
.acs-glyph--hued i:nth-child(3) { background: var(--p-knowledge); }
.acs-glyph--hued i:nth-child(4) { background: var(--p-scripts); }
.acs-glyph--hued i:nth-child(5) { background: var(--p-tests); }

/* ---------- header and nav ---------- */
.acs-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--raised);
  border-bottom: 1px solid var(--hairline);
}
@supports ((backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px))) {
  .acs-header {
    background: var(--header-bg);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }
}
.acs-header__inner {
  min-height: var(--header-h);
  display: flex;
  align-items: center;
  gap: 16px;
  justify-content: space-between;
}

.acs-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--primary);
  flex: none;
}
.acs-brand__text {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.5;
}
.acs-brand__text b { font-weight: 600; color: var(--accent-ink); }

.acs-header__right { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* The switch. Shows the theme you would move to, which is the convention most
   people read correctly without a label. The label is there anyway. */
.acs-theme {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: transparent;
  color: var(--secondary);
  cursor: pointer;
}
.acs-theme:hover { color: var(--primary); border-color: var(--border); background: var(--surface); }
:root:not([data-theme='light']) .acs-theme__moon { display: none; }
:root[data-theme='light'] .acs-theme__sun { display: none; }

.acs-menu-btn {
  font: 500 13px/1 var(--font-mono);
  color: var(--primary);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 9px 12px;
  cursor: pointer;
}
.no-js .acs-menu-btn { display: none; }

.acs-nav__list { display: flex; align-items: center; gap: 4px; }
.acs-nav__group { position: relative; }

.acs-nav__trigger,
.acs-nav__link {
  font: 500 15px/1 var(--font-sans);
  color: var(--strong);
  background: transparent;
  border: 0;
  border-radius: 6px;
  padding: 10px 12px;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.acs-nav__trigger:hover,
.acs-nav__link:hover { color: var(--primary); background: var(--surface); }
.acs-nav__trigger::after {
  content: '';
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}

/* The panel sits 6px clear of the trigger, which left a dead strip the pointer
   had to cross to reach it. Crossing it dropped :hover on the group and the menu
   closed under the cursor. This bridges the gap with an invisible strip that is
   part of the panel, so the group stays hovered the whole way down.

   IT LIVES OUTSIDE THE PANEL'S BOX, at a negative top, so ANY `overflow` other
   than visible on the panel deletes it. That shipped: the wide panel carried
   `overflow: hidden` to keep the catalog column inside the rounded corners, which
   clipped this strip and nothing else, so the wide menu closed under the cursor
   while the narrow one beside it worked perfectly. The clipping now happens on
   the column itself, which is the element that actually needed it. Do not put
   `overflow` back on the panel. */
.acs-nav__panel::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: -10px;
  height: 10px;
}
.acs-nav__panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 268px;
  background: var(--raised);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 6px;
  box-shadow: var(--shadow-panel);
  display: none;
}
/* Opens on hover, on focus inside, and on an explicit toggle. The
   focus-within rule is what makes the menu keyboard reachable with no
   JavaScript at all: tab to the trigger, the panel appears, tab into it. */
.acs-nav__group:hover .acs-nav__panel,
.acs-nav__group:focus-within .acs-nav__panel,
.acs-nav__trigger[aria-expanded='true'] + .acs-nav__panel { display: block; }

.acs-nav__item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  justify-content: space-between;
  padding: 9px 10px;
  border-radius: 6px;
  font-size: 15px;
  text-decoration: none;
  color: var(--strong);
}
a.acs-nav__item:hover { background: var(--surface); color: var(--primary); }
.acs-nav__static { color: var(--muted); cursor: default; }
.acs-nav__static:hover { background: transparent; color: var(--muted); }
.acs-nav__item--off { color: var(--muted); }

/* ---------- the wide Use cases menu ----------
   Two columns: the use cases on the left, because that is how a visitor picks,
   and a way past them on the right for anyone who would rather see everything
   at once. */
.acs-nav__panel--wide { padding: 0; }
/* The show rules below set display:block at (0,3,0), which beat a plain
   .acs-nav__panel--wide and flattened the two columns into one. The grid has to
   be declared on the same selectors to win. */
/* The nav sits hard right now that the theme switch is beside it, so a panel
   anchored to the left edge of its trigger runs off the viewport. Anchoring to
   the right edge of the group keeps every panel on screen whatever its width. */
@media (min-width: 900px) {
  .acs-nav__panel { left: auto; right: 0; }
  .acs-nav__panel--wide { min-width: 620px; }
  .acs-nav__group:hover .acs-nav__panel--wide,
  .acs-nav__group:focus-within .acs-nav__panel--wide,
  .acs-nav__trigger[aria-expanded='true'] + .acs-nav__panel--wide {
    display: grid;
    grid-template-columns: 1fr 232px;
  }
}
.acs-nav__col { padding: 8px; }
/* The chips sat flush right, so their right edges lined up and their left edges
   were ragged: LIVE is about half the width of COMING SOON. A fixed column with
   the chip centred in it gives them one shared axis, and each pill keeps its
   natural width. */
.acs-nav__panel--wide .acs-nav__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 116px;
  align-items: center;
  gap: 10px;
}
.acs-nav__panel--wide .acs-nav__item .acs-chip { justify-self: center; }
.acs-nav__col--alt {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  justify-content: center;
  padding: 20px;
  background-image: var(--menu-aside);
  border-top: 1px solid var(--hairline);
  text-decoration: none;
}
.acs-nav__col--alt::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--card-hi) 40%, transparent);
  pointer-events: none;
}
@media (min-width: 900px) {
  .acs-nav__col--alt::before {
    top: 0;
    left: auto;
    right: 0;
    width: 1px;
    height: 100%;
    background: linear-gradient(180deg, var(--card-hi), transparent 60%);
  }
}
@media (min-width: 900px) {
  /* The column runs to three of the panel's inner edges, so it is the thing that
     has to respect the rounding. 9px, because the panel's 10px radius is measured
     outside a 1px border. Its own overflow clips its own highlight and nothing
     that belongs to the panel. */
  .acs-nav__col--alt {
    border-top: 0;
    border-left: 1px solid var(--hairline);
    border-radius: 0 9px 9px 0;
    overflow: hidden;
  }
}
.acs-nav__col--alt:hover { background-image: var(--menu-aside-hover); }
.acs-nav__colhead {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 8px 10px 6px;
}
.acs-nav__col--alt .acs-nav__colhead { padding: 0; color: var(--strong); }
.acs-nav__colnote { font-size: 13px; line-height: 1.45; color: var(--muted); }
.acs-nav__colgo { font-size: 14px; font-weight: 600; color: var(--primary); margin-top: 4px; }
.acs-nav__col--alt:hover .acs-nav__colgo { text-decoration: underline; text-underline-offset: 3px; }

.acs-chip {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 1px 7px;
  white-space: nowrap;
  flex: none;
}
.acs-chip--live { color: var(--accent-ink); border-color: var(--accent-ink); }

/* ---------- the menu on a phone ----------
   The desktop menu is three peers side by side, two of which open panels. Poured
   into one column that reads as a flat list with no hierarchy: the group heading
   and the panel's own column heading both showed, so "Use cases" was immediately
   followed by "Start by use case", and the single top level link in the middle
   looked like a third heading.

   So on a phone: one heading per group, items aligned to it, a rule between
   groups, and the catalog card demoted to an ordinary row. */
@media (max-width: 899px) {
  .acs-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--raised);
    border-bottom: 1px solid var(--rule);
    padding: 4px 20px 24px;
    display: none;
    /* On a short phone the menu can outgrow the screen, and it is positioned
       against a sticky header, so the page scrolling underneath does not bring
       the bottom of it into reach. It has to scroll itself. */
    max-height: calc(100vh - var(--header-h));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .acs-nav[data-open='true'] { display: block; }
  .no-js .acs-nav { display: block; position: static; border: 0; padding: 0 0 16px; }
  .acs-nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .acs-nav__trigger { display: none; }

  /* Use cases, What is a context system, and Getting started are three peers in
     the nav, so on a phone they get one styling. Two of them happen to open
     into children and one does not, and that difference is carried by the
     lighter rows underneath rather than by making the headings look unrelated.
     The panel's own column heading is a desktop device and stays hidden. */
  .acs-nav__grouplabel,
  .acs-nav__link,
  .acs-nav__static {
    display: block;
    font-family: var(--font-sans);
    font-size: 16px;
    font-weight: 600;
    letter-spacing: normal;
    text-transform: none;
    color: var(--primary);
  }
  .acs-nav__grouplabel { padding: 22px 0 8px; }
  .acs-nav__link,
  .acs-nav__static { padding: 22px 0; }
  .acs-nav__static { color: var(--muted); }
  .acs-nav__link:hover { background: transparent; }
  .acs-nav__colhead { display: none; }

  /* every top level entry is separated the same way, which is what says they
     are the same kind of thing */
  .acs-nav__list > li + li { border-top: 1px solid var(--hairline); }

  /* Children are indented from their heading. Weight alone was carrying the
     hierarchy and it was not enough: a bold row above a set of lighter rows
     still reads as a flat list until the left edge steps in. */
  .acs-nav__panel,
  .acs-nav__panel--wide {
    display: block;
    position: static;
    min-width: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0 0 0 16px;
    background: transparent;
    overflow: visible;
  }
  .acs-nav__panel::before { display: none; }
  .acs-nav__col { padding: 0; }

  /* every row sits on the same left edge as the heading above it */
  .acs-nav__item,
  .acs-nav__panel--wide .acs-nav__item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    padding: 14px 0;
    font-size: 16px;
    font-weight: 400;
    color: var(--secondary);
    border-radius: 0;
  }
  .acs-nav__panel--wide .acs-nav__item .acs-chip { justify-self: end; }
  a.acs-nav__item:hover { background: transparent; }

  /* the catalog panel is a card on a wide screen and a row here */
  /* separated from the use cases above it, because it is the way past them
     and not one more of them */
  .acs-nav__col--alt {
    display: block;
    margin-top: 8px;
    padding: 18px 0 14px;
    background: none;
    background-image: none;
    border: 0;
    border-top: 1px solid var(--hairline);
  }
  .acs-nav__col--alt::before { display: none; }
  .acs-nav__col--alt:hover { background-image: none; }
  .acs-nav__colnote { display: none; }
  .acs-nav__colgo { margin: 0; font-size: 16px; font-weight: 500; color: var(--secondary); }

}

@media (min-width: 900px) {
  .acs-menu-btn { display: none; }
  .acs-nav__grouplabel { display: none; }
}

/* ---------- buttons ---------- */
.acs-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font: 600 15px/1 var(--font-sans);
  padding: 14px 18px;
  border-radius: 8px;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
}
/* Amber fills take INK text. White on this amber measures 1.80 and fails,
   and so does the accent ink the generic link rule would otherwise apply:
   #966100 on #ffb224 is 2.05, and in dark mode it is amber on amber, which
   is invisible. Both were caught by looking at a render, not at the CSS.
   These selectors carry the .acs-page prefix to outrank `.acs-page a`. */
.acs-page .acs-btn--primary { background: var(--accent); color: var(--on-accent); }
.acs-page .acs-btn--primary:hover { opacity: 0.88; }
.acs-page .acs-btn--ghost { border-color: var(--border); color: var(--primary); background: transparent; }
.acs-page .acs-btn--ghost:hover { background: var(--surface); }

/* ---------- hero ---------- */
/* The hero is now one centred column and nothing else. The figure that used to
   sit beside it moved into its own card below, because at 45/55 the two halves
   were competing for the same glance and the whole thing read as clutter. */
.acs-hero { padding: 64px 0 40px; position: relative; text-align: center; }
.acs-hero::before {
  content: '';
  position: absolute;
  left: -10%;
  right: -10%;
  top: -180px;
  height: 700px;
  background: radial-gradient(42% 46% at 50% 48%, rgba(255, 255, 255, var(--glow)), transparent 72%);
  pointer-events: none;
}
.acs-hero > * { position: relative; }
@media (min-width: 960px) { .acs-hero { padding: 96px 0 48px; } }

.acs-hero__inner { max-width: 820px; }

/* Signal's emphasis device: the setup is dimmed and the payoff is left lit, so
   the bright half is the half that matters. The contrast between them IS the
   design. Do not brighten the dim half to "fix" it. */
.acs-hero h1 { color: var(--muted); }
.acs-hero h1 .acs-turn { color: var(--primary); }
/* Bounded in px rather than ch. The ch unit measures the "0" glyph, which in
   Inter is wider than this headline's average character, so a ch cap forces a
   line break earlier than the text actually needs. */
.acs-hero h1 {
  font-size: clamp(32px, 5.2vw, 54px);
  margin: 0 auto 24px;
  max-width: 800px;
  letter-spacing: -0.025em;
}
.acs-hero__def {
  font-size: 18px;
  color: var(--secondary);
  max-width: 58ch;
  margin: 0 auto;
}
@media (min-width: 720px) { .acs-hero__def { font-size: 19px; } }
.acs-hero__def b { color: var(--primary); font-weight: 600; }
.acs-hero__meta {
  margin-top: 24px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
  line-height: 1.5;
}
@media (max-width: 599px) { .acs-wide-only { display: none; } }

/* ---------- the rotating word ----------
   Words are stacked in one inline-grid cell so they overlap instead of
   reflowing, and only the container's width animates, which lets the centred
   line re-centre smoothly rather than jumping. Only one word is visible at a
   time, so the others overflowing the narrowed container costs nothing and
   saves clipping descenders.

   The whole thing is aria-hidden and a plain static word sits beside it in the
   accessibility tree, so a screen reader hears one clean sentence instead of a
   churn of verbs. */
/* Three states, and the CSS has to be correct in all of them without help:
   no script, script but motion reduced, and script with motion. So the default
   is plain inline text showing the first word, and the grid stacking only
   switches on when the script is actually about to rotate. Getting this the
   other way round left the headline with no verb at all under reduced motion,
   because the script returns before it ever reaches this.

   THE WORD OWNS ITS OWN LINE, and the slot sizes itself. Alone on a line, the
   grid's track is as wide as the longest word and every word is centred inside
   it, so each one lands centred on the line and the left edge never wanders.

   Three earlier attempts got this wrong in three different ways. Animating the
   slot per word let a long word push a shared line past its measure and add a
   line. Freezing it at the widest word while it shared a line left a gap after
   every short one. Animating it on its own line meant the new word was centred
   inside a slot still transitioning from the previous word's width, which is
   what made the start position appear to wander. Setting no width at all is
   both the simplest and the only correct one. Do not reintroduce a width. */
.acs-rot { display: inline; color: var(--spot); }
.acs-rot > span:not(:first-child) { display: none; }

.acs-rot.is-live {
  display: inline-grid;
  vertical-align: baseline;
}
.acs-rot.is-live > span {
  display: block;
  grid-area: 1 / 1;
  justify-self: center;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(0.28em);
  transition: opacity 300ms ease, transform 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.acs-rot.is-live > span.is-on { opacity: 1; transform: none; }

/* Forced breaks so the headline is three lines by design rather than by luck.
   A forced break only ADDS one, so a narrower viewport still wraps normally,
   and below 860px they are switched off entirely. */
.acs-br { display: none; }
@media (min-width: 860px) { .acs-br { display: inline; } }

/* ---------- the card: the page's one piece of furniture ---------- */
.acs-card {
  position: relative;
  border: 1px solid var(--rule);
  border-radius: 16px;
  background-image: var(--card-glow), var(--card-fill);
  overflow: hidden;
}
.acs-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--card-hi) 28%, var(--card-hi) 72%, transparent);
  pointer-events: none;
}
.acs-card__inner { position: relative; padding: 28px 22px 32px; }
@media (min-width: 720px) { .acs-card__inner { padding: 44px 48px 48px; } }

/* ---------- the hero figure: what you carry, and where it belongs ----------
   This replaced a five slat diagram of the system's internals. The reason
   is recorded in WEBSITE-BRIEF.md section 19: a parts diagram explains the
   machine to someone who has already decided to care, and the hero's job
   is to make them care. It also promised five parts that not every system
   has. This one is about the reader's week, not the repo's directories,
   and it is true of every system here regardless of what is inside it.

   The drawing is the boundary: four things cross into the repo, one never
   does, and the one that does not is the only amber thing on the page at
   that moment. */
.acs-shift { margin: 0 auto; max-width: 820px; }
.acs-figsection { padding: 8px 0 0; }
@media (min-width: 960px) { .acs-figsection { padding: 16px 0 0; } }

.acs-shift__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 48px minmax(0, 1fr);
  align-items: stretch;
}
/* Sentence case, not uppercase. These are five word phrases, and uppercase mono
   with letter-spacing is fine for a two word eyebrow and genuinely hard to read
   at sentence length. Size and colour both lifted for the same reason. */
.acs-shift__head,
.acs-shift__boxlabel {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--secondary);
  padding-bottom: 14px;
  align-self: end;
}
.acs-shift__head { grid-column: 1; }
.acs-shift__boxlabel { grid-column: 3; padding-left: 14px; }

.acs-shift__from {
  grid-column: 1;
  align-self: center;
  font-size: 15px;
  line-height: 1.45;
  color: var(--secondary);
  padding: 15px 0;
}
.acs-shift__arrow {
  grid-column: 2;
  align-self: center;
  display: flex;
  justify-content: center;
  color: var(--border);
}
.acs-shift__arrow svg { transform-origin: left center; }
.acs-shift__arrow { position: relative; }
.acs-shift__arrow::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 13px;
  width: 5px;
  height: 5px;
  margin-top: -2.5px;
  border-radius: 50%;
  background: var(--primary);
  opacity: 0;
  pointer-events: none;
}
@keyframes acs-trace {
  0% { transform: translateX(0); opacity: 0; }
  18% { opacity: 0.95; }
  72% { opacity: 0.95; }
  100% { transform: translateX(17px); opacity: 0; }
}

/* The repo is drawn by the destination cells themselves: shared side rules,
   a rounded top on the first and a rounded bottom on the last. Doing it
   with a single box element does not work, because a grid item that spans
   those rows occupies the very cells its contents need. */
.acs-shift__to {
  grid-column: 3;
  display: flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.5;
  color: var(--strong);
  padding: 15px 14px;
  background: var(--surface);
  border-left: 1px solid var(--rule);
  border-right: 1px solid var(--rule);
  border-top: 1px solid var(--hairline);
}
.acs-shift__to--first {
  border-top: 1px solid var(--rule);
  border-radius: 8px 8px 0 0;
}
.acs-shift__to--last {
  border-bottom: 1px solid var(--rule);
  border-radius: 0 0 8px 8px;
}
/* the one row that never crosses the boundary, so it sits outside the box */
.acs-shift__from--yours { color: var(--primary); font-weight: 600; padding-top: 26px; }
.acs-shift__arrow--yours { align-self: end; padding-bottom: 14px; }
.acs-shift__to--yours {
  align-self: end;
  justify-self: start;
  flex: none;
  margin-top: 14px;
  padding: 9px 14px;
  border: 0;
  border-radius: 6px;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}

.acs-shift__keep {
  margin-top: 30px;
  padding-top: 26px;
  border-top: 1px solid var(--rule);
  display: grid;
  gap: 10px;
}
/* Matches .acs-shift__head and .acs-shift__boxlabel exactly. All three are
   column labels doing the same job in the same figure, and they had drifted
   into three different sizes, weights and cases: one sentence case at 500, one
   sentence case at 600 and brighter, one uppercase at 11px and dimmer. There
   was no reason for any of it. Keep them identical. */
.acs-shift__keeplabel {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--secondary);
}
.acs-shift__keeptext {
  font-size: 17px;
  line-height: 1.5;
  color: var(--primary);
  max-width: 60ch;
}
.acs-shift__keeptext b { color: var(--primary); font-weight: 600; }
.acs-shift__keeppill {
  display: inline-block;
  margin-left: 4px;
  padding: 4px 12px;
  border-radius: 6px;
  background: var(--spot-fill);
  color: var(--on-spot);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}

.acs-figcap {
  margin-top: 18px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
}

/* The sticky mini-spine and its prose blocks lived here. Removed 2026-08-20
   when the anatomy became a feature grid: five short units read in a glance,
   where five prose blocks read as a wall. The Scale 2 device survives on the
   system pages as .acs-parts, annotated with each repo's real paths. */

/* ---------- the wedge ---------- */
.acs-swap { margin-top: 32px; border-top: 1px solid var(--hairline); }
.acs-swap__row {
  display: grid;
  gap: 6px;
  padding: 20px 0;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 800px) {
  .acs-swap__row { grid-template-columns: 1fr 1.35fr; gap: 32px; align-items: start; }
}
.acs-swap__default {
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}
.acs-swap__default::before {
  content: 'default ';
  color: var(--border);
}
.acs-swap__real { font-size: 16px; color: var(--strong); }

/* ---------- session panels ----------
   #argues is the one section that had nothing to look at, and it is the section
   carrying the emotional wedge. It should SHOW an argument rather than describe
   one. Two panels, one per live system, which also fixes the bias problem by
   symmetry rather than by going vague. */
.acs-sessions { margin-top: 36px; display: grid; gap: 16px; }
@media (min-width: 900px) { .acs-sessions { grid-template-columns: 1fr 1fr; gap: 20px; } }

.acs-session { position: relative; overflow: hidden; }
/* This label is the context for everything in the panel, and at 11px uppercase
   muted the eye jumped straight past it into the dialogue. It is now the second
   loudest thing in the card, after the pushback itself. */
.acs-session__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--strong);
}
.acs-session__dots { display: inline-flex; gap: 4px; }
.acs-session__dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--rule); }
.acs-session__body { padding: 20px 18px 22px; display: grid; gap: 16px; }
@media (min-width: 720px) { .acs-session__body { padding: 24px 22px 26px; } }

.acs-session__turn { display: grid; grid-template-columns: 40px 1fr; gap: 12px; align-items: start; }
.acs-session__who {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.7;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.acs-session__said { font-size: 15px; line-height: 1.55; color: var(--secondary); }
.acs-session__turn--push .acs-session__who { color: var(--accent-ink); font-weight: 600; }
.acs-session__turn--push .acs-session__said { color: var(--primary); }
.acs-session__why {
  display: block;
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--muted);
  padding-left: 12px;
  border-left: 1px solid var(--rule);
}

/* ---------- the ledger ---------- */
.acs-ledger { margin-top: 40px; display: grid; gap: 16px; }
.acs-entry {
  position: relative;
  border: 1px solid var(--rule);
  border-radius: 14px;
  background-image: var(--card-glow), var(--card-fill);
  padding: 26px 24px 28px;
  display: grid;
  gap: 16px;
  overflow: hidden;
}
.acs-entry::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--card-hi) 28%, var(--card-hi) 72%, transparent);
  pointer-events: none;
}
.acs-entry > * { position: relative; }
@media (min-width: 800px) {
  .acs-entry { grid-template-columns: 132px 1fr; gap: 32px; padding: 32px 32px 34px; }
}
.acs-entry--faint { opacity: 0.72; }

.acs-entry__rail {
  display: flex;
  align-items: center;
  gap: 12px;
}
@media (min-width: 800px) {
  .acs-entry__rail { flex-direction: column; align-items: flex-start; gap: 14px; }
}
.acs-entry__num {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}
.acs-entry h3 { font-size: 24px; margin-bottom: 4px; }
.acs-entry h3 span { color: var(--muted); font-weight: 500; }
.acs-entry p { color: var(--secondary); max-width: 64ch; }
.acs-entry p + p { margin-top: 10px; }

.acs-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--secondary);
}
.acs-status::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--border);
  flex: none;
}
.acs-status--live::before { background: var(--accent-ink); }
.acs-entry__links { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 16px; }
.acs-entry__links a { font-size: 15px; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }

/* ---------- the deal ---------- */
.acs-triad { margin-top: 40px; display: grid; gap: 16px; }
@media (min-width: 900px) { .acs-triad { grid-template-columns: repeat(3, 1fr); gap: 20px; } }
.acs-col {
  position: relative;
  border: 1px solid var(--rule);
  border-radius: 14px;
  background-image: var(--card-glow), var(--card-fill);
  padding: 26px 24px 28px;
  overflow: hidden;
}
.acs-col::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--card-hi) 28%, var(--card-hi) 72%, transparent);
  pointer-events: none;
}
.acs-col > * { position: relative; }
/* Amber means the human's part everywhere on this site, and this card is the
   human's part, so it gets the third and last use of it. A tinted bloom in the
   corner and an amber edge, which lifts it off the two beside it without
   changing a single word. */
.acs-col--yours {
  border-color: var(--spot);
  background-image:
    radial-gradient(72% 58% at 0% 0%, var(--spot-wash) 0, transparent 70%),
    var(--card-fill);
}
.acs-col--yours::before {
  background: linear-gradient(90deg, transparent, var(--spot) 28%, var(--spot) 72%, transparent);
  opacity: 0.7;
}
/* The wash is warmest exactly where this label sits, which took --muted down to
   4.26 against it. Lifting the label beats thinning the glow: 6.56, and the card
   keeps the presence it was given the glow for. */
.acs-col--yours .acs-col__sub { color: var(--secondary); }
.acs-col h3 { font-size: 18px; margin-bottom: 4px; }
.acs-col__sub { font-family: var(--font-mono); font-size: 12px; color: var(--muted); line-height: 1.5; }
.acs-col ul { margin-top: 16px; }
.acs-col li {
  padding: 10px 0;
  border-top: 1px solid var(--hairline);
  color: var(--secondary);
  font-size: 15px;
}
.acs-col li b { color: var(--primary); font-weight: 600; }

/* ---------- start ---------- */
.acs-steps { margin-top: 40px; display: grid; gap: 24px; }
@media (min-width: 900px) { .acs-steps { grid-template-columns: repeat(3, 1fr); gap: 32px; } }
.acs-step__num {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--accent-ink);
  letter-spacing: 0.08em;
}
.acs-step h3 { font-size: 18px; margin: 8px 0 8px; }
.acs-step p { color: var(--secondary); font-size: 15px; }

.acs-code {
  position: relative;
  margin-top: 24px;
  border: 1px solid var(--rule);
  border-radius: 14px;
  background-image: var(--card-glow), var(--card-fill);
  display: flex;
  align-items: stretch;
  gap: 0;
  overflow: hidden;
}
.acs-code pre {
  margin: 0;
  padding: 14px 16px;
  overflow-x: auto;
  flex: 1;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.5;
  color: var(--strong);
}
.acs-code pre .acs-cue { color: var(--muted); }
.acs-copy {
  flex: none;
  border: 0;
  border-left: 1px solid var(--hairline);
  background: transparent;
  color: var(--secondary);
  font: 500 12px/1 var(--font-mono);
  padding: 0 14px;
  cursor: pointer;
}
.acs-copy:hover { background: var(--surface); color: var(--primary); }
.acs-copy[hidden] { display: none; }

/* ---------- footer ---------- */
.acs-footer {
  border-top: 1px solid var(--rule);
  padding: 48px 0 56px;
  background: var(--surface);
}
.acs-footer__grid { display: grid; gap: 32px; }
@media (min-width: 800px) {
  .acs-footer__grid { grid-template-columns: 1.6fr 1fr; gap: 48px; }
}
.acs-footer h2 {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 14px;
}
.acs-footer li { padding: 5px 0; font-size: 15px; color: var(--secondary); }
.acs-footer li a { text-decoration: underline; text-underline-offset: 3px; }
.acs-footer__legal {
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--hairline);
  display: grid;
  gap: 10px;
  font-size: 13px;
  color: var(--muted);
  max-width: 78ch;
}

/* ---------- motion ----------
   Three motions and no others. Every one of them is choreography on top
   of markup that is already complete and already coloured, so a failed
   script or a reduced motion preference costs nothing but the animation. */
@media (prefers-reduced-motion: no-preference) {
  /* Scroll reveal. Read off Resend's own bundle, which animates
     initial {opacity:0, y:20} to whileInView {opacity:1, y:0} with
     viewport once. That is the entire effect, and it needs no library:
     one IntersectionObserver and one transition. */
  .js [data-reveal] { opacity: 0; transform: translateY(20px); }
  .js [data-reveal].is-in {
    opacity: 1;
    transform: none;
    transition: opacity 620ms ease, transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
    transition-delay: calc(var(--r, 0) * 90ms);
  }

  /* Two more motions, and both are decoration. Nothing that carries meaning is
     hidden until a script runs: the earlier version faded in the session
     lines, which were real text, and a thrown exception anywhere above
     would have deleted them. Arrows and a legend highlight can afford it. */
  /* The figure animates the MAPPING, not the elements. Each row arrives as one
     unit, left label and arrow and destination together, one row after another,
     so the eye is walked through five pairings instead of watching five
     unrelated things fade. Sequencing is the job; reading happens afterwards at
     the reader's own pace, because nothing is ever hidden again once shown.

     NOTE the selector: data-drawn sits on the element carrying data-shift, which
     is the card, NOT on .acs-shift inside it. Getting that wrong shipped every
     arrow at scaleX(0) forever. */
  .js [data-shift] .acs-shift__from,
  .js [data-shift] .acs-shift__to { opacity: 0; }
  .js [data-shift] .acs-shift__from { transform: translateY(8px); }
  .js [data-shift] .acs-shift__to { transform: translateX(-16px); }
  .js [data-shift] .acs-shift__arrow svg { transform: scaleX(0); }

  .js [data-shift][data-drawn='true'] .acs-shift__from,
  .js [data-shift][data-drawn='true'] .acs-shift__to {
    opacity: 1;
    transform: none;
    transition: opacity 420ms ease, transform 560ms cubic-bezier(0.22, 0.61, 0.36, 1);
    transition-delay: calc(var(--i, 0) * 340ms);
  }
  .js [data-shift][data-drawn='true'] .acs-shift__arrow svg {
    transform: scaleX(1);
    transition: transform 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
    transition-delay: calc(120ms + var(--i, 0) * 340ms);
  }
  .js [data-shift] .acs-shift__to--yours { transform: translateX(-16px) scale(0.94); }
  .js [data-shift][data-drawn='true'] .acs-shift__to--yours {
    transform: none;
    transition: opacity 420ms ease, transform 560ms cubic-bezier(0.34, 1.4, 0.64, 1);
    /* the shorthand above resets transition-delay to 0, which silently dropped
       this row out of the stagger. Restate it, and never rely on a shorthand
       to preserve a longhand set by an earlier rule. */
    transition-delay: calc(var(--i, 0) * 340ms);
  }

  /* And then it keeps moving. A light travels the arrow, tracing the direction
     of the mapping, once the reveal has finished. It hides nothing: every row
     stays readable the whole time, which is the difference between motion that
     teaches and motion that makes you wait for a loop to come round again.

     Three repeats rather than infinite, restarted whenever the card re-enters
     view. WCAG 2.2.2 wants a pause control for anything auto-animating past
     five seconds, and this way there is nothing to pause. One word to make it
     infinite if that reads as too shy. */
  .js [data-shift][data-trace='true'] .acs-shift__arrow::after {
    animation: acs-trace 2200ms cubic-bezier(0.45, 0, 0.35, 1) calc(2100ms + var(--i, 0) * 300ms) 3;
  }

  .acs-legend__label,
  .acs-legend__idx { transition: color 220ms linear; }
}

/* ==========================================================
   PAGE TYPES BEYOND THE HUB
   Added 2026-08-20 with /keyline/, /rfi/ and /what-is-a-context-system/.
   ========================================================== */

/* ---------- system and article page hero ---------- */
.acs-phero { padding: 48px 0 8px; }
@media (min-width: 960px) { .acs-phero { padding: 64px 0 8px; } }
.acs-phero h1 {
  font-size: clamp(32px, 5vw, 46px);
  max-width: 20ch;
  margin: 0 0 20px;
}
.acs-phero__tag {
  font-size: 19px;
  line-height: 1.5;
  color: var(--strong);
  max-width: 58ch;
  font-weight: 500;
}
.acs-phero__lede { font-size: 17px; color: var(--secondary); max-width: 64ch; margin-top: 18px; }
.acs-phero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 20px;
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px solid var(--hairline);
}

/* ---------- the anatomy legend, scale 2, annotated with real paths ----------
   Every system page carries this. It is the same five parts as the hub, with
   that repo's actual paths and an emphasis bar, so "a system uses the parts its
   job needs" is visible rather than asserted. A part a system does not have is
   shown at zero and labelled, never omitted. */
.acs-parts { margin-top: 32px; border-top: 1px solid var(--rule); }
.acs-parts__row {
  display: grid;
  grid-template-columns: 8px auto 1fr;
  align-items: baseline;
  gap: 6px 12px;
  padding: 16px 0;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 800px) {
  .acs-parts__row { grid-template-columns: 8px 26px 148px 210px 1fr 60px; align-items: center; }
}
.acs-parts__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--part, var(--border)); }
.acs-parts__idx { font-family: var(--font-mono); font-size: 11px; font-weight: 600; color: var(--muted); }
.acs-parts__name { font-family: var(--font-mono); font-size: 13px; font-weight: 600; color: var(--primary); }
.acs-parts__path {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--part, var(--muted));
  overflow-wrap: anywhere;
}
.acs-parts__note { font-size: 14px; color: var(--secondary); grid-column: 1 / -1; }
@media (min-width: 800px) { .acs-parts__note { grid-column: auto; } }
.acs-parts__row--none .acs-parts__name,
.acs-parts__row--none .acs-parts__path { color: var(--muted); }
.acs-parts__row--none .acs-parts__dot { background: var(--border); }

/* the emphasis bar: how hard this system leans on this part */
.acs-bar {
  display: none;
  height: 4px;
  border-radius: 2px;
  background: var(--hairline);
  overflow: hidden;
}
@media (min-width: 800px) { .acs-bar { display: block; } }
.acs-bar i { display: block; height: 100%; background: var(--part, var(--border)); width: calc(var(--w, 0.2) * 100%); }

/* ---------- comparison table ---------- */
.acs-tablewrap { margin-top: 32px; width: 100%; overflow-x: auto; }
.acs-table { border-collapse: collapse; width: 100%; min-width: 720px; font-size: 15px; }
.acs-table caption {
  text-align: left;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  padding-bottom: 12px;
}
.acs-table th {
  text-align: left;
  font-size: 13px;
  font-weight: 600;
  color: var(--primary);
  padding: 0 16px 10px 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: bottom;
}
.acs-table th:first-child { width: 150px; }
.acs-table td {
  padding: 14px 16px 14px 0;
  border-bottom: 1px solid var(--hairline);
  color: var(--secondary);
  vertical-align: top;
  line-height: 1.5;
}
.acs-table td:first-child { color: var(--primary); font-weight: 600; }
.acs-table code {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--accent-ink);
  overflow-wrap: anywhere;
}
.acs-table tr:last-child td { border-bottom: 0; }

/* ---------- a bounded aside ---------- */
.acs-callout {
  margin-top: 32px;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent-ink);
  border-radius: 8px;
  background: var(--surface);
  padding: 22px 24px;
}
.acs-callout h3 { font-size: 17px; margin-bottom: 8px; }
.acs-callout p { color: var(--secondary); font-size: 15px; max-width: 68ch; }
.acs-callout p + p { margin-top: 10px; }

/* a swap row used for a plain numbered sequence rather than a default/real pair */
.acs-swap--plain .acs-swap__default::before { content: none; }
.acs-swap--plain .acs-swap__default { color: var(--secondary); font-weight: 600; }

/* ==========================================================
   FEATURE GRID AND CLOSING STATEMENT
   Added 2026-08-20. The sections after the hero were reading as a wall because
   detail was set as prose. The fix is structural: a short head, then the detail
   broken into a grid of small units. No borders on these, deliberately, so they
   read as a different kind of object from the cards.
   ========================================================== */

.acs-grid { margin-top: 44px; display: grid; gap: 34px 28px; }
@media (min-width: 700px) { .acs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .acs-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 46px 40px; } }

.acs-feat__icon { display: block; color: var(--part, var(--strong)); margin-bottom: 16px; }
.acs-feat h3 {
  font-size: 17px;
  letter-spacing: -0.01em;
  margin-bottom: 6px;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.acs-feat h3 code {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--part, var(--muted));
  letter-spacing: 0;
}
.acs-feat p { font-size: 15px; line-height: 1.6; color: var(--secondary); max-width: 42ch; }

/* ---------- the closing statement ---------- */
.acs-final {
  position: relative;
  border-top: 1px solid var(--hairline);
  padding: 88px 0 96px;
  text-align: center;
  overflow: hidden;
}
@media (min-width: 960px) { .acs-final { padding: 120px 0 128px; } }
.acs-final::before {
  content: '';
  position: absolute;
  left: -10%;
  right: -10%;
  bottom: -320px;
  height: 640px;
  background: radial-gradient(42% 46% at 50% 50%, rgba(255, 255, 255, var(--glow)), transparent 72%);
  pointer-events: none;
}
.acs-final > * { position: relative; }
.acs-final .acs-eyebrow { margin-bottom: 18px; }
.acs-final h2 {
  font-size: clamp(30px, 4.6vw, 48px);
  letter-spacing: -0.025em;
  max-width: 20ch;
  margin: 0 auto;
  color: var(--muted);
}
.acs-final h2 .acs-turn { color: var(--primary); }
.acs-final__cta {
  margin-top: 34px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
}

/* ---------- centred section heads ----------
   Added with the copy pass, 2026-08-20. Centring only works once the deck is
   two lines: centre a long paragraph and it gets harder to read, not easier.
   So this class arrived at the same time the copy was cut, and the two are a
   pair. If a deck grows back past about thirty words, take the centring off
   rather than leaving a centred wall. */
.acs-sechead { text-align: center; max-width: 720px; margin: 0 auto 8px; }
.acs-sechead .acs-h2 { max-width: none; margin-left: auto; margin-right: auto; }
.acs-sechead .acs-lede { margin-left: auto; margin-right: auto; max-width: 58ch; }
.acs-sechead .acs-eyebrow { margin-bottom: 14px; }

/* Loose prose between a centred head and a structure has to be centred too.
   Left-aligned copy sandwiched between centred blocks reads worse than either
   choice on its own. Only for short passages: anything past a couple of
   sentences goes inside a structure instead. */
.acs-mid { text-align: center; max-width: 720px; margin-left: auto; margin-right: auto; }
.acs-mid .acs-lede { margin-left: auto; margin-right: auto; }
.acs-mid .acs-mark { text-align: left; }


/* ---------- one clone row per system ---------- */
.acs-clones { margin-top: 32px; display: grid; gap: 14px; }
.acs-clone {
  position: relative;
  border: 1px solid var(--rule);
  border-radius: 14px;
  background-image: var(--card-glow), var(--card-fill);
  padding: 18px 20px;
  display: grid;
  gap: 12px;
  align-items: center;
  overflow: hidden;
}
@media (min-width: 820px) {
  .acs-clone { grid-template-columns: 210px 1fr auto; gap: 20px; }
}
.acs-clone__name { font-size: 15px; font-weight: 600; color: var(--primary); }
.acs-clone pre {
  margin: 0;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
  color: var(--strong);
}
.acs-clone pre .acs-cue { color: var(--muted); }
.acs-clone .acs-copy {
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 8px 14px;
  justify-self: start;
}

/* ==========================================================
   ARTICLE LAYOUT
   For /what-is-a-context-system/, which is explanatory writing and reads badly
   as a landing page. Left aligned, one reading measure, headings that sit on
   the same axis as the prose under them. Grids and tables are allowed to break
   out to the full shell width, because a three column grid inside a 760px
   measure is cramped.
   ========================================================== */
.acs-article { max-width: 760px; }
.acs-article h1 { font-size: clamp(32px, 5vw, 46px); max-width: 18ch; margin-bottom: 22px; }
.acs-article h2 {
  font-size: clamp(25px, 3.2vw, 32px);
  letter-spacing: -0.02em;
  max-width: 24ch;
  margin-bottom: 18px;
}
.acs-article h3 { font-size: 19px; margin-bottom: 8px; }
.acs-article p {
  font-size: 17px;
  line-height: 1.7;
  color: var(--secondary);
  max-width: 68ch;
}
.acs-article p + p { margin-top: 18px; }
.acs-article p b { color: var(--primary); font-weight: 600; }
.acs-article__standfirst { font-size: 19px; color: var(--strong); }
.acs-article + .acs-grid,
.acs-article + .acs-tablewrap,
.acs-article + .acs-triad { margin-top: 40px; }

/* A concrete example under a feature, for the one page where naming real files
   is the point. Mono, quiet, and set off by a rule so it reads as an aside. */
.acs-feat__eg {
  display: block;
  margin-top: 12px;
  padding-left: 12px;
  border-left: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.55;
  color: var(--muted);
}
.acs-feat__eg b { color: var(--secondary); font-weight: 500; }

/* ==========================================================
   GUIDE PAGES
   Numbered steps inside the article measure, for /claude-code/.
   ========================================================== */
.acs-steplist { counter-reset: acs-step; margin-top: 40px; display: grid; gap: 40px; }
.acs-stepblock { position: relative; }
.acs-stepblock__n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin-bottom: 14px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--secondary);
}
.acs-stepblock h3 { font-size: 21px; letter-spacing: -0.015em; margin-bottom: 10px; }
.acs-stepblock p { font-size: 16px; line-height: 1.7; color: var(--secondary); max-width: 68ch; }
.acs-stepblock p + p { margin-top: 14px; }
.acs-stepblock p b { color: var(--primary); font-weight: 600; }
.acs-stepblock code,
.acs-article code,
.acs-callout code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  color: var(--strong);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 1px 5px;
}
.acs-stepblock .acs-code,
.acs-article .acs-code { max-width: 760px; }
.acs-stepblock .acs-code code,
.acs-article .acs-code code { border: 0; background: none; padding: 0; }

.acs-callout--warn { border-left-color: var(--spot); }
.acs-callout--warn h3 { color: var(--primary); }

.acs-kv { margin-top: 32px; display: grid; gap: 0; border-top: 1px solid var(--hairline); }
.acs-kv__row { display: grid; gap: 4px 24px; padding: 18px 0; border-bottom: 1px solid var(--hairline); }
@media (min-width: 800px) { .acs-kv__row { grid-template-columns: 260px 1fr; } }
.acs-kv__k { font-size: 15px; font-weight: 600; color: var(--primary); }
.acs-kv__v { font-size: 15px; line-height: 1.6; color: var(--secondary); }
.acs-kv__v code { font-size: 13px; }
