/* Reliquary web UI. Design system: docs/research/ui-design-system.md.

   Conventional first: neutral warm grays, one sans (Inter, self-hosted),
   sentence case everywhere, small radii, borders rather than shadows, and
   functional colors with fixed meanings (blue links and focus, green
   success, amber attention, red danger). Vermilion is the brand: the logo
   diamond, "you are here" bars, the Review count and text selection. It
   never means danger and is never used for text. Filled and hollow diamonds
   mark canon and open.

   No client script (the CSP forbids it): menus are <details>, header buttons
   submit forms further down with form="". */

/* Inter is the design's deliberate choice: the most common neutral UI face,
   which is the point (see the design doc's Font section). */
/* Type (owner, 2026-10-13; docs/research/ui-design-system.md): Atkinson
   Hyperlegible Next, drawn for legibility, for text; Geist Mono for code and
   metadata. Both OFL, self-hosted (the CSP allows fonts only from here). */
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("/fonts/atkinson-hyperlegible-next-latin-wght-normal.woff2") format("woff2-variations"), url("/fonts/atkinson-hyperlegible-next-latin-wght-normal.woff2") format("woff2");
  font-weight: 200 800; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("/fonts/atkinson-hyperlegible-next-latin-wght-italic.woff2") format("woff2-variations"), url("/fonts/atkinson-hyperlegible-next-latin-wght-italic.woff2") format("woff2");
  font-weight: 200 800; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("/fonts/geist-mono-latin-wght.woff2") format("woff2-variations"), url("/fonts/geist-mono-latin-wght.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}

/* Tokens ------------------------------------------------------------------ */

:root {
  color-scheme: light;

  --font-sans: "Atkinson Hyperlegible Next", -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --text-xs: 0.75rem;   --lh-xs: 1rem;
  --text-sm: 0.875rem;  --lh-sm: 1.25rem;
  --text-md: 1rem;      --lh-md: 1.5rem;
  --text-lg: 1.125rem;  --lh-lg: 1.75rem;
  --text-xl: 1.25rem;   --lh-xl: 1.75rem;
  --text-2xl: 1.5rem;   --lh-2xl: 2rem;

  --space-1: 2px;  --space-2: 4px;  --space-3: 8px;  --space-4: 12px; --space-5: 16px;
  --space-6: 24px; --space-7: 32px; --space-8: 40px; --space-9: 48px; --space-10: 64px;

  --radius-sm: 0;
  --radius-md: 0;
  --radius-lg: 0;
  --radius-full: 999px; /* pills and labels only: badges, chips, counts. Every box is square. */

  --control-sm: 28px;
  --control-md: 36px;
  --topbar-h: 56px;
  --sidebar-w: 248px;
  --content-max: 1280px;
  --measure: 60ch; /* about 75 characters of Inter: "ch" is the wide zero */

  /* Light */
  --bg: #ffffff;
  --bg-subtle: #f7f6f5;
  --bg-muted: #efedeb;
  --border: #e2dfdc;
  --border-strong: #8c8580;
  --fg: #1c1917;
  --fg-muted: #5c5652;
  --link: #0a58ca;
  --brand: #e8393a;
  --brand-strong: #c8302c;
  --on-brand: #ffffff;
  --primary-bg: #1c1917;
  --primary-hover: #3b3633;
  --primary-fg: #ffffff;
  --success: #1a7f37;      --success-bg: #dafbe1;
  --attention: #9a6700;    --attention-bg: #fff8c5;
  --danger: #cf222e;       --danger-bg: #ffebe9;
  --info: #0a58ca;         --info-bg: #ddf4ff;
  --diff-add: #e6ffec;     --diff-add-word: #abf2bc;
  --diff-del: #ffebe9;     --diff-del-word: #ffcecb;
  --diff-word-fg: #1c1917;
  --selection: rgb(232 57 58 / 0.22);
  --shadow-menu: 0 8px 24px -6px rgb(28 25 23 / 0.18), 0 0 0 1px var(--border);
}

/* A fingertip needs about 44px: on phones every button and field grows from
   36px, and the small ones in table rows and menus from 28px. */
@media (max-width: 640px) {
  :root { --control-sm: 44px; --control-md: 44px; }
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #141312;
    --bg-subtle: #1c1a19;
    --bg-muted: #262322;
    --border: #34302e;
    --border-strong: #6f6863;
    --fg: #edebe9;
    --fg-muted: #a8a19c;
    --link: #6cb6ff;
    --brand: #ff5f57;
    --brand-strong: #ff5f57;
    --on-brand: #141312;
    --primary-bg: #edebe9;
    --primary-hover: #d3cfcc;
    --primary-fg: #141312;
    --success: #6bc46d;      --success-bg: #1b2e1f;
    --attention: #d4a72c;    --attention-bg: #2e2615;
    --danger: #ff7b72;       --danger-bg: #3a1d1b;
    --info: #6cb6ff;         --info-bg: #172a3d;
    --diff-add: #1b3524;     --diff-add-word: #2b6a3c;
    --diff-del: #40201f;     --diff-del-word: #7a2e2b;
    --diff-word-fg: #ffffff;
    --selection: rgb(255 95 87 / 0.3);
    --shadow-menu: 0 8px 24px -6px rgb(0 0 0 / 0.6), 0 0 0 1px var(--border);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #141312;
  --bg-subtle: #1c1a19;
  --bg-muted: #262322;
  --border: #34302e;
  --border-strong: #6f6863;
  --fg: #edebe9;
  --fg-muted: #a8a19c;
  --link: #6cb6ff;
  --brand: #ff5f57;
  --brand-strong: #ff5f57;
  --on-brand: #141312;
  --primary-bg: #edebe9;
  --primary-hover: #d3cfcc;
  --primary-fg: #141312;
  --success: #6bc46d;      --success-bg: #1b2e1f;
  --attention: #d4a72c;    --attention-bg: #2e2615;
  --danger: #ff7b72;       --danger-bg: #3a1d1b;
  --info: #6cb6ff;         --info-bg: #172a3d;
  --diff-add: #1b3524;     --diff-add-word: #2b6a3c;
  --diff-del: #40201f;     --diff-del-word: #7a2e2b;
  --diff-word-fg: #ffffff;
  --selection: rgb(255 95 87 / 0.3);
  --shadow-menu: 0 8px 24px -6px rgb(0 0 0 / 0.6), 0 0 0 1px var(--border);
}

/* Base -------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html {
  background: var(--bg);
  scrollbar-color: var(--border-strong) transparent;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: var(--lh-md);
  font-optical-sizing: auto;
  caret-color: var(--brand);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  display: flex; flex-direction: column; min-height: 100vh;
}
/* Closed disclosures render nothing, whatever the browser's default. */
details:not([open]) > :not(summary) { display: none; }
::selection { background: var(--selection); color: var(--fg); }
:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }

a {
  color: var(--link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
}
a:hover { text-decoration-color: currentColor; }

code, pre, kbd { font-family: var(--font-mono); }
code { font-size: 0.875em; background: var(--bg-muted); padding: 1px 5px; border-radius: var(--radius-sm); overflow-wrap: anywhere; }
strong { font-weight: 600; }

.skip {
  position: absolute; left: var(--space-5); top: -100px; z-index: 10;
  background: var(--primary-bg); color: var(--primary-fg); padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-md); font-size: var(--text-sm); font-weight: 500; text-decoration: none;
}
.skip:focus { top: var(--space-3); }

/* Top bar ----------------------------------------------------------------- */

.top { background: var(--bg-subtle); border-bottom: 1px solid var(--border); }
.top-inner {
  max-width: var(--content-max); margin: 0 auto; padding: 0 var(--space-6);
  min-height: var(--topbar-h);
  display: flex; align-items: center; gap: var(--space-7);
}
.wordmark {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  color: var(--fg); text-decoration: none;
  font-size: var(--text-md); font-weight: 600; letter-spacing: -0.01em;
  min-height: var(--control-md);
}
.logo { width: 28px; height: 28px; background: var(--brand); mask: url(/logo.svg) center / contain no-repeat; flex: none; }
.top nav { display: flex; align-items: stretch; gap: var(--space-2); align-self: stretch; }
.top nav a {
  display: inline-flex; align-items: center; gap: 6px; position: relative;
  padding: 0 var(--space-3); color: var(--fg-muted); text-decoration: none;
  font-size: var(--text-sm); font-weight: 500; white-space: nowrap;
}
.top nav a:hover { color: var(--fg); }
.top nav a[aria-current="page"] { color: var(--fg); }
.top nav a[aria-current="page"]::after {
  content: ""; position: absolute; left: var(--space-3); right: var(--space-3); bottom: -1px;
  height: 2px; background: var(--brand); border-radius: 2px 2px 0 0;
}
.top nav a:focus-visible { outline-offset: -2px; border-radius: var(--radius-md); }
.count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--radius-full);
  font-size: var(--text-xs); line-height: 1; font-weight: 600;
  background: var(--bg-muted); color: var(--fg);
}
.top nav .count { background: var(--brand-strong); color: var(--on-brand); }

/* Menus (<details>): the top bar's, a file's More, a row's Snooze */
.menu-wrap { position: relative; }
.menu-wrap > summary { list-style: none; }
.menu-wrap:not([open]) > .menu { display: none; }
.menu-wrap > summary::-webkit-details-marker { display: none; }
.menu-wrap > summary::after {
  content: ""; width: 6px; height: 6px; margin: -3px 2px 0 2px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
}
.menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 5;
  width: max-content; min-width: 240px; max-width: calc(100vw - 32px);
  background: var(--bg); border-radius: var(--radius-lg); box-shadow: var(--shadow-menu);
  padding: var(--space-4); display: grid; gap: var(--space-4);
}
.menu-meta { margin: 0; font-size: var(--text-sm); color: var(--fg-muted); }
.menu-meta strong { color: var(--fg); }
.menu-label { font-size: var(--text-sm); font-weight: 600; }
.theme { display: grid; gap: var(--space-3); margin: 0; }

/* The app's top bar (html.ts, appBar): brand, main nav with the vault
   switcher, then search, the inbox and the account menu at the right. On a
   tablet the nav gets its own row; on a phone the search folds into a
   button and the menus open full width under the bar. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.icon { display: block; flex: none; }
.app-top .top-inner { position: relative; gap: var(--space-5); }
.app-top .top-inner > .stage { margin-left: calc(-1 * var(--space-3)); }
.app-nav { min-width: 0; }
.app-nav > .vault-switch { display: flex; align-items: stretch; }
.vault-switch > summary {
  display: inline-flex; align-items: center; gap: 6px; position: relative; cursor: pointer;
  padding: 0 var(--space-3); color: var(--fg-muted); font-size: var(--text-sm); font-weight: 500; white-space: nowrap;
}
.vault-switch > summary:hover, .vault-switch[open] > summary, .vault-switch > summary[aria-current="page"] { color: var(--fg); }
.vault-switch > summary[aria-current="page"]::before {
  content: ""; position: absolute; left: var(--space-3); right: var(--space-3); bottom: -1px;
  height: 2px; background: var(--brand); border-radius: 2px 2px 0 0;
}
.vault-switch > summary:focus-visible { outline-offset: -2px; border-radius: var(--radius-md); }
.vault-switch-label { max-width: 18ch; overflow: hidden; text-overflow: ellipsis; }
.vault-menu { left: 0; right: auto; top: calc(100% + 1px); min-width: 260px; max-height: min(70vh, 32rem); overflow-y: auto; }

.top-tools { margin-left: auto; display: flex; align-items: center; gap: var(--space-2); }
.top-search { margin: 0 var(--space-2) 0 0; }
.top-search-field { position: relative; display: flex; align-items: center; }
.top-search-field .icon { position: absolute; left: 10px; color: var(--fg-muted); pointer-events: none; }
.top-search input[type="search"] {
  width: 15rem; min-height: 32px; padding: 4px 10px 4px 32px; font-size: var(--text-sm); background: var(--bg);
}
.search-pop { display: none; }
.icon-button { position: relative; padding: 0 10px; color: var(--fg-muted); }
.icon-button:hover, .menu-wrap[open] > .icon-button { color: var(--fg); }
.menu-wrap > summary.icon-button::after { content: none; }
.icon-button .count {
  position: absolute; top: 1px; right: -2px; min-width: 18px; height: 18px; padding: 0 5px;
  font-size: 0.6875rem; background: var(--brand-strong); color: var(--on-brand);
  box-shadow: 0 0 0 2px var(--bg-subtle);
}
.top-tools [aria-current="page"].icon-button, .top-tools [aria-current="page"].account-button { background: var(--bg-muted); color: var(--fg); }
.account-button { gap: var(--space-3); padding: 0 var(--space-3) 0 6px; color: var(--fg); max-width: 15rem; }
.account-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.avatar {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 24px; height: 24px; border-radius: var(--radius-sm);
  background: var(--primary-bg); color: var(--primary-fg); font-size: var(--text-xs); font-weight: 600;
}

.menu-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-5); margin: 0; font-size: var(--text-sm); }
.menu-who { display: grid; gap: 2px; margin: 0; font-size: var(--text-sm); }
.menu-who strong { overflow-wrap: anywhere; }
.menu-list { list-style: none; margin: 0 calc(-1 * var(--space-3)); padding: 0; display: grid; gap: 1px; }
.menu-list a {
  display: grid; gap: 1px; padding: 6px var(--space-3); border-radius: var(--radius-md);
  color: var(--fg); text-decoration: none; font-size: var(--text-sm); line-height: var(--lh-sm);
}
.menu-list a:hover { background: var(--bg-muted); }
.menu-list a[aria-current="page"] { background: var(--bg-muted); font-weight: 600; }
.menu-list a:focus-visible { outline-offset: -2px; }
.menu-item-title { overflow-wrap: anywhere; }
.menu-item-meta { color: var(--fg-muted); font-size: var(--text-xs); line-height: var(--lh-xs); font-weight: 400; }
.vault-menu .menu-list a { grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: var(--space-4); }
/* The switcher's menu sits inside the main nav: undo the nav's link style. */
.app-nav .menu a { position: static; white-space: normal; font-weight: 400; }
.app-nav .menu a[aria-current="page"]::after { content: none; }
.app-nav .menu .menu-list a { display: grid; padding: 6px var(--space-3); color: var(--fg); }
.app-nav .menu .menu-list a:hover { background: var(--bg-muted); }
.app-nav .menu .menu-list a[aria-current="page"] { font-weight: 600; }
.app-nav .menu .menu-foot a { display: inline; padding: 0; color: var(--link); text-decoration: underline; }
.menu > p.menu-label { margin: 0; }
.menu-who { color: var(--fg-muted); }
.menu-who strong { color: var(--fg); }
.menu-foot { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin: 0; padding-top: var(--space-3); border-top: 1px solid var(--border); font-size: var(--text-sm); }
.inbox-menu { width: min(24rem, calc(100vw - 32px)); }
.inbox-empty { max-width: 22rem; }
.search-menu { width: min(24rem, calc(100vw - 32px)); }
.search-menu .top-search { margin: 0; }
.search-menu .top-search input[type="search"] { width: 100%; }
/* The Feedback button and its short form (html.ts, feedbackPop). */
.feedback-button { gap: 6px; }
.feedback-label { font-size: var(--text-sm); font-weight: 500; }
.feedback-menu { width: min(24rem, calc(100vw - 32px)); }
.feedback-form { display: grid; gap: var(--space-3); margin: 0; }
.feedback-form .actions { margin: 0; }
.feedback-form .hint { margin: 0; }
.feedback-form textarea { min-height: 6rem; }
.feedback-kinds { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); border: 0; margin: 0; padding: 0; min-width: 0; }
.feedback-kinds label, .feedback-include {
  display: inline-flex; align-items: center; gap: 6px; margin: 0; font-weight: 400; font-size: var(--text-sm); cursor: pointer;
}
.feedback-include { flex-wrap: wrap; }
.feedback-include code { overflow-wrap: anywhere; font-size: var(--text-xs); }
/* The Feedback page (feedback.ts) */
.feedback-page-form textarea { min-height: 8rem; }
.feedback-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; max-width: 60ch; }
.feedback-list td { vertical-align: top; }
/* Below wide screens the button is its icon, like the inbox: the label
   would push the search box over the main links. On phones there is no
   room for it beside the logo; the account menu's Send feedback opens the
   Feedback page with the page you were on. */
@media (max-width: 1240px) {
  .feedback-label {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}
@media (max-width: 640px) {
  .top-tools > .feedback-pop { display: none; }
}

/* Search across vaults (search.ts) and Account settings (settings.ts) */
.search-page { display: grid; gap: var(--space-3); margin: 0 0 var(--space-6); max-width: 40rem; }
.search-page .hint { margin: 0; }
.settings-form { max-width: 32rem; }
.settings-form .actions { margin-top: var(--space-4); }

/* The nav always takes a row of its own under the bar, rather than sharing
   it with the search box and tools. This used to be a tablet-and-narrower
   behaviour (a shared single row above 1080px, squeezed narrower still
   between 901 and 1080px), on the assumption that nav plus search plus
   tools would fit beside each other on any wider screen. They don't: the
   bar's own content is capped at --content-max (1280px) no matter how wide
   the viewport is, and nav alone (a real vault name, not "Short", plus
   Home/Activity/Connect/Docs) already needs most of that, so a shared row
   silently overflowed nav's own links behind the search box on every
   screen, not just narrow ones. Its own row has the full bar width and
   nothing else to share it with, so it isn't capacity-limited this way. */
.app-top .top-inner { flex-wrap: wrap; row-gap: 0; }
.app-top .app-nav {
  order: 3; width: calc(100% + 2 * var(--space-6)); margin: 0 calc(-1 * var(--space-6));
  padding: 0 var(--space-4); border-top: 1px solid var(--border); min-height: 44px;
  /* The rule spans the window like the bar's bottom border, not just the
     capped content width (outset is ink overflow: it adds no scroll). */
  border-image: linear-gradient(var(--border), var(--border)) 1 0 0 / 1px 0 0 / 0 100vw;
}
@media (max-width: 1080px) {
  .app-top .top-inner { gap: var(--space-4); }
  .app-top .top-inner > .stage { margin-left: calc(-1 * var(--space-2)); }
  .top-search input[type="search"] { width: 14rem; }
}
/* Phones: search behind a button; every menu opens full width under the bar. */
@media (max-width: 640px) {
  .app-top .app-nav {
    width: calc(100% + 2 * var(--space-5)); margin: 0 calc(-1 * var(--space-5));
    padding: 0 var(--space-2); overflow: visible; flex-wrap: wrap;
  }
  .app-top .app-nav a, .vault-switch > summary { padding: 0 10px; min-height: 44px; }
  .app-top .top-inner { column-gap: var(--space-3); }
  .app-top .top-inner > .stage { margin-left: 0; }
  .top-tools { gap: 0; flex: none; }
  /* Two classes: .button, further down, would otherwise win the padding,
     and the bar needs these narrow to hold the badge and all three
     buttons on one row at 320px. The account button is its avatar alone. */
  .top-tools .icon-button { padding: 0 10px; min-height: 44px; }
  .top-tools .account-button { padding: 0 6px; min-height: 44px; }
  .top-tools .account-button::after { content: none; }
  .top-tools > .top-search { display: none; }
  .search-pop { display: block; }
  .account-name { display: none; }
  .app-top .top-tools > .menu-wrap, .app-top .app-nav > .vault-switch { position: static; }
  .app-top .top-tools > .menu-wrap > .menu {
    left: var(--space-5); right: var(--space-5); top: 50px; width: auto; min-width: 0; max-width: none;
  }
  .app-top .vault-menu { left: var(--space-5); right: var(--space-5); top: calc(100% + 1px); width: auto; min-width: 0; max-width: none; }
}
/* Narrow phones: the badge, the wordmark and three buttons are 296px wide
   with their gaps, and a 320px screen has 288px, so each gives up a little
   rather than the buttons dropping to a second line. The main links do the
   same so "Docs" doesn't sit alone on a second line (a long vault name
   still wraps them, and a wrapped link is still 44px tall). */
@media (max-width: 374px) {
  .app-top .app-nav a, .vault-switch > summary { padding: 0 8px; }
}
@media (max-width: 359px) {
  .top-tools .icon-button { padding: 0 8px; }
  .app-top .top-inner > .stage { padding: 0 6px; }
  .app-top .app-nav { gap: 0; }
  .app-top .app-nav a, .vault-switch > summary { padding: 0 6px; }
}

/* Layout ------------------------------------------------------------------- */

main { flex: 1; width: 100%; max-width: var(--content-max); margin: 0 auto; padding: var(--space-7) var(--space-6) var(--space-10); }
footer {
  border-top: 1px solid var(--border); color: var(--fg-muted); font-size: var(--text-sm);
}
footer {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); justify-content: space-between;
  max-width: var(--content-max); width: 100%; margin: 0 auto; padding: var(--space-6);
}

/* Vault shell: sidebar + content */
.vault { display: grid; grid-template-columns: var(--sidebar-w) minmax(0, 1fr); gap: var(--space-7); align-items: start; }
.content { min-width: 0; }

/* Type ---------------------------------------------------------------------- */

h1 {
  font-size: var(--text-2xl); line-height: var(--lh-2xl); font-weight: 600; letter-spacing: -0.01em;
  margin: 0; text-wrap: balance;
}
h1.path { overflow-wrap: anywhere; }
h2 {
  font-size: var(--text-lg); line-height: var(--lh-lg); font-weight: 600;
  margin: var(--space-8) 0 var(--space-4);
}
/* A short brand rule before the app's section headings, the same red as the
   sidebar's current marker. Not in written content (README, docs, previews)
   or on the public site, whose headings are someone else's text or design. */
main#main:not([class]) h2:not(.prose *)::before {
  content: ""; display: inline-block; width: 12px; height: 3px; margin-right: var(--space-3);
  vertical-align: 0.3em; background: var(--brand);
}
/* Metadata in the mono face: times and numbers in tables. A catalogue's
   index next to the body text, and figures that line up. Not whole
   sentences (a .meta line reads as prose, so it keeps the body face), and
   word gaps tightened, since a mono space is as wide as a letter. */
time, td.num { font-family: var(--font-mono); font-size: 0.92em; letter-spacing: -0.01em; word-spacing: -0.3em; }
.meta time, td.num time { font-size: 1em; }
p { margin: 0 0 var(--space-4); max-width: var(--measure); }
.lede { color: var(--fg-muted); max-width: var(--measure); margin-bottom: var(--space-6); }
.muted { color: var(--fg-muted); }
.small { font-size: var(--text-sm); line-height: var(--lh-sm); }
.meta { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); margin: 0; }
.meta span + span::before { content: "·"; margin: 0 var(--space-3); }

/* Page header ---------------------------------------------------------------- */

.page-head { margin: 0 0 var(--space-6); display: grid; gap: var(--space-3); }
.crumb { font-size: var(--text-sm); line-height: var(--lh-sm); margin: 0; color: var(--fg-muted); overflow-wrap: anywhere; }
.crumb a { color: var(--fg-muted); text-decoration: none; }
.crumb a:hover { color: var(--link); text-decoration: underline; }
.page-title-row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-4) var(--space-6); }
.page-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); min-width: 0; flex: 1 1 20rem; }
.page-title h1 { min-width: 0; }
.page-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.page-head .rule { margin: 0; }
.form-title { margin-top: 0; }

/* Buttons ------------------------------------------------------------------ */

.button, button, .segmented > a {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-3);
  min-height: var(--control-md); padding: 0 14px;
  font: 500 var(--text-sm)/1.2 var(--font-sans); letter-spacing: 0;
  border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  background: var(--bg); color: var(--fg); text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background-color 120ms ease-out, border-color 120ms ease-out, color 120ms ease-out;
}
.button:hover, button:hover, .segmented > a:hover { background: var(--bg-subtle); border-color: var(--fg-muted); }
.button:active, button:active { background: var(--bg-muted); }
button:disabled { opacity: 0.5; cursor: not-allowed; }

.primary, a.button.primary { background: var(--primary-bg); border-color: var(--primary-bg); color: var(--primary-fg); }
.primary:hover, a.button.primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.primary:active { background: var(--primary-hover); }

.danger { color: var(--danger); border-color: var(--danger); }
.danger:hover { background: var(--danger-bg); border-color: var(--danger); }

/* Ghost: Cancel, toolbar actions, the account menu. */
.quiet { background: transparent; border-color: transparent; color: var(--fg-muted); }
.quiet:hover { background: var(--bg-muted); border-color: transparent; color: var(--fg); }

.actions { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; margin: var(--space-5) 0 0; }
.actions form { margin: 0; }

/* Segmented: a row of buttons or links, one current. */
.segmented { display: inline-flex; }
.segmented > a, .segmented > button { border-radius: 0; margin-left: -1px; min-height: var(--control-sm); padding: 0 12px; font-size: 0.8125rem; }
.segmented > :first-child { border-radius: var(--radius-md) 0 0 var(--radius-md); margin-left: 0; }
.segmented > :last-child { border-radius: 0 var(--radius-md) var(--radius-md) 0; }
.segmented > [aria-current="page"], .segmented > [aria-pressed="true"] {
  background: var(--bg-muted); color: var(--fg); font-weight: 600; position: relative; z-index: 1;
}
.segmented > :focus-visible { position: relative; z-index: 2; }

/* Forms --------------------------------------------------------------------- */

form.panel {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--space-5) var(--space-6) var(--space-6); margin: 0 0 var(--space-6); max-width: 80ch;
}
/* A form straight under a table (Rules, Links) is a separate thing, not the table's last row. */
.table-wrap + form.panel { margin-top: var(--space-6); }
label { display: block; font-weight: 600; font-size: var(--text-sm); line-height: var(--lh-sm); margin: var(--space-5) 0 6px; }
form.panel > label:first-of-type, form > label:first-child { margin-top: 0; }
.hint { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); margin: var(--space-2) 0 0; font-weight: 400; }
input[type="text"], input[type="search"], input[type="date"], input[type="number"], textarea, select {
  width: 100%; min-height: var(--control-md);
  font: 400 var(--text-md)/1.4 var(--font-sans); color: var(--fg);
  background: var(--bg); border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  padding: 6px 12px; transition: border-color 120ms ease-out;
}
input::placeholder, textarea::placeholder { color: var(--fg-muted); opacity: 1; }
input[type="text"]:hover, input[type="search"]:hover, input[type="date"]:hover, input[type="number"]:hover, textarea:hover, select:hover { border-color: var(--fg-muted); }
input[type="text"]:focus-visible, input[type="search"]:focus-visible, input[type="date"]:focus-visible, input[type="number"]:focus-visible,
textarea:focus-visible, select:focus-visible { outline: 2px solid var(--link); outline-offset: 0; border-color: var(--link); }
/* The Add a link form's credential is the app's one password input. Its own
   rules, not the list above, which components_unit.test.mjs pins. */
input[type="password"] {
  width: 100%; min-height: var(--control-md);
  font: 400 var(--text-md)/1.4 var(--font-sans); color: var(--fg);
  background: var(--bg); border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  padding: 6px 12px; transition: border-color 120ms ease-out;
}
input[type="password"]:hover { border-color: var(--fg-muted); }
input[type="password"]:focus-visible { outline: 2px solid var(--link); outline-offset: 0; border-color: var(--link); }
/* A locked field (the Rules form's path while changing a rule) must not look editable. */
input[readonly] { background: var(--bg-subtle); }
textarea { min-height: 280px; resize: vertical; line-height: 1.6; padding: 10px 12px; }
textarea.short { min-height: 96px; }
textarea.note-field { min-height: 0; }
select { width: auto; min-width: 10rem; max-width: 100%; padding-right: 32px; }
input.narrow { width: 5rem; }
input[type="radio"], input[type="checkbox"] { accent-color: var(--fg); width: 16px; height: 16px; margin: 0; }

.fields { display: grid; grid-template-columns: minmax(0, 1fr) 10rem 7rem; gap: var(--space-4); align-items: end; }
.fields label { margin-top: 0; }
.fields select { width: 100%; }
/* The Links form's three fields are a name, a URL and a credential, not the
   Rules form's path, policy and approvals: the URL gets the room. */
@media (min-width: 641px) {
  #add-link .fields { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr); }
}
.inline-field { display: flex; gap: var(--space-3); align-items: stretch; }
.inline-field input { flex: 1; }
.result { margin: var(--space-4) 0 0; }

/* Forms with radio or checkbox choices (tokens, new vault) */
:is(.token-form, .choice-form) fieldset { border: 0; padding: 0; margin: var(--space-5) 0 0; min-width: 0; }
:is(.token-form, .choice-form) legend { font-weight: 600; font-size: var(--text-sm); padding: 0; margin-bottom: var(--space-2); }
:is(.token-form, .choice-form) label.choice {
  display: flex; align-items: center; gap: 10px; margin: 0; min-height: 32px;
  font-weight: 400; font-size: var(--text-md); line-height: var(--lh-md); cursor: pointer;
}
.token-form .choice input, .choice-form .choice input { flex: none; }
/* A choice with a sentence after it: the control aligns with the first line. */
.choice-form label.choice { align-items: flex-start; }
.choice-form label.choice input { margin-top: 4px; }
.token-form .choice-list { margin: 0 0 0 7px; padding-left: 18px; border-left: 1px solid var(--border); }
.token-form select.token-expiry { min-width: 12rem; }
@media (max-width: 640px) {
  :is(.token-form, .choice-form) label.choice { min-height: 44px; padding: 10px 0; }
}

/* Callouts ------------------------------------------------------------------ */

.callout {
  display: block; margin: 0 0 var(--space-5);
  padding: var(--space-4) var(--space-5); border: 1px solid; border-radius: var(--radius-lg);
  font-size: var(--text-sm); line-height: var(--lh-sm);
  background: var(--bg-subtle); border-color: var(--border); color: var(--fg);
}
.callout > :last-child { margin-bottom: 0; }
/* A callout spans the content column like the table under it; only its
   text keeps a reading measure. */
.callout p { margin: 0 0 var(--space-3); max-width: var(--measure); }
.callout.info { background: var(--info-bg); border-color: color-mix(in srgb, var(--info) 30%, transparent); }
.callout.success { background: var(--success-bg); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.callout.attention { background: var(--attention-bg); border-color: color-mix(in srgb, var(--attention) 35%, transparent); }
.callout.danger { background: var(--danger-bg); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
.callout.neutral { color: var(--fg-muted); }
.callout form { margin: 0; }
.flash { margin-bottom: var(--space-6); }

/* The one-time token: an attention callout with the secret in a mono field. */
.reveal strong { display: block; font-size: var(--text-md); }
.reveal p { margin: var(--space-2) 0 0; }
.secret {
  font: 500 var(--text-sm)/1.5 var(--font-mono); color: var(--fg);
  word-break: break-all; user-select: all;
  background: var(--bg); padding: 10px 12px; margin-top: var(--space-4) !important;
  border: 1px solid var(--border-strong); border-radius: var(--radius-md);
}

/* Badges -------------------------------------------------------------------- */

.badge {
  display: inline-flex; align-items: center; gap: 6px; vertical-align: middle;
  min-height: 20px; padding: 0 8px; border: 1px solid var(--border); border-radius: var(--radius-full);
  font-size: var(--text-xs); line-height: var(--lh-xs); font-weight: 500; white-space: nowrap;
  background: var(--bg-muted); color: var(--fg-muted);
}
.badge.info, .state.open { background: var(--info-bg); color: var(--info); border-color: color-mix(in srgb, var(--info) 30%, transparent); }
.badge.success, .state.applied { background: var(--success-bg); color: var(--success); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.badge.attention, .state.changes_requested { background: var(--attention-bg); color: var(--attention); border-color: color-mix(in srgb, var(--attention) 35%, transparent); }
.badge.danger { background: var(--danger-bg); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
.page-title .badge { min-height: 24px; font-size: var(--text-sm); }

/* Canon: filled diamond. Open: hollow diamond on an outline badge. */
.policy::before { content: ""; width: 6px; height: 6px; flex: none; transform: rotate(45deg); }
.policy.canon { color: var(--fg); }
.policy.canon::before { background: currentColor; }
.policy.open { background: transparent; border-color: var(--border-strong); }
.policy.open::before { box-shadow: inset 0 0 0 1.25px currentColor; }

/* Boxes: lists and tables ------------------------------------------------- */

.rows {
  list-style: none; margin: 0; padding: 0;
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); overflow: hidden;
}
.rows li {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-5);
  padding: var(--space-4) var(--space-5); min-height: 56px; border-top: 1px solid var(--border);
}
/* The box clips its rows to its rounded corners; while a row's menu is open
   it must not, or the menu is cut to a sliver under the last row. */
.rows:has(.menu-wrap[open]) { overflow: visible; }
.rows li:first-child { border-top: 0; }
.rows li:hover { background: var(--bg-subtle); }
.rows .name { font-weight: 500; color: var(--fg); text-decoration: none; overflow-wrap: anywhere; }
.rows .name:hover { color: var(--link); text-decoration: underline; }
.rows li form { margin: 0; flex: none; }
.rows .row-end { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-3) var(--space-4); flex: none; }
.results li { display: block; }
.rows + p { margin-top: var(--space-4); }
.results .snippet { display: block; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); margin-top: var(--space-2); max-width: var(--measure); }
.results .snippet-line { display: block; overflow-wrap: anywhere; }
.results .line-no { font-family: var(--font-mono); font-size: 0.92em; }
.results mark { background: none; color: var(--fg); font-weight: 600; }
.results .badge { margin-left: var(--space-2); }

/* Positioned, so the visually hidden "Actions" header (position: absolute) is
   clipped here: left to the page it would sit at the table's far edge and
   make the whole page scroll sideways, where the table itself scrolls. */
.table-wrap { overflow-x: auto; position: relative; }
table {
  width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--text-sm); line-height: var(--lh-sm);
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); overflow: hidden;
}
th, td { text-align: left; padding: 10px var(--space-5); border-top: 1px solid var(--border); vertical-align: middle; }
tr:first-child > th, tr:first-child > td { border-top: 0; }
th { font-size: 0.8125rem; font-weight: 600; color: var(--fg-muted); background: var(--bg-subtle); white-space: nowrap; }
td { height: 40px; }
tr:hover > td { background: var(--bg-subtle); }
td a { color: var(--fg); text-decoration: none; font-weight: 500; }
td a:hover { color: var(--link); text-decoration: underline; }
td.num, th.num { text-align: right; }
td form { margin: 0; }
td .button, td button { min-height: var(--control-sm); padding: 0 10px; font-size: 0.8125rem; }
td .quiet { color: var(--fg-muted); }
a.dir { font-weight: 600; }
.prose .table-wrap, .prose table { border: 0; }

.token-list .token-client, .env-log .token-client { display: block; color: var(--fg-muted); }
.token-list tr.inactive td:not(.num) { color: var(--fg-muted); }
/* Members: a role picker in a table cell (Settings, Members). */
.role-form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.role-form select { min-width: 7rem; }

/* Empty states ------------------------------------------------------------- */

.empty {
  border: 1px dashed var(--border-strong); border-radius: var(--radius-lg);
  padding: var(--space-6); text-align: center; color: var(--fg-muted);
  font-size: var(--text-sm); line-height: var(--lh-sm);
}
.empty strong { display: block; color: var(--fg); font-size: var(--text-md); margin-bottom: var(--space-2); }
.empty p { max-width: var(--measure); margin: 0 auto var(--space-4); }
.empty p:last-child { margin-bottom: 0; }
.empty + form.panel { margin-top: var(--space-6); }

/* Tabs ----------------------------------------------------------------------- */

.tabs {
  display: flex; gap: var(--space-2); overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
  box-shadow: inset 0 -1px 0 var(--border); margin: 0 0 var(--space-5);
}
.tabs a {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0 var(--space-4); position: relative;
  color: var(--fg-muted); text-decoration: none; font-size: var(--text-sm); font-weight: 500; white-space: nowrap;
}
.tabs a:hover { color: var(--fg); }
.tabs a[aria-current="page"] { color: var(--fg); font-weight: 600; }
.tabs a[aria-current="page"]::after {
  content: ""; position: absolute; left: var(--space-4); right: var(--space-4); bottom: 0;
  height: 2px; background: var(--brand); border-radius: 2px 2px 0 0;
}
.tabs a:focus-visible { outline-offset: -2px; border-radius: var(--radius-md); }
/* A strip that scrolls sideways with no scrollbar shows no sign there is
   more of it, and the current tab can sit out of sight. Where the tabs
   don't fit on one line they wrap (the page has no script to scroll the
   current one into view), and the current one is filled rather than
   underlined, since a row of underlines under each line would read as
   dividers. 800px is where the Connect page's six client tabs stop fitting. */
@media (max-width: 800px) {
  .tabs { flex-wrap: wrap; box-shadow: none; }
  .tabs a { border-radius: var(--radius-md); }
  .tabs a[aria-current="page"] { background: var(--bg-muted); }
  .tabs a[aria-current="page"]::after { content: none; }
}
@media (max-width: 640px) {
  .tabs a { min-height: var(--control-md); }
}

/* Sidebar --------------------------------------------------------------------- */

.side {
  position: sticky; top: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4);
  font-size: var(--text-sm); line-height: var(--lh-sm);
  background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--space-4); max-height: calc(100vh - 32px); overflow-y: auto;
}
.side-title { font-weight: 600; font-size: var(--text-md); color: var(--fg); text-decoration: none; padding: var(--space-2) var(--space-3) 0; overflow-wrap: anywhere; }
.side-title:hover { color: var(--link); }
/* The search box carries its own button, so nobody has to know Enter
   submits it; the button sits inside the field's right edge. */
.side-search { position: relative; }
.side-search input { width: 100%; min-height: 32px; font-size: var(--text-sm); padding: 4px 36px 4px 10px; }
.side-search button {
  position: absolute; right: 2px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center; width: 28px; height: 28px; padding: 0; border: 0; border-radius: var(--radius-sm, 4px);
  background: transparent; color: var(--fg-muted); cursor: pointer;
}
.side-search button:hover { background: var(--bg-muted); color: var(--fg); }
.side-tree-label { margin: 0 var(--space-3) var(--space-1); }
/* A group's name is a quiet heading, never a target: small, uppercase,
   no padding box, with a rule above every group after the first, so it
   can't be mistaken for a link. The links are the opposite: an icon, a
   full-width hit area, a hover fill, and a filled pill when current. */
.side-group {
  display: block; margin: var(--space-4) var(--space-3) var(--space-1); padding-top: var(--space-3);
  border-top: 1px solid var(--border); color: var(--fg-muted); cursor: default;
  font-size: var(--text-xs); line-height: var(--lh-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
}
.side-group:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.side-links { display: flex; flex-direction: column; gap: 2px; }
.side-links a {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 34px; padding: 0 var(--space-3); border-radius: var(--radius-md); position: relative;
  color: var(--fg-muted); text-decoration: none; font-weight: 500;
  transition: background-color 120ms ease-out, color 120ms ease-out;
}
.side-links a .icon { flex: none; opacity: 0.85; }
.side-links .side-label { flex: 1; }
.side-links a:hover { background: var(--bg-muted); color: var(--fg); }
.side-links a:hover .icon { opacity: 1; }
.side-links a:active { background: var(--border); }
.side-links a:focus-visible { outline-offset: -2px; }
.side-links a[aria-current="page"] {
  background: var(--bg); color: var(--fg); font-weight: 600; box-shadow: 0 0 0 1px var(--border);
}
.side-links a[aria-current="page"] .icon { color: var(--brand-strong); opacity: 1; }
.side-links a[aria-current="page"]::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px; width: 3px; border-radius: 2px; background: var(--brand);
}
.tree { border-top: 1px solid var(--border); padding-top: var(--space-3); }
.tree ul { list-style: none; margin: 0; padding: 0 0 0 14px; }
.tree > ul { padding-left: 0; }
.tree li { margin: 0; }
.tree summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  min-height: 28px; padding: var(--space-2) var(--space-3) var(--space-2) var(--space-2); border-radius: var(--radius-md);
}
.tree summary::-webkit-details-marker { display: none; }
.tree summary::before {
  content: ""; width: 5px; height: 5px; flex: none;
  border-right: 1.5px solid var(--fg-muted); border-bottom: 1.5px solid var(--fg-muted);
  transform: rotate(-45deg); transition: transform 120ms ease-out;
}
.tree details[open] > summary::before { transform: rotate(45deg); }
.tree summary:hover, .tree .leaf:hover { background: var(--bg-muted); }
.tree a { color: var(--fg); text-decoration: none; overflow-wrap: anywhere; flex: 1; }
.tree a:hover { color: var(--link); }
.tree a[aria-current="page"] { font-weight: 600; }
.tree .leaf { display: flex; align-items: center; min-height: 28px; padding: var(--space-2) var(--space-3) var(--space-2) 21px; border-radius: var(--radius-md); }
.tree .leaf:has(a[aria-current="page"]), .tree summary:has(a[aria-current="page"]) { background: var(--bg-muted); }
.tree-empty { padding: 0 var(--space-3); margin: 0; }
/* Folder marks: filled diamond for canon, hollow for open. */
.mark { width: 7px; height: 7px; flex: none; transform: rotate(45deg); }
.mark.canon { background: var(--fg); }
.mark.open { box-shadow: inset 0 0 0 1.25px var(--fg-muted); }
.vault-menu { display: none; }

/* Rule line on file and folder headers */
.rule { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); margin: 0; }
.rule a { color: inherit; }

/* File text and rendered markdown ---------------------------------------------- */

.file {
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg);
  padding: var(--space-5) var(--space-6); margin: 0 0 var(--space-3); max-width: 100%;
  white-space: pre-wrap; word-break: break-word;
  font: 400 var(--text-sm)/1.6 var(--font-mono);
}

.prose {
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg);
  padding: var(--space-6) var(--space-7); line-height: 1.65; overflow-wrap: anywhere;
}
.prose > * { max-width: var(--measure); }
.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }
.prose h1, .prose h2, .prose h3, .prose h4 { color: var(--fg); font-weight: 600; margin: var(--space-7) 0 var(--space-3); }
.prose h1 { font-size: var(--text-2xl); line-height: var(--lh-2xl); letter-spacing: -0.01em; }
.prose h2 { font-size: var(--text-xl); line-height: var(--lh-xl); }
.prose h3, .prose h4 { font-size: var(--text-md); line-height: var(--lh-md); }
.prose p, .prose ul, .prose ol { margin: 0 0 14px; }
.prose ul, .prose ol { padding-left: 1.4em; }
.prose li + li { margin-top: var(--space-2); }
.prose blockquote { margin: 0 0 14px; padding: 0 0 0 var(--space-5); border-left: 1px solid var(--border-strong); color: var(--fg-muted); }
.prose pre { background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5); overflow-x: auto; font-size: var(--text-sm); }
.prose pre code { background: none; padding: 0; font-size: inherit; }
.prose hr { border: 0; border-top: 1px solid var(--border); margin: var(--space-6) 0; }
.prose table { margin: 0 0 14px; border: 1px solid var(--border); }

pre.code {
  background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5); overflow-x: auto; max-width: 80ch; margin: 0 0 var(--space-4);
  font: var(--text-sm)/1.55 var(--font-mono);
}
.endpoint { display: flex; flex-direction: column; gap: var(--space-2); margin: 0 0 var(--space-5); }
.endpoint code { font-size: var(--text-md); padding: 6px 10px; align-self: flex-start; max-width: 100%; }
section { scroll-margin-top: var(--space-5); }

/* Diffs --------------------------------------------------------------------- */

.diff-box { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); margin: 0 0 var(--space-6); overflow: hidden; }
.diff-head {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-5);
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-5);
  background: var(--bg-subtle); border-bottom: 1px solid var(--border);
}
.diff-stat { margin: 0; font-size: var(--text-sm); font-weight: 600; }
.diff-stat .plus { color: var(--success); }
.diff-stat .minus { color: var(--danger); }
.diff-stat .muted { font-weight: 400; }
.diff-note { padding: var(--space-4) var(--space-5) 0; margin: 0; font-size: var(--text-sm); }
.diff-box > .file { border: 0; border-radius: 0; margin: 0; }

.diff { font: 400 0.8125rem/18px var(--font-mono); padding: var(--space-2) 0; }
.diff.unified > div, .diff.unified .fold > div { display: grid; grid-template-columns: 3rem 3rem 1.25rem minmax(0, 1fr); padding: 3px 0; }
.diff.unified > div > span:last-child, .diff.unified .fold > div > span:last-child { grid-column: 4; white-space: pre-wrap; word-break: break-word; padding-right: var(--space-5); }
.diff.unified > div::before, .diff.unified .fold > div::before { grid-column: 3; grid-row: 1; text-align: center; color: var(--fg-muted); }
.diff .ln { text-align: right; padding-right: var(--space-3); color: var(--fg-muted); user-select: none; }
.diff.unified .ln:nth-child(1) { grid-column: 1; grid-row: 1; }
.diff.unified .ln:nth-child(2) { grid-column: 2; grid-row: 1; }
.diff .add { background: var(--diff-add); }
.diff .add::before { content: "+"; }
.diff .del { background: var(--diff-del); }
.diff .del::before { content: "\2212"; }
.diff .same::before { content: ""; }
.diff ins { background: var(--diff-add-word); color: var(--diff-word-fg); text-decoration: none; border-radius: 2px; }
.diff del { background: var(--diff-del-word); color: var(--diff-word-fg); text-decoration: line-through; text-decoration-color: var(--danger); border-radius: 2px; }

/* Folded unchanged lines: a strip that opens in place. */
.diff .fold > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; min-height: 28px;
  padding: 0 var(--space-5) 0 calc(6rem + 1.25rem);
  background: var(--bg-subtle); color: var(--fg-muted); font: 500 0.8125rem/1.2 var(--font-sans);
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.diff .fold > summary::-webkit-details-marker { display: none; }
.diff .fold > summary::before { content: "Show "; white-space: pre; }
.diff .fold[open] > summary::before { content: "Hide "; }
.diff .fold > summary:hover { color: var(--fg); }

/* Split: current left, proposed right. It scrolls inside its own box on a
   narrow screen, so the page never scrolls sideways. */
.split-scroll { overflow-x: auto; }
.diff.split { min-width: 36rem; padding-top: 0; }
.diff.split .row { display: grid; grid-template-columns: 3rem minmax(0, 1fr) 3rem minmax(0, 1fr); }
.diff.split .row > span:not(.ln) { padding: 3px var(--space-4) 3px var(--space-2); white-space: pre-wrap; word-break: break-word; }
.diff.split .row > .ln { padding-top: 3px; padding-bottom: 3px; }
.diff.split .row > .ln + span + .ln { box-shadow: inset 1px 0 0 var(--border); }
.diff.split .add::before, .diff.split .del::before { margin-right: var(--space-3); color: var(--fg-muted); }
.diff.split .none { background: var(--bg-subtle); }
.diff.split .head > span {
  font: 600 var(--text-sm)/1.2 var(--font-sans); color: var(--fg-muted);
  padding: var(--space-3) var(--space-4) var(--space-3) var(--space-2); border-bottom: 1px solid var(--border);
}

/* Rendered: proposed and current as they'll read, side by side when there's
   room (current left, like the split), stacked with the proposal first. */
.rendered { display: grid; gap: var(--space-5) var(--space-6); padding: var(--space-5); }
.rendered .current, .rendered .proposed { min-width: 0; }
.pane-label { font-size: var(--text-sm); line-height: var(--lh-sm); font-weight: 600; color: var(--fg-muted); margin: 0 0 var(--space-3); }
.rendered .prose { padding: var(--space-5) var(--space-6); }
@media (min-width: 1000px) {
  .rendered { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .rendered .current { grid-column: 1; grid-row: 1; }
  .rendered .proposed { grid-column: 2; grid-row: 1; }
}

/* Proposal page ------------------------------------------------------------- */

/* Above the diff, one status strip: each message a ruled row of one box,
   keeping its tone's mark, instead of a stack of separate boxes. */
.review-top { margin: 0 0 var(--space-6); border: 1px solid var(--border); background: var(--bg); }
.review-top:not(:has(> *)) { display: none; }
.review-top > * { margin: 0; border: 0; border-radius: 0; max-width: none; }
.review-top > * + * { border-top: 1px solid var(--border); }
.review-top > :not(.callout):not(.feedback) { padding: var(--space-3) var(--space-5); }
.review-top > .callout p { max-width: none; }
/* The decision beside the diff when there's room; above it otherwise. */
@media (min-width: 1100px) {
  .review-layout:has(> .review-side) { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--space-6); align-items: start; }
  .review-layout > .review-side { grid-column: 2; grid-row: 1; position: sticky; top: var(--space-4); }
  .review-layout > .review-body { grid-column: 1; grid-row: 1; min-width: 0; }
}
.review-side { margin: 0 0 var(--space-6); }
.review-body > :first-child { margin-top: 0; }
.risks { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-3); }
.risks .badge { min-height: 24px; font-size: var(--text-sm); }

.feedback {
  padding: var(--space-4) var(--space-5); border-radius: var(--radius-lg);
  background: var(--attention-bg); border: 1px solid color-mix(in srgb, var(--attention) 35%, transparent);
}
.feedback h2 { font-size: var(--text-md); line-height: var(--lh-md); margin: 0; }
.feedback p { margin: 0 0 var(--space-3); }
.feedback blockquote.claim { background: var(--bg); }

/* The decision: compact and always open. */
form.decide { margin: 0; padding: var(--space-4) var(--space-5); background: var(--bg-subtle); }
form.decide label { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); }
form.decide .actions { margin-top: var(--space-4); }

blockquote.claim {
  margin: 0; padding: var(--space-4) var(--space-5); max-width: 80ch; white-space: pre-wrap;
  background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-lg);
}

/* Discussion: comments, review notes and approvals in one timeline. Entries
   an agent wrote sit on a tinted ground, so a reader always knows which
   words came from a model; the meta line names the agent. */
.discussion { max-width: 80ch; }
.notes { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; }
.notes li { padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border); }
.notes li:first-child { border-top: 0; }
.notes li p { margin: 0; white-space: pre-wrap; }
.notes li p + p { margin-top: var(--space-2); }
.thread li.by-agent { background: var(--bg-subtle); }
form.comment { margin-top: var(--space-5); }
form.comment .actions { margin-top: var(--space-4); }

/* Review rows (reviewItem in html.ts): proposals and threads alike. The path
   is a mono chip, not a link: the title is the row's one link. A resolved
   thread's title is quieter, and its state is always a word beside it. */
.rows .review-main { min-width: 0; }
.rows .review-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); margin-top: var(--space-1); }
.path-chip {
  display: inline-block; padding: 0 var(--space-2); border: 1px solid var(--border); border-radius: var(--radius-full);
  background: var(--bg-subtle); color: var(--fg); font: 400 var(--text-xs)/1.7 var(--font-mono); overflow-wrap: anywhere;
}
.rows li.is-resolved .name { color: var(--fg-muted); }
/* One thread (threadview.ts): a message's text keeps its line breaks and breaks long words. */
.thread li p { overflow-wrap: anywhere; }
.page-actions .inline-form { margin: 0; }
.redacted { font-style: italic; }

/* Snooze: a quiet row of small buttons. */
.snooze, .snoozed-note {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  margin: 0; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm);
}
.snooze span, .snoozed-note span { margin-right: var(--space-2); }
.snooze button, .snoozed-note button { min-height: var(--control-sm); padding: 0 10px; font-size: 0.8125rem; }
.snooze .hint { flex-basis: 100%; margin: 0; }
.snooze-toggle { margin: var(--space-5) 0 0; }
/* Review rows: one "Snooze" menu per row. */
.row-snooze-menu > summary { min-height: var(--control-sm); padding: 0 10px; font-size: 0.8125rem; gap: var(--space-2); }
.rows form.row-snooze { min-width: 200px; gap: var(--space-2); padding: var(--space-3); }
.rows form.row-snooze button { justify-content: flex-start; width: 100%; border-color: transparent; background: transparent; }
.rows form.row-snooze button:hover { background: var(--bg-muted); }
.rows form.row-snooze .menu-label { padding: 0 14px var(--space-2); color: var(--fg-muted); font-weight: 500; }
/* Risk badge in a row: the first reason, the rest in its title. */
.risk-count { max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The three snooze choices read as one segmented control. */
.snooze { column-gap: 0; }
.snooze > span { margin-right: var(--space-3); }
.snooze > button { border-color: var(--border); border-radius: 0; margin-left: -1px; }
.snooze > button:hover { border-color: var(--border); position: relative; }
.snooze > button:focus-visible { position: relative; z-index: 1; }
.snooze > span + button { border-radius: var(--radius-md) 0 0 var(--radius-md); margin-left: 0; }
.snooze > button:last-of-type { border-radius: 0 var(--radius-md) var(--radius-md) 0; }

/* Edit page: a delete section set apart. */
.danger-zone {
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5); max-width: 80ch;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-5);
}
.danger-zone p { margin: 0; }

/* A page header's "More" menu: rare or destructive actions, as links. */
.more-menu .menu { min-width: 200px; padding: var(--space-2); gap: var(--space-1); }
.more-menu .menu a {
  display: flex; align-items: center; min-height: var(--control-sm); padding: 0 12px;
  border-radius: var(--radius-md); text-decoration: none;
}
.more-menu .menu a:hover { background: var(--bg-muted); }
.more-menu .menu a.danger { color: var(--danger); }
.more-menu .menu a.danger:hover { background: var(--danger-bg); }

/* Activity ------------------------------------------------------------------- */

form.filters { max-width: none; background: var(--bg-subtle); padding: var(--space-4) var(--space-5); }
.filter-fields { display: grid; grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr)); gap: var(--space-4); }
.filter-fields label { margin: 0 0 6px; }
.filter-fields > div { min-width: 0; }
.filter-fields select { width: 100%; min-width: 0; }
.filters .actions { margin-top: var(--space-4); }
table.activity .num:first-child { color: var(--fg-muted); }
table.activity .nowrap { white-space: nowrap; }
table.activity .path-cell { overflow-wrap: anywhere; }
.pager { display: flex; justify-content: space-between; gap: var(--space-6); padding: var(--space-5) 0; font-weight: 500; font-size: var(--text-sm); }
.pager .older { margin-left: auto; }

/* Variables ------------------------------------------------------------------ */

/* A column per environment where there's room; where there isn't (a phone,
   or a narrow content column beside the sidebar), one block per variable
   with a labelled line per environment. No horizontal scroll either way. */
.vars-wrap { container: vars / inline-size; margin: 0 0 var(--space-6); }
table.vars { table-layout: fixed; }
table.vars th[scope="row"] { background: transparent; font-weight: 500; color: var(--fg); white-space: normal; vertical-align: top; }
table.vars th[scope="row"] code { overflow-wrap: anywhere; font-size: var(--text-sm); color: var(--fg); }
table.vars td { vertical-align: top; }
table.vars tbody tr:hover > td { background: transparent; }
@container vars (max-width: 44rem) {
  table.vars, table.vars tbody, table.vars tr, table.vars th, table.vars td { display: block; }
  table.vars thead { display: none; }
  table.vars tr + tr { border-top: 1px solid var(--border); }
  table.vars th[scope="row"] { background: var(--bg-subtle); border-top: 0; }
  table.vars td {
    height: auto; border-top: 1px solid var(--border);
    display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); column-gap: var(--space-4); align-items: start;
  }
  table.vars td::before { content: attr(data-label); font-size: 0.8125rem; font-weight: 600; color: var(--fg-muted); }
  table.vars tr > td:first-child { border-top: 0; }
  table.env-log td:first-child { background: var(--bg-subtle); font-weight: 500; }
}
@container vars (max-width: 26rem) {
  table.vars td { grid-template-columns: minmax(0, 1fr); }
  table.env-log td { grid-template-columns: 5rem minmax(0, 1fr); }
}

.var-set { font-weight: 600; font-size: var(--text-sm); }
.var-readers { display: block; color: var(--fg-muted); margin-top: var(--space-1); }
.var-readers a { color: var(--link); text-decoration: underline; font-weight: 400; }
.var-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.var-actions form { margin: 0; }
table.env-log td:nth-child(2) { min-width: 7rem; }
table.env-log tr.refused td { background: color-mix(in srgb, var(--danger-bg) 50%, transparent); }
.var-caveats { list-style: none; padding: 0; margin: var(--space-5) 0 0; display: grid; gap: var(--space-3); max-width: var(--measure); }
.var-caveats strong { color: var(--fg); }
pre.secret { white-space: pre-wrap; overflow-wrap: anywhere; margin-bottom: 0; }
textarea.secret-input { font-family: var(--font-mono); font-size: var(--text-sm); }

/* Small screens ---------------------------------------------------------------- */

@media (max-width: 900px) {
  .vault { grid-template-columns: 208px minmax(0, 1fr); gap: var(--space-6); }
}

@media (max-width: 767px) {
  .vault { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
  .side { display: none; }
  /* One menu names the section you're in; open, it is the sidebar. */
  .vault-menu { display: block; }
  .vault-menu > summary {
    display: flex; align-items: center; gap: var(--space-3); list-style: none; cursor: pointer;
    min-height: var(--control-md); padding: 0 14px; font-size: var(--text-sm); font-weight: 600;
    border: 1px solid var(--border-strong); border-radius: var(--radius-md); background: var(--bg);
  }
  .vault-menu > summary::-webkit-details-marker { display: none; }
  .vault-menu > summary .side-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .vault-menu > summary::after {
    content: ""; width: 6px; height: 6px; margin-top: -3px;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
  }
  .vault-menu[open] > summary::after { margin-top: 3px; transform: rotate(-135deg); }
  .vault-menu .side-links, .vault-menu .tree {
    background: var(--bg-subtle); border: 1px solid var(--border); border-top: 0; padding: var(--space-3);
  }
  .vault-menu .side-links a, .vault-menu .tree summary, .vault-menu .tree .leaf { min-height: 44px; }
  .vault-menu .tree summary, .vault-menu .tree .leaf { padding-top: 0; padding-bottom: 0; }
  .vault-menu .tree a { align-self: stretch; display: flex; align-items: center; }
}

@media (max-width: 640px) {
  .top-inner { flex-wrap: wrap; column-gap: var(--space-5); row-gap: 0; padding: 0 var(--space-5); }
  .wordmark { min-height: 52px; }
  .top nav {
    order: 3; width: calc(100% + 2 * var(--space-5)); margin: 0 calc(-1 * var(--space-5));
    padding: 0 var(--space-3); overflow-x: auto; scrollbar-width: none;
    border-top: 1px solid var(--border); min-height: 44px;
  }
  .top nav::-webkit-scrollbar { display: none; }
  main { padding: var(--space-5) var(--space-5) var(--space-9); }
  footer { padding: var(--space-5); }
  h2 { margin-top: var(--space-7); }
  .fields { grid-template-columns: minmax(0, 1fr); }
  .fields select { width: 100%; }
  .rows li { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
  .rows .row-end { justify-content: flex-start; }
  /* Rows stack here, so the snooze menu opens under the row, full width. */
  .rows li:has(.row-snooze-menu) { position: relative; }
  .row-snooze-menu { position: static; }
  .rows form.row-snooze { left: var(--space-4); right: var(--space-4); top: calc(100% - 4px); width: auto; min-width: 0; }
  .hide-sm { display: none; }
  th, td { padding: 10px var(--space-3); }
  th { white-space: normal; }
  .prose { padding: var(--space-5); }
  .rendered { padding: var(--space-3); }
  .rendered .prose { padding: var(--space-4); }
  form.panel { padding: var(--space-4); }
  .inline-field { flex-direction: column; }
  .inline-field button { align-self: flex-start; }
  .filter-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  table.activity, table.token-list { min-width: 34rem; }
  /* Wide tables scroll edge to edge, starting in line with the text. */
  .table-wrap { margin: 0 calc(-1 * var(--space-5)); padding: 0 var(--space-5); }
  .split-scroll { overscroll-behavior-x: contain; }
  .diff.unified > div, .diff.unified .fold > div { grid-template-columns: 2.5rem 2.5rem 1rem minmax(0, 1fr); }
  .diff .fold > summary { padding-left: 6rem; }
  .snooze > span { flex-basis: 100%; }
  .snooze > span + button { margin-left: 0; }
}

/* Components (package A: html.ts time, crumb, tabs, pageHeader, flash,
   callout, policyBadge, menu, emptyState, confirmPage; .table-stack). Shared
   by every page; page CSS goes in its package's section further down. ---- */

/* Figures line up only where numbers are compared: tables, counts, times,
   diff stats. Elsewhere Inter's tabular hyphen would put a wide gap in
   "read-only" or "Alpha". */
td, th, .num, time, .count, .diff-stat, .meter { font-variant-numeric: tabular-nums; }
time { white-space: nowrap; }

/* Breadcrumb: vault / folder / … / this page, the last not a link. */
.crumb ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: baseline; }
.crumb li { min-width: 0; }
.crumb li + li::before { content: "/"; margin: 0 var(--space-3); color: var(--border-strong); }
.crumb li[aria-current="page"] { color: var(--fg); }
.crumb a { display: inline-block; padding: 2px 0; }
/* On a phone the breadcrumb links and the stage badge are 20 to 24px tall.
   Growing them would push every page header down, so only the part that
   takes a tap grows, past the box. */
@media (max-width: 640px) {
  .crumb a, .stage { position: relative; }
  .crumb a::after { content: ""; position: absolute; inset: -12px -6px; }
  .stage::after { content: ""; position: absolute; inset: -11px -4px; }
}

/* Page header: a one-sentence description, and tabs flush under it. */
.page-desc { margin: 0; color: var(--fg-muted); max-width: var(--measure); }
.page-head.has-tabs { gap: var(--space-3); }
.page-head > .tabs { margin: var(--space-2) 0 0; }
.tabs .count { margin-left: 6px; min-width: 18px; height: 18px; padding: 0 5px; font-weight: 500; }
.tabs a[aria-current="page"] .count { background: var(--fg); color: var(--bg); }

/* The flash sits right under the page header, in the content column. */
.page-head + .flash { margin-top: calc(-1 * var(--space-2)); }
.flash { overflow-wrap: anywhere; }
.callout-title { margin: 0 0 var(--space-2); }
.callout.warning { background: var(--attention-bg); border-color: color-mix(in srgb, var(--attention) 35%, transparent); }
.badge.warning { background: var(--attention-bg); color: var(--attention); border-color: color-mix(in srgb, var(--attention) 35%, transparent); }
/* A tone mark before the text, so the tone never rests on colour alone. */
.callout.success, .callout.warning, .callout.attention, .callout.danger { position: relative; padding-left: calc(var(--space-5) + 14px); }
.callout.success::before, .callout.warning::before, .callout.attention::before, .callout.danger::before {
  content: ""; position: absolute; left: var(--space-5); top: calc(var(--space-4) + 6px);
  width: 7px; height: 7px; transform: rotate(45deg);
}
.callout.success::before { background: var(--success); }
.callout.warning::before, .callout.attention::before { background: var(--attention); }
.callout.danger::before { box-shadow: inset 0 0 0 2px var(--danger); }

/* Buttons: primary (one per page, last), secondary (the default look),
   ghost (.ghost or .quiet: Cancel, toolbar, menus), danger (outlined; the
   confirm page's final step is .danger.solid, filled). */
.secondary { background: var(--bg); border-color: var(--border-strong); color: var(--fg); }
.ghost { background: transparent; border-color: transparent; color: var(--fg-muted); }
.ghost:hover { background: var(--bg-muted); border-color: transparent; color: var(--fg); }
td .quiet:hover, td .ghost:hover { background: var(--bg-muted); color: var(--fg); }
.danger.solid { background: var(--danger); border-color: var(--danger); color: var(--bg); }
.danger.solid:hover { background: color-mix(in srgb, var(--danger) 85%, var(--fg)); border-color: color-mix(in srgb, var(--danger) 85%, var(--fg)); }

/* Action menus (html.ts menu()): a button that opens a list of links and
   one-button forms. */
.action-menu { display: inline-block; }
.action-menu > summary { cursor: pointer; }
.action-list { min-width: 220px; padding: var(--space-2); gap: var(--space-1); }
.action-list.menu-left { left: 0; right: auto; }
.action-list > .menu-label { margin: var(--space-2) var(--space-3) 0; color: var(--fg-muted); }
.action-list .menu-list { margin: 0; }
.action-list form { margin: 0; }
.action-list .menu-item {
  display: grid; gap: 1px; justify-items: start; width: 100%; min-height: var(--control-sm);
  padding: 6px var(--space-3); border: 0; border-radius: var(--radius-md); background: transparent;
  color: var(--fg); font: 400 var(--text-sm)/var(--lh-sm) var(--font-sans); text-align: left; text-decoration: none; white-space: normal;
}
.action-list .menu-item:hover { background: var(--bg-muted); }
.action-list .menu-item:focus-visible { outline-offset: -2px; }
.action-list .menu-item.danger { color: var(--danger); }
.action-list .menu-item.danger:hover { background: var(--danger-bg); }
.action-list .menu-item.danger .menu-item-meta { color: var(--fg-muted); }

/* Empty state's action, and the confirm page. */
.empty-action { margin-top: var(--space-4) !important; }
.consequences { max-width: var(--measure); margin: 0 0 var(--space-5); padding-left: 1.25em; }
.consequences li + li { margin-top: var(--space-2); }
form.confirm { max-width: 40rem; }
form.confirm .actions:first-child { margin-top: 0; }

/* Tables that stack on a phone: each row a block, each cell a line with its
   column's name (data-label on the td) instead of a sideways scroll. */
@media (max-width: 640px) {
  table.table-stack { min-width: 0; }
  .table-wrap:has(> table.table-stack) { margin: 0; padding: 0; overflow: visible; }
  .table-stack, .table-stack tbody, .table-stack tr, .table-stack th, .table-stack td { display: block; }
  .table-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .table-stack tr { padding: var(--space-3) 0; border-top: 1px solid var(--border); }
  .table-stack tbody tr:first-child { border-top: 0; }
  .table-stack td, .table-stack tbody th {
    height: auto; border-top: 0; padding: var(--space-1) var(--space-4);
    display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); column-gap: var(--space-4); align-items: baseline;
    text-align: left; overflow-wrap: anywhere;
  }
  .table-stack td::before, .table-stack tbody th::before { content: attr(data-label); font-size: 0.8125rem; font-weight: 600; color: var(--fg-muted); }
  .table-stack td:not([data-label]), .table-stack td[data-label=""] { grid-template-columns: minmax(0, 1fr); }
  .table-stack td:not([data-label])::before, .table-stack td[data-label=""]::before { content: none; }
  .table-stack tr:hover > td { background: transparent; }
}

/* Tasks (tasks.ts): compact rows, Todoist-style. The state word, the title
   and who holds it on one line, the row's ⋯ menu pushed to the end, then a
   quiet line under it. Plans are cards with a bar (a <progress>, since the
   CSP allows no inline width). */
.task-list { list-style: none; margin: 0 0 var(--space-6); padding: 0; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); overflow: hidden; }
.task-row { padding: var(--space-3) var(--space-4); transition: background-color 120ms ease-out; }
.task-row + .task-row { border-top: 1px solid var(--border); }
.task-row:hover { background: var(--bg-subtle); }
/* The state as a shape, Todoist's circle: a ring when it can be picked up,
   half filled while someone has it, a ring with a dot while it waits for
   a person's review, dashed while it waits, filled with a
   tick when done, struck through when cancelled. The word beside it is
   the state; the shape only lets the eye scan a long list. */
.task-dot {
  flex: none; position: relative; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--border-strong); box-sizing: border-box;
}
.task-dot.ready { border-color: var(--success); }
.task-dot.claimed { border-color: var(--info); background: linear-gradient(90deg, var(--info) 50%, transparent 50%); }
.task-dot.awaiting_review { border-color: var(--attention); }
.task-dot.awaiting_review::after { content: ""; position: absolute; inset: 3px; border-radius: 50%; background: var(--attention); }
.task-dot.blocked { border-style: dashed; border-color: var(--attention); }
.task-dot.blocked_by_cancelled { border-style: dashed; border-color: var(--danger); }
.task-dot.done { border-color: var(--success); background: var(--success); }
.task-dot.done::after {
  content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
  border: solid var(--bg); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.task-dot.cancelled::after { content: ""; position: absolute; left: -2px; right: -2px; top: 5px; height: 2px; background: var(--border-strong); transform: rotate(-45deg); }
.task-row:has(.task-dot.done) .task-title, .task-row:has(.task-dot.cancelled) .task-title { color: var(--fg-muted); }
.task-row:has(.task-dot.cancelled) .task-title { text-decoration: line-through; }
.task-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.task-line .badge { white-space: normal; padding-block: 2px; }
.task-title { font-weight: 500; overflow-wrap: anywhere; }
.task-line > :is(.action-menu, .button) { margin-left: auto; }
.task-holder { color: var(--fg); }
/* Only the two top priorities and a passed due date take colour, so a
   colour on the line always means look here. */
.task-prio { font-weight: 600; }
.task-prio.p1 { color: var(--danger); }
.task-prio.p2 { color: var(--attention); }
.task-due.overdue { color: var(--danger); font-weight: 500; }
.task-meta { margin: var(--space-2) 0 0; max-width: none; color: var(--fg-muted); font-size: var(--text-sm); overflow-wrap: break-word; }
.task-done > summary { cursor: pointer; }
.task-done > summary h2 { display: inline; }
.plan-cards { list-style: none; margin: 0 0 var(--space-6); padding: 0; display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
.plan-card { position: relative; padding: var(--space-5); border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); transition: border-color 120ms ease-out; }
.plan-card:hover { border-color: var(--border-strong); }
.plan-card h3 { margin: 0; overflow-wrap: anywhere; }
.plan-card p { margin: var(--space-2) 0 0; overflow-wrap: anywhere; }
.task-progress {
  display: block; width: 100%; height: 6px; margin: var(--space-4) 0 0;
  -webkit-appearance: none; appearance: none; border: 0; border-radius: var(--radius-full); background: var(--bg-muted); overflow: hidden;
}
.task-progress::-webkit-progress-bar { background: var(--bg-muted); border-radius: var(--radius-full); }
.task-progress::-webkit-progress-value { background: var(--success); border-radius: var(--radius-full); }
.task-progress::-moz-progress-bar { background: var(--success); border-radius: var(--radius-full); }

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

/* Public site: landing and legal pages (web/src/site.ts, landing.ts, legal.ts).
   Mobile first; the same tokens, header and buttons as the app. -------------- */

.footer-links { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); }
.footer-links a, .site-footer > a { display: inline-block; padding: var(--space-1) 0; }
footer a { color: var(--fg-muted); }
footer a:hover { color: var(--link); }
.footer-version { display: inline-block; padding: var(--space-1) 0; font-variant-numeric: tabular-nums; }
/* The links are 20px tall otherwise, and a phone's footer is five of them. */
@media (max-width: 640px) {
  .footer-links { row-gap: 0; }
  .footer-links a, .site-footer > a, .footer-version { display: inline-flex; align-items: center; min-height: 44px; padding: 0; }
}

/* Reading copy, not tables: proportional figures and punctuation. */
body.site { font-variant-numeric: normal; }
.wordmark-by { color: var(--fg-muted); font-weight: 400; margin-left: -4px; }
.site-signin { margin-left: auto; flex: none; }
.site-main { padding-top: var(--space-8); }
.site-footer { align-items: center; }
.site-footer-brand { display: inline-flex; align-items: center; gap: 10px; color: var(--fg); font-weight: 500; }

.site-cta { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.site-cta .button { min-height: 44px; padding: 0 20px; font-size: var(--text-md); }

.hero-card {
  margin: 0; padding: var(--space-5); display: grid; gap: var(--space-4);
  background: var(--bg); border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
}
.hero-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.hero-card-path { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; }
.hero-card-meta { margin: 0; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.hero-card-meta strong { color: var(--fg); }
.hero-diff {
  border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden;
  font: 400 var(--text-sm)/1.7 var(--font-mono);
}
.hero-diff > div { padding: 6px var(--space-4); overflow-wrap: anywhere; }
.hero-diff span { display: inline-block; width: 1.5ch; color: var(--fg-muted); }
.hero-diff .del { background: var(--diff-del); }
.hero-diff .add { background: var(--diff-add); }
.hero-card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: 0; padding: 0; border: 0; }
.hero-card-actions label { cursor: pointer; }
/* The ring goes on the group, not the label: the checked radio's label may
   be hidden in the state it just chose, and the group is always there. */
.hero-card-actions:has(> input:focus-visible) { outline: 2px solid var(--link); outline-offset: 4px; border-radius: var(--radius-md); }
.hero-reset { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); text-decoration: underline; text-underline-offset: 0.2em; }
.hero-card figcaption { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); border-top: 1px solid var(--border); padding-top: var(--space-4); }
/* The card's three states (landing.ts, proposalCard): the checked radio
   decides which data-when parts show. Open is the default, and what a
   browser without :has() shows. revert = the element's own display, so
   the wrapped badges and buttons keep their inline-flex. */
.hero-card [data-when] { display: none; }
.hero-card [data-when~="open"] { display: revert; }
.hero-card:has([value="approve"]:checked) [data-when] { display: none; }
.hero-card:has([value="approve"]:checked) [data-when~="approved"] { display: revert; }
.hero-card:has([value="changes"]:checked) [data-when] { display: none; }
.hero-card:has([value="changes"]:checked) [data-when~="changes"] { display: revert; }
.hero-canon > div { background: var(--bg-subtle); }
.hero-log { margin: 0; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.hero-log strong { color: var(--fg); }
.hero-note label { display: block; margin: 0 0 var(--space-2); font-size: var(--text-sm); line-height: var(--lh-sm); font-weight: 600; }
.hero-note textarea { width: 100%; resize: vertical; }
.hero-canon, .hero-log, .hero-note { animation: demo-in 200ms ease-out; }
@keyframes demo-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .hero-canon, .hero-log, .hero-note { animation: none; } }
/* A secret's value is a row of filled diamonds: a value nobody reads. */
.term { margin: var(--space-4) 0 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg); font: 400 var(--text-sm)/1.7 var(--font-mono); white-space: pre-wrap; overflow-wrap: anywhere; }
.term-muted { color: var(--fg-muted); }
.term-value { color: var(--brand); letter-spacing: 0.1em; }

.who-builds { margin: var(--space-7) 0 0; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); max-width: 60ch; }

/* Pricing */
.tier-for { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); margin: 0 0 var(--space-5); }
.tier-price { margin: 0; }
.tier-price .amount { font-size: var(--text-2xl); line-height: var(--lh-2xl); font-weight: 600; letter-spacing: -0.01em; }
.tier-price .per, .tier-yearly { color: var(--fg-muted); font-size: var(--text-sm); }
.tier-yearly { margin: 0 0 var(--space-5); line-height: var(--lh-sm); }
/* FAQ */
.faq { max-width: 48rem; border-top: 1px solid var(--border); }
.faq details { border-bottom: 1px solid var(--border); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-5);
  min-height: 52px; padding: var(--space-3) 0; cursor: pointer; list-style: none; font-weight: 600;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 8px; height: 8px; margin-right: 4px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
}
.faq details[open] > summary::after { transform: rotate(225deg); margin-top: 6px; }
.faq details p { color: var(--fg-muted); margin: 0 0 var(--space-5); }

/* Legal pages */
.legal { max-width: 46rem; }
.legal .crumb { margin-bottom: var(--space-3); }
.legal h1 { font-size: clamp(1.5rem, 1.2rem + 1.5vw, 2rem); line-height: 1.2; margin-bottom: var(--space-5); }

.legal h2 { margin: var(--space-8) 0 var(--space-3); }
.legal ul { padding-left: 1.25em; margin: 0 0 var(--space-4); max-width: var(--measure); }
.legal li + li { margin-top: var(--space-2); }
.legal .table-wrap { margin-bottom: var(--space-4); }
.legal th[scope="row"] { white-space: normal; width: 11rem; vertical-align: top; }
.legal td { vertical-align: top; height: auto; }
.legal td a { color: var(--link); text-decoration: underline; font-weight: 400; }
.legal .caveats li { margin-top: var(--space-3); }
mark.placeholder { background: none; color: var(--attention); font-weight: 500; text-decoration: underline dashed; text-underline-offset: 0.2em; }

@media (max-width: 640px) {
  .site-main { padding-top: var(--space-6); }
  .wordmark-by { display: none; }
  .legal th[scope="row"] { width: 7rem; }
  /* The sub-processor table stacks: one bordered block per provider. */
  .legal .table-wrap:has(> .subprocessors) { margin: 0 0 var(--space-4); padding: 0; }
  table.subprocessors, .subprocessors tbody, .subprocessors tr, .subprocessors td { display: block; }
  table.subprocessors { border: 0; background: none; }
  .subprocessors thead { display: none; }
  .subprocessors tr { border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-4); margin-bottom: var(--space-4); }
  .subprocessors td { border: 0; padding: var(--space-2) 0; }
  .subprocessors td[data-label]::before { content: attr(data-label); display: block; font-size: var(--text-xs); font-weight: 600; color: var(--fg-muted); }
  .subprocessors tr:hover > td { background: none; }
}

/* Stage: the alpha badge in every top bar, and its sentence (html.ts). */
.stage {
  display: inline-flex; align-items: center; flex: none; min-height: 22px; padding: 0 8px;
  border: 1px solid color-mix(in srgb, var(--attention) 35%, transparent); border-radius: var(--radius-full);
  background: var(--attention-bg); color: var(--attention);
  font-size: var(--text-xs); line-height: var(--lh-xs); font-weight: 600; text-decoration: none; white-space: nowrap;
}
.top-inner .stage { margin-left: calc(-1 * var(--space-5)); }
.stage:hover { text-decoration: underline; }
.alpha-note { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); margin: var(--space-3) 0 0; }
.alpha-note strong { color: var(--attention); }
.menu-links { display: flex; gap: var(--space-5); margin: 0; font-size: var(--text-sm); }

/* The site menu: below 960px the site's links move into a drawer, a
   <details> (site.ts), instead of wrapping into rows under the header. Open,
   its summary's ::before dims the page and covers it, so a tap outside the
   panel lands on the summary and closes it. The landing's band sets its own
   colours. */
.site-menu { display: none; --menu-bg: var(--bg); --menu-fg: var(--fg); --menu-muted: var(--fg-muted); --menu-line: var(--border); }
.p-inv .site-menu { --menu-bg: var(--ib); --menu-fg: var(--if); --menu-muted: var(--ifm); --menu-line: var(--ibd); }
@media (max-width: 960px) {
  .top-inner > nav[aria-label="Site"], .p-top > nav[aria-label="Site"] { display: none; }
  .site-menu { display: block; flex: none; margin-left: auto; }
  .site-menu + .site-signin { display: none; }
  .top-inner, .p-top { position: relative; }
}
.site-menu > summary {
  position: relative; z-index: 41; list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px;
  color: var(--menu-fg); font-size: var(--text-sm); font-weight: 600; border-radius: var(--radius-md);
}
.site-menu > summary::-webkit-details-marker { display: none; }
.site-menu > summary:hover { background: color-mix(in srgb, var(--menu-fg) 8%, transparent); }
.site-menu-icon { position: relative; width: 18px; height: 12px; border-block: 2px solid currentColor; }
.site-menu-icon::before { content: ""; position: absolute; inset: 3px 0 auto; border-top: 2px solid currentColor; }
.site-menu[open] .site-menu-icon { border-color: transparent; }
.site-menu[open] .site-menu-icon::before { inset: 3px 0 auto; transform: rotate(45deg); }
.site-menu[open] .site-menu-icon::after { content: ""; position: absolute; inset: 3px 0 auto; border-top: 2px solid currentColor; transform: rotate(-45deg); }
.site-menu-opened, .site-menu[open] .site-menu-closed { display: none; }
.site-menu[open] .site-menu-opened { display: inline; }
.site-menu[open] > summary::before { content: ""; position: fixed; inset: 0; z-index: -1; background: rgb(0 0 0 / 0.45); cursor: default; }
.top .site-menu > nav, .p-top .site-menu > nav {
  position: absolute; z-index: 42; top: 100%; left: 0; right: 0;
  display: flex; flex-direction: column; gap: 0; margin: 0; padding: 8px 20px 20px; width: auto; min-height: 0; overflow: visible;
  background: var(--menu-bg); border-block: 1px solid var(--menu-line);
  font-size: var(--text-lg); font-weight: 600;
}
.top .site-menu > nav a, .p-top .site-menu > nav a {
  display: flex; align-items: center; min-height: 52px; padding: 0 4px;
  color: var(--menu-fg); text-decoration: none; border-bottom: 1px solid var(--menu-line);
}
.top .site-menu > nav a:nth-last-child(2), .p-top .site-menu > nav a:nth-last-child(2) { border-bottom: 0; }
.top .site-menu > nav .site-menu-signin, .p-top .site-menu > nav .site-menu-signin { justify-content: center; margin-top: 12px; min-height: 48px; border: 0; }
.p-top .site-menu > nav .site-menu-signin { background: var(--ipb); color: var(--ipf); }
.p-top .site-menu > nav .site-menu-signin:hover { background: var(--iph); color: var(--ipf); }
.top .site-menu > nav a[aria-current="page"], .p-top .site-menu > nav a[aria-current="page"] { color: var(--menu-fg); box-shadow: inset 3px 0 0 var(--brand); padding-left: 12px; }
.top .site-menu > nav a[aria-current="page"]::after { content: none; }
.top .site-menu > nav a:hover, .p-top .site-menu > nav a:hover { color: var(--menu-muted); }
@media (prefers-reduced-motion: no-preference) {
  .site-menu[open] > nav { animation: site-menu-in 160ms ease-out; }
  @keyframes site-menu-in { from { opacity: 0; transform: translateY(-6px); } }
}
@media (max-width: 400px) { .site-menu-closed, .site-menu[open] .site-menu-opened { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); } }

/* Docs (web/src/docs.ts): sidebar, article, on-page contents. No script:
   the phone menu is a <details>, like the vault sidebar. ------------------- */

.docs { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-6); align-items: start; }
.docs-side { display: none; }
.docs-nav-section + .docs-nav-section { margin-top: var(--space-5); }
.docs-nav-title { margin: 0 0 var(--space-2); padding: 0 var(--space-3); font-size: var(--text-xs); line-height: var(--lh-xs); font-weight: 600; color: var(--fg-muted); }
.docs-nav-section ul, .docs-toc ul { list-style: none; margin: 0; padding: 0; }
.docs-nav-section a {
  display: flex; align-items: center; min-height: 32px; padding: 6px var(--space-3); border-radius: var(--radius-md); position: relative;
  color: var(--fg-muted); text-decoration: none; font-size: var(--text-sm); line-height: var(--lh-sm); font-weight: 500;
}
.docs-nav-section a:hover { background: var(--bg-muted); color: var(--fg); }
.docs-nav-section a[aria-current="page"] { background: var(--bg-muted); color: var(--fg); font-weight: 600; }
.docs-nav-section a[aria-current="page"]::before {
  content: ""; position: absolute; left: 0; top: 7px; bottom: 7px; width: 2px; border-radius: 2px; background: var(--brand);
}
.docs-side .alpha-note { margin-top: var(--space-6); padding: var(--space-4) var(--space-3) 0; border-top: 1px solid var(--border); }

.docs-menu > summary {
  display: inline-flex; align-items: center; gap: var(--space-3); list-style: none; cursor: pointer;
  min-height: var(--control-md); padding: 0 14px; font-size: var(--text-sm); font-weight: 500;
  border: 1px solid var(--border-strong); border-radius: var(--radius-md); background: var(--bg);
}
.docs-menu > summary::-webkit-details-marker { display: none; }
.docs-menu > summary::after {
  content: ""; width: 6px; height: 6px; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
}
.docs-menu[open] > summary { margin-bottom: var(--space-3); }
.docs-menu > nav { background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-4) var(--space-3); }

.docs-article { min-width: 0; }
.docs-article > .crumb { margin-bottom: var(--space-4); }
.docs-prose { border: 0; border-radius: 0; background: none; padding: 0; }
.docs-prose h1 { font-size: clamp(1.5rem, 1.2rem + 1.5vw, 2rem); line-height: 1.2; margin-bottom: var(--space-5); }
.docs-prose h1 + p { color: var(--fg-muted); font-size: var(--text-lg); line-height: var(--lh-lg); }
.docs-prose h2 { margin-top: var(--space-8); padding-top: var(--space-2); }
.docs-prose [id] { scroll-margin-top: var(--space-5); }
.docs-prose .table-wrap { margin: 0 0 var(--space-5); max-width: 100%; }
.docs-prose table { border: 1px solid var(--border); margin: 0; }
.docs-prose td { height: auto; vertical-align: top; }
.docs-prose th { white-space: normal; }
.docs-prose td a { color: var(--link); text-decoration: underline; font-weight: 400; }
.docs-prose pre { max-width: 100%; }

.docs-pager { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); margin: var(--space-9) 0 var(--space-5); max-width: var(--measure); }
.docs-pager a {
  display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-4) var(--space-5);
  border: 1px solid var(--border); border-radius: var(--radius-lg); text-decoration: none; color: var(--fg); font-weight: 500;
}
.docs-pager a:hover { border-color: var(--border-strong); background: var(--bg-subtle); }
.docs-pager span { font-size: var(--text-xs); line-height: var(--lh-xs); color: var(--fg-muted); font-weight: 500; }
.docs-next { grid-column: 2; text-align: right; align-items: flex-end; }
.docs-source { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }

.docs-toc { display: none; font-size: var(--text-sm); line-height: var(--lh-sm); }
.docs-toc li a { display: block; padding: 6px 0 6px var(--space-3); border-left: 1px solid var(--border); color: var(--fg-muted); text-decoration: none; }
.docs-toc li.toc-3 a { padding-left: var(--space-6); }
.docs-toc li a:hover { color: var(--link); border-left-color: var(--border-strong); }
.docs-toc .docs-nav-title { padding: 0; }

@media (min-width: 768px) {
  .docs { grid-template-columns: 216px minmax(0, 1fr); gap: var(--space-8); }
  .docs-menu { display: none; }
  .docs-side { display: block; position: sticky; top: var(--space-5); max-height: calc(100vh - 32px); overflow-y: auto; scrollbar-width: thin; }
}
@media (min-width: 1180px) {
  .docs { grid-template-columns: 216px minmax(0, 1fr) 200px; }
  .docs-toc { display: block; position: sticky; top: var(--space-5); max-height: calc(100vh - 32px); overflow-y: auto; }
}
@media (max-width: 640px) {
  .top-inner .stage { margin-left: calc(-1 * var(--space-3)); }
  /* Wide tables scroll sideways rather than squeeze a column to a word. */
  .docs-prose th, .docs-prose td { padding: 10px var(--space-4); }
  .docs-prose table:has(th:nth-child(4)) { min-width: 38rem; }
  .docs-pager { grid-template-columns: minmax(0, 1fr); }
  .docs-next { grid-column: 1; }
}


/* New vault: a template's folders and suggested variables, under its name. */
.template-detail { display: block; margin: 2px 0 var(--space-2); color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }

/* Error pages (errorpage.ts): what, where, why and the reference, then the
   same as plain text to copy. */
.failure { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-2) var(--space-5); margin: 0 0 var(--space-6); max-width: 80ch; }
.failure dt { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-md); }
.failure dd { margin: 0; overflow-wrap: anywhere; }
.failure-copy { white-space: pre-wrap; overflow-wrap: anywhere; }

/* Package I: signed-out and error pages */
/* Error pages (errorpage.ts): the lines to copy into a report, folded away. */
.failure-details { margin: 0 0 var(--space-6); max-width: 80ch; }
.failure-details > summary { cursor: pointer; width: fit-content; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.failure-details > summary:hover { color: var(--fg); }
.failure-details[open] > summary { margin-bottom: var(--space-3); }

/* Package B: files and folders */
/* The root's Search button stands in for the sidebar's search box, which is
   hidden on phones. */
.vault-search-link { display: none; }
@media (max-width: 767px) {
  .vault-search-link { display: inline-flex; }
}
/* The root's rule line: the default, the rules, what canon means. */
.root-rule .badge { margin: 0 calc(-1 * var(--space-1)); }
/* Folder table: the policy column holds a badge, so rows keep one height. */
.folder-list td:nth-child(2) { width: 1%; white-space: nowrap; }
/* A folder's README, boxed under the list with its file name as the header
   bar (not a second heading above the README's own). */
.file-references { margin-top: var(--space-6); }
.references { list-style: none; padding: 0; margin: 0 0 var(--space-4); }
.references li { padding: var(--space-1) 0; overflow-wrap: anywhere; }
.references .meta { display: inline; }
.readme { margin-top: var(--space-6); border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); overflow: hidden; }
.readme-head {
  margin: 0; max-width: none; padding: var(--space-3) var(--space-5); background: var(--bg-subtle); border-bottom: 1px solid var(--border);
  font: 500 var(--text-sm)/var(--lh-sm) var(--font-mono);
}
.readme-head a { color: var(--fg-muted); text-decoration: none; }
.readme-head a:hover { color: var(--link); text-decoration: underline; }
.readme > .prose { border: 0; border-radius: 0; }
/* File page: "Last written by … · 6 min ago" on one line where it fits. */
.file-meta { overflow-wrap: anywhere; }
/* Delete and erase items say what they do under their label. */
.file-more .action-list { min-width: 260px; }
@media (max-width: 640px) {
  .readme-head { padding: var(--space-3) var(--space-4); }
  .file-more .action-list { min-width: 0; width: min(18rem, calc(100vw - 2 * var(--space-5))); }
}

/* Package D: access */
/* Connections (/tokens, access.ts): the name leads each row, and on a phone
   is the block's heading; the last use and its client share a line. */
.token-list td:first-child { font-weight: 500; overflow-wrap: anywhere; min-width: 8rem; }
.token-list td[data-label="Type"] { white-space: nowrap; }
.token-list .token-client { display: inline; }
.token-list td.num { width: 1%; white-space: nowrap; }
/* Expired and revoked, folded under the live ones. */
.connections-ended { margin-top: var(--space-6); }
.connections-ended > summary {
  cursor: pointer; width: fit-content; display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: 32px; color: var(--fg-muted); font-size: var(--text-sm); font-weight: 500; line-height: var(--lh-sm);
}
.connections-ended > summary { list-style: none; }
.connections-ended > summary::-webkit-details-marker { display: none; }
.connections-ended > summary::before {
  content: ""; width: 5px; height: 5px; flex: none; margin: 0 2px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); transition: transform 120ms ease-out;
}
.connections-ended[open] > summary::before { transform: rotate(45deg); }
.connections-ended > summary:hover { color: var(--fg); }
.connections-ended[open] > summary { margin-bottom: var(--space-2); }
.connections-ended .hint { margin: 0 0 var(--space-3); }
@media (max-width: 640px) { .connections-ended > summary { min-height: 44px; } }
.new-token-hint { margin: 0 0 var(--space-4); }
/* Connect (/connect): the URL in the header, one client per tab, and a
   click selects a whole command. */
.page-head .endpoint { margin: 0; }
.endpoint code { overflow-wrap: anywhere; }
.connect-panel section > h2:first-child { margin-top: 0; }
.connect-panel pre.code { user-select: all; }
.connect-panel .callout { margin-top: var(--space-4); max-width: 80ch; }
.setup { margin: var(--space-4) 0 0; padding-left: 1.4em; max-width: 80ch; }
.setup > li { margin: 0 0 var(--space-5); padding-left: var(--space-2); }
.setup > li > pre.code, .setup > li > .quick-token { margin-top: var(--space-3); }
.setup pre.code { user-select: all; }
.quick-token { max-width: 36rem; }
@media (max-width: 639px) {
  .token-list td.num { width: auto; }
}

/* Package C: proposals and review */
/* Worth a closer look (proposals.ts): each flag's short label, then the sentence. */
.risks { display: grid; gap: var(--space-2); }
.risks li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); }
.risks .badge { flex: none; }
.risk-long { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
/* The decision box: the hint under its label, a refusal at the top, the field marked. */
form.decide > label { margin-bottom: var(--space-1); }
form.decide > .hint { margin: 0 0 var(--space-2); }
form.decide > .callout { margin: 0 0 var(--space-4); }
textarea[aria-invalid="true"] { border-color: var(--danger); box-shadow: 0 0 0 1px var(--danger); }
/* How a decided proposal ended; in lists, at the end of the row. */
.outcome-line time, .rows .outcome time { white-space: nowrap; }
.rows .outcome { text-align: right; }
/* Edit, then approve and Revise: the file as it is now, folded above the editor. */
.current-file { margin: 0 0 var(--space-5); max-width: 80ch; }
.current-file > summary { cursor: pointer; width: fit-content; color: var(--fg-muted); font-size: var(--text-sm); }
.current-file > summary:hover { color: var(--fg); }
.current-file[open] > summary { margin-bottom: var(--space-3); }
.current-text { margin: 0; max-height: 24rem; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5); font-family: var(--font-mono); font-size: var(--text-sm); }
/* The Snooze menu in a proposal's header: its descriptions are sentences. */
.snooze-menu .action-list { min-width: 260px; }
/* Buttons centre their content; a menu item lines up at the start. */
.snooze-menu .menu-item { justify-content: start; }
@media (max-width: 640px) {
  .rows .outcome { text-align: left; }
  .snooze-menu .action-list { min-width: 0; }
}

/* Package E: activity ------------------------------------------------------ */
/* The filter bar: a Filters button that opens the form, the filters in use
   as chips (each removes itself), Clear filters. Then the events: a table,
   and below 640px a two-line list (what and when; who, vault and path). */
.activity-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: 0 0 var(--space-5); }
.activity-filter-panel[open] { flex-basis: 100%; }
.activity-filter-panel > summary { list-style: none; }
.activity-filter-panel > summary::-webkit-details-marker { display: none; }
.activity-filter-panel > summary::after {
  content: ""; width: 6px; height: 6px; margin: -3px 2px 0 2px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
}
.activity-filter-panel[open] > summary { background: var(--bg-muted); }
.activity-filter-panel[open] > summary::after { margin-top: 3px; transform: rotate(-135deg); }
.activity-filter-panel > summary .count { margin-left: 2px; }
.activity-filter-panel > form.filters { margin: var(--space-3) 0 0; }
.filter-chips { display: flex; flex-wrap: wrap; gap: var(--space-3); list-style: none; margin: 0; padding: 0; min-width: 0; }
.filter-chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: var(--control-sm); max-width: 100%;
  padding: 0 4px 0 12px; border: 1px solid var(--border); border-radius: var(--radius-full);
  background: var(--bg-subtle); color: var(--fg); font-size: 0.8125rem; line-height: 1.3; text-decoration: none; overflow-wrap: anywhere;
}
.filter-chip-key { color: var(--fg-muted); font-weight: 500; }
.filter-chip-x {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 20px; height: 20px; border-radius: var(--radius-full); color: var(--fg-muted); font-size: 15px; line-height: 1;
}
.filter-chip:hover { border-color: var(--border-strong); color: var(--fg); }
.filter-chip:hover .filter-chip-x { background: var(--bg-muted); color: var(--fg); }
table.activity .ev-when { width: 1%; color: var(--fg-muted); }
table.activity tr.ev:target > td { background: var(--attention-bg); }
@media (max-width: 640px) {
  .table-wrap.activity-wrap { margin: 0; padding: 0; overflow: visible; }
  table.activity, table.activity tbody { display: block; min-width: 0; }
  table.activity thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  table.activity tr.ev {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px var(--space-2);
    padding: var(--space-3) var(--space-4); border-top: 1px solid var(--border);
  }
  table.activity tbody tr.ev:first-child { border-top: 0; }
  table.activity tr.ev:hover { background: var(--bg-subtle); }
  table.activity tr.ev > td { display: block; height: auto; padding: 0; border: 0; background: transparent; min-width: 0; }
  table.activity tr.ev > td:empty { display: none; }
  /* Line one: what (it wraps) and when, filling the line. */
  table.activity .ev-what { order: 1; flex: 1 1 calc(100% - 6.5rem - var(--space-2)); font-size: var(--text-sm); font-weight: 600; color: var(--fg); }
  table.activity .ev-when { order: 2; flex: 0 0 6.5rem; width: auto; text-align: right; font-size: 0.8125rem; }
  /* Line two: who, then the vault and the path. */
  table.activity tr.ev > td:last-child { order: 3; }
  table.activity .ev-vault { order: 4; }
  table.activity .path-cell { order: 5; }
  table.activity tr.ev > td:last-child, table.activity .ev-vault, table.activity .path-cell { font-size: 0.8125rem; color: var(--fg-muted); }
  table.activity .ev-vault::before, table.activity .path-cell::before { content: "·"; margin-right: var(--space-2); color: var(--fg-muted); }
  table.activity .ev-vault a, table.activity .path-cell a { font-weight: 500; }
}

/* Package J: rules */
/* Rules table (rules.ts): the path in mono, with what it covers and the
   rule it overrides on a quiet line under it; policy and actions keep one
   width; "Set by" never breaks between the name and the time. */
.rules-table .rule-path { overflow-wrap: anywhere; }
.rules-table .rule-scope { display: block; margin-top: var(--space-1); color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.rules-table .rule-scope code { font-size: inherit; }
/* A path's named owners (pathowners.ts): a link on its own line under the scope. */
.rules-table .rule-owners { display: inline-block; margin-top: var(--space-1); font-size: var(--text-sm); line-height: var(--lh-sm); }
.owner-form, .watch-add { scroll-margin-top: var(--space-10); }
.rules-table td:nth-child(2), .rules-table .rule-actions { width: 1%; white-space: nowrap; }
/* Links reuses this table, but its second column is a URL of up to 2048
   characters: it must wrap, or the table scrolls sideways and pushes the
   actions out of sight. Same specificity as the rule above, so it follows it. */
.rules-table td.link-url { width: auto; white-space: normal; overflow-wrap: anywhere; }
.rules-table .rule-actions .action-list { min-width: 240px; }
.rule-form { scroll-margin-top: var(--space-10); }
.rule-form .hint + .hint { margin-top: var(--space-1); }
/* "What applies to a path?" is folded under the list until asked for. */
.rule-check { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-3) var(--space-5); margin: var(--space-6) 0 0; max-width: 80ch; }
.rule-check > summary { cursor: pointer; font-weight: 600; padding: var(--space-2) 0; }
.rule-check[open] > summary { margin-bottom: var(--space-3); }
.rule-check .result { margin: var(--space-3) 0 0; }
.rules-help { margin-top: var(--space-5); }
@media (max-width: 640px) {
  .rules-table td:nth-child(2), .rules-table .rule-actions { width: auto; }
  .rules-table .rule-actions { text-align: left; }
  .rules-table .rule-actions .action-list { min-width: 0; width: min(16rem, calc(100vw - 2 * var(--space-5))); left: auto; transform: none; }
}

/* Claim rules (claimrulespage.ts): two fields a row, a number beside its unit,
   and presets as buttons that say what they set. */
.claim-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: var(--space-5); }
.duration { display: flex; gap: var(--space-2); }
.duration select { width: auto; }
.presets { margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--border); }
.presets .actions { margin-top: var(--space-2); }
.presets .button { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px; height: auto; padding: var(--space-2) var(--space-4); }
.presets .token-client { color: var(--fg-muted); font-size: var(--text-xs); line-height: var(--lh-xs); font-weight: 400; }
@media (max-width: 640px) {
  .claim-fields { grid-template-columns: minmax(0, 1fr); }
}

/* Package H: home and new vault */
/* Home (pages.ts home()): the plan line under Your vaults, the badge beside
   the count when the plan is full. */
.plan-line .badge { margin-left: var(--space-2); }
h2 + .plan-line { margin: calc(-1 * var(--space-2)) 0 var(--space-4); }
/* Cards: a grid of link cards, one column on a phone. A card's title link
   is stretched over it with ::after, so the whole card is one click target
   without nesting links; the other links in it sit above that layer. */
.card-grid { list-style: none; margin: 0 0 var(--space-6); padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr)); gap: var(--space-4); }
/* Home's filter and sort, shown past six vaults: the box with its own
   button, the sorts as chips, and how many vaults are shown. */
.home-filter { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); margin: var(--space-7) 0 var(--space-5); }
.home-filter .chips { margin: 0; }
.home-count { margin: 0; flex-basis: 100%; }
.home-search { position: relative; flex: 1 1 18rem; max-width: 28rem; margin: 0; }
.home-search input { width: 100%; padding-right: 40px; }
.home-search button {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center; width: 30px; height: 30px; padding: 0; border: 0; border-radius: var(--radius-md);
  background: transparent; color: var(--fg-muted); cursor: pointer;
}
.home-search button:hover { background: var(--bg-muted); color: var(--fg); }
.card {
  position: relative; display: grid; gap: var(--space-3); align-content: start; min-width: 0;
  padding: var(--space-5); border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg);
  font-size: var(--text-sm); line-height: var(--lh-sm);
  transition: border-color 120ms ease-out;
}
/* Flat and ruled (owner, 2026-10-13): hover darkens the rule, nothing lifts. */
.card:hover { border-color: var(--border-strong); }
.card:active { border-color: var(--fg-muted); }
.card:has(.card-link:focus-visible) { outline: 2px solid var(--link); outline-offset: 2px; }
.card p { margin: 0; }
.card-head { display: flex; align-items: center; gap: var(--space-3); }
.card-head .card-title { flex: 1; }
.vault-mark {
  flex: none; display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--radius-md);
  font-weight: 700; font-size: var(--text-md); line-height: 1;
}
/* Six tints, light and dark, each dark text on a pale fill (or the reverse)
   well past 4.5:1, so the letter reads in either theme. */
.tint-0 { background: #fde2e1; color: #8a1c1b; } .tint-1 { background: #dfeafe; color: #0b3b8c; }
.tint-2 { background: #dcf3e4; color: #145a32; } .tint-3 { background: #fdf0d5; color: #7a4a00; }
.tint-4 { background: #ece3fd; color: #4b2391; } .tint-5 { background: #d9f2f4; color: #0c5560; }
:root[data-theme="dark"] .tint-0 { background: #4a1f1e; color: #ffd2d0; } :root[data-theme="dark"] .tint-1 { background: #1c2c4c; color: #cfe0ff; }
:root[data-theme="dark"] .tint-2 { background: #1b3a27; color: #c8f0d6; } :root[data-theme="dark"] .tint-3 { background: #42331a; color: #fbe5b8; }
:root[data-theme="dark"] .tint-4 { background: #2f2350; color: #e2d6ff; } :root[data-theme="dark"] .tint-5 { background: #173a3e; color: #c6eef2; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tint-0 { background: #4a1f1e; color: #ffd2d0; } :root:not([data-theme="light"]) .tint-1 { background: #1c2c4c; color: #cfe0ff; }
  :root:not([data-theme="light"]) .tint-2 { background: #1b3a27; color: #c8f0d6; } :root:not([data-theme="light"]) .tint-3 { background: #42331a; color: #fbe5b8; }
  :root:not([data-theme="light"]) .tint-4 { background: #2f2350; color: #e2d6ff; } :root:not([data-theme="light"]) .tint-5 { background: #173a3e; color: #c6eef2; }
}
.card-title { margin: 0; font-size: var(--text-md); line-height: var(--lh-md); font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.card-link { color: var(--fg); text-decoration: none; }
.card-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.card-link:focus-visible { outline: none; }
.card a:not(.card-link) { position: relative; z-index: 1; }
.card-role, .card-foot { color: var(--fg-muted); }
.card-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); margin: 0; }
.card-stats dt { color: var(--fg-muted); font-size: var(--text-xs); line-height: var(--lh-xs); }
.card-stats dd { margin: 0; overflow-wrap: anywhere; }
.card-stats .usage-meter { margin-bottom: 0; }
/* What waits in a vault, as plain links in a row: on a grid of cards, a
   pill per count was the loudest thing on each card. */
.card-counts { display: flex; flex-wrap: wrap; gap: 0 var(--space-4); font-size: var(--text-sm); font-weight: 500; }
.card-foot .badge { background: none; border: 0; padding: 0; font-weight: 400; color: inherit; }
.card-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--border); font-size: var(--text-xs); line-height: var(--lh-xs); }
/* A vault's Overview (overview.ts): a line of facts under the title, then
   short ruled lists, two side by side when there is room. A row is the
   thing on the left, who and when on the right; a long title wraps between
   words, the right side never wraps. */
.overview-glance { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-2); margin: 0; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.overview-glance a { color: inherit; text-decoration-color: var(--border-strong); }
.overview-glance a:hover { color: var(--fg); }
.overview-glance .sep { color: var(--border-strong); }
.overview-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); gap: 0 var(--space-6); }
.overview-section { margin: 0 0 var(--space-6); min-width: 0; }
.overview-section .section-head { margin: 0; padding-bottom: var(--space-2); border-bottom: 1px solid var(--border); }
.overview-section .see-all { font-size: var(--text-sm); }
.overview-section > p { margin: var(--space-3) 0 0; }
.overview-list { list-style: none; margin: 0; padding: 0; }
.overview-list li { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-4); padding: var(--space-2) 0; border-bottom: 1px solid var(--border); min-width: 0; }
.overview-list li > :first-child { min-width: 0; overflow-wrap: break-word; }
/* A path wraps as a whole, onto its own line, never at its hyphens. */
.overview-list li > :first-child a { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
#connect-nudge p { max-width: none; }
.overview-list li > :last-child:not(:first-child) { flex: none; max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg-muted); font-size: var(--text-sm); }
.callout.info p strong { display: inline; }
/* The first-vault checklist: three numbered steps, read left-aligned. */
.first-steps { max-width: var(--measure); margin: 0 auto var(--space-5); padding-left: 1.5em; text-align: left; color: var(--fg); }
.first-steps li + li { margin-top: var(--space-3); }
.first-steps strong { display: inline; font-size: inherit; margin: 0; }
.first-steps .button { margin-left: var(--space-2); }
/* New vault (pages.ts newVault(), templates.ts templateChoices()): the
   template and the default policy as cards. The radio sits inside the
   label, so the whole card picks it; the checked card is outlined in the
   brand colour, so the choice never rests on the small radio alone. */
.new-vault-form .choice-cards > .hint { margin: 0 0 var(--space-3); max-width: var(--measure); }
.choice-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: var(--space-3); }
label.choice-card {
  display: flex; align-items: flex-start; gap: var(--space-3); margin: 0; min-width: 0;
  padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg);
  font-weight: 400; font-size: var(--text-sm); line-height: var(--lh-sm); cursor: pointer;
  transition: border-color 120ms ease-out, background-color 120ms ease-out, box-shadow 120ms ease-out;
}
label.choice-card:hover { border-color: var(--border-strong); background: var(--bg-subtle); }
label.choice-card:has(input:checked) { border-color: var(--brand-strong); box-shadow: inset 0 0 0 1px var(--brand-strong); background: var(--bg-subtle); }
label.choice-card:has(input:focus-visible) { outline: 2px solid var(--link); outline-offset: 2px; }
label.choice-card input { flex: none; margin-top: 2px; }
label.choice-card input:focus-visible { outline: none; }
.choice-card-body { display: grid; gap: var(--space-1); min-width: 0; }
.choice-card-title { font-weight: 600; font-size: var(--text-md); line-height: var(--lh-md); color: var(--fg); }
.choice-card-text { color: var(--fg-muted); }
.choice-card-rules, .choice-card-vars { color: var(--fg-muted); font-size: var(--text-xs); line-height: var(--lh-xs); }
.choice-card-rules { display: flex; flex-wrap: wrap; gap: 2px var(--space-3); margin-top: var(--space-1); }
.choice-card code { font-size: inherit; padding: 0 3px; }
/* At the vault limit: the callout is the page, its way on as buttons. */
.callout-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: var(--space-4) 0 0; }
.refused-ref { color: var(--fg-muted); }
@media (max-width: 640px) {
  .choice-card-grid, .card-grid { grid-template-columns: minmax(0, 1fr); }
}
/* Package G: vault admin and members */
/* A page's tabs: the first h2 under them sits close, the rest keep the page rhythm. */
.page-head.has-tabs + h2, .page-head.has-tabs + .section-head > h2 { margin-top: var(--space-2); }
/* Settings (vaultadmin.ts settingsPage): a grouped sub-nav beside the
   section on wide screens; on narrow ones it stacks above, each group's
   links in a wrapping row so the section is still near the top. */
.settings-layout { display: grid; grid-template-columns: 12rem minmax(0, 1fr); gap: var(--space-7); align-items: start; margin-top: var(--space-5); }
.settings-nav ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.settings-nav-group + .settings-nav-group { margin-top: var(--space-5); }
.settings-nav-label { margin: 0 0 var(--space-2); padding: 0 var(--space-3); color: var(--fg-muted); font-size: var(--text-xs); line-height: var(--lh-xs); font-weight: 600; }
.settings-nav a { display: flex; align-items: center; min-height: 32px; padding: 0 var(--space-3); border-radius: var(--radius-md); position: relative; color: var(--fg-muted); text-decoration: none; font-weight: 500; }
.settings-nav a:hover { background: var(--bg-muted); color: var(--fg); }
.settings-nav a[aria-current="page"] { background: var(--bg-muted); color: var(--fg); font-weight: 600; }
.settings-nav a[aria-current="page"]::before { content: ""; position: absolute; left: 0; top: 7px; bottom: 7px; width: 2px; border-radius: 2px; background: var(--brand); }
.settings-main > :first-child, .settings-main > .section-head:first-child > h2 { margin-top: 0; }
@media (max-width: 900px) {
  .settings-layout { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
  .settings-nav { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6); padding-bottom: var(--space-4); border-bottom: 1px solid var(--border); }
  .settings-nav-group + .settings-nav-group { margin-top: 0; }
  .settings-nav ul { flex-direction: row; flex-wrap: wrap; }
}
@media (max-width: 640px) { .settings-nav a { min-height: var(--control-md); } }
/* Diagnostics (diagnostics.ts): Flags, Claims and the log are a second row
   under the Settings tabs, lighter than them so the two read as two levels;
   the Variables page's environment views (values.ts) are the same second row. */
:is(.diag-tabs, .var-envtabs) > .tabs { box-shadow: none; gap: var(--space-1); margin: var(--space-2) 0 var(--space-5); }
:is(.diag-tabs, .var-envtabs) > .tabs a { min-height: 32px; padding: 0 var(--space-3); border-radius: var(--radius-md); }
:is(.diag-tabs, .var-envtabs) > .tabs a[aria-current="page"] { background: var(--bg-muted); }
:is(.diag-tabs, .var-envtabs) > .tabs a[aria-current="page"]::after { content: none; }
@media (max-width: 640px) { :is(.diag-tabs, .var-envtabs) > .tabs a { min-height: var(--control-md); } }
.diag-tabs + h2 { margin-top: 0; }
/* A section heading with a quiet line at its right: "People · 3 of 10 places". */
.section-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-5); margin: var(--space-8) 0 var(--space-4); }
.section-head > h2 { margin: 0; }
.section-meta { margin: 0; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.section-lede { color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); margin-top: calc(-1 * var(--space-2)); }
/* General, for editors and viewers: the facts, not a form. */
.settings-facts { display: grid; gap: 0; margin: 0 0 var(--space-4); max-width: 40rem; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); }
.settings-facts > div { display: grid; grid-template-columns: 10rem minmax(0, 1fr); gap: var(--space-4); padding: var(--space-3) var(--space-5); border-top: 1px solid var(--border); align-items: baseline; }
.settings-facts > div:first-child { border-top: 0; }
.settings-facts dt { font-size: var(--text-sm); font-weight: 600; color: var(--fg-muted); }
.settings-facts dd { margin: 0; overflow-wrap: anywhere; }
/* Members: the role picker and Change line up at the small control height;
   row actions stay on one line at the right. */
.member-list .role-form select { min-height: var(--control-sm); min-width: 7rem; padding-top: 2px; padding-bottom: 2px; font-size: var(--text-sm); }
.member-list .role-form { flex-wrap: nowrap; }
td.row-actions { width: 1%; white-space: nowrap; }
/* A cell's second line (the only owner, a tier's source, a connection's kind). */
:is(.member-list, .usage-table, .plan-vaults, .connection-list) .token-client { display: block; color: var(--fg-muted); font-size: var(--text-sm); }
.connection-list .conn-name { font-weight: 500; overflow-wrap: anywhere; }
.invite-list td:first-child { overflow-wrap: anywhere; }
.invite-form input[type="text"] { max-width: 28rem; }
.reveal .callout-title strong { display: inline; }
/* Danger zone, at the foot of General: a red-outlined box, a row per action, the button at the end. */
.settings-danger { margin-top: var(--space-9); }
.danger-rows { border: 1px solid var(--danger); border-radius: var(--radius-lg); background: var(--bg); max-width: 80ch; }
.danger-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-6); padding: var(--space-5); border-top: 1px solid var(--border); }
.danger-row:first-child { border-top: 0; }
.danger-row > div { flex: 1 1 22rem; min-width: 0; }
.danger-row h3 { font-size: var(--text-md); line-height: var(--lh-md); margin: 0 0 var(--space-1); }
.danger-row p { margin: 0; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.danger-rows + .hint { margin-top: var(--space-4); }
.export-facts { max-width: var(--measure); padding-left: 1.25em; margin: 0; }
.export-facts li + li { margin-top: var(--space-2); }
/* Usage: a row per limit with a meter (plans.ts meter(): a <meter>, since
   the CSP allows no inline width). */
.usage-table { max-width: 44rem; }
.usage-table th[scope="row"] { width: 8rem; background: var(--bg-subtle); vertical-align: top; padding-top: 12px; }
.usage-table td { padding-top: 10px; padding-bottom: 10px; }
.usage-table + .hint, .table-wrap:has(> .usage-table) + .hint { margin-top: var(--space-4); }
.usage-meter {
  display: block; width: 100%; max-width: 14rem; height: 6px; margin: var(--space-2) 0 var(--space-1);
  -webkit-appearance: none; appearance: none; border: 0; border-radius: var(--radius-full); background: var(--bg-muted); overflow: hidden;
}
.usage-meter::-webkit-meter-bar { height: 6px; border: 0; border-radius: var(--radius-full); background: var(--bg-muted); }
.usage-meter::-webkit-meter-optimum-value { background: var(--fg-muted); border-radius: var(--radius-full); }
.usage-meter::-webkit-meter-suboptimum-value { background: var(--attention); border-radius: var(--radius-full); }
.usage-meter::-webkit-meter-even-less-good-value { background: var(--danger); border-radius: var(--radius-full); }
.usage-meter::-moz-meter-bar { background: var(--fg-muted); border-radius: var(--radius-full); }
.usage-meter:-moz-meter-sub-optimum::-moz-meter-bar { background: var(--attention); }
.usage-meter:-moz-meter-sub-sub-optimum::-moz-meter-bar { background: var(--danger); }
/* Plan and usage (/account): the plan with its meter, then the vaults. */
.plan-summary { max-width: 32rem; margin: 0 0 var(--space-4); }
.plan-summary .usage-line { margin: 0; }
.plan-summary .hint { margin-top: var(--space-2); }
.plan-vaults td:first-child { min-width: 10rem; }
.plan-vaults .usage-meter { max-width: 10rem; }
.usage-status { display: inline-flex; flex-wrap: wrap; gap: var(--space-2); }
.plan-note { margin-top: var(--space-6); }
@media (max-width: 640px) {
  .settings-facts > div { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
  .danger-row { padding: var(--space-4); }
  .danger-row > .button { width: 100%; }
  .usage-table th[scope="row"] { width: 6rem; padding-left: var(--space-4); }
  .usage-table td { padding-right: var(--space-4); }
  .table-stack .usage-meter { max-width: none; }
  .member-list .role-form { flex-wrap: wrap; }
  td.row-actions { width: auto; }
  /* Stacked rows: the title cell reads as a line of text, a cell's second
     line sits under its value (not its label), and actions start left. */
  :is(.member-list, .invite-list, .connection-list, .plan-vaults) td:first-child { display: block; font-weight: 500; }
  :is(.member-list, .invite-list, .connection-list, .plan-vaults) td:first-child .token-client { font-weight: 400; }
  :is(.member-list, .connection-list, .plan-vaults) td[data-label] > :is(.token-client, .usage-meter, .usage-status) { grid-column: 2; }
  .table-stack td.row-actions { display: block; text-align: left; padding-top: var(--space-2); }
}

/* Package F: variables */
/* The All view (values.ts): a column per environment, the name column
   sticky while the rest scrolls sideways inside its box; each cell Set or
   Not set. On a phone, one block per variable. */
.var-values { margin: 0 0 var(--space-6); }
.var-missing { margin-left: var(--space-2); font-weight: 500; }
.var-list .var-meta { white-space: nowrap; }
.var-howto { margin: 0 0 var(--space-6); }
.var-howto > summary { cursor: pointer; width: fit-content; font-weight: 600; }
.var-howto[open] > summary { margin-bottom: var(--space-3); }
.var-grid-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); }
/* No clipping on the table itself (the base table hides overflow), so the
   sticky column sticks to the scrolling box and the menus aren't cut off. */
table.var-grid { border: 0; border-radius: 0; overflow: visible; }
.var-grid th, .var-grid td { padding: var(--space-2) var(--space-4); vertical-align: middle; }
.var-grid td { min-width: 10.5rem; height: 44px; padding-right: var(--space-2); }
.var-grid thead th { vertical-align: bottom; }
.var-grid tr:hover > td { background: transparent; }
.var-grid th:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--bg);
  box-shadow: inset -1px 0 0 var(--border);
}
.var-grid thead th:first-child { background: var(--bg-subtle); z-index: 2; }
.var-grid th[scope="row"] { font-weight: 500; color: var(--fg); }
.var-grid th[scope="row"] code { white-space: nowrap; font-size: var(--text-sm); color: var(--fg); }
.var-env { color: var(--fg); }
/* The footnote under the Environments table would otherwise touch its border. */
.table-wrap:has(> .var-envtable) + p { margin-top: var(--space-4); }
.var-owners { margin-left: var(--space-1); }
.var-owners::before {
  /* A small padlock: shackle and body, drawn in CSS. */
  content: ""; width: 8px; height: 7px; margin-top: 3px; flex: none;
  border: 1.5px solid currentColor; border-radius: 1px;
  box-shadow: 0 -4px 0 -2.5px currentColor;
}
.var-cell { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); min-height: var(--control-sm); }
.var-state { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px var(--space-2); min-width: 0; }
.var-set { font-weight: 600; font-size: var(--text-sm); color: var(--fg); }
.var-meta { color: var(--fg-muted); font-size: var(--text-sm); }
.var-none { color: var(--fg-muted); font-size: var(--text-sm); }
.var-readers { display: inline-flex; align-items: center; gap: 6px; color: var(--fg-muted); font-size: var(--text-xs); line-height: var(--lh-xs); flex-basis: 100%; }
.var-readers::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--info); flex: none; }
td .button.var-add { min-height: 26px; padding: 0 var(--space-3); }

/* A ⋯ menu inside a table (every menu() with icon "more"): positioned from
   where it would sit (under its button, aligned to its right edge) rather
   than from the cell, so a table or a scrolling box never clips it. A
   table's own overflow (the wrapper's scroll, the table's rounded corners)
   cuts off anything positioned from inside it, which showed as an empty
   sliver on a table with one or two rows. */
.var-menu.menu-wrap { position: static; flex: none; }
.var-menu > summary.icon-button { width: 32px; min-height: var(--control-sm); padding: 0; }
@media (max-width: 640px) { .var-menu > summary.icon-button { width: 44px; } }
.var-menu > .menu { top: auto; right: auto; left: auto; margin-top: 4px; transform: translateX(calc(-100% + 32px)); }
.var-menu > .menu > .menu-label { max-width: 17rem; font-weight: 400; font-size: var(--text-xs); line-height: var(--lh-xs); white-space: normal; }
.var-row-end { text-align: right; width: 1%; }
/* A one-button form item lines up with the link items (the base button
   centres its content). */
.var-menu .menu-item { justify-content: start; }

/* "Set" in an empty cell is quiet until hover or focus where there is a
   pointer to hover with, but never invisible: hidden, "Not set" offered
   nothing to click. Always full on touch screens and phones. 0.7 keeps it
   above 3:1 (contrast.test.mjs). */
@media (hover: hover) and (min-width: 641px) {
  .var-grid .var-add { opacity: 0.7; transition: opacity 120ms ease-out; }
  .var-grid tr:hover .var-add, .var-grid .var-add:focus-visible { opacity: 1; }
}

@media (max-width: 640px) {
  .var-grid-wrap { overflow: visible; border: 0; background: transparent; }
  table.var-grid, .var-grid tbody, .var-grid tr, .var-grid th, .var-grid td { display: block; }
  .var-grid thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .var-grid tr { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); margin: 0 0 var(--space-3); }
  .var-grid th[scope="row"] {
    position: static; box-shadow: none; background: var(--bg-subtle);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0; padding: var(--space-3) var(--space-4);
    overflow-wrap: anywhere;
  }
  .var-grid th[scope="row"] code { white-space: normal; overflow-wrap: anywhere; }
  .var-grid td {
    min-width: 0; height: auto; border-top: 1px solid var(--border);
    display: grid; grid-template-columns: 6.5rem minmax(0, 1fr); column-gap: var(--space-3); align-items: center;
  }
  .var-grid td::before { content: attr(data-label); font-size: 0.8125rem; font-weight: 600; color: var(--fg-muted); overflow-wrap: anywhere; }
}

/* Environments and an environment's view: a menu at the end of each row;
   the stacked phone layout keeps it on its own line, at the right. */
@media (max-width: 640px) {
  :is(.var-envtable, .var-list) td.var-row-end { width: auto; display: flex; justify-content: flex-end; }
  .var-imports td[data-label=""] .button { width: 100%; }
}

/* Set a value: the environments as radios, the ones a role can't set shown
   disabled. */
.var-envs label.choice.is-disabled { color: var(--fg-muted); cursor: not-allowed; }
.var-envs label.choice .badge { margin-left: var(--space-1); }

/* Import a .env: the accepted syntax, folded. */
.var-syntax { margin: var(--space-2) 0 0; }
.var-syntax > summary { cursor: pointer; width: fit-content; color: var(--fg-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.var-syntax > summary:hover { color: var(--fg); }

/* Review an import: Apply and Reject in the header (and under a long list). */
.import-decide { display: inline-flex; flex-wrap: wrap; gap: var(--space-3); }
.import-decide form { margin: 0; }
.import-actions .import-decide { margin-top: var(--space-2); }

/* The stated-plainly caveats, one callout. */
.callout.var-caveats p { max-width: var(--measure); }
.callout.var-caveats p + p { margin-top: var(--space-3); }

/* A revealed value selects in one click; long confirm titles wrap. */
.reveal pre.secret { user-select: all; }
.var-confirm h1 { overflow-wrap: anywhere; }

/* Access log: who, then the client, on one line. */
table.env-log td[data-label="Environment"] { white-space: nowrap; }

/* The Welcome tour (welcome.ts): one card, one slide at a time. */
.welcome { max-width: 34rem; margin: var(--space-6) auto; padding: var(--space-5); border: 1px solid var(--border); border-radius: 8px; background: var(--bg-subtle); }
.welcome h1 { margin: 0 0 var(--space-3); }
.welcome-sub { margin: 0 0 var(--space-3); font-size: var(--text-lg, 1.125rem); }
.welcome-step { margin: 0 0 var(--space-2); color: var(--fg-muted); font-size: var(--text-sm); }
.welcome-body p { margin: 0 0 var(--space-3); max-width: 60ch; }
.welcome-dots ol { display: flex; gap: var(--space-3); justify-content: center; list-style: none; margin: var(--space-5) 0 var(--space-4); padding: 0; }
.welcome-dot { display: block; width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--border-strong); background: transparent; }
.welcome-dot[aria-current="step"] { background: var(--primary-bg); border-color: var(--primary-bg); }
.welcome-actions { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
.welcome-actions form { margin: 0; }
.welcome-skip { margin: var(--space-4) 0 0; text-align: center; }
@media (max-width: 640px) { .welcome { margin: var(--space-3) 0; padding: var(--space-4); } }

/* Changes (changes.ts): a heading per day, a line per change, the sentence
   first and when it happened after it (below it on phones, as .rows does). */
.feed-day h2 { margin: var(--space-6) 0 var(--space-3); font-size: var(--text-md); line-height: var(--lh-md); }
.chips + .feed-day h2, .hint + .feed-day h2 { margin-top: var(--space-5); }
.feed .change { align-items: baseline; }
.change-what { min-width: 0; overflow-wrap: anywhere; }
.change-agent { margin-left: var(--space-1); color: var(--fg-muted); font-size: var(--text-sm); }
.change-when { flex: none; color: var(--fg-muted); font-size: var(--text-sm); white-space: nowrap; }
/* Updates' New for you (flagspage.ts): above the chips, which only filter the feed. */
.new-for-you { margin-bottom: var(--space-6); }
.new-for-you h2 { margin: 0 0 var(--space-3); font-size: var(--text-md); line-height: var(--lh-md); }
.feed .flag { align-items: baseline; flex-wrap: wrap; }

/* Changes: Everyone, Mine, Watching, as links with one marked (changes.ts). */
.chips { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: var(--space-4) 0 0; padding: 0; }
.chip {
  display: inline-flex; align-items: center; min-height: var(--control-sm); padding: 0 var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-full); background: var(--bg-subtle);
  color: var(--fg); font-size: var(--text-sm); text-decoration: none;
}
.chip:hover { border-color: var(--border-strong); }
.chip[aria-current="true"] { background: var(--fg); border-color: var(--fg); color: var(--bg); font-weight: 600; }
.chips + .hint { margin: var(--space-3) 0 0; }

/* Sign-in's bot trap (signin.ts TRAP): off screen and out of the tab
   order, for people and screen readers alike; display:none would let a
   bot skip it. */
.trap {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Poster: the mark ------------------------------------------------------
   One typeface at two extremes (200 is open, 800 is canon), hairlines, no
   cards, no shadows, the diamond as the only picture. The first and last
   screens are inverted against the page. The mark, big, is the first band's
   picture; its silhouette repeats down the page as a margin rail that fills
   as the reader scrolls. */

/* The inverted band carries its own palette: the dark theme's values when
   the page is light, the light theme's when it is dark. Muted text on it is
   the band's own foreground, dimmed, never a grey from the other theme. */
.p-inv {
  --ib: #141312; --ibs: #1c1a19; --ibd: #34302e; --ibds: #6f6863;
  --if: #edebe9; --ifm: #a8a19c; --ilink: #6cb6ff; --ibrand: #ff5f57;
  --ipb: #edebe9; --ipf: #141312; --iph: #d3cfcc;
  background: var(--ib); color: var(--if);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .p-inv {
    --ib: #ffffff; --ibs: #f7f6f5; --ibd: #e2dfdc; --ibds: #8c8580;
    --if: #1c1917; --ifm: #5c5652; --ilink: #0a58ca; --ibrand: #e8393a;
    --ipb: #1c1917; --ipf: #ffffff; --iph: #3b3633;
  }
}
:root[data-theme="dark"] .p-inv {
  --ib: #ffffff; --ibs: #f7f6f5; --ibd: #e2dfdc; --ibds: #8c8580;
  --if: #1c1917; --ifm: #5c5652; --ilink: #0a58ca; --ibrand: #e8393a;
  --ipb: #1c1917; --ipf: #ffffff; --iph: #3b3633;
}
.p-inv a { color: var(--ilink); }
.p-inv ::selection { background: color-mix(in srgb, var(--ibrand) 25%, transparent); color: var(--if); }
.p-inv :focus-visible { outline: 2px solid var(--ilink); outline-offset: 3px; }
.p-inv .button { background: transparent; color: var(--if); border-color: var(--ibds); }
.p-inv .button:hover { background: var(--ibs); border-color: var(--if); }
.p-inv .button.primary { background: var(--ipb); color: var(--ipf); border-color: var(--ipb); }
.p-inv .button.primary:hover { background: var(--iph); border-color: var(--iph); }
.p-inv .logo { background: var(--ibrand); }

/* Browser surfaces carry the palette too. */
:root:has(.p-site) { scrollbar-color: var(--border-strong) var(--bg); scrollbar-width: thin; }
body.p-site { display: block; }
.p-site :focus-visible { outline-offset: 3px; }
.p-wrap { max-width: 1280px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 56px); }
.p-site a { text-underline-offset: 0.2em; }

/* Top bar at the band's own grid edges. */
.p-top { display: flex; align-items: center; justify-content: space-between; gap: 24px; min-height: 72px; }
.p-top .wordmark { color: inherit; }
.p-top .site-signin { margin-left: 0; flex: none; }
/* The badge takes the band's palette: the page's attention tokens belong to the
   other theme here, and the band's link colour would win over its text. */
.p-top .stage { flex: none; background: transparent; color: var(--if); border-color: var(--ibds); }
.p-top nav { display: flex; gap: 8px 24px; flex-wrap: wrap; justify-content: flex-end; margin-left: auto; font-size: var(--text-sm); font-weight: 500; }
.p-top nav a { color: var(--ifm); text-decoration: none; padding: 6px 0; border-bottom: 1px solid transparent; transition: color 120ms ease-out, border-color 120ms ease-out; }
.p-top nav a:hover { color: var(--if); border-bottom-color: var(--if); }
@media (max-width: 719px) { .p-top { gap: 12px; } }

/* The GitHub link: one shape wherever it sits, the stars split off by a hairline. */
.p-gh { display: inline-flex; align-items: center; gap: 8px; min-height: 36px; padding: 0 12px; border: 1px solid var(--ibds, var(--border-strong)); border-radius: 999px; color: inherit; font-size: var(--text-sm); font-weight: 600; text-decoration: none; transition: border-color 120ms ease-out; }
.p-site a.p-gh, .p-inv a.p-gh { color: var(--if, var(--fg)); text-decoration: none; }
.p-gh:hover { border-color: currentColor; }
.p-gh svg { width: 16px; height: 16px; fill: currentColor; flex: none; }
.p-gh-stars { display: inline-flex; align-items: center; gap: 4px; padding-left: 8px; border-left: 1px solid var(--ibds, var(--border-strong)); font-variant-numeric: tabular-nums; }
.p-gh-stars svg { width: 13px; height: 13px; }
.p-fold-text > .p-gh, .p-why .p-gh { margin-top: 16px; }
.p-top .p-gh { flex: none; }
/* On a phone the top bar keeps the mark and the count; the name stays for screen readers. */
@media (max-width: 719px) { .p-top .p-gh > span:not(.p-gh-stars) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } }

/* First screen ------------------------------------------------------------ */
.p-fold { min-height: min(100svh, 960px); display: flex; flex-direction: column; position: relative; }
/* Flex items with auto margins are not stretched, so the wrap says so. */
.p-fold > .p-wrap { width: 100%; box-sizing: border-box; }
.p-fold-body { flex: 1; display: grid; gap: 40px 64px; padding-block: 32px 48px; align-content: center; }
.p-fold-text { max-width: 44rem; }
/* Sized so each of the three lines stays one line across the band at 1280
   and 1440; below 900px the longest wraps once. */
.p-h1 { margin: 0; font-size: clamp(2.5rem, 1rem + 3.9vw, 4.75rem); line-height: 0.98; letter-spacing: -0.035em; font-weight: 800; }
.p-h1 > span { display: block; position: relative; padding-left: 0.78em; }
/* Open is light, canon is heavy: the weight is the mark's meaning again. */
.p-h1 .p-open { font-weight: 200; }
.p-h1 .p-canon { font-weight: 800; }
.p-h1 > span::before { content: ""; position: absolute; left: 0.08em; top: 0.33em; width: 0.3em; height: 0.3em; transform: rotate(45deg); }
.p-h1 .p-open::before { box-shadow: inset 0 0 0 0.035em var(--ibrand); }
.p-h1 .p-canon::before { background: var(--ibrand); }
/* Three filled diamonds in a row, one element: the shadows are offset along
   the rotated axes, which lands them on a horizontal line on screen. */
.p-sub { margin: 0; max-width: 32rem; font-size: clamp(1.125rem, 1rem + 0.5vw, 1.375rem); line-height: 1.4; font-weight: 500; }
.p-lede { margin: 16px 0 0; max-width: 36rem; color: var(--ifm); font-size: var(--text-md); line-height: var(--lh-md); }
/* The key: the three states, each with its mark, as the first thing under
   the H1. It is the legend for every diamond on the page. */
.p-key { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: var(--text-sm); line-height: var(--lh-sm); color: var(--ifm); }
.p-key li { position: relative; padding-left: 2rem; }
.p-key strong { color: var(--if); font-weight: 600; }
.p-key li::before { content: ""; position: absolute; left: 0.3rem; top: 0.45em; width: 0.5rem; height: 0.5rem; transform: rotate(45deg); }
.p-key-open::before { box-shadow: inset 0 0 0 1.5px var(--ibrand); }
.p-key-canon::before { background: var(--ibrand); }
.p-key-sealed::before { left: 0.1rem; top: 0.62em; width: 0.24rem; height: 0.24rem; background: var(--ibrand); box-shadow: 0.32rem -0.32rem 0 0 var(--ibrand), 0.64rem -0.64rem 0 0 var(--ibrand); }

/* The hub: tools, a link, the vault, a link, people; the key under it.
   Phones stack it; from 900px it runs left to right. Chips and hairlines
   only, in the band's own colours. */
.p-hub { margin: 0; display: grid; gap: 0; justify-items: center; grid-template-areas: "tools" "l1" "vault" "l2" "people" "cap"; }
.p-hub-side { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.p-hub-side li { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border: 1px solid var(--ibds); color: var(--if); font-size: var(--text-sm); font-weight: 600; line-height: 1.2; }
.p-hub-side svg { width: 16px; height: 16px; fill: currentColor; flex: none; }
.p-hub-tools { grid-area: tools; }
.p-hub-people { grid-area: people; }
.p-hub-vault { grid-area: vault; display: grid; justify-items: center; gap: 4px; padding: 20px 24px; border: 1px solid var(--if); text-align: center; max-width: 16rem; }
.p-hub-vault strong { font-weight: 800; letter-spacing: -0.02em; font-size: var(--text-lg); }
.p-hub-vault span:last-child { font-size: var(--text-sm); color: var(--ifm); }
.p-hub-mark { width: 56px; height: 56px; margin-bottom: 6px; background: var(--ibrand); -webkit-mask: url(/logo.svg) no-repeat center / contain; mask: url(/logo.svg) no-repeat center / contain; }
.p-hub-link { position: relative; display: grid; place-items: center; width: 100%; height: 56px; }
.p-hub-propose { grid-area: l1; }
.p-hub-approve { grid-area: l2; }
.p-hub-link::before { content: ""; position: absolute; left: 50%; top: 0; bottom: 0; border-left: 1px solid var(--ibds); }
.p-hub-link i { position: relative; width: 10px; height: 10px; transform: rotate(45deg); background: var(--ib); }
.p-hub-propose i { box-shadow: inset 0 0 0 1.5px var(--ibrand); }
.p-hub-approve i { background: var(--ibrand); }
.p-hub-link span { position: absolute; left: calc(50% + 16px); top: 50%; transform: translateY(-50%); font-size: var(--text-sm); color: var(--ifm); }
.p-hub figcaption { grid-area: cap; margin-top: 24px; justify-self: stretch; }
@media (min-width: 900px) {
  .p-hub { grid-template-columns: auto minmax(40px, 1fr) auto minmax(40px, 1fr) auto; grid-template-areas: "tools l1 vault l2 people" "cap cap cap cap cap"; align-items: center; }
  .p-hub-side { flex-direction: column; align-items: stretch; }
  .p-hub-link { height: auto; align-self: stretch; }
  .p-hub-link::before { left: 0; right: 0; top: 50%; bottom: auto; border-left: 0; border-top: 1px solid var(--ibds); }
  .p-hub-link span { left: 50%; top: calc(50% + 12px); transform: translateX(-50%); }
}
.p-fold .site-cta { margin-top: 32px; align-items: center; }
.site-cta-link, .p-inv .site-cta-link { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 0.25em; text-decoration-color: var(--ibds, var(--border-strong)); }
.site-cta-link:hover { text-decoration-color: currentColor; }
.p-small { margin: 8px 0 0; font-size: var(--text-sm); line-height: var(--lh-sm); color: var(--ifm); max-width: 44rem; }
.p-small strong { color: var(--if); }
.p-fold .alpha-note { margin: 8px 0 0; font-size: var(--text-sm); line-height: var(--lh-sm); color: var(--ifm); max-width: 44rem; }
.p-fold .alpha-note strong { color: var(--if); }

/* The mark: the logo masked in the band's brand colour. Below 900px it
   closes the band under the text; above, it is the right column and runs
   past the band's edge, cropped, the way a poster crops its image. */
.p-mark { position: relative; min-height: 160px; margin: 0; }
.p-mark::before {
  content: ""; position: absolute; inset: 0; background: var(--ibrand);
  -webkit-mask: url(/logo.svg) no-repeat center / contain; mask: url(/logo.svg) no-repeat center / contain;
}
@media (prefers-reduced-motion: no-preference) {
  /* Only the first band settles: one authored moment, and the closing mark
     is never caught mid-settle when it scrolls into view. */
  header .p-hub { animation: p-settle 1100ms cubic-bezier(0.16, 1, 0.3, 1) both; }
  @keyframes p-settle { from { opacity: 0; transform: scale(0.92); } }
}
@media (min-width: 900px) {
  .p-fold-body { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); grid-template-areas: "head head" "text field"; align-items: center; }
  /* The H1 runs across both columns; the mark's left edge is far enough
     right that the longest line clears it at every width. */
  .p-fold-head { grid-area: head; position: relative; z-index: 1; }
  .p-fold-text { grid-area: text; }
  .p-fold { overflow: hidden; }
  .p-fold-body .p-hub { grid-area: field; }
}

/* The rail: the mark's silhouette repeats down the left margin on wide screens,
   hollow at the top and filling as the reader passes the approval sections.
   Scroll-driven where supported and motion is welcome; a static
   hollow-then-filled column otherwise. */
.p-rail { display: none; }
@media (min-width: 1100px) {
  .p-rail { display: grid; gap: 16px; position: fixed; top: 50%; transform: translateY(-50%); left: 16px; z-index: 1; pointer-events: none; }
  .p-rail i { display: block; width: 8px; height: 8px; transform: rotate(45deg); box-shadow: inset 0 0 0 1.5px var(--brand); }
  .p-rail i:nth-child(n+8) { box-shadow: none; background: var(--brand); }
  @supports (animation-timeline: scroll()) { @media (prefers-reduced-motion: no-preference) {
    .p-rail i { box-shadow: inset 0 0 0 1.5px var(--brand); background: none; animation: p-fill linear both; animation-timeline: scroll(root); }
    .p-rail i:nth-child(1) { animation-range: 4% 8%; }   .p-rail i:nth-child(2) { animation-range: 8% 12%; }
    .p-rail i:nth-child(3) { animation-range: 12% 16%; } .p-rail i:nth-child(4) { animation-range: 16% 20%; }
    .p-rail i:nth-child(5) { animation-range: 20% 24%; } .p-rail i:nth-child(6) { animation-range: 24% 28%; }
    .p-rail i:nth-child(7) { animation-range: 28% 32%; } .p-rail i:nth-child(8) { animation-range: 32% 36%; }
    .p-rail i:nth-child(9) { animation-range: 36% 40%; } .p-rail i:nth-child(10) { animation-range: 40% 44%; }
    .p-rail i:nth-child(11) { animation-range: 44% 48%; } .p-rail i:nth-child(12) { animation-range: 48% 52%; }
    .p-rail i:nth-child(13) { animation-range: 52% 56%; } .p-rail i:nth-child(14) { animation-range: 56% 60%; }
    @keyframes p-fill { to { background: var(--brand); box-shadow: inset 0 0 0 1.5px var(--brand); } }
  } }
}

/* Sections ---------------------------------------------------------------- */
.p-sec { padding: clamp(80px, 10vw, 144px) 0 0; }
.p-sec[id] { scroll-margin-top: 24px; }
.p-sec h2 { margin: 0 0 40px; font-size: clamp(1.75rem, 1.2rem + 2.2vw, 3rem); line-height: 1.05; letter-spacing: -0.03em; font-weight: 800; max-width: 22ch; text-wrap: balance; }
.p-sec h3 { margin: 0; font-size: var(--text-lg); line-height: var(--lh-lg); font-weight: 600; letter-spacing: -0.01em; }
.p-sec p { max-width: 60ch; }

/* The ceiling: five lines, each at display size, with a drawn cross. */
.p-ceiling { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--fg); }
.p-ceiling li { display: grid; grid-template-columns: 2.5rem minmax(0, 1fr); align-items: center; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--border); font-size: clamp(1.375rem, 1rem + 1.4vw, 2.25rem); line-height: 1.1; letter-spacing: -0.025em; font-weight: 800; }
.p-x { position: relative; width: 0.45em; height: 0.45em; justify-self: center; }
.p-x::before, .p-x::after { content: ""; position: absolute; left: 50%; top: 0; width: 0.055em; height: 100%; margin-left: -0.0275em; background: var(--fg); transform: rotate(45deg); }
.p-x::after { transform: rotate(-45deg); }
.p-note { margin: 24px 0 0; max-width: 48rem; position: relative; padding-left: calc(1.25rem + 12px); color: var(--fg-muted); }
.p-note::before { content: ""; position: absolute; left: 5px; top: 8px; width: 9px; height: 9px; transform: rotate(45deg); background: var(--brand); }
.p-note a { white-space: nowrap; }
.p-note-who { margin-top: 12px; }
.p-note-who::before { background: none; box-shadow: inset 0 0 0 1.5px var(--brand); }

/* The ledger: a hairline grid, pains hollow and fixes filled. */
.p-ledger-head { display: grid; border-top: 1px solid var(--fg); }
.p-ledger-head span { padding: 12px 24px 12px 48px; font-size: var(--text-sm); font-weight: 600; color: var(--fg-muted); }
.p-ledger { margin: 0; display: grid; }
.p-ledger > div { display: grid; border-top: 1px solid var(--border); }
.p-ledger > div:last-child { border-bottom: 1px solid var(--border); }
.p-ledger dt, .p-ledger dd { margin: 0; padding: 24px 24px 24px 48px; position: relative; }
.p-ledger dt { font-size: var(--text-lg); line-height: var(--lh-lg); font-weight: 600; letter-spacing: -0.01em; }
.p-ledger dd { color: var(--fg-muted); max-width: 60ch; }
.p-ledger dt::before, .p-ledger dd::before { content: ""; position: absolute; left: 22px; top: 33px; width: 9px; height: 9px; transform: rotate(45deg); }
.p-ledger dt::before { box-shadow: inset 0 0 0 1.5px var(--brand); }
.p-ledger dd::before { background: var(--brand); }
@media (min-width: 720px) {
  .p-ledger > div, .p-ledger-head { grid-template-columns: 1fr 1fr; }
  .p-ledger dd, .p-ledger-head span:last-child { border-left: 1px solid var(--border); }
}
@media (max-width: 719px) { .p-ledger-head span:last-child { display: none; } .p-ledger dd { padding-top: 0; } .p-ledger dd::before { top: 9px; } }

/* Rows: a heading on the left, its text on the right, a hairline between. */
/* Why Reliquary: six reasons on a hairline grid, one column on a phone. */
.p-why { display: grid; border-top: 1px solid var(--fg); }
.p-why > div { padding: 24px 0; border-bottom: 1px solid var(--border); }
.p-why h3 { margin: 0 0 8px; font-size: var(--text-lg); line-height: 1.2; letter-spacing: -0.015em; font-weight: 800; }
.p-why p { margin: 0; color: var(--fg-muted); max-width: 40ch; }
@media (min-width: 720px) { .p-why { grid-template-columns: 1fr 1fr; column-gap: 48px; } }
@media (min-width: 1100px) { .p-why { grid-template-columns: repeat(3, 1fr); } }
.p-rows { display: grid; border-top: 1px solid var(--fg); }
.p-rows > div { display: grid; gap: 8px 48px; padding: 24px 0; border-bottom: 1px solid var(--border); }
.p-rows > div p { margin: 0; color: var(--fg-muted); }
@media (min-width: 720px) { .p-rows > div { grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr); } }

/* How it works: two reserved frames, then the steps. */
.p-frames { display: grid; gap: 24px; margin: 0 0 64px; }
@media (min-width: 900px) { .p-frames { grid-template-columns: 1fr 1fr; align-items: start; } }
.p-frame { margin: 0; display: grid; grid-template-rows: 1fr auto; border: 1px solid var(--border-strong); }
/* What it looks like: the reel and the screens, in the frames' hairline */
.p-reel video, .p-reel img, .p-shot img { display: block; width: 100%; height: auto; background: var(--bg); }
/* On auto the page carries both reels (landing.ts) and one shows. Reduced
   motion wins over both: `.p-reel video` outranks `.reel-dark`. */
.reel-still, .reel-dark { display: none; }
@media (prefers-color-scheme: dark) {
  .reel-light { display: none; }
  .reel-dark { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .p-reel video { display: none; }
  .reel-still { display: block; }
}
.p-reel figcaption, .p-shot figcaption { padding: 12px 24px 14px; border-top: 1px solid var(--border-strong); font-size: var(--text-sm); line-height: var(--lh-sm); color: var(--fg-muted); }
.p-shots { display: grid; gap: 24px; margin-top: 24px; }
.p-frame-art { padding: 0; display: grid; align-content: center; }
.p-frame figcaption { padding: 12px 24px 14px; border-top: 1px solid var(--border-strong); font-size: var(--text-sm); line-height: var(--lh-sm); color: var(--fg-muted); }
.p-frame .hero-card { max-width: none; margin: 0; width: 100%; border: 0; border-radius: 0; padding: 24px; background: var(--bg); }
.p-frame .term { margin: 0; max-width: none; width: 100%; border: 0; border-radius: 0; padding: 24px; background: var(--bg); }
.p-steps { list-style: none; margin: 0; padding: 0; counter-reset: p; display: grid; border-top: 1px solid var(--fg); }
.p-steps li { counter-increment: p; display: grid; gap: 8px 48px; padding: 24px 0; border-bottom: 1px solid var(--border); }
.p-steps h3::before { content: counter(p) "  "; font-weight: 200; font-variant-numeric: tabular-nums; white-space: pre; }
.p-steps p { margin: 0; color: var(--fg-muted); }
@media (min-width: 720px) { .p-steps li { grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr); } }

/* The log, running: one line per entry, repeated so the strip has no end.
   It pauses under the pointer, and under reduced motion it is a row you
   scroll by hand. */
.p-log { margin: 64px 0 0; border-top: 1px solid var(--fg); border-bottom: 1px solid var(--border); }
.p-log-cap { margin: 0; padding: 12px 0 0; font-size: var(--text-sm); font-weight: 600; color: var(--fg-muted); }
.p-log-track { display: flex; flex-wrap: wrap; gap: 8px 48px; padding: 12px 0 16px; font-size: var(--text-sm); line-height: var(--lh-sm); color: var(--fg-muted); }
.p-log-track span { max-width: 100%; }
.p-log-track span::before { content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 12px 1px 0; transform: rotate(45deg); background: var(--brand); }
.p-log-track span.p-o::before { background: none; box-shadow: inset 0 0 0 1.5px var(--brand); }
.p-log-track b { color: var(--fg); font-weight: 600; }


/* Pricing as a three-cell ledger. */
.tier-price .amount-word { font-size: var(--text-lg); line-height: var(--lh-lg); font-weight: 400; color: var(--fg-muted); }
#pricing .site-cta { margin-top: 32px; }
.p-beta { margin: 0 0 32px; max-width: 60ch; color: var(--fg-muted); display: grid; grid-template-columns: 1.25rem minmax(0, 1fr); gap: 12px; }
.p-beta::before { content: ""; width: 9px; height: 9px; margin-top: 8px; transform: rotate(45deg); background: var(--brand); }
.p-beta strong { color: var(--fg); }
.p-tiers { list-style: none; margin: 0; padding: 0; display: grid; border-top: 1px solid var(--fg); }
.p-tiers > li { padding: 24px 0; display: grid; gap: 8px; align-content: start; border-bottom: 1px solid var(--border); }
.p-tiers > li p { margin: 0; }
.p-tiers h3 { display: flex; align-items: center; gap: 10px; }
.p-tiers .tier-for { color: var(--fg-muted); }
.p-tiers .tier-price { margin-top: 8px; }
.p-tiers .tier-price .amount { font-size: clamp(2rem, 1.5rem + 1.5vw, 3rem); font-weight: 200; letter-spacing: -0.03em; line-height: 1; }
.p-tiers .tier-yearly { color: var(--fg-muted); font-size: var(--text-sm); }
.p-tiers ul { margin: 16px 0 0; padding: 16px 0 0; border-top: 1px solid var(--border); list-style: none; display: grid; gap: 8px; font-size: var(--text-sm); color: var(--fg-muted); }
.p-tiers ul li { display: flex; gap: 10px; padding: 0; }
.p-tiers ul li::before { content: ""; flex: none; width: 6px; height: 6px; margin-top: 7px; transform: rotate(45deg); background: var(--fg-muted); }
@media (min-width: 720px) {
  .p-tiers { grid-template-columns: repeat(2, 1fr); max-width: 56rem; }
  .p-tiers > li { padding: 24px; }
  .p-tiers > li + li { border-left: 1px solid var(--border); }
  .p-tiers > li:first-child { padding-left: 0; }
}
.p-tiers-note { margin: 24px 0 0; font-size: var(--text-sm); line-height: var(--lh-sm); color: var(--fg-muted); max-width: 60ch; }

/* Questions: the existing disclosure list, wider. */
.p-sec .faq { max-width: 56rem; border-top-color: var(--fg); }
.p-sec .faq { padding-top: 8px; }
.p-sec .faq summary { font-size: var(--text-lg); min-height: 60px; transition: color 120ms ease-out; }
.p-sec .faq summary:hover { color: var(--link); }
.p-sec .faq details p { max-width: 60ch; }

/* Closing band: mirrors the first. */
/* footer in style.css is a centred 1280px block; the band is full-bleed like the first. */
.p-close { margin: clamp(80px, 10vw, 144px) 0 0; max-width: none; width: 100%; padding: 0; border-top: 0; min-height: min(80svh, 760px); }
.p-close .p-fold-body { padding-block: 64px 48px; }
.p-close-h2 { margin: 0; font-size: clamp(2.5rem, 1rem + 3.9vw, 4.75rem); line-height: 0.98; letter-spacing: -0.035em; font-weight: 800; }
.p-close-h2 b { display: block; font-weight: 200; }
.p-close .p-lede { max-width: 44rem; margin-top: 0; }
.p-close .who-builds { color: var(--ifm); max-width: 44rem; }
.p-close .p-mark { min-height: 160px; }
@media (min-width: 900px) { .p-close .p-mark::before { inset: 10% 0 10% 30%; } }
.p-footer { padding-block: 20px 28px; border-top: 1px solid var(--ibd); display: flex; flex-wrap: wrap; align-items: center; gap: 8px 24px; font-size: var(--text-sm); color: var(--ifm); }
.p-footer .site-footer-brand { color: inherit; margin-right: auto; }
.p-footer .footer-links { display: contents; }
.p-footer .footer-version { color: var(--ifm); }
.p-footer a { color: var(--ifm); padding: 4px 0; transition: color 120ms ease-out; }
.p-footer a:hover { color: var(--if); }


/* Motion: one easing and two durations for the whole poster, so everything
   moves the same way. Load: the first band's lines, text and mark settle in
   order, one authored moment. Scroll: each block lifts in over its first
   240px of entry where scroll-driven animation is supported, and is simply
   there where not. Hover: colour and border, never size. All of it off
   under prefers-reduced-motion. */
.p-site { --ease: cubic-bezier(0.16, 1, 0.3, 1); --quick: 160ms; --slow: 800ms; }
.p-site :is(a, .button, summary) { transition: color var(--quick) var(--ease), border-color var(--quick) var(--ease), background-color var(--quick) var(--ease); }
@media (prefers-reduced-motion: no-preference) {
  html:has(.p-site) { scroll-behavior: smooth; }
  header .p-h1 > span, header .p-fold-text > * { animation: p-rise var(--slow) var(--ease) both; }
  header .p-h1 > span:nth-child(2) { animation-delay: 80ms; }
  header .p-h1 > span:nth-child(3) { animation-delay: 160ms; }
  header .p-fold-text > :nth-child(1) { animation-delay: 300ms; }
  header .p-fold-text > :nth-child(2) { animation-delay: 360ms; }
  header .p-fold-text > :nth-child(3) { animation-delay: 420ms; }
  header .p-fold-text > :nth-child(4) { animation-delay: 480ms; }
  header .p-fold-text > :nth-child(5) { animation-delay: 540ms; }
  header .p-fold-text > :nth-child(6) { animation-delay: 600ms; }
  header .p-hub { animation-delay: 240ms; }
  @keyframes p-rise { from { opacity: 0; transform: translateY(14px); } }
  @supports (animation-timeline: view()) {
    .p-sec > *, .p-close .p-fold-body > * { animation: p-rise linear both; animation-timeline: view(); animation-range: entry 0% entry 240px; }
  }
}

/* Phones: calls to action stack full width (one thumb, one target each),
   and the poster's spacing comes down to the screen. Last in the file: these
   override the poster's own rules above, at the same specificity. */
@media (max-width: 599px) {
  .site-cta, .p-fold .site-cta { flex-direction: column; align-items: stretch; gap: 8px; }
  .site-cta .button { justify-content: center; min-height: 48px; }
  .site-cta .site-cta-link { display: flex; align-items: center; justify-content: center; min-height: 44px; }
  .hero-card-actions > span { flex: 1 1 100%; }
  .hero-card-actions label.button { width: 100%; justify-content: center; min-height: 44px; }
  .p-fold-body { gap: 32px; padding-block: 24px 40px; }
  .p-sec { padding-top: 64px; }
  .p-sec h2 { margin-bottom: 24px; }
  .p-ceiling li { grid-template-columns: 1.5rem minmax(0, 1fr); gap: 12px; padding: 14px 0; }
  .p-frame figcaption { padding: 12px 16px; }
  .p-close { margin-top: 64px; }
  .p-close .p-fold-body { padding-block: 48px 40px; }
}
