/* The pages the directory server serves: the card of a person (/u/<n>), of an organisation (/o/<n>), and the base of
   every app screen (/start, /login, /me, /account, /o/new, /staff, /verify, /embed, the sign-in return). design/DESIGN.md,
   "Il sistema" (24 October 2026) and its "Seconda passata" (28 October 2026) are the rule book; design/tokens.css the
   values, copied below.
   Layout: no-sidebar shell, a 1152px column; the identity is the page header, on the ground; one 6-column grid
   (6 x 165.33 + 5 x 32 = 1152): the lead (4 columns) beside its companion (2),
   then a main column (4) and a rail (2). Since 28 October 2026 only the lead has a ground of its own: it is the record
   the screen is about. Everything else sits on the page as a register (a heading, then ruled rows), so nothing has an
   edge to level. Three devices from the subject: the stamp (one verdict per screen, large, with its figures), the
   ledger line (the chain of proofs as one ruled line with its stations) and the roll (lists as ruled registers, the
   witnesses by name and time). */
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap; src: url(fonts/inter-latin.woff2) format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-style: normal; font-weight: 100 800; font-display: swap; src: url(fonts/jetbrains-mono-latin.woff2) format("woff2"); } /* taste-skill-ignore: keys, hashes and paths only */

/* ---------- tokens (design/tokens.css) ---------- */
:root {
  color-scheme: dark;
  --ground: #1e1f22; --panel: #252629; --surface: #2b2d31; --raised: #313338;
  --active: #3a3c42; --active-hover: #44474e; --rule: #393b41; --control: #5a5d65; --control-hover: #6c6f78;
  --text: #f2f3f5; --muted: #b5bac1; --faint: #9aa0a9;
  --accent: #78aaff;            /* Veil blue: only on the proof chain and verified data */
  --primary: #f2f3f5; --primary-ink: #111214; --primary-hover: #ffffff;
  --positive: #5cc985; --pill-positive-bg: #213529; --pill-positive-ink: #7fdba1;
  --negative: #f07a7c; --pill-negative-bg: #3a2427; --pill-negative-ink: #f5a3a4; --negative-border: #8a4a4d;
  --warning: #e8b85c; --pill-warning-bg: #3a3122; --pill-warning-ink: #f0cf8a; --warning-border: #7a6a45; /* not recent: a warning, not a failure */
  --pill-neutral-bg: #3a3c42; --pill-neutral-ink: #dfe1e5;
  --person-bg: #24403c; --person-ink: #a6e3d8;
  --p1-bg: #3b3527; --p1-ink: #f0d79b;
  --p2-bg: #24403c; --p2-ink: #a6e3d8;
  --p3-bg: #402630; --p3-ink: #f2b8c6;
  --shadow-float: 0 10px 28px rgba(0, 0, 0, 0.45); /* taste-skill-ignore: only what floats (menus, tooltips) */

  --font: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "JetBrains Mono", "Veil Mono Fallback A", "Veil Mono Fallback B", "Veil Mono Fallback C", ui-monospace, "SFMono-Regular", Menlo, monospace; /* taste-skill-ignore: keys, hashes and paths only; the fallbacks carry its metrics (session.css) */
  --fs-small: 12px; --lh-small: 16px;
  --fs-body: 14px; --lh-body: 20px;
  --fs-section: 16px; --lh-section: 24px;
  --fs-title: 20px; --lh-title: 26px;
  --fs-lead: 24px; --lh-lead: 30px;
  --fs-stamp: 32px; --lh-stamp: 36px; /* the stamp: the screen's one verdict, its one large thing */
  --fs-meta: var(--fs-small);

  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px;
  --gap: 16px; --gap-in: 12px;
  --col-gap: 32px;  /* between the grid's columns: the rail sits on the page, so it needs air, not an edge */
  --sec-gap: 48px;  /* between two sections on the page: space, not a box, tells them apart */
  --pad-x: 24px; --pad-lead: 24px; --pad-panel: 16px; --card-pad: var(--pad-x);
  --field: var(--ground); /* the ground of a text field */
  --radius-card: 14px; --radius-nested: 10px; --radius-small: 6px; --round: 999px;
  --column: 1152px;
  --control-height: 36px;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --t-fast: 150ms; --t-slow: 250ms;
}
:root[data-theme="light"] {
  color-scheme: light;
  --ground: #eceef1; --panel: #f6f7f8; --surface: #ffffff; --raised: #eff0f2;
  --active: #e2e4e8; --active-hover: #d6d9de; --rule: #dcdfe3; --control: #b4b8bf; --control-hover: #8c919a;
  --text: #1e1f22; --muted: #4b4e56; --faint: #5c6068;
  --accent: #2f6fd8;
  --primary: #1e1f22; --primary-ink: #ffffff; --primary-hover: #000000;
  --positive: #1f7a4a; --pill-positive-bg: #dcf1e4; --pill-positive-ink: #145a35;
  --negative: #c4242a; --pill-negative-bg: #fbe6e6; --pill-negative-ink: #9b1f24; --negative-border: #e0a2a4;
  --warning: #a8640c; --pill-warning-bg: #fbefd9; --pill-warning-ink: #714405; --warning-border: #dcc08f;
  --pill-neutral-bg: #e2e4e8; --pill-neutral-ink: #2e3036;
  --person-bg: #d4ede6; --person-ink: #1b4f45;
  --p1-bg: #f3e6c8; --p1-ink: #5f450c;
  --p2-bg: #d4ede6; --p2-ink: #1b4f45;
  --p3-bg: #f4dbe2; --p3-ink: #74283d;
  --shadow-float: 0 10px 28px rgba(16, 18, 22, 0.16); /* taste-skill-ignore: only what floats */
  --field: #ffffff;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--ground);
  color: var(--text);
  font: 400 var(--fs-body)/var(--lh-body) var(--font);
  -webkit-font-smoothing: antialiased;
}
body::before { content: ""; position: fixed; inset: 0 0 auto; height: env(safe-area-inset-top, 0px); z-index: 10; background: var(--ground); }
h1, h2, h3, p, ul, ol, dl, dd, figure { margin: 0; }
ul[class], ol[class] { padding: 0; list-style: none; }
button, input, textarea, select { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
svg { display: block; flex: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-small); }
.num { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); font-size: var(--fs-small); letter-spacing: 0; } /* taste-skill-ignore: keys, hashes and paths only */
[hidden] { display: none !important; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.minw0 { min-width: 0; }
/* "a · b · c" wraps between parts (inside one only when it is wider than the line): each part carries
   its dot in a gutter in front, and a part that starts a line has its dot outside the clip, so no
   line starts or ends on "·" */
.dots { overflow: hidden; }
.dots > .parts { display: block; margin-left: -0.9em; }
.dots .nw { position: relative; display: inline-block; max-width: 100%; padding-left: 0.9em; vertical-align: top; }
.dots .nw::before { content: "·"; position: absolute; left: 0; width: 0.9em; text-align: center; }

/* ---------- top bar ---------- */
.topbar { position: sticky; top: env(safe-area-inset-top, 0px); z-index: 5; background: var(--ground); border-bottom: 1px solid transparent; transition: border-color var(--t-fast) var(--ease-out); }
.topbar.scrolled { border-bottom-color: var(--rule); }
.bar-inner, .page-inner {
  max-width: calc(var(--column) + 2 * var(--s6));
  margin: 0 auto;
  padding-left: max(var(--s6), env(safe-area-inset-left, 0px));
  padding-right: max(var(--s6), env(safe-area-inset-right, 0px));
}
.bar-inner { display: flex; align-items: center; gap: var(--s5); height: 48px; }
.brand { display: flex; align-items: center; gap: var(--s2); font-weight: 600; font-size: var(--fs-section); letter-spacing: -0.01em; }
.brand svg { width: 23px; height: 18px; }
.bar-links { display: flex; gap: var(--s5); }
.bar-links a { font-size: var(--fs-body); font-weight: 500; color: var(--muted); white-space: nowrap; transition: color var(--t-fast) var(--ease-out); }
.bar-links a:hover { color: var(--text); }
.bar-links a[aria-current="page"] { color: var(--text); }
.bar-right { margin-left: auto; display: flex; align-items: center; gap: var(--s3); }
/* the language switch: navigation, so grey like the links, never the accent */
.lang { border: 0; background: none; padding: 0; font: 500 var(--fs-body)/var(--lh-body) var(--font); color: var(--muted); cursor: pointer; transition: color var(--t-fast) var(--ease-out); }
.lang:hover { color: var(--text); }
.search { position: relative; width: 320px; display: block; }
.search svg { position: absolute; left: 12px; top: 9px; width: 14px; height: 14px; color: var(--faint); }
.search input {
  width: 100%; height: 32px; padding: 0 12px 0 36px; border: 0; border-radius: var(--round);
  background: var(--surface); color: var(--text); font-size: var(--fs-body);
}
:root[data-theme="light"] .search input { box-shadow: inset 0 0 0 1px var(--rule); } /* taste-skill-ignore: the field's edge on a light ground */
.search input::placeholder { color: var(--faint); }
.icon-btn.menu-btn { display: none; }
@media (min-width: 901px) { .menu-sheet.open { display: none; } }

/* ---------- page ---------- */
.page-inner { padding-block: var(--s5) var(--s7); }

/* the page's header: the identity on the ground (not a panel), its one primary action on the right */
.object { display: flex; align-items: center; gap: var(--s4); padding: var(--s2) 0 0; }
.avatar { width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center; flex: none; background: var(--person-bg); color: var(--person-ink); font-weight: 600; font-size: 18px; letter-spacing: 0.01em; } /* taste-skill-ignore: the initials in a 56px avatar */
/* an organisation is a rounded square, like its logo next to its members' names */
.avatar.org { border-radius: var(--radius-card); background: var(--active); color: var(--text); overflow: hidden; }
.avatar.org svg { width: 30px; height: 23px; }
/* an organisation's own logo (since 24 October 2026): an <img> from this server, the square and its radius set here */
.avatar.org img { display: block; width: 56px; height: 56px; object-fit: contain; }
/* a person's profile picture (since 25 October 2026): the same <img> from this server, round and filling the disc */
.avatar:not(.org) { overflow: hidden; }
.avatar:not(.org) img { display: block; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
/* a person beside their name in a list: the picture, or the initials, in a 24px disc */
.pic24 { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; flex: none; overflow: hidden; background: var(--person-bg); color: var(--person-ink); font-size: 11px; font-weight: 600; letter-spacing: 0.01em; } /* taste-skill-ignore: 11px initials in a 24px disc, as the operators' faces */
.pic24 img { display: block; width: 24px; height: 24px; border-radius: 50%; object-fit: cover; }
.with-pic { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
.who { min-width: 0; flex: 1; }
.name-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2); }
/* affiliated organisations: each logo is its own image (a mark on its own ground), linked to the organisation */
.orgs { display: flex; gap: var(--s2); }
.org-logo { display: grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-small); flex: none; overflow: hidden; background: var(--active); color: var(--text); font-size: var(--fs-small); font-weight: 600; letter-spacing: 0.01em; transition: background-color var(--t-fast) var(--ease-out); }
.org-logo:hover { background: var(--active-hover); }
.org-logo svg { width: 15px; height: 12px; }
.org-logo img { display: block; width: 24px; height: 24px; object-fit: contain; }
.name-line h1 { font-size: var(--fs-title); line-height: var(--lh-title); font-weight: 600; letter-spacing: -0.015em; overflow-wrap: anywhere; }
.who .meta { margin-top: var(--s1); color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
/* badges: their icons in one quiet pill next to the name, like the badges of the Veil app; each icon
   is flat, in the page's greys, and opens its entry in the log. The label shows on hover and focus. */
.badges { display: inline-flex; align-items: center; gap: var(--s2); height: 28px; padding: 0 var(--s2); border-radius: var(--round); background: var(--panel); }
:root[data-theme="light"] .badges { background: var(--active); }
.badge { position: relative; display: grid; place-items: center; min-width: 22px; height: 22px; border-radius: var(--radius-small); }
.badge img { width: 22px; height: 22px; display: block; object-fit: contain; }
.badge-text { padding: 0 var(--s1); color: var(--muted); font-size: var(--fs-small); font-weight: 500; white-space: nowrap; }
.badge .tip { display: none; position: absolute; z-index: 6; top: calc(100% + var(--s2)); left: 50%; transform: translateX(-50%); width: max-content; max-width: 240px; padding: var(--s2) var(--s3); border-radius: var(--radius-small); background: var(--surface); box-shadow: var(--shadow-float); /* taste-skill-ignore: a tooltip floats */ color: var(--text); font-size: var(--fs-small); line-height: var(--lh-small); font-weight: 400; text-align: left; pointer-events: none; }
.badge .tip b { display: block; font-weight: 600; }
.badge .tip span { display: block; color: var(--muted); }
.badge:hover .tip, .badge:focus-visible .tip { display: block; }
.actions { display: flex; gap: var(--s3); flex: none; }

/* ---------- actions: one filled primary per screen, outlined secondaries, text tertiaries ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  height: var(--control-height); padding: 0 var(--s4); border-radius: var(--round); border: 1px solid var(--control);
  background: transparent; color: var(--text); font-weight: 500; font-size: var(--fs-body); cursor: pointer; white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
.btn:hover { background: var(--raised); border-color: var(--control-hover); }
.btn:active { transform: scale(0.97); }
.btn:disabled { cursor: default; opacity: 0.6; }
.btn.primary { background: var(--primary); color: var(--primary-ink); border-color: var(--primary); }
.btn.primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.btn.small { height: 28px; padding: 0 var(--s3); font-size: var(--fs-small); }
.btn svg { width: 15px; height: 15px; }
/* the danger tone is for confirmations only: an action that ends something is neutral until its confirmation opens */
.btn.danger { border-color: var(--control); color: var(--text); }
.confirm .btn.danger, .confirm.danger .btn.danger, .btn.danger.confirming { border-color: var(--negative-border); color: var(--pill-negative-ink); }
.confirm .btn.danger:hover, .btn.danger.confirming:hover { background: var(--pill-negative-bg); border-color: var(--negative); }
.icon-btn {
  width: 28px; height: 28px; display: inline-grid; place-items: center; border: 0; border-radius: var(--radius-small);
  background: transparent; color: var(--muted); cursor: pointer; transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.icon-btn:hover { background: var(--raised); color: var(--text); }
.icon-btn.done { color: var(--positive); }
.icon-btn svg { width: 15px; height: 15px; }
.text-btn { border: 0; background: none; padding: 0; color: var(--muted); font: 500 var(--fs-body)/var(--lh-body) var(--font); cursor: pointer; text-underline-offset: 3px; transition: color var(--t-fast) var(--ease-out); }
.text-btn:hover { color: var(--text); text-decoration: underline; }
.text-btn[aria-expanded="true"] { color: var(--text); }
.text-btn:disabled { opacity: 0.55; cursor: default; text-decoration: none; }
/* a link in a sentence: underlined in grey; a link that goes elsewhere from a panel's title: words and a chevron */
a.inline { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--control); }
a.inline:hover { text-decoration-color: var(--text); }
.card-link { display: inline-flex; align-items: center; gap: 2px; border: 0; padding: 0; background: none; color: var(--text); font-weight: 500; font-size: var(--fs-body); cursor: pointer; text-underline-offset: 3px; }
.card-link:hover { text-decoration: underline; }
.card-link svg { width: 12px; height: 12px; }

/* ---------- chips: six kinds (design/DESIGN.md, rule 2) ---------- */
.pill { display: inline-flex; align-items: center; gap: var(--s2); height: 20px; padding: 0 var(--s2); border-radius: var(--round); font-size: var(--fs-small); line-height: var(--lh-small); font-weight: 500; white-space: nowrap; flex: none; vertical-align: middle; }
/* state: the word alone, no fill and no dot (28 October 2026). The usual state of a row (Active, Member) is plain grey;
   only a state that asks for attention takes a tone, in its words: revoked or refused in the danger ink, waiting in the
   warning ink. Offline and Invited are quieter than Active. */
.pill.ok, .pill.off, .pill.bad, .pill.wait { padding: 0; background: none; color: var(--muted); font-weight: 400; }
.pill.off { color: var(--faint); }
.pill.bad { color: var(--pill-negative-ink); }
.pill.wait { color: var(--pill-warning-ink); }
/* verified: what this browser checked, with the accent's tick */
.pill.verified { padding: 0; background: none; color: var(--text); font-weight: 400; }
.pill.verified::before { content: ""; width: 10px; height: 6px; margin-top: -3px; border: solid var(--accent); border-width: 0 0 2px 2px; transform: rotate(-45deg); flex: none; }
/* role: outlined */
.pill.role, .pill.here { border: 1px solid var(--control); background: none; color: var(--text); }
/* alert: the pale danger (or warning) fill */
.pill.alert { background: var(--pill-negative-bg); color: var(--pill-negative-ink); }
.pill.alert.warn, .pill.warn { background: var(--pill-warning-bg); color: var(--pill-warning-ink); }
/* category: the neutral fill */
.pill.cat { background: var(--pill-neutral-bg); color: var(--pill-neutral-ink); }
/* count: a bare number */
.count { color: var(--faint); font-weight: 400; font-variant-numeric: tabular-nums; }

/* a plain notice under the header: a ban, an erasure on its way */
.notice { display: flex; gap: var(--s3); align-items: flex-start; margin-top: var(--s4); padding: var(--s3) var(--s4); border-radius: var(--radius-nested); background: var(--pill-negative-bg); color: var(--pill-negative-ink); }
.notice.neutral { background: var(--panel); color: var(--text); }
.notice svg { width: 18px; height: 18px; margin-top: 1px; }
.notice b { display: block; font-weight: 600; }
.notice span { font-size: var(--fs-small); line-height: var(--lh-small); }
#notices .notice, .own-notices .notice { font-variant-numeric: tabular-nums; } /* a card's notices carry dates and entries */

/* ---------- the tab bar: the views on the left, the freshness of the check on the right ---------- */
.tabbar { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--s2) var(--s5); margin-top: var(--s6); border-bottom: 1px solid var(--rule); }
.tabs { display: flex; gap: var(--s5); margin-top: var(--s6); border-bottom: 1px solid var(--rule); }
.tabbar > .tabs { margin-top: 0; border-bottom: 0; }
.tab {
  position: relative; padding: 0 0 var(--s3); border: 0; background: none; cursor: pointer;
  color: var(--muted); font-weight: 500; font-size: var(--fs-body); transition: color var(--t-fast) var(--ease-out);
}
.tab:hover { color: var(--text); }
.tab[aria-selected="true"] { color: var(--text); }
.tab[aria-selected="true"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--text); border-radius: 2px; }
.tab .count { margin-left: var(--s1); }

.status-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); margin: var(--s4) 0; }
.tabbar > .status-row { margin: 0; padding-bottom: var(--s3); justify-content: flex-end; }
.stamp { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); display: flex; align-items: center; gap: var(--s2); }
.stamp .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--faint); flex: none; }
.stamp.ok .dot { background: var(--accent); }
.stamp.bad .dot { background: var(--negative); }
.stamp.warn .dot { background: var(--warning); }
.status-row .text-btn { font-size: var(--fs-small); line-height: var(--lh-small); }

/* ---------- grid and sections ---------- */
.grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--sec-gap) var(--col-gap); align-items: start; }
.tabbar + .grid, .tabs + .grid, #storico { margin-top: var(--s5); }
.span-4 { grid-column: span 4; }
.span-2 { grid-column: span 2; }
.span-6 { grid-column: 1 / -1; }
.stack { display: flex; flex-direction: column; gap: var(--sec-gap); min-width: 0; }
/* A section (since 28 October 2026): on the page, no ground and no box; its heading and its rows carry it. */
.panel { min-width: 0; display: flex; flex-direction: column; }
/* the lead: the record the screen is about, the one ground on the page (the brightest) */
.panel.lead { background: var(--surface); border-radius: var(--radius-card); padding: var(--pad-lead) var(--pad-x); }
/* the lead's companion starts where the lead's words start, so the two headings share a line */
.grid > .panel.lead + .panel { padding-top: var(--pad-lead); }
/* a card's overview (28 October 2026): the lead in the first row, the main column under it, and the rail beside both
   from the top, the fingerprint first, so the rail never waits for the lead's row to end */
#panoramica > .panel.lead { grid-column: 1 / span 4; grid-row: 1; }
#panoramica > .stack.span-4 { grid-column: 1 / span 4; grid-row: 2; }
#panoramica > .stack.span-2 { grid-column: 5 / -1; grid-row: 1 / span 2; padding-top: var(--pad-lead); }
/* the rail spans both rows: the second row takes what the rail adds, so the main column starts right under the lead, one
   section gap below it, however long the rail is (third pass, 29 October 2026: an organisation's members sat 180 px down) */
#panoramica { grid-template-rows: auto 1fr; }
/* the history and the members are registers on the page like the devices: their rules run from the column's left edge to its
   right, the edges of the tab bar above, and their text starts on that edge */
#storico .table-wrap, #panoramica .stack > .panel:not(#devices) > .table-wrap { margin: 0; }
#storico th:first-child, #storico td:first-child, #panoramica .stack > .panel:not(#devices) > .table-wrap th:first-child, #panoramica .stack > .panel:not(#devices) > .table-wrap td:first-child { padding-left: 0; }
#storico th:last-child, #storico td:last-child, #panoramica .stack > .panel:not(#devices) > .table-wrap th:last-child, #panoramica .stack > .panel:not(#devices) > .table-wrap td:last-child { padding-right: 0; }
/* the quiet lists of the first polish are sections like the others now */
.panel.quiet { padding: 0; }
/* a list on the page has no row rules: its rows are told apart by their spacing (tables keep theirs) */
.panel.quiet .link-row + .link-row, .panel.quiet .event + .event, .panel.quiet .row + .row, .panel.quiet .note-row + .note-row,
.panel.quiet .report-row + .report-row, .panel.quiet .org-row + .org-row, .panel.quiet .inv-row + .inv-row { border-top: 0; }
.panel.quiet .event { padding: var(--s2) 0; }
.panel > header { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--s1) var(--s3); margin-bottom: var(--gap-in); }
#histMeta { white-space: normal; }
.panel h2 { font-size: var(--fs-section); line-height: var(--lh-section); font-weight: 600; letter-spacing: -0.005em; }
.panel h3 { font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 600; }
.panel .meta { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); white-space: nowrap; }
/* what only the server says (the history, its dates), under what the card signs: grey, never the accent (Q2) */
.panel .server-note { white-space: normal; margin-top: var(--s2); }
.panel p.note { color: var(--muted); }
.empty { color: var(--muted); padding: var(--s3) 0; }

/* ---------- the stamp: the lead's verdict, the one large thing on the screen ----------
   Words, not a tick in a circle: the tone of a status that is not in good standing is the colour of the words. */
.answer { font-size: var(--fs-stamp); line-height: var(--lh-stamp); font-weight: 600; letter-spacing: -0.025em; display: flex; align-items: baseline; gap: var(--s3); }
.answer svg { display: none; }
.answer.bad { color: var(--pill-negative-ink); }
/* not recent (F3): the proofs check out but the newest cosignature is old; a warning, not a failure */
.answer.warn { color: var(--pill-warning-ink); }
.lead > header + .answer { margin-top: var(--s1); }
.finding { margin-top: var(--s2); color: var(--muted); max-width: 66ch; }

/* ---------- the ledger line: the chain of proofs as one ruled line with its stations ----------
   Each station names its proof above the line and writes its figure on it; the rule under the figures runs from one end
   of the record to the other, and the part of each station turns to the accent once this browser has verified it.
   A tick marks where each station starts. No boxes, no icons. */
.chain { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); margin-top: var(--s6); }
.step { position: relative; min-width: 0; padding-right: var(--s4); --line: var(--active); }
.step:last-child { padding-right: 0; }
.step.ok { --line: var(--accent); }
.step.bad { --line: var(--negative); }
.step .k { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
.step .k svg { display: none; }
.step .v { margin: var(--s1) calc(-1 * var(--s4)) 0 0; padding: 0 var(--s4) var(--s2) 0; border-bottom: 2px solid var(--line); font-size: var(--fs-section); line-height: var(--lh-section); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: border-color var(--t-slow) var(--ease-out); }
.step:last-child .v { margin-right: 0; padding-right: 0; }
/* A figure not known yet (the cosignature's until the witnesses are read, the log's host until GET /v1/log answers) keeps
   its line: an empty slot would lift that station's rule above the others while the check waits (29 October 2026). */
.step .v:empty::before { content: "\00a0"; }
.step .v a { text-decoration: none; }
.step .v a:hover { text-decoration: underline; text-underline-offset: 3px; }
.step::before { content: ""; position: absolute; left: 0; top: calc(var(--lh-small) + var(--s1) + var(--lh-section) + var(--s2) - 5px); width: 2px; height: 12px; background: var(--line); transition: background-color var(--t-slow) var(--ease-out); }
.step .s { margin-top: var(--s2); color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); overflow-wrap: anywhere; }

/* ---------- the roll: who cosigned the checkpoint, by name, each with the time of its cosignature ---------- */
.lead-foot { display: grid; gap: var(--s3); margin-top: var(--s6); }
.wit { display: grid; gap: var(--s2); }
.wit .lbl { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
.wit .lbl span + span:not(:empty)::before { content: " · "; }
.wit .faces { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 0 var(--s6); }
.roll { display: flex; align-items: center; gap: var(--s2); min-width: 0; height: 28px; }
.roll .face { width: 20px; height: 20px; font-size: 10px; } /* taste-skill-ignore: 10px initials in a 20px face */
.roll .wn { flex: 1 1 auto; min-width: 0; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.roll .wt { flex: none; color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); font-variant-numeric: tabular-nums; }
.roll.off .wn { color: var(--faint); font-weight: 400; }
.roll.off .wt { color: var(--faint); }
.since { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s1) var(--s4); color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
.since > span:empty { display: none; }
.since b { color: var(--text); font-weight: 500; }
.face { width: 24px; height: 24px; border-radius: 50%; flex: none; display: grid; place-items: center; overflow: hidden; background: #ffffff; color: #1e1f22; font-size: 11px; font-weight: 600; letter-spacing: 0.02em; transition: opacity var(--t-slow) var(--ease-out); } /* taste-skill-ignore: the operators' logos sit on white discs, as on log.veil.rip; 11px initials in a 24px face */
:root[data-theme="light"] .face { border: 1px solid var(--rule); } /* a white disc's edge on white */
.face img { width: 100%; height: 100%; display: block; }
.face.p1 { background: var(--p1-bg); color: var(--p1-ink); border: 0; }
.face.p2 { background: var(--p2-bg); color: var(--p2-ink); border: 0; }
.face.p3 { background: var(--p3-bg); color: var(--p3-ink); border: 0; }
.face.off { opacity: 0.35; }

/* identity fingerprint: twelve words set like a specimen, on the page beside the record */
.fp { display: grid; justify-content: start; gap: var(--s1) var(--s4); font-size: var(--fs-section); line-height: var(--lh-section); }
/* words are read aloud, not code: the text face, a step larger than the card's text; the digits are the neutral fallback, in mono */
.fp.words { grid-template-columns: repeat(3, minmax(0, max-content)); gap: var(--s1) var(--s5); font-weight: 500; }
#fp.words { font-size: var(--fs-title); line-height: 32px; letter-spacing: -0.01em; }
.fp.digits { grid-template-columns: repeat(4, auto); font-family: var(--mono); letter-spacing: 0.02em; font-variant-numeric: tabular-nums; } /* taste-skill-ignore: the 60-digit fallback of the fingerprint */
.fp-note { margin-top: var(--gap-in); color: var(--muted); max-width: 44ch; }
.fp-note.bad { color: var(--pill-negative-ink); }
/* not opened yet (F4): the words appear once this browser has opened version 1; until then only their places */
.fp.pending span { color: transparent; background: var(--raised); border-radius: var(--radius-small); user-select: none; }
.fp.pending.bad span { background: var(--pill-negative-bg); }
/* the panel's actions at its foot (pinned there when its row is taller: an action may sit at the foot, never a gap above words) */
.panel-foot { margin-top: auto; padding-top: var(--s4); display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; }
.copied { color: var(--positive); font-size: var(--fs-small); }
.copied.plain { color: var(--text); }

/* keys and members tables: one row pattern, one header style, no bands */
.panel-sub { margin: calc(-1 * var(--s1)) 0 var(--s2); color: var(--muted); }
.table-wrap { overflow-x: auto; margin: 0 calc(-1 * var(--s2)); }
table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
th { height: 32px; padding: 0 var(--s2); text-align: left; font-weight: 400; font-size: var(--fs-small); color: var(--muted); white-space: nowrap; border-bottom: 1px solid var(--rule); }
td { padding: var(--s3) var(--s2); vertical-align: middle; border-bottom: 1px solid var(--rule); }
tbody tr:last-child td { border-bottom: 0; }
th.r, td.r { text-align: right; }
/* a state is words: it lines up on the left, its dot in one column */
td.c-state { text-align: left; }
td.c-date { white-space: nowrap; }
.kname { font-weight: 500; overflow-wrap: anywhere; }
/* a key's name and its kind on one line (one register since phase 2, 29 October 2026): the kind says the algorithm once */
.kline { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--s2); row-gap: 2px; min-width: 0; }
.kkind { color: var(--muted); white-space: nowrap; }
a.kname:hover { text-decoration: underline; text-underline-offset: 3px; }
.ksub { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); margin-top: 2px; }
.kfp { display: flex; align-items: center; gap: var(--s1); white-space: nowrap; }
/* a fingerprint in a register is an ID: mono at the body's size (29 October 2026) */
.keys-table .kfp .mono { font-size: var(--fs-body); }
tr.revoked .kname, tr.revoked .kfp .mono { color: var(--muted); }
/* no backup file: the one gap a card can have that nobody can close for it later. A row of the devices' group, without a band
   since phase 2 (29 October 2026): "Missing" is the one word in the danger tone, the sentence is grey under the name */
.keys-table tr.missing .ksub { max-width: 64ch; }
.keys-table tr.missing a.inline { color: var(--text); text-decoration-color: var(--pill-negative-ink); font-weight: 500; }
/* A person's devices sit on the page (no ground since 28 October 2026), so their table no longer bleeds past the column:
   its rules and the "No backup file" band run from the column's left edge to its right, the edges of the panel and the
   notices above, and every row, the band included, keeps the same 12 px inside. The device names, the status words and the
   actions then stand in the same places on every row (29 October 2026). */
#devices .table-wrap { margin: 0; overflow: visible; }
#devices .keys-table th:first-child, #devices .keys-table td:first-child { padding-left: var(--s3); }
#devices .keys-table th:last-child, #devices .keys-table td:last-child { padding-right: var(--s3); }
/* One register of keys (phase 2, 29 October 2026): the devices, then the public keys from elsewhere, two groups of one table
   under one header. Each group opens with a quiet line, its name in the ink and what it holds in grey, and the second carries
   "Export" at its end. No band, no second header, no box. */
.keys-table tr.group th { height: auto; padding: var(--s5) var(--s3) var(--s2); text-align: left; white-space: normal; font-size: var(--fs-small); line-height: var(--lh-small); color: var(--muted); }
.keys-table tbody:first-of-type > tr.group:first-child th { padding-top: var(--s3); }
.group-line { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--s3); row-gap: 2px; }
.group-line .gname { color: var(--text); font-weight: 500; }
.group-line .ext-export { margin-left: auto; }
/* the key's column holds a name and its kind on one line: it keeps a third of the register, the action column or not */
#devices .keys-table thead th:first-child { width: 36%; }
/* the public keys from elsewhere: the proof's verdict is the state column, in the accent only once this browser has checked it;
   a proof that fails says why under the fingerprint, and an OpenPGP key's user IDs stand under its name once it checks out */
#external .ksub.bad { color: var(--pill-negative-ink); }
#external .c-fp .ksub { white-space: normal; }
.ext-ids { display: grid; gap: 2px; margin-top: var(--s1); }
.ext-id { overflow-wrap: anywhere; }
/* the fingerprint opens the row's details: the fingerprint whole, the proof, an OpenPGP key's expiry */
.kfp-more { border: 0; padding: 0; background: none; color: inherit; cursor: pointer; text-decoration: underline dotted var(--control); text-underline-offset: 3px; }
.kfp-more:hover, .kfp-more[aria-expanded="true"] { text-decoration-color: var(--text); }
.keys-table tr[data-ext]:has(+ tr.ext-more:not([hidden])) td { border-bottom: 0; }
.keys-table tr.ext-more td { padding-top: 0; }
.ext-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--s1) var(--s4); margin: 0; font-size: var(--fs-small); line-height: var(--lh-small); }
.ext-facts > div { display: contents; }
.ext-facts dt { color: var(--muted); }
.ext-facts dd { margin: 0; overflow-wrap: anywhere; }
/* "Export": the keys as files for the tools, in a small menu that floats under the group's line */
.ext-export { position: relative; }
.ext-export > summary { list-style: none; font-size: var(--fs-small); line-height: var(--lh-small); }
.ext-export > summary::-webkit-details-marker { display: none; }
.ext-export[open] > summary { color: var(--text); }
.ext-menu { position: absolute; z-index: 6; top: calc(100% + var(--s2)); right: 0; display: grid; min-width: 248px; padding: var(--s2); border-radius: var(--radius-nested); background: var(--surface); box-shadow: var(--shadow-float); /* taste-skill-ignore: a menu floats */ }
.ext-file { display: grid; gap: 2px; padding: var(--s2) var(--s3); border-radius: var(--radius-small); color: var(--text); text-align: left; }
.ext-file:hover { background: var(--active); }
.ext-file .mono { color: var(--text); }
.ext-for { color: var(--muted); }
/* the owner's empty group: its line and one sentence */
.keys-table tr.ext-invite td p { max-width: 72ch; color: var(--muted); }

/* linked accounts: one row per account, the platforms without one as short grey rows */
.links { display: grid; }
.link-row { display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; align-items: center; column-gap: var(--s3); padding: var(--s3) 0; }
.link-row + .link-row { border-top: 1px solid var(--rule); }
.link-row svg { width: 16px; height: 16px; color: var(--muted); }
.link-row .l1 { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.link-row .link-handle { color: inherit; text-decoration: none; text-underline-offset: 3px; }
.link-row .link-handle:hover { text-decoration: underline; }
.link-row .l1 span { color: var(--muted); font-weight: 400; }
.link-row .l2 { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); margin-top: 2px; }
.link-row time, .link-row .r { color: var(--muted); font-size: var(--fs-small); text-align: right; }
.link-row.none { padding: var(--s2) 0; }
.link-row.none svg { color: var(--faint); }
.link-row.none .l1 { color: var(--muted); font-weight: 400; }
.link-row.none .r { color: var(--faint); }
.links.cols { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); column-gap: var(--s6); align-content: start; }
/* The platforms a card has no account on (28 October 2026): for a visitor, one sentence of names after its accounts,
   not a grey row each ("Not linked yet: Discord, GitHub, Email"). Each row keeps its state for a screen reader. The owner's
   layer (its Link, its reasons) keeps the rows. */
#linksList:not(:has([data-owner-ctl])) { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--s2); }
#linksList:not(:has([data-owner-ctl])) > .link-row:not(.none) { flex: 1 1 100%; }
#linksList:not(:has([data-owner-ctl]))[data-none]:has(> .none)::before { content: attr(data-none); order: 1; padding-top: var(--s2); color: var(--muted); }
#linksList:not(:has([data-owner-ctl])) > .link-row.none { order: 2; display: inline-flex; padding: var(--s2) 0 0; }
#linksList:not(:has([data-owner-ctl])) > .link-row.none > svg { display: none; }
#linksList:not(:has([data-owner-ctl])) > .link-row.none .l1 { color: var(--text); font-weight: 400; }
#linksList:not(:has([data-owner-ctl])) > .link-row.none:not(:last-child) .l1::after { content: ","; }
#linksList:not(:has([data-owner-ctl])) > .link-row.none > .r { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.links.cols .link-row + .link-row { border-top: 0; }
/* who signs for an organisation: names on the page, no icon before each */
#signersList .link-row { grid-template-columns: minmax(0, 1fr) auto; }
#signersList .link-row > svg { display: none; }
#signersList .l2 { font-variant-numeric: tabular-nums; } /* the entries each signer signed */
.role-name { font-weight: 500; display: flex; align-items: center; gap: var(--s2); }
.role-name + .role-text + .role-name { margin-top: var(--gap-in); }
.role-text { margin-top: var(--s1); color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
/* a staff role on the Veil organisation's card: the icon of its badge before the role */
.role { display: inline-flex; align-items: center; gap: var(--s2); }
.role-icon { width: 16px; height: 16px; display: block; flex: none; }

/* history */
.events { display: grid; }
.event { display: grid; grid-template-columns: 92px minmax(0, 1fr) auto; column-gap: var(--s4); align-items: baseline; padding: var(--s3) 0; }
.event + .event { border-top: 1px solid var(--rule); }
.event time { color: var(--muted); font-size: var(--fs-small); }
.event .what { font-weight: 500; }
.event .by { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); margin-top: 2px; overflow-wrap: anywhere; }
.event .ep { color: var(--muted); font-size: var(--fs-small); text-align: right; white-space: nowrap; }
/* in the narrow column: the date and the entry on one line, the change and its signer under them */
.events.narrow .event { grid-template-columns: minmax(0, 1fr) auto; }
.events.narrow .event time { grid-column: 1; grid-row: 1; }
.events.narrow .event .ep { grid-column: 2; grid-row: 1; }
.events.narrow .event .minw0 { grid-column: 1 / -1; margin-top: 2px; }

/* the current version as signed, folded to one line under the latest changes */
.record-sum { margin-top: var(--s3); }
.rs-title { font-weight: 600; }
.rs-meta { margin-top: 2px; color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
.record-sum .text-btn { margin-top: var(--s2); font-size: var(--fs-small); line-height: var(--lh-small); }
/* the record itself, under the two stacks: full width, so the long values have room when unfolded */
.record-panel header { margin-bottom: var(--s2); }
.record-panel h2:focus { outline: none; }
.record-view .note { color: var(--muted); max-width: 80ch; }
pre.record-text { margin: var(--gap-in) 0 0; padding: var(--s3) var(--s4); border-radius: var(--radius-nested); background: var(--raised); font-family: var(--mono); font-size: var(--fs-small); line-height: var(--lh-body); color: var(--muted); white-space: pre-wrap; overflow-wrap: anywhere; } /* taste-skill-ignore: the signed record is code */
pre.record-text .fold { color: var(--text); }
/* a long value (a composite key, a signature) shows its two ends; "show all" unfolds that value only */
.fold-btn { margin: 0 2px 0 var(--s2); font: 500 var(--fs-small)/var(--lh-body) var(--font); vertical-align: baseline; }
.fold-copy { width: 20px; height: 20px; border-radius: var(--radius-small); vertical-align: -5px; }
.fold-copy svg { width: 13px; height: 13px; }
.rec-facts { display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: var(--s2) var(--s4); margin-top: var(--gap-in); font-size: var(--fs-small); }
.rec-facts dt { color: var(--muted); }
.rec-facts dd { min-width: 0; overflow-wrap: anywhere; }
.record-view .panel-foot { padding-top: var(--gap-in); }
/* format 2: a version's operations in words, and the evidence of an index that leaves one out (hidden unless there is some) */
.rec-facts ol.ops { margin: 0; padding-left: 1.2em; }
.evidence { display: grid; gap: var(--s4); margin-top: var(--s4); }
.evidence .note b { color: var(--negative); font-weight: 500; }
.since .text-btn { font-size: var(--fs-small); line-height: var(--lh-small); }
/* a version's record in the History tab opens in a row under it */
.history-table tr.rec-row > td { padding: var(--s1) var(--s2) var(--s4); }
.history-table td > .text-btn[data-hrec] { display: block; margin-top: 2px; font-size: var(--fs-small); line-height: var(--lh-small); }

/* signature check: the live thing. The message and the signature side by side, at their own height. */
.field { display: grid; gap: var(--s2); margin-top: var(--gap-in); }
.sig-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--s4); }
.sig-fields textarea { height: 96px; min-height: 96px; }
.field label { font-weight: 500; }
textarea, input[type="text"], input[type="email"], input[type="password"], input[type="number"], input[type="search"], select { font-size: var(--fs-body); }
textarea {
  width: 100%; resize: vertical; border: 1px solid var(--control); border-radius: var(--radius-nested); background: var(--field);
  padding: var(--s2) var(--s3); line-height: var(--lh-body); color: var(--text);
}
textarea:focus-visible { outline-offset: 0; }
#sig { font-family: var(--mono); font-size: var(--fs-small); line-height: 18px; word-break: break-all; } /* taste-skill-ignore: a signature is hex */
.verdict { display: flex; gap: var(--s3); align-items: flex-start; margin-top: var(--gap-in); padding: var(--s3) var(--s4); border-radius: var(--radius-nested); background: var(--raised); }
.verdict svg { width: 18px; height: 18px; margin-top: 1px; }
.verdict.ok svg { color: var(--positive); }
.verdict.bad svg { color: var(--negative); }
.verdict.wait svg { color: var(--faint); }
/* waiting for a message is not a result: a quiet line under the fields, not a box */
.verdict.wait { padding: 0; background: none; color: var(--muted); }
.verdict.wait svg { display: none; }
.verdict.wait b { font-weight: 400; }
.verdict b { display: block; font-weight: 600; }
.verdict span { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
/* An error says one plain sentence (since 25 October 2026): no title line, the sentence in the body's colour and size. */
.verdict.one p b { display: none; }
.verdict.one p span { color: var(--text); font-size: inherit; line-height: inherit; margin-top: 0; }

/* full history view */
.history-table td.when { white-space: nowrap; color: var(--muted); }

/* a card that could not be shown: not found, erased, removed, or the server unreachable: the lead, alone */
.state { margin-top: var(--s6); max-width: 752px; background: var(--surface); padding: var(--pad-lead) var(--pad-x); }
.state .answer svg { color: var(--faint); }
/* a status that stops the card (suspended, closed, removed): the danger tone, its statement linked under it */
.answer.stop { color: var(--pill-negative-ink); }
.answer.stop svg, .state .answer.stop svg { color: var(--negative); }
.state p + p { margin-top: var(--s2); }
.state .actions { margin-top: var(--s4); }
/* while the card loads (30 October 2026, audit P2 and P3; app.js firstPaint): the waiting panel takes about the place of the
   card's lead panel, which replaces it, and the footer waits for the card, so nothing moves when it is drawn. In a browser that manages the
   card, the card itself waits, out of sight, until the owner's layer is drawn on it (html[data-owner-wait]; app.js, "the
   owner's card, at once"). Without scripts the page is the no-script message and the footer, as before. */
/* the scroll bar's place is kept on a card's page: where a scroll bar takes room, the page grew past the screen when the card
   came and the whole column moved 7 px to the left (Lighthouse desktop, 30 October 2026) */
:root:has(> body[data-page="person"], > body[data-page="org"]) { scrollbar-gutter: stable; }
@media (scripting: enabled) {
  #state[data-wait] { min-height: max(240px, min(560px, calc(100svh - 49px - 2 * var(--s6)))); } /* about the card's lead panel */
  main:has(> #state[data-wait]) + .page-end,
  html[data-owner-wait] main > :not(#state), html[data-owner-wait] .page-end { visibility: hidden; }
}

/* "Report this card" (report.js): a quiet line above the footer, its form in a panel under it */
.report-zone { margin-top: var(--s6); }
.report-line { display: flex; align-items: center; gap: var(--s2); color: var(--muted); }
.report-line svg { display: none; }
.report-line .text-btn { font-size: var(--fs-small); line-height: var(--lh-small); }
.report-panel { margin-top: var(--s3); max-width: 752px; }
.report-panel h2 { font-size: var(--fs-section); line-height: var(--lh-section); font-weight: 600; }
.report-panel .note { margin-top: var(--s1); max-width: 66ch; }
.report-fields .field + .field { margin-top: var(--s4); }
.report-fields select { height: 40px; padding: 0 var(--s3); border: 1px solid var(--control); border-radius: var(--radius-nested); background: var(--field); color: var(--text); font: inherit; max-width: 100%; }
.report-fields .hint { color: var(--muted); font-size: var(--fs-small); }
.report-panel .err { margin-top: var(--s3); color: var(--pill-negative-ink); font-size: var(--fs-small); }
.report-actions { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3) var(--s4); margin-top: var(--s4); }
main:has(> .report-zone:not([hidden])) + .page-end > .foot { margin-top: var(--s5); }

/* the footer says one thing, then the utilities: the public log, the theme */
.foot { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--s2) var(--s5); margin-top: var(--s7); color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
.foot > p:first-child { max-width: 80ch; }
.foot-u { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s1) var(--s4); color: var(--faint); }
.foot-u .text-btn { font-size: var(--fs-small); line-height: var(--lh-small); color: var(--faint); }
.foot-u .text-btn:hover { color: var(--text); }
.foot-u a.inline { color: var(--muted); }
/* the footer is its own landmark (30 October 2026): after <main>, in the page's column, with the space it had inside it */
main.page-inner:has(+ .page-end) { padding-bottom: 0; }
.page-end { padding-top: 0; }

/* ---------- the front page (the old minimal one, kept for its states) ---------- */
.home { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--gap); margin-top: var(--s5); }
.home .lead { grid-column: span 4; padding: var(--s5); }
.home .side { grid-column: span 2; }
.home h1 { font-size: var(--fs-lead); line-height: var(--lh-lead); font-weight: 600; letter-spacing: -0.02em; }
.home .what { margin-top: var(--s3); font-size: var(--fs-section); line-height: var(--lh-section); color: var(--text); max-width: 60ch; }
.home .search.big { width: 100%; margin-top: var(--s5); }
.home .search.big input { height: 44px; font-size: var(--fs-section); padding-left: 40px; background: var(--field); border: 1px solid var(--control); }
.home .search.big svg { top: 15px; left: 15px; }
.home .hint { margin-top: var(--s3); color: var(--muted); font-size: var(--fs-small); }
.home .result { margin-top: var(--s4); }
.benefits { display: grid; gap: var(--s4); }
.benefits h2 { font-size: var(--fs-section); line-height: var(--lh-section); font-weight: 600; }
.benefits p { margin-top: var(--s1); color: var(--muted); }
.home .side .btn { margin-top: var(--s4); align-self: flex-start; }
.home .logpanel { grid-column: 1 / -1; }

/* ---------- tablet and phone ---------- */
@media (max-width: 1080px) {
  .home .lead, .home .side { grid-column: 1 / -1; }
}
/* the two columns hold down to 961px (a 1024 screen keeps them); under that every panel takes the full
   width, in the order of the page */
@media (max-width: 960px) {
  .grid { grid-template-columns: minmax(0, 1fr); }
  .span-4, .span-2, .span-6, .stack > * { grid-column: 1 / -1; }
  .stack { display: contents; }
  .grid > .panel.lead + .panel { padding-top: 0; }
  /* one column: the lead, the fingerprint, the main sections, then the rail's lists, in that order */
  #panoramica > .panel.lead, #panoramica > .stack.span-4, #panoramica > .stack.span-2 { grid-column: 1 / -1; grid-row: auto; padding-top: 0; }
  #panoramica { grid-template-rows: none; }
  #panoramica > .panel.lead { order: 1; }
  #panoramica > .stack.span-2 > :first-child { order: 2; }
  #panoramica > .stack.span-4 > * { order: 3; }
  #panoramica > .stack.span-2 > :not(:first-child) { order: 4; }
  #panoramica > .span-6 { order: 5; }
}
@media (max-width: 900px) {
  .bar-links { display: none; }
  .icon-btn.menu-btn { display: inline-grid; }
}
@media (max-width: 760px) {
  /* on a phone the smallest step reads at 13px: sublines and meta are most of the text there */
  :root { --pad-x: 16px; --pad-lead: 16px; --fs-small: 13px; --lh-small: 18px; }
  .bar-inner, .page-inner { padding-left: max(var(--s4), env(safe-area-inset-left, 0px)); padding-right: max(var(--s4), env(safe-area-inset-right, 0px)); }
  .bar-links, .bar-right .search { display: none; }
  .bar-inner { gap: var(--s3); }
  textarea, input[type="text"], input[type="email"], input[type="password"], input[type="number"], input[type="search"], select { font-size: var(--fs-section); }
  .object { flex-wrap: wrap; }
  .actions { width: 100%; }
  .actions .btn { flex: 1; }
  .tabbar { margin-top: var(--s5); }
  .tabbar > .status-row { width: 100%; justify-content: space-between; padding-bottom: var(--s3); order: 2; border-top: 0; }
  .tabbar > .tabs { order: 1; }
  :root { --fs-stamp: 26px; --lh-stamp: 30px; --sec-gap: 40px; }
  /* on a phone the ledger line stands up: one ruled column down the left, each station's name, figure and note beside it */
  ol.chain { grid-template-columns: 1fr; margin-top: var(--s5); }
  .step { display: grid; grid-template-columns: 96px minmax(0, 1fr); column-gap: var(--s3); align-items: baseline; padding: var(--s1) 0 var(--s3) var(--s4); border-left: 2px solid var(--line); }
  .step:last-child { padding-bottom: var(--s1); }
  .step::before { left: -2px; top: calc(var(--s1) + 9px); width: 12px; height: 2px; }
  .step .k { grid-row: 1 / span 2; }
  .step .v, .step:last-child .v { margin: 0; padding: 0; border: 0; }
  .step .s { grid-column: 2; margin-top: 0; }
  .wit .faces { grid-template-columns: minmax(0, 1fr); }
  #sig { min-height: 96px; }
  .sig-fields { grid-template-columns: minmax(0, 1fr); }
  .rec-facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .rec-facts dd + dt { margin-top: var(--s2); }
  .keys-table tr.missing td.c-state { grid-column: 2; grid-row: 1; }
  .fp.digits { grid-template-columns: repeat(3, auto); }
  .event { grid-template-columns: minmax(0, 1fr) auto; }
  .event time { grid-column: 1 / -1; margin-bottom: 2px; }
  /* keys and members tables become two-line rows */
  .keys-table thead { display: none; }
  .keys-table tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--s3); padding: var(--s3) var(--s2); border-bottom: 1px solid var(--rule); }
  .keys-table tbody tr:last-child { border-bottom: 0; }
  .keys-table td { padding: 0; border-bottom: 0; }
  .keys-table td.c-fp { grid-column: 1; margin-top: var(--s2); }
  .keys-table td.c-date { grid-column: 2; grid-row: 2; align-self: end; text-align: right; color: var(--muted); font-size: var(--fs-small); }
  .keys-table td.c-state { grid-column: 2; grid-row: 1; text-align: right; }
  /* the devices, on the phone: each row, the band too, 12 px inside the column on every side */
  #devices .keys-table tr, #devices .keys-table tr.missing { padding: var(--s3); }
  #devices .keys-table td:first-child, #devices .keys-table td:last-child { padding: 0; }
  /* the register's group lines and a key's details, on the phone: blocks the width of the column */
  #devices .keys-table tr.group { display: block; padding: var(--s5) var(--s3) var(--s2); }
  #devices .keys-table tbody:first-of-type > tr.group:first-child { padding-top: var(--s2); }
  #devices .keys-table tr.group th { display: block; padding: 0; border: 0; }
  #devices .keys-table tr.ext-more, #devices .keys-table tr.ext-invite { display: block; padding: 0 var(--s3) var(--s3); }
  #devices .keys-table tr.ext-invite { padding-top: var(--s3); }
  #devices .keys-table tr.ext-more td, #devices .keys-table tr.ext-invite td { display: block; }
  .ext-facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
  /* the group's name and its "Export" on the first line, what the group holds under them */
  .group-line .gtext { order: 3; flex-basis: 100%; }
  .ext-facts dd + dt { margin-top: var(--s2); }
  /* the history becomes rows of two lines: the date and the entry, then the change and who signed it */
  .history-table thead { display: none; }
  .history-table tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--s3); padding: var(--s3) var(--s2); border-bottom: 1px solid var(--rule); }
  .history-table tbody tr:last-child { border-bottom: 0; }
  .history-table td { padding: 0; border-bottom: 0; }
  .history-table td.when { grid-column: 1; grid-row: 1; font-size: var(--fs-small); }
  .history-table td.r { grid-column: 2; grid-row: 1; font-size: var(--fs-small); }
  .history-table td:nth-child(2) { grid-column: 1 / -1; margin-top: 2px; font-weight: 500; }
  .history-table td:nth-child(3) { grid-column: 1 / -1; color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); }
  .history-table tr.rec-row { display: block; padding: var(--s1) var(--s2) var(--s4); }
  .history-table tr.rec-row > td { display: block; padding: 0; }
  .home .lead { padding: var(--s5); }
  .home h1 { font-size: var(--fs-title); line-height: var(--lh-title); }
  .foot { flex-direction: column; }
}
.menu-sheet { display: none; }
.menu-sheet.open { display: grid; gap: var(--s1); padding: var(--s2) max(var(--s4), env(safe-area-inset-right, 0px)) var(--s4) max(var(--s4), env(safe-area-inset-left, 0px)); background: var(--ground); border-bottom: 1px solid var(--rule); }
.menu-sheet a { padding: var(--s3) 0; font-weight: 500; color: var(--muted); }
.menu-sheet a[aria-current="page"] { color: var(--text); }
.menu-sheet .search { width: 100%; margin: var(--s1) 0 var(--s2); }
@media (min-width: 761px) { .menu-sheet .search { display: none; } }
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
.foot > p:empty { display: none; }
/* Chosen addresses stay readable at phone widths, including a 32-character alias. */
.card-alias { overflow-wrap: anywhere; }

/* keys from elsewhere: the flow that adds one (external-owner.js), the same on the owner's card and in /start (29 October 2026).
   The key, the challenge, the command and the signature are code, in mono; the fixed sentence about private keys sits in a
   neutral notice right before each field that takes key material. */
.ext-form .field { display: grid; gap: var(--s2); margin-top: var(--s4); min-width: 0; }
.ext-form .field label { font-weight: 500; }
.ext-form textarea { min-height: 88px; font-family: var(--mono); font-size: var(--fs-small); line-height: 18px; word-break: break-all; } /* taste-skill-ignore: a key or a signature is code */
.ext-form input[type="text"], .ext-form select {
  width: 100%; height: var(--control-height); padding: 0 var(--s3); border: 1px solid var(--control); border-radius: var(--radius-nested);
  background: var(--field); color: var(--text);
}
.ext-form select { padding-right: var(--s6); }
.ext-form .hint { color: var(--muted); font-size: var(--fs-small); line-height: var(--lh-small); max-width: 62ch; }
.ext-form .hint code { font-family: var(--mono); color: var(--text); overflow-wrap: anywhere; } /* taste-skill-ignore: a command */
.ext-form .ext-row { display: grid; grid-template-columns: minmax(0, 240px) minmax(0, 1fr); gap: 0 var(--s4); align-items: start; }
.ext-form .ext-row > .field { margin-top: var(--s4); align-content: start; }
.ext-form .ext-never { margin-top: var(--s4); max-width: 720px; }
.ext-form h3 + .ext-never { margin-top: var(--s3); }
.ext-form .ext-never svg { color: var(--muted); }
.ext-form .ext-key { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s1) var(--s3); margin-top: var(--s3); }
.ext-form .ext-key .mono { font-size: var(--fs-small); overflow-wrap: anywhere; color: var(--muted); }
.ext-form .ext-why { margin-top: var(--s2); max-width: 72ch; }
.ext-form .ext-cmd-h { margin-top: var(--s4); font-weight: 500; }
.ext-form pre.ext-cmd { color: var(--text); }
.ext-form > p.muted { margin-top: var(--s2); }
.ext-form .verdict { margin-top: var(--s3); }
.ext-form .actions-row.tight { margin-top: var(--s3); }
/* an OpenPGP key read in the flow (phase 2): its fingerprint, the user IDs to keep or not, the warning, what stays out */
.ext-form .ext-pgp { margin-top: var(--s3); max-width: 720px; }
.ext-form .ext-pgp-fp { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); align-items: baseline; }
.ext-form .ext-pgp-fp .mono { overflow-wrap: anywhere; }
.ext-form .ext-pgp-wait { margin-top: var(--s3); }
.ext-form fieldset.ext-ids { margin: var(--s4) 0 0; padding: 0; border: 0; min-width: 0; }
.ext-form fieldset.ext-ids legend { padding: 0; font-weight: 500; }
.ext-form fieldset.ext-ids .hint { margin-top: var(--s1); }
.ext-form fieldset.ext-ids .check-line { margin-top: var(--s2); font-weight: 400; overflow-wrap: anywhere; }
.ext-form .notice.warn { background: var(--pill-warning-bg); color: var(--pill-warning-ink); margin-top: var(--s3); }
.ext-form .notice.warn svg { color: var(--warning); }
.ext-form .ext-dropped { margin-top: var(--s3); }
.ext-form .ext-key-ids { margin-top: var(--s1); overflow-wrap: anywhere; }
@media (max-width: 760px) { .ext-form .ext-row { grid-template-columns: minmax(0, 1fr); } }
/* /start, the optional step of the keys one already uses: the types and how each signs the challenge, a register */
.keys-types { margin-top: var(--s4); }
.keys-types td { vertical-align: top; }
.keys-types td:first-child { width: 38%; font-weight: 500; }
.keys-types code { font-family: var(--mono); font-size: var(--fs-small); overflow-wrap: anywhere; color: var(--muted); } /* taste-skill-ignore: commands */
.keys-types tr.later td { color: var(--muted); font-weight: 400; }
@media (max-width: 760px) {
  .keys-types thead { display: none; }
  .keys-types tr { display: grid; padding: var(--s3) 0; border-bottom: 1px solid var(--rule); }
  .keys-types td { padding: 0; border: 0; width: auto !important; }
  .keys-types td + td { margin-top: var(--s1); }
}

/* ---------- the sections of a card (UX pass, 29 October 2026) ----------
   One way to start a section, the one the system has: the heading at 16/600 on the page, a stable id, and beside it two quiet
   controls, "?" where a word needs explaining (two sentences open in place under the heading, never a dialog) and the link that
   copies the section's address, shown on hover and focus. On a long card a strip under the tabs names the sections; it stays
   under the top bar while the card scrolls, and a tick in the ink marks the one in view, as a station on the ledger line. What
   changes with the reader (long, stuck, in view) is on <html>; #card is the same markup for everyone. */
.panel > header > .sec-link, .panel > header > .help-btn { align-self: center; margin-left: calc(-1 * var(--s1)); }
.panel > header > .sec-link { margin-right: auto; }
.sec-link { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-small); color: var(--faint); opacity: 0; transition: opacity var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out); }
.sec-link svg { width: 14px; height: 14px; }
.sec-link:hover { color: var(--text); }
.panel > header:hover > .sec-link, .sec-link:focus-visible { opacity: 1; }
@media (hover: none) { .sec-link { opacity: 1; } }
.help-btn { display: inline-grid; place-items: center; flex: none; width: 20px; height: 20px; padding: 0; border: 1px solid var(--control); border-radius: 50%; background: none; color: var(--muted); font: 600 var(--fs-small)/1 var(--font); cursor: pointer; transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out); }
.help-btn:hover, .help-btn[aria-expanded="true"] { color: var(--text); border-color: var(--text); }
.help-text { max-width: 52ch; margin-bottom: var(--gap-in); color: var(--muted); }
.wit .lbl .help-btn { display: inline-grid; margin-left: var(--s2); width: 18px; height: 18px; vertical-align: middle; }
.wit .help-text { margin: 0; font-size: var(--fs-small); line-height: var(--lh-small); }
#card h2[tabindex="-1"]:focus, main :is(h2, h3)[tabindex="-1"]:focus { outline: none; }
#card .panel[id], #card section[id] { scroll-margin-top: calc(49px + 40px + var(--s5)); }
/* The strip of a long page's sections (jump.js): the card's, and since 30 October 2026 the one index of /staff, /canary,
   /developers and /docs. It shows on a page longer than about 1.3 screens, stays under the top bar, and the section in view
   has the 2 × 12 px tick and its name in the ink, like a station of the log row; never the accent. The card writes its
   state on <html> (data-card-long, data-card-section, data-index-stuck) so #card stays the same for every reader; the other
   pages write it on the strip (data-long, data-stuck, aria-current on the marked name). */
.sec-index { display: none; }
:root[data-card-long] #cardIndex, .sec-index[data-long] {
  display: flex; align-items: center; gap: var(--s5); position: sticky; top: calc(49px + env(safe-area-inset-top, 0px)); z-index: 4;
  height: 40px; background: var(--ground); border-bottom: 1px solid var(--rule); overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
  transition: border-color var(--t-fast) var(--ease-out);
}
.sec-index::-webkit-scrollbar { display: none; }
#card:has(#panoramica[hidden]) .card-index { display: none; }
:root[data-index-stuck] #cardIndex, .sec-index[data-stuck] { border-bottom-color: var(--rule); }
:root[data-index-stuck] .topbar.scrolled, :root:has(.sec-index[data-stuck]) .topbar.scrolled { border-bottom-color: transparent; }
:root[data-card-long] #cardIndex + .grid { margin-top: var(--s4); }
#cardIndex + .grid { margin-top: var(--s5); }
.sec-index :is(a, button) { position: relative; flex: none; display: inline-flex; align-items: center; gap: var(--s2); height: 40px; padding: 0; border: 0; background: none; color: var(--muted); font: 500 var(--fs-small)/var(--lh-small) var(--font); white-space: nowrap; cursor: pointer; transition: color var(--t-fast) var(--ease-out); }
/* the section in view carries a 2px mark on the strip's baseline, like a station on the ledger line; the labels sit on one hairline with an even gap (30 October 2026, after the ticks before each label read as separators) */
.sec-index :is(a, button)::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; border-radius: 1px; background: transparent; transition: background-color var(--t-fast) var(--ease-out); }
.sec-index :is(a, button):hover, .sec-index [aria-current] { color: var(--text); }
.sec-index [aria-current]::after { background: var(--text); }
.sec-index [hidden] { display: none; }
#card:has(#rolesBox[hidden]) .card-index a[href="#rolesBox"] { display: none; }
:root[data-card-section="status"] .card-index a[href="#status"], :root[data-card-section="fingerprint"] .card-index a[href="#fingerprint"],
:root[data-card-section="devices"] .card-index a[href="#devices"], :root[data-card-section="firma"] .card-index a[href="#firma"],
:root[data-card-section="links"] .card-index a[href="#links"], :root[data-card-section="rolesBox"] .card-index a[href="#rolesBox"],
:root[data-card-section="latest"] .card-index a[href="#latest"], :root[data-card-section="members"] .card-index a[href="#members"],
:root[data-card-section="signers"] .card-index a[href="#signers"], :root[data-card-section="ownDanger"] .card-index a[href="#ownDanger"] { color: var(--text); }
:root[data-card-section="status"] .card-index a[href="#status"]::before, :root[data-card-section="fingerprint"] .card-index a[href="#fingerprint"]::before,
:root[data-card-section="devices"] .card-index a[href="#devices"]::before, :root[data-card-section="firma"] .card-index a[href="#firma"]::before,
:root[data-card-section="links"] .card-index a[href="#links"]::before, :root[data-card-section="rolesBox"] .card-index a[href="#rolesBox"]::before,
:root[data-card-section="latest"] .card-index a[href="#latest"]::before, :root[data-card-section="members"] .card-index a[href="#members"]::before,
:root[data-card-section="signers"] .card-index a[href="#signers"]::before, :root[data-card-section="ownDanger"] .card-index a[href="#ownDanger"]::before { background: var(--text); }

/* a key's row opens its details from anywhere on it; the details are the same list for a device and a key from elsewhere */
#devices tr[data-key], #devices tr[data-ext] { cursor: pointer; }
.keys-table tr[data-key]:has(+ tr.key-more:not([hidden])) td { border-bottom: 0; }
.ext-facts code { font-family: var(--mono); font-size: var(--fs-small); overflow-wrap: anywhere; color: var(--text); } /* taste-skill-ignore: a command */
.ext-facts .mono { overflow-wrap: anywhere; }

/* the history: a filter in words above the table (the choice on the --active ground, as the top bar marks where you are), and
   each row's entry as a link to the log with its chevron */
.hist-filter { display: flex; flex-wrap: wrap; gap: var(--s2); margin: 0 0 var(--s3); }
.hf { display: inline-flex; align-items: center; gap: var(--s1); height: 28px; padding: 0 var(--s3); border: 0; border-radius: var(--round); background: none; color: var(--muted); font: 500 var(--fs-body)/var(--lh-body) var(--font); cursor: pointer; transition: color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out); }
.hf:hover { color: var(--text); }
.hf[aria-pressed="true"] { background: var(--active); color: var(--text); }
.history-table .hist-open { font-weight: 400; font-size: inherit; white-space: nowrap; }

/* what a copy says, by the control that copied: it floats, like a menu */
.copy-tip { position: fixed; z-index: 30; max-width: 280px; padding: var(--s1) var(--s2); border-radius: var(--radius-small); background: var(--surface); color: var(--text); font-size: var(--fs-small); line-height: var(--lh-small); box-shadow: var(--shadow-float); pointer-events: none; } /* taste-skill-ignore: a tooltip floats */
.copy-tip.bad { color: var(--pill-negative-ink); }
@media (max-width: 760px) {
  :root[data-card-long] #cardIndex, .sec-index[data-long] { gap: var(--s4); }
}
/* Audit of 30 October 2026 (U15, U1). An anchor, and whatever a flow scrolls to, lands under the sticky bars: the top bar,
   plus the strip of sections where a page has one. And a warning said in a line of its own, in the warning's ink: a verdict
   about a card that no verified account ties to anyone. */
main [id] { scroll-margin-top: calc(49px + var(--s5)); }
#card [id], :root:has(.sec-index[data-long]) main [id] { scroll-margin-top: calc(49px + 40px + var(--s5)); }
.warn-line, .verdict .warn-line { display: block; margin-top: var(--s2); color: var(--pill-warning-ink); }
.verdict .warn-line { margin: 0 0 var(--s1); }

/* a section the strip brought into view flashes twice (UX, 30 October 2026): the raised ground, never the accent */
@keyframes sec-flash { 0%, 100% { box-shadow: none; } 20%, 60% { box-shadow: inset 0 0 0 2px var(--rule), 0 0 0 6px color-mix(in srgb, var(--text) 10%, transparent); } 40%, 80% { box-shadow: none; } }
.sec-flash { animation: sec-flash 1.3s ease-out 1; border-radius: var(--r2, 8px); }
@media (prefers-reduced-motion: reduce) { .sec-flash { animation: none; box-shadow: inset 0 0 0 2px var(--rule), 0 0 0 6px color-mix(in srgb, var(--text) 10%, transparent); } }

/* ---------- Stability (polish pass, 30 October 2026): nothing pushes the page around when it changes ----------
   What opens in place (a "?" help, a key's details, the record, a confirmation, an owner's form) slides its rows from 0fr
   to 1fr: what is under it moves down with it instead of jumping, and closing slides it back. The script toggles .open on
   the .rv box (VeilCard.slide on the card pages); shut, its content is out of sight and out of the tab order at once,
   while the space closes. The inner box keeps 4 px around the content so a focus ring is not clipped. */
.rv { display: grid; grid-template-rows: 0fr; visibility: hidden; transition: grid-template-rows var(--t-slow) var(--ease-out); }
.rv.open { grid-template-rows: 1fr; visibility: visible; }
.rv > .rv-in { min-height: 0; overflow: hidden; margin: -4px; padding: 4px; }
@media (prefers-reduced-motion: reduce) { .rv { transition: none; } }
/* the witnesses' "?" sits in a grid with an 8 px gap: the slot gives that gap back while shut and carries it inside */
.wit > .rv { margin-bottom: calc(-1 * var(--s2)); }
.wit > .rv .help-text { margin-bottom: var(--s2); }
/* a key's details: the row's bottom space travels inside the slide, and the rule under the key moves to the details row
   (devices and keys from elsewhere alike), so opening adds nothing at once */
.keys-table tr.ext-more > td { padding-bottom: 0; }
.keys-table tr.ext-more .rv-in > * { margin-bottom: var(--s3); }
.keys-table tr:has(+ tr.ext-more:not([hidden])) td { border-bottom: 0; }
@media (max-width: 760px) {
  #devices .keys-table tr.ext-more { padding-bottom: 0; }
  .keys-table tr:has(+ tr.ext-more:not([hidden])) { border-bottom: 0; }
}
/* the record, under the grid: it brings its own gap inside the slide, so the grid's row gap does not land at once */
.record-panel { margin-top: calc(-1 * var(--sec-gap)); }
.record-panel > .rv > .rv-in { padding-top: calc(var(--sec-gap) + 4px); }
.record-panel .rv-in > header { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--s1) var(--s3); }
/* the lead keeps its place while the check runs: the witnesses' roll as blank rows (app.js renderFaces), the line under the
   roll, and the stamp by the tabs in a box as wide as "Checked at 13:49 · checkpoint 12 345", so its dot, its words and
   "Recheck" stand still when the words change */
.roll.ph { visibility: hidden; }
#status .since { min-height: var(--lh-small); }
@media (min-width: 761px) {
  .tabbar > .status-row .stamp { min-width: 290px; }
  :root:lang(it) .tabbar > .status-row .stamp { min-width: 322px; }
}
/* the verdict's line under the stamp, while the check runs: two lines, the usual "In good standing" (three on the phone),
   so the chain under it stays put when "Checking…" gives way to the answer; an answer that is shorter (the log could not be
   read) then takes its own height */
html:not([data-check-hold]) #card:has(#stampBox:not(.ok, .bad, .warn)) #status .finding { min-height: calc(2 * var(--lh-body)); }
@media (max-width: 760px) { html:not([data-check-hold]) #card:has(#stampBox:not(.ok, .bad, .warn)) #status .finding { min-height: calc(3 * var(--lh-body)); } }
/* the fingerprint as words or as digits: both take the words' height (four rows), and the sentence under it three lines,
   so "Show as digits" and "Copy fingerprint" stay where the reader clicked */
#fingerprint .fp { min-height: 140px; align-content: start; }
#fingerprint .fp-note { min-height: calc(3 * var(--lh-body)); }
/* a <details> in a page opens by sliding its content's height (where the browser can: ::details-content with
   interpolate-size; elsewhere it opens at once). Its summary stays where it is. Not the menus that float (Export). */
main details:not(.ext-export) { interpolate-size: allow-keywords; }
main details:not(.ext-export)::details-content { block-size: 0; overflow: clip; transition: block-size var(--t-slow) var(--ease-out), content-visibility var(--t-slow) allow-discrete; }
main details:not(.ext-export)[open]::details-content { block-size: auto; }
@media (prefers-reduced-motion: reduce) { main details::details-content { transition: none; } }
/* a key's details span the register's columns without widening them */
.keys-table tr.ext-more > td > .rv { contain: inline-size; }
/* a page that reads before it draws (the staff panel, the account, /me) keeps its footer out of sight while it says
   "Loading…", as the card does, so the footer does not jump down when the page is drawn */
@media (scripting: enabled) {
  main:has(> #state:not([hidden]) #stateText:empty) + .page-end,
  main:has(> #state:not([hidden]) #stateText:empty) > .foot { visibility: hidden; }
}

/* The motion vocabulary of this pass (design/DESIGN.md, "Movimento e risposte"), on the card's own pieces, once the page is
   drawn (html[data-motion], theme.js): what opens in place arrives from transparent and 4 px above as its rows slide, the
   "Export" menu floats in over --t-fast, and the stamp's words come in from transparent when the check ends. */
@media (prefers-reduced-motion: no-preference) {
  html[data-motion] .rv > .rv-in { transition: opacity var(--t-slow) var(--ease-out), translate var(--t-slow) var(--ease-out); }
  html[data-motion] .rv:not(.open) > .rv-in { opacity: 0; translate: 0 -4px; transition: none; }
  html[data-motion] .ext-export[open] > .ext-menu { transition: opacity var(--t-fast) var(--ease-out), translate var(--t-fast) var(--ease-out); }
  @starting-style { html[data-motion] .ext-export[open] > .ext-menu { opacity: 0; translate: 0 -4px; } }
  @keyframes stamp-in { from { opacity: 0; } }
  html[data-motion] #answer:is(.ok, .bad, .warn) > #answerText { animation: stamp-in var(--t-slow) var(--ease-out); }
}

/* Tablet (from the tablet-and-motion pass, 30 October 2026). 761-960 px: the fingerprint stands beside the list under it in
   the rail (a person's verified links, an organisation's signers) instead of taking a whole row half empty. 961-1100 px in
   Italian: the root's station is a little wider, so "dimensione 27" is not cut. */
@media (min-width: 761px) and (max-width: 960px) {
  #panoramica { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #panoramica > .panel.lead, #panoramica > .span-6, #panoramica > .stack.span-4 > *, #panoramica > .stack.span-2 > :nth-child(n+3) { grid-column: 1 / -1; }
  #panoramica > .stack.span-2 > :nth-child(-n+2) { grid-column: auto; order: 2; }
}
@media (min-width: 961px) and (max-width: 1100px) {
  :root:lang(it) #status .chain { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 1fr); }
}
/* the footer's "Warrant canary" line grows when canary.js reads the date ("· signed 29 September 2026"): it holds that
   width from the start, so the footer's other links do not slide when it does. The error page's search, which session.js
   draws, holds its place (the field and "Make yours") from the first paint. */
.foot-u a[data-canary] { min-width: 250px; }
:root:lang(it) .foot-u a[data-canary] { min-width: 258px; }
@media (max-width: 760px) { .foot-u a[data-canary] { min-width: 0; } }
.err-lost:empty { min-height: 92px; }
/* the card's tables and lists that the owner's layer puts rows into glide from <html> (app.js, "a block that changes height
   glides"), so #card itself carries nothing of it */
html[data-glide~="devices"] #devices .table-wrap { height: var(--glide-devices); overflow: clip; }
html[data-glide~="members"] #members .table-wrap { height: var(--glide-members); overflow: clip; }
html[data-glide~="links"] #linksList { height: var(--glide-links); overflow: clip; }
html[data-glide~="roles"] #rolesList { height: var(--glide-roles); overflow: clip; }
html[data-glide-run~="devices"] #devices .table-wrap, html[data-glide-run~="members"] #members .table-wrap,
html[data-glide-run~="links"] #linksList, html[data-glide-run~="roles"] #rolesList { transition: height var(--t-slow) var(--ease-out); }
/* the strip of sections scrolls sideways on a narrow screen: scrolled to its end, its last name keeps a margin from the edge */
:root[data-card-long] #cardIndex, .sec-index[data-long] { padding-inline-end: var(--s4); scroll-padding-inline: 0 var(--s4); }
:root[data-card-long] #cardIndex::after, .sec-index[data-long]::after { content: ""; flex: none; width: 1px; }
/* "Check every version" keeps its slot in the line under the roll when it goes (its check passed): on a phone, where it
   wraps to a line of its own, that line no longer closes up under the reader's finger */
#status #checkAll[hidden] { display: inline-block !important; visibility: hidden; }
/* ...and says its result there (follow-ups, 30 October 2026): the result sits in the same cell as the button, held from the
   first frame as wide as itself, so the line never grows when it arrives and the chain above stays where it is */
#status .check-all { display: inline-grid; justify-items: start; }
#status .check-all > * { grid-area: 1 / 1; }
#status .check-done { visibility: hidden; color: var(--text); }
#status .check-done.on { visibility: visible; }
/* the slot has a line of its own under the line about the last visit, which keeps its own line too: when that line's words
   change (or go, while the check runs) the slot stays where it is instead of jumping to the line above or across it.
   A format 1 card has no "Check every version" (app.js hides the result's cell): no line for it. */
#status .since { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: start; }
#status .since > #since { display: block; min-height: var(--lh-small); }
#status .check-all:has(> .check-done[hidden]) { display: none; }
/* 761-960 px: the card's eight section names do not fit one line (about 850 px in English, 924 in Italian, in a 704 px
   column), and a strip cut at the column's edge left a name 6 px from the screen's edge; there it takes two lines of 32 px
   instead of scrolling sideways, and the anchors land under both */
@media (min-width: 761px) and (max-width: 960px) {
  :root[data-card-long] #cardIndex { flex-wrap: wrap; height: auto; column-gap: var(--s4); overflow: visible; padding-inline-end: 0; }
  :root[data-card-long] #cardIndex :is(a, button) { height: 32px; }
  #card [id], :root:has(.sec-index[data-long]) main [id] { scroll-margin-top: calc(49px + 64px + var(--s5)); }
}
/* the stamp by the tabs keeps its first line where it is when its words take one line or two (on a phone "Checking in this
   browser…" and "Checked at …" wrap differently): the dot sits on the first line, "Recheck" on the top of the row */
.tabbar > .status-row { align-items: flex-start; }
.tabbar > .status-row .stamp { align-items: flex-start; }
.tabbar > .status-row .stamp .dot { margin-top: 5px; }
@media (max-width: 760px) { .tabbar > .status-row { min-height: calc(2 * var(--lh-small) + var(--s3)); } }
/* a check run again holds the stamp and its line at the height of the verdict before (app.js, holdLead) */
html[data-check-hold] #status .answer { min-height: var(--hold-answer); }
html[data-check-hold] #card #status .finding { min-height: var(--hold-finding); }
html[data-check-hold] #card #status #since { min-height: var(--hold-since); }
