/* ═══ BROTTO — "Ink & Rule", extended for prose ═══════════════════════════
   The tokens below are lifted verbatim from the extension's panel-tokens.css
   so the blog renders in the same system as the product. Same rules: square
   corners, no shadow anywhere, monochrome with colour reserved for state, and
   hierarchy carried by border weight rather than by size.

   What changes in print is the measure. The panel is 320px wide and can
   afford 13.5px; prose needs a 680px column, so the type scale grows and the
   h2 rule becomes the main separator instead of the panel's card borders.
═══════════════════════════════════════════════════════════════════════ */

@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('fonts/geist-latin.woff2') format('woff2');
  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: 'Geist';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('fonts/geist-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/geist-mono-latin.woff2') format('woff2');
  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: 'Geist Mono';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/geist-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* Ink — the brand is its own black */
  --ink:       #000000;
  --ink-2:     #5C5C5C;
  --ink-3:     #6E6E6E;

  /* Paper — layered surfaces, no elevation, only tone */
  --paper:     #FFFFFF;
  --paper-2:   #F5F5F5;
  --paper-3:   #EBEBEB;

  /* Rules — the entire hierarchy system */
  --rule:      #E5E5E5;
  --rule-2:    #C9C9C9;
  --rule-ink:  #000000;

  /* State */
  --ok:        #15803D;
  --wait:      #B45309;
  --bad:       #DC2626;

  --font-ui:   'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Prose measure. 680px at 17px is roughly 78 characters, which is the top
     of the comfortable range — any wider and the eye loses the line return
     on a scroll. */
  --measure: 680px;

  --t: 120ms;
}

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  /* The system has no curves. Non-negotiable — this is the look. */
  border-radius: 0 !important;
}

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

body {
  background: var(--paper);
  color: var(--ink);
  font: 400 17px/1.65 var(--font-ui);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection { background: var(--ink); color: var(--paper); }

/* ─── Grain: 1.5% scanlines + 2% noise ───────────────────────────────────
   Kept from the panel unchanged. It is what stops pure white from reading as
   clinical, and a long article on a white page is the case where it matters
   most. Fixed, pointer-events off, so it never eats a click or scrolls. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
}
.grain::before {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    180deg,
    rgba(0, 0, 0, 0.015) 0 1px,
    transparent 1px 4px
  );
}
.grain::after {
  content: '';
  position: absolute;
  inset: 0;
  opacity: 0.02;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ─── The one label style ───────────────────────────────────────────────
   Every meta line, nav link, and footer credit, exactly as in the panel. */
.label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ─── Header ──────────────────────────────────────────────────────────────
   The panel's header rule carried straight over: a black hairline under a
   56px bar, with the wordmark taking the identity and the nav taking mono
   labels, because those are actions rather than content. */
header {
  display: flex;
  align-items: center;
  gap: 20px;
  height: 56px;
  padding: 0 24px;
  border-bottom: 1px solid var(--rule-ink);
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--ink);
  text-decoration: none;
  flex: 1;
  min-width: 0;
}
.brand-logo { width: 20px; height: 20px; flex-shrink: 0; display: block; }
.brand-name {
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.03em;
  line-height: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

nav { display: flex; gap: 6px; flex-shrink: 0; align-items: center; }
.nav-link {
  color: var(--ink-2);
  text-decoration: none;
  padding: 5px 9px;
  border: 1px solid transparent;
  transition: color var(--t), background var(--t), border-color var(--t);
}
/* The panel inverts its pill on hover rather than tinting it. Inversion is
   the strongest signal the system has, and a border keeps the hit area from
   changing shape mid-hover. */
.nav-link:hover, .nav-link:focus-visible {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
/* The repository link, as a mark rather than a word. It is the only external
   destination in the nav, and a mark says "this leaves the site" without a
   label competing with the CTA beside it. Inverts on the same rule as the
   links, so the whole bar answers hover the same way. */
.nav-gh {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin-left: 4px;
  color: var(--ink-2);
  border: 1px solid transparent;
  transition: color var(--t), background var(--t), border-color var(--t);
}
.nav-gh svg { display: block; }
.nav-gh:hover, .nav-gh:focus-visible {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
/* The one filled control in the nav, so "Get Brotto" is distinguishable from
   the links beside it without a second colour. It points at the install
   section of this page rather than at the repository: the site is the front
   door, and the commands are two scrolls down. */
.nav-cta {
  color: var(--paper);
  background: var(--ink);
  padding: 5px 12px;
  border: 1px solid var(--ink);
  transition: background var(--t), color var(--t);
}
.nav-cta:hover, .nav-cta:focus-visible { background: var(--paper); color: var(--ink); }

/* ─── Main + footer ───────────────────────────────────────────────────── */
main { padding: 0 24px 96px; }
footer {
  border-top: 1px solid var(--rule-ink);
  padding: 20px 24px 32px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 20px;
  color: var(--ink-3);
}
footer a { color: var(--ink-2); text-decoration: none; border-bottom: 1px solid var(--rule-2); }
footer a:hover { color: var(--ink); border-bottom-color: var(--ink); }
.footer-mark { width: 15px; height: 15px; display: block; align-self: center; }
/* The mark, not the word, for the same reason as in the nav: the footer's job
   is to be findable, not to be read. No underline — it is an icon, and the
   rule under an icon reads as a rendering fault. */
.footer-gh {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  align-self: center;
  color: var(--ink-3);
  border-bottom: 0 !important;
}
.footer-gh svg { display: block; }
.footer-gh:hover { color: var(--ink); }
.footer-sep { color: var(--rule-2); }
/* Pushed to the end of the row rather than given its own line, so the footer
   stays one band however narrow it gets. */
.footer-note { margin-left: auto; color: var(--ink-3); }

/* ─── Post ──────────────────────────────────────────────────────────────
   Title and meta sit above a hairline, then the prose column. The rule under
   the meta is the panel's card-header rule doing structural work: it says
   "the header ended" without a box or a shadow. */
article, .page { max-width: var(--measure); margin: 0 auto; }

/* The landing page runs wider than the prose measure: a single centred column
   on a 16:10 display reads as a blog post, and the product page needs the
   width for a split hero and a three-up screen grid. Prose blocks inside keep
   their own measure, so the text column does not stretch with the layout.
   Declared after `.page` on purpose — same specificity, so source order
   decides. */
.page--wide { max-width: 1140px; }
.page--wide p { max-width: 62ch; }

.post-head { padding: 56px 0 28px; border-bottom: 1px solid var(--rule); margin-bottom: 40px; }
.post-title {
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.15;
  margin-bottom: 14px;
}
.post-meta { color: var(--ink-2); font-variant-numeric: tabular-nums; }

.page { padding-top: 56px; }

/* A plain page — privacy, security, screens — carries its own H1 rather than
   getting one from the layout, because the landing page must not have one and
   the two shapes share this file. Same measure as `.post-title`, and the rule
   underneath is `.post-head`'s. */
.page h1 {
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.15;
  margin: 0 0 26px;
  padding-bottom: 26px;
  border-bottom: 1px solid var(--rule);
}

/* ─── Hero ─────────────────────────────────────────────────────────────────
   Two columns: the claim on the left at a reading measure, the product
   itself on the right at whatever is left. The mark is 48px because at that
   size it reads as a mark rather than as an icon in a list — Brotto's is a
   solid square with a notch cut into its right wall, and the notch is the
   action window. The status bar underneath is a real run: 14 steps, 41.2%
   context, outcome DONE.
   ───────────────────────────────────────────────────────────────────────── */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
  gap: 0 64px;
  padding: 76px 0 0;
  align-items: start;
}
.hero-mark { width: 48px; height: 48px; display: block; margin-bottom: 22px; }
.hero-title {
  font-size: 52px;
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  margin: 0 0 20px;
}
/* The README's own line, unchanged: the site and the repository should not
   disagree about what the thing is. */
.hero-line {
  font-size: 20px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--ink);
  max-width: 30ch;
  margin: 0 0 14px;
}
.hero-sub {
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 44ch;
  margin: 0 0 30px;
}
.hero-panel { padding-top: 6px; }

/* Buttons — the panel's pill, promoted to page scale. Solid inverts to paper,
   ghost goes the other way; both keep their border weight so the hit area
   never changes shape on hover, and both are scoped under `.actions` because
   `.page a` below is one class plus one type, which outranks a bare `.btn`
   and would leave the solid button as ink text on an ink fill. */
.actions { display: flex; flex-wrap: wrap; gap: 10px; }
.actions .btn {
  display: inline-block;
  padding: 13px 24px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background var(--t), color var(--t);
}
.actions .btn:hover, .actions .btn:focus-visible { background: var(--paper); color: var(--ink); }
.actions .btn--ghost { background: var(--paper); color: var(--ink); }
.actions .btn--ghost:hover, .actions .btn--ghost:focus-visible { background: var(--ink); color: var(--paper); }

.prose p, .page p { margin-bottom: 22px; overflow-wrap: break-word; }

.prose h2, .page h2 {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.3;
  /* Hierarchy from border weight, not from size: an h2 is separated from what
     precedes it by a rule, and is not itself boxed. */
  margin: 52px 0 18px;
  padding-top: 20px;
  border-top: 1px solid var(--rule);
}
.prose h3, .page h3 {
  font-size: 17px;
  font-weight: 600;
  margin: 34px 0 10px;
}
.prose h4, .page h4 {
  font-size: 15px;
  font-weight: 600;
  margin: 28px 0 8px;
}

.prose ul, .page ul, .prose ol, .page ol { margin: 0 0 22px; padding-left: 22px; }
.prose li, .page li { margin-bottom: 8px; }
.prose li::marker, .page li::marker { color: var(--ink-3); }

.prose strong, .page strong { font-weight: 600; }

/* Inline code. paper-2 is the panel's sunken tone, and the 1px vertical
   padding keeps the mono's taller ascenders from lifting off the line. */
.prose code, .page code {
  background: var(--paper-2);
  padding: 1px 5px;
  font-family: var(--font-mono);
  font-size: 0.88em;
  word-break: break-word;
}

/* Fenced blocks. The 2px ink rule down the left edge is the panel's code
   idiom exactly, and it is what makes a 20-line listing readable — the eye
   gets a spine to follow back down the gutter. */
.prose pre, .page pre {
  background: var(--paper-2);
  border-left: 2px solid var(--rule-ink);
  padding: 16px 18px;
  margin: 0 0 24px;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
}
.prose pre code, .page pre code { background: transparent; padding: 0; font-size: inherit; }

.prose blockquote, .page blockquote {
  margin: 0 0 22px;
  padding: 2px 0 2px 16px;
  border-left: 2px solid var(--rule-2);
  color: var(--ink-2);
}

.prose hr, .page hr { border: 0; border-top: 1px solid var(--rule); margin: 44px 0; }

.prose a, .page a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--ink-3);
  transition: border-color var(--t);
}
.prose a:hover, .page a:hover { border-bottom-color: var(--ink); }

/* Tables — the panel's md-table, rules and all: mono uppercase header with a
   full ink underline, hairline row separators, no zebra and no fills. */
.prose table, .page table {
  border-collapse: collapse;
  width: 100%;
  margin: 0 0 24px;
  font-size: 15px;
  display: block;
  overflow-x: auto;
}
.prose th, .page th {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  text-align: left;
  padding: 6px 14px 6px 0;
  white-space: nowrap;
  border-bottom: 1px solid var(--ink);
}
.prose td, .page td {
  padding: 8px 14px 8px 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.prose tr:last-child td, .page tr:last-child td { border-bottom: 0; }

/* ─── The post list ──────────────────────────────────────────────────────
   Two entries, so a bulleted list reads as filler. Each entry is a full-width
   row between two hairlines that inverts on hover, which is the panel's
   button idiom applied to a whole row: the link, the date and the standfirst
   all light up together, because they are one target. */
.page ul.post-list {
  list-style: none;
  padding: 0;
  margin: 28px 0 0;
  border-top: 1px solid var(--rule-ink);
}
.page ul.post-list li {
  margin: 0;
  padding: 22px 14px 22px 12px;
  font-size: 15px;
  color: var(--ink-2);
  border-bottom: 1px solid var(--rule);
  transition: background var(--t), color var(--t);
}
.page ul.post-list a {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ink);
  border-bottom: 0;
}
/* The date sits on the title's baseline rather than its own line, so the row
   still reads as one entry at 390px where a separate line would triple it. */
.page ul.post-list .post-when {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  margin-left: 10px;
  white-space: nowrap;
}
.page ul.post-list .post-stand { display: block; margin-top: 7px; max-width: 54ch; }
.page ul.post-list li:hover { background: var(--ink); color: var(--paper); }
.page ul.post-list li:hover a { color: var(--paper); }
.page ul.post-list li:hover .post-when,
.page ul.post-list li:hover .post-stand { color: var(--paper-3); }
.page ul.post-list li:hover em { color: var(--paper); font-style: italic; }

/* ─── Landing page ─────────────────────────────────────────────────────────
   Everything below is the extension's own interface rebuilt at page scale, so
   the marketing page shows the product's real surface rather than a picture
   of it. The construction is unchanged — the status bar's hairline cell grid,
   the message bubbles, the approval card's 2px state-coloured left rule — and
   only the measure grows.

   The one structural change from the panel is the split: on a 16:10 display a
   single centred column reads as a blog post, so sections that have a claim
   and a demonstration sit in two columns, and sections that have neither are
   allowed to run the full width.
   ───────────────────────────────────────────────────────────────────────── */

/* The panel's status bar. Four cells, hairline rules doing the dividing: the
   bottom border on the top row, the left border on the right column, and
   nothing else. The outcome cell carries the state colour, which is the only
   place on the page where one appears outside a link. */
.statusbar {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--rule-ink);
}
.statusbar .cell {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 14px 16px 15px;
}
.statusbar .cell:nth-child(-n+2) { border-bottom: 1px solid var(--rule-2); }
.statusbar .cell:nth-child(even) { border-left: 1px solid var(--rule-2); }
.statusbar .cell .label { color: var(--ink-2); }
.statusbar .cell .value {
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.statusbar .outcome[data-state="done"] { --state: var(--ok); }
.statusbar .outcome .value { color: var(--state, var(--ink-2)); }
.statusbar .outcome .value::before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  background: var(--state, var(--ink-3));
  vertical-align: 1px;
}

/* ─── Split sections ───────────────────────────────────────────────────────
   A claim on the left at a fixed width, the thing that proves it on the
   right. The left column stops at a measure so the two never run into each
   other, and the whole pair carries a top rule — the same rule that ends the
   hero, so the page reads as a stack of bands rather than a stack of boxes. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 0 64px;
  border-top: 1px solid var(--rule-ink);
  padding: 60px 0 64px;
  align-items: start;
}
.split--flip > :first-child { order: 2; }
.split--flip > :last-child { order: 1; }
.split .claim { position: sticky; top: 32px; }
.split .claim h2 {
  border: 0;
  padding: 0;
  margin: 0 0 16px;
}
.split .claim p {
  font-size: 16px;
  color: var(--ink-2);
  max-width: 42ch;
  margin-bottom: 16px;
}
.split .claim .eyebrow { display: block; margin-bottom: 14px; color: var(--ink-3); }

/* ─── The card grid ─────────────────────────────────────────────────────────
   Cells share one border, drawn around the grid and between the cells, so a
   row of three reads as one object rather than three. This is the status
   bar's construction generalised, and it is why the page needs no card
   shadows: the rules are the separation. */
.cardgrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border: 1px solid var(--rule-ink);
}
.cardgrid > div {
  padding: 26px 24px 28px;
  border-left: 1px solid var(--rule);
}
.cardgrid > div:first-child { border-left: 0; }
.cardgrid h3 {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0 0 10px;
}
.cardgrid p {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--ink-2);
  margin: 0;
}
.cardgrid .card-idx { display: block; margin-bottom: 16px; color: var(--ink-3); }
.cardgrid em { color: var(--ink); font-style: normal; font-weight: 600; }

/* A two-up variant, for the two decisions everything else follows from. */
.cardgrid--2 { grid-template-columns: repeat(2, 1fr); }

/* The three asks in "What it does" are quoted speech rather than headings:
   the request *is* the interface, so it carries the weight and the sentence
   explaining what came back stays in the quiet grey. Italic is the only
   second voice the system has, and it is spent here. */
.cardgrid h3.ask { font-weight: 500; font-style: italic; letter-spacing: -0.01em; }

/* ─── Gate cards ─────────────────────────────────────────────────────────────
   The three things an agent holding your cookies must not be able to skip.
   Each is numbered and closed with the same sentence, because the reason they
   hold is that none of them can be switched off. */
.gate {
  border: 1px solid var(--rule-ink);
  border-left: 2px solid var(--wait);
  padding: 22px 24px 24px;
  background: var(--paper);
}
.gate h3 { font-size: 16px; font-weight: 600; margin: 0 0 9px; letter-spacing: -0.015em; }
.gate p { font-size: 14.5px; line-height: 1.6; color: var(--ink-2); margin: 0; }
.gate .gate-lock {
  display: block;
  margin-top: 14px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wait);
}

/* ─── The panel mock ────────────────────────────────────────────────────────
   Same construction as sidepanel.html at 420px instead of 320px: header rule,
   message column, bubbles, an approval card. */
.panel {
  border: 1px solid var(--rule-ink);
  background: var(--paper);
}
.panel-head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--rule-ink);
}
.panel-logo { width: 18px; height: 18px; display: block; }
.panel-brand { font-weight: 700; font-size: 15px; letter-spacing: -0.03em; }
.panel-pill {
  margin-left: auto;
  border: 1px solid var(--rule-2);
  padding: 4px 9px;
  color: var(--ink-2);
}
.panel-pill::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  background: var(--ink);
  vertical-align: 1px;
}
.panel-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 20px 16px 22px;
  background: var(--paper-2);
}
.panel-body .bubble {
  max-width: 84%;
  padding: 11px 14px;
  font-size: 14.5px;
  line-height: 1.5;
  margin: 0;
}
.bubble--user {
  align-self: flex-end;
  background: var(--ink);
  color: var(--paper);
}

/* A step line: a 6px square, then the sentence. The panel indents this under
   a bubble, which does not survive being 420px wide with no history above
   it, so it stands on its own here. */
.step { display: flex; gap: 11px; align-items: flex-start; padding: 3px 0; }
.step-mark { width: 6px; height: 6px; margin-top: 7px; background: var(--ink-3); flex-shrink: 0; }
.step-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.step-head { font-size: 14px; line-height: 1.5; }
.step-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* The approval card. The 2px left rule in --wait is the single loudest thing
   in the panel and it is the reason this card is on the page at all. */
.card {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-left: 2px solid var(--wait);
  padding: 15px 17px 16px;
  margin: 4px 0 0;
}
.card-top { margin-bottom: 10px; }
.badge {
  display: inline-block;
  border: 1px solid var(--wait);
  color: var(--wait);
  padding: 3px 8px;
}
.card-body { font-size: 14px; line-height: 1.55; margin: 0 0 11px; }
.card-url {
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--paper-2);
  border-left: 2px solid var(--rule-ink);
  padding: 8px 11px;
  margin: 0 0 13px;
  word-break: break-all;
}
.card-actions { display: flex; gap: 8px; }
.btn-sm {
  display: inline-block;
  padding: 8px 15px;
  border: 1px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.btn-sm--primary { background: var(--ink); color: var(--paper); }
.btn-sm--danger { border-color: var(--bad); color: var(--bad); }

/* ─── Coming soon ───────────────────────────────────────────────────────────
   A dashed border is the system's only non-solid line, so it is reserved for
   exactly one meaning: not built yet. Nothing that ships uses it, which is
   what makes it legible without a word. */
.soon {
  display: inline-block;
  border: 1px dashed var(--rule-2);
  color: var(--ink-3);
  padding: 3px 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.btn:disabled, .btn[aria-disabled="true"] {
  background: var(--paper);
  color: var(--ink-3);
  border-color: var(--rule-2);
  border-style: dashed;
  cursor: default;
  pointer-events: none;
}
.soon-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  /* The gap above, not below: this sits directly under the buttons, and at
     phone width they wrap, so a zero top margin reads as a collision. */
  margin: 20px 0 4px;
  font-size: 14px;
  color: var(--ink-2);
}

/* ─── Screens ────────────────────────────────────────────────────────────────
   Three panels across at full width. A run is the same three-up with the
   numbers from the README's own walkthrough. */
.shots {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px 22px;
  margin: 4px 0 0;
}
.shots figure { margin: 0; }
.shots img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule-2);
  background: var(--paper-2);
}
.shots figcaption {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
  margin-top: 11px;
}
.shots figcaption b { color: var(--ink); font-weight: 600; }
.shots--2 { grid-template-columns: repeat(2, 1fr); }

/* A numbered walkthrough step. The number is the panel's mono label at a size
   that survives being the first thing read. */
.moment {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 0 28px;
  padding: 34px 0 38px;
  border-top: 1px solid var(--rule);
  align-items: start;
}
.moment:first-child { border-top: 0; padding-top: 0; }
.moment .n {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-top: 5px;
}
.moment h3 { font-size: 19px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 9px; }
.moment p { font-size: 15px; line-height: 1.6; color: var(--ink-2); margin: 0 0 18px; max-width: 62ch; }
.moment img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule-2);
  background: var(--paper-2);
}

/* ─── Architecture strip ───────────────────────────────────────────────────
   Three boxes and two connectors, drawn with rules rather than a diagram
   library. The connector is a hairline with a label on it, because the thing
   travelling across it is the whole design. */
.arch {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto 1fr;
  align-items: stretch;
  border: 1px solid var(--rule-ink);
}
.arch .node {
  padding: 22px 22px 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.arch .node .label { color: var(--ink-3); }
.arch .node b { font-size: 15px; font-weight: 600; letter-spacing: -0.015em; }
.arch .node span:last-child { font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }
.arch .link {
  align-self: center;
  padding: 0 16px;
  text-align: center;
  color: var(--ink-3);
  white-space: nowrap;
}
.arch .link::after {
  content: '';
  display: block;
  height: 1px;
  background: var(--rule-2);
  margin-top: 8px;
  position: relative;
}
.arch .link::before {
  content: '';
  position: absolute;
}

/* ─── Video ─────────────────────────────────────────────────────────────────
   A 2px ink rule down the left, same as the code block: the eye gets a spine
   to follow, and a black letterboxed rectangle on a white page needs
   something holding it. */
.demo { margin: 0; }
.demo video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--ink);
  border-left: 2px solid var(--rule-ink);
}
.demo figcaption {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
  margin-top: 12px;
  max-width: 66ch;
}

.section-note {
  font-size: 16px;
  color: var(--ink-2);
  margin: 0 0 26px;
  max-width: 62ch;
}

/* The spec table on the landing page. */
.spec { max-width: none; display: table; }
.spec td:first-child {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  width: 34%;
  white-space: nowrap;
}

/* ─── Narrow ────────────────────────────────────────────────────────────
   Two breakpoints, because the layouts fail differently. At 940px the split
   sections go to one column, which is the graceful version — the claim is
   still above the thing it claims. At 700px the grids go to one column too,
   and the nav drops its section anchors, which are all reachable by
   scrolling anyway. */
@media (max-width: 940px) {
  /* minmax(0, …), not a bare 1fr: a bare track floors at min-content, so a
     `pre` that scrolls would still push the whole page sideways. */
  .hero { grid-template-columns: minmax(0, 1fr); gap: 40px; padding-top: 52px; }
  .hero-line { max-width: none; }
  .split, .split--flip { grid-template-columns: minmax(0, 1fr); gap: 34px; padding: 44px 0 48px; }
  .split .claim { position: static; }
  .split--flip > :first-child, .split--flip > :last-child { order: 0; }
  .arch { grid-template-columns: minmax(0, 1fr); }
  .arch .link { padding: 14px 22px; }
  .arch .link::after { height: 1px; }
}

@media (max-width: 700px) {
  body { font-size: 16px; }
  header { padding: 0 16px; gap: 12px; }
  main { padding: 0 16px 64px; }
  footer { padding: 18px 16px 28px; }
  .post-head, .page { padding-top: 40px; }
  .hero { padding-top: 40px; }
  .hero-title { font-size: 38px; }
  .hero-line { font-size: 18px; }
  .hero-sub { font-size: 15px; }
  .post-title { font-size: 27px; }
  .prose h2, .page h2 { font-size: 19px; margin-top: 42px; }

  /* The status bar is the panel's 2×2 grid and stays 2×2 — the four values
     are too short to need the width, and two rows read better than one. */
  .statusbar .cell:nth-child(-n+2) { border-bottom: 1px solid var(--rule-2); }
  .statusbar .cell:nth-child(even) { border-left: 1px solid var(--rule-2); }
  .statusbar .cell .value { font-size: 17px; }

  /* Every three-up grid collapses. A cell narrower than ~200px puts a
     three-word label on two lines, which is the point at which a grid stops
     reading as a set. */
  .cardgrid, .cardgrid--2, .shots, .shots--2 { grid-template-columns: 1fr; }
  .cardgrid > div { border-left: 0; border-top: 1px solid var(--rule); }
  .cardgrid > div:first-child { border-top: 0; }

  .moment { grid-template-columns: 1fr; gap: 10px; }
  .panel-body .bubble { max-width: 92%; }

  .page ul.post-list a { font-size: 18px; }
  .page ul.post-list .post-when { display: block; margin: 6px 0 0; }
  .page ul.post-list .post-stand { font-size: 14px; max-width: none; }

  /* Four links plus a mark and a CTA do not fit under a wordmark at 390px.
     The wordmark and the CTA are the two that earn the width — the wordmark
     is the way back to the top of the page, and the CTA is the only reason
     most of these visits happen. The links are all still one tap away in the
     footer, which is where a phone user already scrolls to look. */
  .nav-link { display: none; }
  .nav-cta { padding: 5px 10px; }
  .footer-note { margin-left: 0; width: 100%; }

  .spec { display: block; overflow-x: auto; }
  .spec td:first-child { width: auto; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
