/* himeru — "Hanko" identity (design port #12, variant D of the overnight
   design run: DESIGN-D.md / STYLESEED-D.md)
   stark white + one vermilion accent (named for hanko ink — the seal-red of
   a Japanese stamp) · flat 1px borders, sharp 6px radii · Archivo
   (display+body) + IBM Plex Mono (ids/links/table meta).
   NOTE (correction from Pat, see PORT-D.md): the vermilion-square-with-
   asterisk is NOT a brand mark/device — the overnight design run misread a
   typographic footnote ("himeru*" + a translation line) as a logo. Do not
   introduce it as decoration anywhere. /logo.svg is out of scope for this
   port and keeps its pre-existing mark; a real mark lands there later as a
   single-file swap. The asterisk only ever appears as plain footnote
   typography (.footnote below); a checkmark, never an asterisk, is what
   .hanko boxes actually contain (see .seal-verified).
   CSP: style-src 'self', font-src 'self' — this file is the only stylesheet;
   the two font families are vendored under /fonts/, no external requests. */

@font-face {
  font-family: 'Archivo';
  src: url('/fonts/archivo-latin.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/fonts/plexmono-400-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/fonts/plexmono-500-latin.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light dark;
  /* light (default) — stark, not off-white */
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-2: #f5f6f7;      /* quiet well */
  --ink: #111417;
  --ink-2: #3f464b;
  --muted: #6b7378;
  --line: #e3e6e8;
  --line-strong: #111417;    /* the swiss heavy rule */
  --accent: #d6402f;         /* hanko vermilion */
  --accent-press: #b93424;
  --on-accent: #ffffff;
  --tint: #fbeae7;           /* vermilion wash */
  --tint-line: #f0cfc8;
  /* danger: deliberately NOT a second vivid accent — a muted, low-chroma
     brick/wine red, clearly a different hue-and-saturation family from the
     bright orange-red hanko vermilion, so a delete/danger action never reads
     as "the accent". Weight (bold, bordered CTAs) carries the rest of the
     emphasis — see .danger-cta below. */
  --danger: #9a2b2b;
  --danger-dim: rgba(154, 43, 43, .07);
  --danger-line: rgba(154, 43, 43, .32);
  --ph: #9aa0a4;              /* placeholder hint text */
  --sans: 'Archivo', system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --r-card: 6px; --r-ctl: 6px; --r-chip: 4px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #121416;
    --surface: #1a1d1f;
    --surface-2: #22262a;
    --ink: #e8eaec;
    --ink-2: #b4bbc0;
    --muted: #8b939a;
    --line: #2a2f33;
    --line-strong: #e8eaec;
    --accent: #ff7a6b;
    --accent-press: #ff8f82;
    --on-accent: #23100c;
    --tint: #2b1d1a;
    --tint-line: #46302b;
    --danger: #e08585;
    --danger-dim: rgba(224, 133, 133, .10);
    --danger-line: rgba(224, 133, 133, .32);
    --ph: #5f6c7d;
  }
}
/* Manual toggle (frontend/theme.js, shared key himeru-theme) overrides the
   system query in BOTH directions — attribute selectors on :root outrank a
   plain :root inside a media query regardless of source order. */
:root[data-theme="dark"] {
  --bg: #121416;
  --surface: #1a1d1f;
  --surface-2: #22262a;
  --ink: #e8eaec;
  --ink-2: #b4bbc0;
  --muted: #8b939a;
  --line: #2a2f33;
  --line-strong: #e8eaec;
  --accent: #ff7a6b;
  --accent-press: #ff8f82;
  --on-accent: #23100c;
  --tint: #2b1d1a;
  --tint-line: #46302b;
  --danger: #e08585;
  --danger-dim: rgba(224, 133, 133, .10);
  --danger-line: rgba(224, 133, 133, .32);
  --ph: #5f6c7d;
}
:root[data-theme="light"] {
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-2: #f5f6f7;
  --ink: #111417;
  --ink-2: #3f464b;
  --muted: #6b7378;
  --line: #e3e6e8;
  --line-strong: #111417;
  --accent: #d6402f;
  --accent-press: #b93424;
  --on-accent: #ffffff;
  --tint: #fbeae7;
  --tint-line: #f0cfc8;
  --danger: #9a2b2b;
  --danger-dim: rgba(154, 43, 43, .07);
  --danger-line: rgba(154, 43, 43, .32);
  --ph: #9aa0a4;
}

* { box-sizing: border-box; }
/* Backstop (round 2 #6-B): several components below set their own `display`
   (flex/grid) on the SAME element JS toggles via the `hidden` attribute/
   property — e.g. .optfield, .legend, .pkhint. Author CSS beats the
   user-agent's `[hidden]{display:none}` at equal specificity, so without
   this the component's display wins and the element stays visibly shown
   even while `hidden` is set (the Send form's passphrase field bug). One
   global backstop makes `hidden` always mean not-rendered, full stop. */
[hidden] { display: none !important; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

body { font-family: var(--sans);
       background: var(--bg); color: var(--ink);
       max-width: 560px; margin: 48px auto; padding: 0 20px;
       font-size: 15px; line-height: 1.6; -webkit-font-smoothing: antialiased; }
body.wide { max-width: 860px; }

/* Selection must contrast with the TINTED surfaces too, not just the page
   background (app#70). It used to be `var(--tint)` — the exact background of
   .ok, .trust, .idlevel.current and the created-link banners — so selecting
   text inside any of those highlighted it in its own colour and looked like
   the text simply couldn't be selected (Pat reported it as exactly that on
   the setup "Fertig" box). A translucent accent wash instead: it darkens
   whatever is beneath it, so it reads on white, on tint, and in dark mode,
   without having to enumerate surfaces. The solid line below is the fallback
   for anything without color-mix — a slightly deeper tint, still visible on
   plain surfaces, which is where most selection happens. */
::selection { background: var(--tint-line); color: var(--ink); }
@supports (background: color-mix(in srgb, red 30%, transparent)) {
  ::selection { background: color-mix(in srgb, var(--accent) 30%, transparent); color: var(--ink); }
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
button, input, textarea, a { transition: background-color .12s ease, border-color .12s ease, color .12s ease; }
@media (prefers-reduced-motion: reduce) {
  button, input, textarea, a { transition: none; }
}

h1 { font-family: var(--sans); font-size: 28px; font-weight: 700; letter-spacing: -.03em;
     line-height: 1.1; margin: 22px 0 8px; color: var(--ink); }
h2 { font-family: var(--mono); font-size: 12px; font-weight: 600; text-transform: uppercase;
     letter-spacing: .1em; color: var(--muted); margin: 30px 0 10px; }
p.intro { color: var(--ink-2); margin: 6px 0 18px; }
a { color: var(--accent); text-underline-offset: 3px; text-decoration: none; }
a:hover { color: var(--accent-press); text-decoration: underline; }
code { font-family: var(--mono); font-size: 12.5px; background: var(--surface-2);
       border: 1px solid var(--line); padding: 2px 5px; border-radius: var(--r-chip);
       word-break: break-all; }

.muted { color: var(--muted); }

/* Kicker — swiss index label, used above a page's h1 on request/send/setup */
.kicker {
  font: 500 12px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 10px;
}

/* ---- Small vermilion seal square — NOT a brand mark (see note at top of
   file). A plain icon container used only by .seal-verified below, which
   puts a checkmark in it — never the asterisk. ---- */
.hanko {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  background: var(--accent); color: var(--on-accent); border-radius: var(--r-chip);
  width: 18px; height: 18px;
}
.hanko svg { width: 11px; height: 11px; display: block; }

/* Footnote device — lab-report style superscript asterisk + hairline rule.
   Once per public surface (start page, /r page) — see index.html / clientpage.js. */
.footnote { font-size: 13px; color: var(--muted); line-height: 1.5;
  border-top: 1px solid var(--line); padding-top: 10px; margin-top: 24px; max-width: 46ch; }
.footnote .ast { color: var(--accent); font-weight: 700; }

/* ---- Intent-banner landing (refactor#71) ----
   body.landing opts into the wider reading column (like body.wide) so the
   two intent cards can sit side by side without feeling cramped — a single
   flat page, no split panel. Collapses to a stacked column below 640px. */
body.landing { max-width: 720px; }
.landing-hero { text-align: center; margin: 34px 0 6px; }
.landing-sub { font: 700 28px/1.25 var(--sans); letter-spacing: -.02em; color: var(--ink); margin: 0; }
@media (max-width: 560px) { .landing-sub { font-size: 22px; } }

.intent-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 30px 0 6px; }
@media (max-width: 640px) {
  .intent-grid { grid-template-columns: 1fr; }
}
.intentcard { display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-card); padding: 22px 20px 20px;
  color: var(--ink); text-decoration: none; }
.intentcard:hover { border-color: var(--accent); text-decoration: none; }
.intentcard.waiting { opacity: .6; pointer-events: none; }
.intentcard .intenticon { width: 26px; height: 26px; color: var(--accent); }
.intentcard-h { display: block; font: 700 19px/1.3 var(--sans); letter-spacing: -.01em;
  color: var(--ink); margin: 0; }
.intentcard p { color: var(--ink-2); font-size: 14px; line-height: 1.5; margin: 0; flex: 1; }
.intentcard-btn { margin-top: 10px; width: 100%; box-sizing: border-box; }

/* Quiet return path (KEY CONSTRAINTS): #go stays a real button (signin.js's
   ceremony trigger) but reads as inline text, not a second loud CTA. */
.landing-quiet { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 30px 0 4px; font-size: 13.5px; color: var(--ink-2); }
.quietlink { display: inline; width: auto; margin: 0; padding: 0; background: none;
  border: 0; font: 500 13.5px/1 var(--sans); color: var(--ink-2); text-decoration: none;
  cursor: pointer; }
.quietlink:hover { color: var(--accent); text-decoration: underline; }
.dot-sep { color: var(--line); }

/* Failed-login recovery (KEY CONSTRAINTS): quiet, hidden until signin.js's
   fail() reveals it — never part of the page's default reading. */
.recoverhint { margin-top: 10px; font-size: 13px; color: var(--ink-2); }
.recoverhint p { margin: 5px 0; }

.footnote.foot-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.footnote.foot-row .version { font-family: var(--mono); flex: none; }
.footnote.foot-row .version:empty { display: none; }

/* instrument panels: every form is a flat, hairline-bordered panel */
form, #auth, .panel { background: var(--surface); border: 1px solid var(--line);
              border-radius: var(--r-card); padding: 18px 18px 20px; margin-top: 14px; }
body.wide #auth { max-width: 480px; margin-left: auto; margin-right: auto; margin-top: 40px; }

label { display: block; margin-top: 14px; font-family: var(--sans); font-size: 13.5px;
        font-weight: 600; color: var(--ink); letter-spacing: 0; text-transform: none; }
.filelabel { margin-top: 14px; }
.hint { color: var(--muted); font-size: 12px; margin-top: 4px; }
.hint .popwrap { margin-left: 6px; }

textarea, input[type=text], input[type=email], input[type=number], input[type=datetime-local], input[type=password] {
  width: 100%; box-sizing: border-box; margin-top: 6px; padding: 10px 12px; font-size: 15px;
  font-family: var(--sans); color: var(--ink); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-ctl); }
textarea { min-height: 120px; resize: vertical; }
textarea, input[type=password], input[readonly] { font-family: var(--mono); font-size: 14px; }
textarea::placeholder, input::placeholder { color: var(--ph); }
textarea:focus, input:focus { border-color: var(--accent); outline: none; }
textarea:focus-visible, input:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }
input[type=file] { width: 100%; box-sizing: border-box; margin-top: 8px; font-size: 13px;
  font-family: var(--mono); color: var(--ink-2); }
input[type=file]::file-selector-button { font-family: var(--sans); font-size: 12.5px; font-weight: 600;
  color: var(--ink-2); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-ctl); padding: 6px 11px; margin-right: 10px; cursor: pointer; }
input[type=file]::file-selector-button:hover { color: var(--ink); border-color: var(--accent); }
input[type=number] { font-family: var(--mono); font-variant-numeric: tabular-nums; }

button { margin-top: 16px; width: 100%; padding: 12px 16px; font-size: 15px; font-weight: 600;
         font-family: var(--sans); letter-spacing: .005em; border: 1px solid transparent;
         border-radius: var(--r-ctl); background: var(--accent); color: var(--on-accent); cursor: pointer; }
button:hover { background: var(--accent-press); border-color: var(--accent-press); }
button:disabled { background: var(--surface-2); color: var(--muted); border-color: var(--line); cursor: not-allowed; }

/* Generic .btn component (D's vocabulary, d.css .btn/.btn-primary/.btn-secondary)
   — for a real <a> that needs to read as the site's primary/secondary button.
   A plain <button> already gets the filled-primary look for free from the
   bare `button` selector above; .btn lets a *link* match it (CSP has no
   inline handlers to fake a button-that-navigates from a real <button>). */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; padding: 12px 16px; font: 600 15px/1 var(--sans); letter-spacing: .005em;
  border-radius: var(--r-ctl); border: 1px solid transparent; text-decoration: none; cursor: pointer; }
.btn-primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn-primary:hover { background: var(--accent-press); border-color: var(--accent-press);
  color: var(--on-accent); text-decoration: none; }
.btn-secondary { background: transparent; color: var(--ink); border-color: var(--ink); }
[data-theme="dark"] .btn-secondary { border-color: var(--ink-2); }
.btn-secondary:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }

/* "or" divider between two auth paths (D's .or) */
.or { font: 500 12px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); display: flex; align-items: center; gap: 12px; margin: 4px 0; }
.or::before, .or::after { content: ""; flex: 1; height: 1px; background: var(--line); }

/* passkey-methods strip (#47): fingerprint / face / security-key glyphs +
   caption, making the ceremony's nature obvious right under the sign-in CTA. */
.auth-methods { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px; color: var(--muted); font-size: 12px; }
.auth-methods svg { width: 20px; height: 20px; flex: none; }

.ok { background: var(--tint); border: 1px solid var(--tint-line);
      padding: 14px 16px; border-radius: var(--r-card); margin-top: 14px; color: var(--ink); }
/* Freshly-created-link banners (round 2 6-B, linkbox.js): an ink border
   instead of the pinkish .tint-line one reads as a calm confirmation, not
   an alert — same warm tint fill, just not the same hue as a warning. The
   link itself (.linkrow input) is the visually dominant element; the copy
   button stays a quiet secondary control, never a second accent CTA. */
.ok.created { border-color: var(--line-strong); }
.ok.created .created-head { display: flex; align-items: center; gap: 8px;
  font-weight: 600; color: var(--ink); }
.ok.created .created-head svg { width: 18px; height: 18px; color: var(--accent); flex: none; }
.ok.created .linkrow { display: flex; gap: 8px; margin-top: 10px; }
.ok.created .linkrow input[readonly] { flex: 1; min-width: 0; margin-top: 0;
  font-weight: 600; font-size: 14.5px; padding: 12px 14px;
  border: 1px solid var(--line-strong); background: var(--surface); }
.ok.created .linkrow button { width: auto; flex: none; margin-top: 0; }
.ok.created .hint { margin-top: 8px; }

/* refactor#75 handover block: the explain line, share row and "I've sent it"
   acknowledgement that extend the .created confirmation box above. */
.ok.created .handover-explain { margin-top: 10px; font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }
.ok.created .sharerow { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.ok.created .sharerow .btn { width: auto; padding: 8px 14px; font-size: 13.5px; }
.ok.created .handover-life { margin-top: 10px; }
.ok.created .handover-ack { margin-top: 12px; }
.ok.created .handover-ack .btn { width: auto; padding: 8px 14px; font-size: 13.5px; }
.err { color: var(--danger); background: var(--danger-dim); border-left: 2px solid var(--danger);
       padding: 8px 10px; margin-top: 12px; font-family: var(--mono); font-size: 13px; }
.cf { margin-top: 16px; }
footer { margin-top: 28px; color: var(--muted); font-size: 12px; }

/* chrome: brand header, language switcher, theme toggle, trust note, footer.
   /logo.svg is out of scope for this port (kept as-is, see note at top of
   file) — .brand only supplies the wordmark type next to whatever mark it
   currently holds. */
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 12px;
          padding-bottom: 14px; border-bottom: 1px solid var(--line); margin-bottom: 18px; }
.topbar-nav { display: flex; align-items: center; gap: 8px; }
.topbar-nav > a { font: 500 14px/1 var(--sans); color: var(--ink-2); text-decoration: none;
  padding: 6px 2px; }
.topbar-nav > a:hover { color: var(--ink); text-decoration: underline; }
.brand, .wordmark { display: flex; align-items: center; gap: 10px; min-width: 0;
  font-weight: 700; font-size: 17px; letter-spacing: -.02em; color: var(--ink); }
a.brand, a.wordmark { color: var(--ink); text-decoration: none; }
a.brand:hover, a.wordmark:hover { color: var(--ink); text-decoration: none; }
.brand img { width: 30px; height: 30px; flex: 0 0 auto; }
.brand .name { font-weight: 700; font-size: 17px; letter-spacing: -.02em; }
.brand .tagline { color: var(--muted); font-size: 12px; line-height: 1.3; font-weight: 400; letter-spacing: 0; }
.langsw { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }
.langsw button { width: auto; margin: 0; padding: 5px 8px; font-family: var(--mono);
  font-size: 11px; font-weight: 500; letter-spacing: .05em; background: none; color: var(--muted);
  border: 1px solid transparent; border-radius: var(--r-chip); cursor: pointer; }
.langsw button:hover { color: var(--ink-2); background: var(--surface-2); }
.langsw button.active { color: var(--accent); font-weight: 700; }

/* Theme toggle (frontend/theme.js wires [data-theme-toggle]) — the icon
   visibility rules key off [data-theme-toggle] rather than .toggle so the
   mobile-pinned .optoggle-mobile button (same markup, different position
   rule) gets the sun/moon swap too, not just the topbar/sidebar .toggle. */
.toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: var(--r-chip); flex: 0 0 auto;
  background: none; border: 1px solid var(--line); color: var(--ink-2); cursor: pointer; margin: 0; padding: 0;
}
.toggle:hover { color: var(--ink); border-color: var(--muted); background: none; }
[data-theme-toggle] svg { width: 16px; height: 16px; display: block; }
[data-theme-toggle] .sun { display: none; }
:root[data-theme="dark"] [data-theme-toggle] .sun { display: block; }
:root[data-theme="dark"] [data-theme-toggle] .moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) [data-theme-toggle] .sun { display: block; }
  :root:not([data-theme="light"]) [data-theme-toggle] .moon { display: none; }
}

/* request trust phrase (#41): three symbols the sender compares against what
   the operator told them out-of-band. Since #62 this lives inline in the
   mail-header "Symbole" row (see .mailhead below) rather than its own boxed
   callout, so it's sized to sit comfortably next to a row label instead of
   the old large centered display. .phrase is the shared chip component —
   request-panel.js's admin-table copy uses it too. */
.trustphrase-symbols { font-size: 20px; letter-spacing: .12em; line-height: 1; vertical-align: middle; }
.phrase { display: inline-flex; gap: 6px; align-items: center; font-size: 18px; line-height: 1;
  white-space: nowrap; border: 1px solid var(--line); border-radius: var(--r-chip);
  padding: 6px 9px; background: var(--surface); }

/* status chips (D's ".chip") — small bordered labels, e.g. Send protection state */
.chip { display: inline-flex; align-items: center; gap: 5px; font: 500 12.5px/1 var(--sans);
  color: var(--ink-2); border: 1px solid var(--line); border-radius: var(--r-chip);
  padding: 5px 8px; white-space: nowrap; }
.chip-tint { background: var(--tint); border-color: var(--tint-line); color: var(--ink); font-weight: 600; }

/* verified seal — hanko checkmark badge next to a requester byline */
.seal-verified { display: inline-flex; align-items: center; gap: 7px;
  font: 500 13px/1.3 var(--mono); color: var(--ink-2); }

/* ---- Mail-style header block (#62, Pat: "read like an email") ----
   Replaces the old numbered 01/02/03 walkthrough on the /r page with a
   From/Symbole/Betreff/Nachricht row list, echoing the operator-side
   .composerow visual language (muted mono-uppercase label + hairline rule)
   but for static values rather than form inputs. A bottom border closes the
   block off from the form below, matching the "────" divider in the spec
   mockup. Rows stack label-above-value on narrow screens (reusing the
   existing 480px breakpoint .composelabel switches at) so a long subject or
   message never gets crushed against the fixed-width label. */
.mailhead { margin: 16px 0 20px; padding-bottom: 2px; border-bottom: 1px solid var(--line); }
.mailrow { display: flex; align-items: flex-start; gap: 14px; padding: 8px 0;
  border-top: 1px solid var(--line); }
.mailrow:first-child { border-top: 0; }
/* overflow-wrap: a flex item's default min-width is its content's min-content
   size, which for ONE long unbreakable word (German "Vertrauenssymbole" has
   no space to break on) wins over the 84px width and overflows the column
   into the value beside it. Letting it wrap mid-word keeps the fixed-width
   two-column layout intact for every label in both languages. */
.mailrow-label { flex: none; width: 84px; font: 600 11.5px/1.4 var(--mono);
  text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
  overflow-wrap: anywhere; padding-top: 1px; }
.mailrow-value { flex: 1; min-width: 0; font-size: 14.5px; line-height: 1.5; color: var(--ink); }
.mailrow-value .popwrap { margin-left: 8px; }
@media (max-width: 480px) {
  .mailrow { flex-direction: column; align-items: flex-start; gap: 3px; }
  .mailrow-label { width: auto; }
}

/* Submit row (#62): with the "03 Absenden" step label gone, the button sits
   alone at the right, matching how the operator-side compose forms dock
   their primary action. */
.recv-actions { display: flex; justify-content: flex-end; margin-top: 16px; }
.recv-actions button { width: auto; margin: 0; padding: 12px 24px; }

/* status chip (D's dot + label) — request-panel.js's table rows */
.st { display: inline-flex; align-items: center; gap: 7px; font-weight: 500; font-size: 13.5px; white-space: nowrap; }
.st .dot { width: 8px; height: 8px; border-radius: 2px; background: var(--line-strong); flex: none; }
.st.new .dot { background: var(--accent); }
.st.new { color: var(--ink); font-weight: 600; }

/* legend line under a .dtable, and the dashed "ask for something new" row
   below it (D's app-receive) */
.tablewrap + .legend { display: flex; gap: 18px; margin-top: 14px; font-size: 12.5px;
  color: var(--muted); flex-wrap: wrap; }
.legend .st { font-size: 12.5px; color: var(--muted); font-weight: 400; }
.newrow { display: flex; align-items: center; gap: 12px; margin-top: 14px;
  border: 1px dashed var(--line); border-radius: var(--r-card); padding: 14px 16px;
  color: var(--muted); font-size: 14px; text-decoration: none; }
.newrow:hover { border-color: var(--accent); color: var(--ink-2); text-decoration: none; }
.newrow svg { width: 18px; height: 18px; color: var(--accent); flex: none; }
.newrow b { color: var(--ink); font-weight: 600; }

.trust { display: flex; gap: 10px; align-items: flex-start; margin-top: 22px; padding: 12px 14px;
  background: var(--tint); border: 1px solid var(--tint-line); border-radius: var(--r-card); }
.trust svg { width: 22px; height: 22px; flex: 0 0 auto; color: var(--accent); margin-top: 1px; }
.trust.danger { background: var(--danger-dim); border-color: var(--danger-line); }
.trust.danger svg { color: var(--danger); }
.trust .why { font-weight: 600; font-size: 14px; margin: 0 0 2px; }
.trust .body { color: var(--ink-2); font-size: 13px; margin: 0; }
.brandfoot { margin-top: 26px; color: var(--muted); font-size: 12px;
  font-family: var(--mono); display: flex; align-items: center; gap: 6px; }
.brandfoot svg { width: 13px; height: 13px; }
.brandfoot .version { margin-left: auto; }
.brandfoot .version:empty { display: none; }

/* server-rendered pages (/r, /s — functions/_lib/clientpage.js): the
   operator-facing content sits in a flat, hairline-bordered card. A .form/
   #auth nested inside loses its own border/padding so the two panels don't
   nest (the card supplies it once). */
.pagewrap { margin-top: 0; }
.card { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-card); padding: 20px 20px 22px; margin-top: 14px; }
.card > h1:first-child { margin-top: 0; }
.card form, .card #auth { background: none; border: 0; padding: 0; margin-top: 18px; }
.card form:first-child, .card #auth:first-child { margin-top: 0; }

/* revealed secret: quiet hover copy control inside the text box (#8) */
.secretbox { position: relative; margin-top: 8px; }
.secretbox textarea { margin-top: 0; display: block; }
.secretbox .copybtn { position: absolute; top: 8px; right: 8px; width: auto; margin: 0;
  padding: 4px 9px; font-size: 14px; line-height: 1.2; font-family: var(--mono); font-weight: 500;
  background: var(--surface); color: var(--ink-2); border: 1px solid var(--line);
  border-radius: var(--r-ctl); opacity: 0; pointer-events: none; transition: opacity .12s ease; }
.secretbox:hover .copybtn, .secretbox:focus-within .copybtn { opacity: 1; pointer-events: auto; }
.secretbox .copybtn:hover { color: var(--accent); background: var(--tint);
  border-color: var(--tint-line); }

/* admin + inbox */
.tagline { color: var(--muted); font-size: 12px; font-weight: 400; }
#created, #s_created { margin-top: 14px; }
#s_text { min-height: 90px; }
.tabs { display: flex; gap: 4px; align-items: center; border-bottom: 1px solid var(--line); margin: 6px 0 16px; }
.tabs button { width: auto; margin: 0 0 -1px; background: none; color: var(--ink-2); border: 0;
  border-bottom: 2px solid transparent; border-radius: 0; padding: 9px 13px; font-size: 14px; font-weight: 500; }
.tabs button:hover { color: var(--ink); background: none; }
.tabs button.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.tabs .logout { margin-left: auto; font-size: 12px; font-family: var(--mono); color: var(--muted); }

.keymode { margin-top: 6px; }
.keymode .opt { font-family: var(--sans); font-size: 14px; font-weight: 400; text-transform: none;
  letter-spacing: 0; color: var(--ink); display: flex; gap: 8px; align-items: flex-start; margin-top: 6px; }
.keymode .opt input { width: auto; margin: 3px 0 0; accent-color: var(--accent); }
.pkout { margin-top: 10px; font-size: 13px; color: var(--ink-2); }

/* Data table (D's dense ".dtable" rows) — request/send/passkey/inbox lists.
   .tablewrap scrolls horizontally instead of crushing columns on narrow
   viewports (D's app-receive reference); dtable gets a min-width so the mono
   link column stays on one line rather than wrapping into a ladder.
   round 2 5.1: a static edge fade on mobile signals there's more to the
   right — a min-width table this narrow is effectively always scrollable
   there, so an always-on fade (rather than a JS scroll-position toggle) is
   a fair, dependency-free approximation. */
.tablewrap { overflow-x: auto; }
.tablewrap .dtable { min-width: 640px; }
/* app#63: the merged Receive list carries five columns instead of six, so it
   fits the operator pane at ordinary widths — the old table's right edge was
   simply cut off (Pat's screenshot), because a 640px floor plus a 220px link
   cell plus a wide actions column could not. A lower floor here means the
   horizontal scroll is a genuine fallback for narrow viewports rather than
   the normal state on a desktop. */
#panel-receive .tablewrap .dtable { min-width: 480px; }
#panel-receive .dtable td.req { max-width: 300px; }
/* The expiry stamp is a full locale date+time — the widest fixed content in
   the row. Letting it wrap keeps the four columns inside the pane. */
#panel-receive .dtable td:nth-child(3) { white-space: normal; max-width: 110px; }
/* And when a viewport IS too narrow even for four columns, the scroll must be
   visible rather than looking like a table someone cut off. */
.tablewrap { scrollbar-width: thin; }
@media (max-width: 640px) {
  .tablewrap { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%); }
}
/* round 2 5.2 (desktop): the flexible text columns truncate with an
   ellipsis (JS adds a title attr with the full value) instead of growing
   the table wide enough to push the actions column out of easy reach. */
.dtable td.req { max-width: 260px; }
.dtable td.req b { display: block; font-weight: 600; font-size: 15px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dtable td.req .reqmeta { font-size: 13px; color: var(--muted);
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dtable td.notecell, .dtable td.subjcell { max-width: 220px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* app#63: the trust symbols and the copy-link control lost their own columns
   and now ride under the subject. The operator pane is a 720px reading column,
   so the old six-column table simply ran off its right edge — the clipping Pat
   saw. Four columns fit; a URL rendered as text never will. */
.dtable td.req > b > a { color: inherit; font: inherit; text-decoration: none; }
.dtable td.req > b > a:hover { text-decoration: underline; }
.reqfoot { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.reqfoot .rowphrase { display: inline-flex; font-size: 15px; margin: 0; }
.reqfoot .copybtn { padding: 3px 8px; font-size: 12px; white-space: nowrap; }
/* When the newest answer landed — a second, quiet line under the status chip
   rather than a sixth column. */
.statuswhen { display: block; margin-top: 4px; font-size: 12px; color: var(--muted);
  white-space: nowrap; }
/* One decrypted arrival inside an expanded row. Several can stack when a
   multi-use request was answered more than once. */
.arrival + .arrival { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line); }
.arrival-files { margin-top: 8px; }
.arrival-files a { display: block; margin-top: 4px; }
.arrival-actions { margin-top: 6px; }
table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 14px;
        font-variant-numeric: tabular-nums; }
tr:has(+ .reveal-row) > td { border-bottom: 0; }
th { font-family: var(--mono); font-size: 11px; font-weight: 500; text-transform: uppercase;
     letter-spacing: .1em; color: var(--muted); }
th, td { text-align: left; padding: 12px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
thead th { border-bottom: 2px solid var(--line-strong); }
tbody tr:hover > td { background: var(--surface-2); }
td a { font-family: var(--mono); font-size: 12.5px; }
/* round 2 5.2: the actions column keeps a reliable min-width and never
   wraps, so "Open"/"Delete" can't be squeezed off to the side. */
.row-actions { display: flex; gap: 6px; align-items: center; justify-content: flex-end;
  flex-wrap: nowrap; min-width: 104px; flex: none; }
/* The row's ONE real action — Reveal on an answered row, Edit on an open one
   (app#63). Neutral by default; .accent marks the one that opens a secret. */
.row-actions .rowmain { width: auto; margin: 0; padding: 6px 10px; font-size: 12.5px; font-weight: 500;
  background: none; color: var(--ink-2); border: 1px solid var(--line-strong); border-radius: var(--r-ctl);
  white-space: nowrap; }
.row-actions .rowmain:hover { background: var(--surface-2); color: var(--ink); }
/* app#63: delete is a red ✕, not the word "Delete" — it stops competing with
   the row's real action for the little width a table row has. */
.row-actions .rowdel { width: 28px; height: 28px; margin: 0; padding: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; color: var(--danger); border: 1px solid transparent; border-radius: var(--r-ctl); }
.row-actions .rowdel:hover { background: var(--danger-dim); border-color: var(--danger-line); }
.row-actions .rowdel svg { width: 15px; height: 15px; display: block; }
/* Settings still uses plain worded row buttons (Remove / Revoke), which are
   destructive — keep the original danger styling for those. */
.row-actions button:not(.rowmain):not(.rowdel) { width: auto; margin: 0; padding: 6px 10px;
  font-size: 12.5px; font-weight: 500; background: none; color: var(--danger);
  border: 1px solid var(--danger-line); border-radius: var(--r-ctl); white-space: nowrap; }
.row-actions button:not(.rowmain):not(.rowdel):hover { background: var(--danger-dim); }

/* admin: mail-client layout (sidebar nav + inbox list + reading pane) */
.mail { display: flex; gap: 22px; align-items: flex-start; margin-top: 16px; }
.mailnav { flex: 0 0 150px; display: flex; flex-direction: column; gap: 2px; }
.mailnav button { width: 100%; margin: 0; text-align: left; background: none; color: var(--ink-2);
  border: 0; border-left: 2px solid transparent; border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
  padding: 8px 12px; font-size: 14px; font-weight: 500; }
.mailnav button:hover { background: var(--surface-2); color: var(--ink); }
.mailnav button.active { color: var(--accent); border-left-color: var(--accent);
  background: var(--tint); font-weight: 600; }
.mailnav .count { font-family: var(--mono); font-size: 11px; color: var(--muted); margin-left: 6px; }
.mailnav .logout { margin: 14px 0 0 14px; font-family: var(--mono); font-size: 12px; color: var(--muted); }
.mailmain { flex: 1; min-width: 0; }
.mailmain h2:first-child, .mailbar h2 { margin-top: 6px; }
.mailbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.msglist { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card);
  overflow: hidden; margin-top: 10px; }
.msg { display: flex; gap: 12px; align-items: baseline; padding: 10px 14px;
  border-bottom: 1px solid var(--line); cursor: pointer; }
.msg:last-child { border-bottom: 0; }
.msg:hover { background: var(--surface-2); }
.msg.active { background: var(--tint); }
.msg .m-subj { font-weight: 600; flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.msg .m-when { font-family: var(--mono); font-size: 12px; color: var(--muted); flex: 0 0 auto; }
.msgdetail { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card);
  padding: 14px 16px; margin-top: 14px; }
.msgdetail .actions { margin-top: 10px; display: flex; gap: 8px; }
@media (max-width: 640px) {
  .mail { flex-direction: column; }
  .mailnav { flex-direction: row; width: 100%; }
  .mailnav button { width: auto; border-left: 0; border-bottom: 2px solid transparent; border-radius: 0; }
  .mailnav button.active { border-left: 0; border-bottom-color: var(--accent); }
  .mailnav .logout { margin: 0 0 0 auto; align-self: center; }
}

/* unified operator nav shell (#33): fixed left sidebar (>=768px) + fixed
   bottom tab bar (<768px), both driven by the same [data-nav] buttons so
   app.js only has one selector to keep in sync. app.js toggles
   body.shell-active while the shell (not the login card) is showing, so it
   can go full-width without touching body.wide anywhere else (how-it-works
   still relies on the 860px cap, and the login card still centers via the
   existing body.wide #auth rule above). */
body.wide.shell-active { max-width: none; margin: 0; padding: 0; }

.opnav, .opbottombar { display: none; }

.opnav-brand { display: flex; align-items: center; gap: 10px; padding: 18px 16px;
  border-bottom: 1px solid var(--line); color: var(--ink); font-weight: 700; font-size: 16px; letter-spacing: -.02em; }
.opnav-brand:hover { color: var(--ink); text-decoration: none; }
.opnav-brand img { width: 26px; height: 26px; flex: 0 0 auto; }

.opnav-items { flex: 1; display: flex; flex-direction: column; gap: 2px; padding: 10px; overflow-y: auto; }
.opnav-item { display: flex; align-items: center; gap: 10px; width: 100%; margin: 0; text-align: left;
  background: none; color: var(--ink-2); border: 0; border-radius: var(--r-ctl);
  padding: 9px 12px; font-size: 14px; font-weight: 500; }
.opnav-item:hover { background: var(--surface-2); color: var(--ink); }
.opnav-item.active { color: var(--ink); background: var(--tint); font-weight: 600; box-shadow: inset 2px 0 0 var(--accent); }
.opnav-icon { width: 18px; height: 18px; flex: 0 0 auto; }

.opnav-foot { border-top: 1px solid var(--line); padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.opnav-foot-row { display: flex; align-items: center; gap: 8px; }
.opnav-foot .langsw { justify-content: flex-start; }
/* #65: icon + label, same gap as .opnav-item above it; padding-left (10px on
   top of .opnav-foot's own 12px) lines its icon column up with the Settings
   item's icon column (10px items-wrapper padding + 12px item padding = 22px
   from the sidebar edge, matched here as 12px + 10px = 22px). */
.opnav-logout { display: flex; align-items: center; gap: 10px; padding: 4px 0 4px 10px;
  font-size: 13px; color: var(--ink-2); }
.opnav-logout:hover { color: var(--danger); text-decoration: none; }
.opnav-foot .version { font-family: var(--mono); font-size: 11px; color: var(--muted); }

.opmain { max-width: 720px; margin: 0 auto; padding: 32px 20px 20px; }

/* mobile-only gear (#40) and theme toggle; hidden wherever the sidebar shows them */
.opgear, .optoggle-mobile { display: none; }

/* conditional-UI sign-in field (#40): a real, focusable input so the browser
   can attach passkey autofill, styled as a quiet single line. */
.signin-hint { max-width: 320px; }

@media (min-width: 768px) {
  .opnav { display: flex; flex-direction: column; position: fixed; top: 0; left: 0;
    width: 240px; height: 100vh; background: var(--surface); border-right: 1px solid var(--line); z-index: 20; }
  .opmain { margin-left: 240px; }
}

@media (max-width: 767.98px) {
  .opbottombar { display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 20;
    background: var(--surface); border-top: 1px solid var(--line); padding-bottom: env(safe-area-inset-bottom, 0); }
  .opbottom-item { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
    width: auto; margin: 0; padding: 8px 4px 10px; background: none; border: 0;
    color: var(--muted); font-size: 10.5px; font-weight: 500; }
  .opbottom-item.active { color: var(--accent); font-weight: 700; }
  .opbottom-icon { width: 20px; height: 20px; }
  body.shell-active .opmain { padding-bottom: 76px; }
  /* Settings behind a gear pinned top-right, theme toggle pinned top-left (#40 + #12). */
  .opgear, .optoggle-mobile { display: flex; position: fixed; top: 10px; z-index: 21;
    width: 40px; height: 40px; margin: 0; padding: 0; align-items: center; justify-content: center;
    background: var(--surface); border: 1px solid var(--line); border-radius: 50%; color: var(--ink-2); }
  .opgear { right: 10px; }
  .optoggle-mobile { left: 10px; }
  .opgear svg, .optoggle-mobile svg { width: 18px; height: 18px; }
  .opgear.active { color: var(--accent); border-color: var(--accent); }
  body.shell-active .opmain { padding-top: 56px; }
}

/* small button variants (ghost/accent/danger) — used by JS-built table actions */
button.ghost, button.accent, button.danger { width: auto; margin: 0; padding: 6px 10px;
  font-size: 12.5px; font-weight: 500; background: none; border: 1px solid var(--line-strong);
  border-radius: var(--r-ctl); color: var(--ink-2); }
button.ghost:hover { background: var(--surface-2); color: var(--ink); }
button.accent { color: var(--accent); border-color: var(--accent); }
button.accent:hover { background: var(--tint); }
button.danger { color: var(--danger); border-color: var(--danger-line); }
button.danger:hover { background: var(--danger-dim); }

/* prominent "Delete from server" CTA after a reveal (#44) — theme-safe:
   danger-tinted by default, inverts to filled danger on hover. Weight +
   border carry the "this is destructive" signal alongside the muted danger
   colour (see --danger above) so it never competes with the vermilion accent. */
button.danger-cta { width: 100%; margin-top: 12px; padding: 11px 14px; font-size: 14px;
  font-weight: 700; background: var(--danger-dim); color: var(--danger);
  border: 1px solid var(--danger); border-radius: var(--r-ctl); }
button.danger-cta:hover { background: var(--danger); color: var(--surface); }
button.danger-cta:disabled { opacity: .55; cursor: not-allowed; }

/* how-it-works (/how-it-works/, SPEC-RADICAL-B 3): graphic-first, text
   minimal — ONE hand-crafted inline SVG pipeline (sender -> server -> you),
   currentColor/CSS-var fills only so light+dark both work. The flowing dots
   are the only animation; style.css's global prefers-reduced-motion rule
   (top of this file) already turns them off, no extra media query needed. */
.hiw-pipeline { margin-top: 22px; }
.hiw-pipeline svg { display: block; width: 100%; height: auto; max-width: 640px; margin: 0 auto; }
.hiw-pipe-ring { fill: var(--surface); stroke: var(--line-strong); stroke-width: 1.5; }
.hiw-pipe-arrow { stroke: var(--line-strong); stroke-width: 1.5; }
.hiw-pipe-arrowhead { fill: var(--line-strong); }
.hiw-pipe-label { font: 600 10.5px/1 var(--mono); text-transform: uppercase;
  letter-spacing: .08em; fill: var(--muted); }
.hiw-pipe-seal { fill: var(--accent); }
.hiw-pipe-seal-check { stroke: var(--on-accent); }
.hiw-pipe-open-check { stroke: var(--accent); }
.hiw-pipe-dot { fill: var(--accent); opacity: 0; }
.hiw-pipe-dot-1 { animation: hiw-pipe-flow 2.6s ease-in-out infinite; }
.hiw-pipe-dot-2 { animation: hiw-pipe-flow 2.6s ease-in-out infinite 1.3s; }
@keyframes hiw-pipe-flow {
  0% { opacity: 0; transform: translateX(0); }
  8% { opacity: 1; }
  85% { opacity: 1; }
  100% { opacity: 0; transform: translateX(154px); }
}

/* exactly three captions, aligned under their stage — each a small numbered
   badge stacked above its one-line fact. */
.hiw-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
  margin: 4px 0 24px; text-align: center; }
.hiw-facts p { display: flex; flex-direction: column; align-items: center;
  margin: 0; font-size: 13.5px; color: var(--ink-2); line-height: 1.4; }
.hiw-facts-n { display: flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; margin: 0 0 6px; border-radius: 50%;
  background: var(--tint); color: var(--accent); font: 700 11px/1 var(--mono); flex: none; }
@media (max-width: 560px) {
  .hiw-facts { grid-template-columns: 1fr; gap: 14px; }
  .hiw-facts p { flex-direction: row; text-align: left; }
  .hiw-facts-n { margin: 0 10px 0 0; }
}

.hiw-back-row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.hiw-back-row .btn { width: auto; padding: 10px 20px; }

/* Staging ribbon (#67) — yellow bar injected by _middleware.js on the staging
   instance only, so it's never mistaken for production. Amber reads the same in
   light and dark, so it needs no theme override. */
.staging-ribbon {
  position: sticky; top: 0; z-index: 1000;
  background: #f5c518; color: #1a1300;
  font-family: var(--sans); font-weight: 700; font-size: 13px; letter-spacing: .02em;
  text-align: center; padding: 6px 12px;
  border-bottom: 1px solid #c99a06;
}

/* "What is a passkey?" disclosure on setup (#64). */
.explainer { margin: 14px 0; font-size: 14px; }
.explainer > summary {
  cursor: pointer; color: var(--accent); font-weight: 600;
  list-style: none; padding: 2px 0;
}
.explainer > summary::-webkit-details-marker { display: none; }
.explainer > summary::before { content: "+ "; font-weight: 700; font-family: var(--mono); }
.explainer[open] > summary::before { content: "\2212 "; }
.explainer > p { color: var(--ink-2); margin-top: 8px; line-height: 1.5; }
/* #61 item 8: the step-4 passkey accordion is the first .explainer to hold a
   <ul> (the platform/hardware-key list from pk_page.work_platform/work_hw) —
   without this, the list fell back to the browser default UA-stylesheet
   color (full-strength ink), clashing with the dimmed .explainer > p text
   right above and below it. */
.explainer ul { color: var(--ink-2); margin: 8px 0 0; padding-left: 20px; line-height: 1.5; }
.explainer li + li { margin-top: 4px; }

/* ---- round-2 refinements (compose-style forms, hierarchy, empty states) ---- */

/* Settings groups into titled cards (reuses .card, the same flat bordered
   panel the server-rendered /r /s pages use) — extend it to also settle a
   heading that's an h2 (this file's admin panels use h2, not h1). */
.card > h2:first-child { margin-top: 0; }

/* Quiet "secondary" submit for a form whose action is NOT the view's single
   primary CTA (Add device / Create token / Save) — bordered, auto-width,
   inline, never competes with the one full-width accent button per view. */
button.secondary-cta { width: auto; margin-top: 16px; padding: 10px 18px;
  font-size: 14px; font-weight: 600; background: none; color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r-ctl); }
button.secondary-cta:hover { background: var(--surface-2); }

/* Zone separation for the Receive panel (new request / existing requests /
   arrivals): a hairline + a small accent index number, numbered purely in
   CSS via a counter so no JS/i18n string has to carry the digit. */
#panel-receive { counter-reset: zone; }
#panel-receive > .zone { counter-increment: zone; margin-top: 30px; padding-top: 22px;
  border-top: 1px solid var(--line); }
#panel-receive > .zone:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* The zone heading sits in a .zonehead row (app#63) so a quiet icon action —
   the list's refresh arrow — can share its line without becoming another
   full-width button below it. */
.zonehead { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
#panel-receive > .zone > .zonehead > h2 { margin-top: 0; position: relative; }
#panel-receive > .zone > .zonehead > h2::before { content: counter(zone) "  "; color: var(--accent); }

/* Icon-only control beside a heading (browser-style circular refresh arrow). */
.iconbtn { width: 32px; height: 32px; margin: 0; padding: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; color: var(--muted); border: 1px solid var(--line);
  border-radius: var(--r-ctl); cursor: pointer; }
.iconbtn:hover { background: var(--surface-2); color: var(--ink); }
.iconbtn svg { width: 16px; height: 16px; display: block; }

/* First-run empty-state teaching card (empty requests table / empty inbox) —
   a quiet, neutral bordered card (not the tinted .ok "success" look, not an
   error), one line explaining what the zone is and what happens next. */
.emptycard { border: 1px solid var(--line); border-radius: var(--r-card);
  padding: 14px 16px; margin-top: 14px; color: var(--ink-2); font-size: 14px; }

/* Requests table LINK column: a truncated single line + copy button, never
   the multi-line mono ladder a full URL wraps into. */
.linkcell { display: inline-flex; align-items: center; gap: 6px; max-width: 220px; }
/* app#63: the truncated link became a real <a> (opening the recipient's view
   replaced the separate "Open" button), so the flex/ellipsis rules move to
   the anchor — the <code> inside just carries the mono face. */
.linkcell > a { flex: 1; min-width: 0; overflow: hidden; text-decoration: none; }
.linkcell > a:hover { text-decoration: underline; }
.linkcell code { display: block; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }

/* Single-passkey warning: a compact inline notice (small muted text + link),
   never a loud full-width banner — the dismiss control is a small ghost
   button, not the page's shouting red CTA. */
.pkhint { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 12px; font-size: 12.5px; color: var(--muted); }

/* Mail-bar-style row (heading/body + a small secondary action beside it) —
   used to keep Refresh a quiet inline control near the arrivals list instead
   of a full-width primary button. */
.row-between { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; }

/* ---- Compose-style forms (#1): Gmail-toolbar options bar at the bottom of
   the Send/Request cards, instead of full-width stacked label/input rows. --- */
.optionsbar { display: flex; flex-wrap: wrap; gap: 18px 26px; align-items: flex-end;
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.optfield { display: flex; flex-direction: column; gap: 4px; }
label.optlabel { margin-top: 0; font: 600 11.5px/1 var(--mono); text-transform: uppercase;
  letter-spacing: .08em; color: var(--muted); }
.optfield .hint { margin-top: 2px; max-width: 24ch; }
.optionsbar-submit { width: auto; margin: 0; padding: 10px 22px; }
@media (max-width: 480px) {
  .optionsbar-submit { width: 100%; }
}

/* [-] [n] [+] stepper (Views / Max uses) — wraps the real numeric input the
   rest of the app already reads by id; typing directly still works. */
.stepper { display: inline-flex; align-items: stretch; border: 1px solid var(--line);
  border-radius: var(--r-ctl); overflow: hidden; width: fit-content; }
.stepper .stepbtn { width: 30px; margin: 0; padding: 0; font-size: 16px; font-weight: 600;
  background: var(--surface-2); color: var(--ink-2); border: 0; border-radius: 0; cursor: pointer; }
.stepper .stepbtn:hover { background: var(--tint); color: var(--accent); }
.stepper input[type=number] { width: 3.5ch; margin: 0; padding: 6px 2px; text-align: center;
  border: 0; border-left: 1px solid var(--line); border-right: 1px solid var(--line);
  border-radius: 0; }
.stepper input[type=number]::-webkit-inner-spin-button,
.stepper input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

/* Days-count field + calendar-popover button (Expires / Valid for) — picking
   a date in the popover back-computes the day count into the visible input. */
.dayfield { display: inline-flex; align-items: center; gap: 6px; position: relative; }
.dayfield input[type=number] { width: 3.5ch; margin: 0; padding: 6px 8px; text-align: center;
  -moz-appearance: textfield; }
.dayfield input[type=number]::-webkit-inner-spin-button,
.dayfield input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.dayfield-unit { font-size: 13px; color: var(--ink-2); }
.calbtn { width: 30px; height: 30px; margin: 0; padding: 0; flex: none; display: inline-flex;
  align-items: center; justify-content: center; background: none; color: var(--ink-2);
  border: 1px solid var(--line); border-radius: var(--r-ctl); cursor: pointer; }
.calbtn:hover { color: var(--accent); border-color: var(--accent); }
.calbtn svg { width: 15px; height: 15px; display: block; }
.calpop { position: absolute; top: calc(100% + 6px); left: 0; z-index: 5;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-ctl);
  padding: 10px; box-shadow: 0 2px 0 var(--line); }
.calpop input[type=date] { margin: 0; width: auto; }

/* Compact "attach files" row (paperclip feel) instead of a raw full-width
   file input. */
.filerow { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.filerow svg { width: 16px; height: 16px; color: var(--muted); flex: none; }
.filerow input[type=file] { width: auto; margin: 0; }

/* ---- Compose rows (Pat 2026-07-24, Gmail-compose reference): the Receive
   create form reads like a mail client's New Message — From / To / Subject /
   Description as hairline-separated rows, muted fixed-width labels on the
   left, borderless inputs filling the row. The form panel supplies the outer
   border; rows only draw separators. ---- */
.compose { padding-top: 6px; }
.composerow { display: flex; align-items: center; gap: 10px;
  border-bottom: 1px solid var(--line); padding: 4px 0; position: relative; }
.composerow-last { border-bottom: 0; }
.composelabel { flex: none; width: 88px; margin: 0; font: 500 13px/1 var(--sans);
  color: var(--muted); letter-spacing: 0; text-transform: none; }
input.composeinput, input.composeinput[type=email], input.composeinput[type=text] {
  flex: 1; min-width: 0; width: auto; margin: 0; padding: 9px 2px;
  border: 0; border-radius: 0; background: none; font-size: 15px; }
input.composeinput:focus, input.composeinput:focus-visible {
  outline: none; box-shadow: inset 0 -2px 0 var(--accent); }
@media (max-width: 480px) { .composelabel { width: 64px; } }

/* app#63/#64: the message row is multi-line in both compose forms — a mail
   body, not a one-line field. Same borderless look as the input rows; the
   label rides at the top of the box instead of centering against it. */
textarea.composeinput { flex: 1; min-width: 0; width: auto; margin: 0; padding: 9px 2px;
  border: 0; border-radius: 0; background: none; font: 400 15px/1.5 var(--sans);
  resize: vertical; min-height: 72px; }
textarea.composeinput:focus, textarea.composeinput:focus-visible {
  outline: none; box-shadow: inset 0 -2px 0 var(--accent); }
.composerow-multi { align-items: flex-start; }
.composerow-multi .composelabel { padding-top: 15px; }
/* The file picker sits in a compose row too (Send) — no extra top margin, it
   is already spaced by the row. */
.composerow .filerow { margin-top: 0; flex: 1; min-width: 0; }

/* From: the sender-identity chip — the identification state the RECIPIENT
   will see on the /r page (anonymous / verified email / verified domain,
   the D11 verified-sender ladder). Hover/focus opens a CSS-only popover
   explaining the three levels; the current one is highlighted. */
.idchip { display: inline-flex; align-items: center; gap: 7px; width: auto;
  margin: 5px 0; padding: 6px 10px; font: 500 13.5px/1 var(--sans); cursor: default;
  color: var(--ink-2); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 999px; }
.idchip:hover { background: var(--surface-2); border-color: var(--muted); color: var(--ink); }
.idchip svg { width: 15px; height: 15px; flex: none; }
.idchip .idchip-q { width: 14px; height: 14px; color: var(--muted); }

/* Shared CSS-only hover/focus popover (no [hidden] toggling — the global
   [hidden] backstop and this pattern don't mix, see the note at the top). */
.popwrap { position: relative; display: inline-flex; align-items: center; }
.composepop { display: none; position: absolute; top: calc(100% + 6px); left: 0; z-index: 30;
  width: min(340px, 78vw); background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-card); padding: 12px 14px; box-shadow: 0 2px 0 var(--line); }
.composepop-right { left: auto; right: 0; }
.popwrap:hover .composepop, .popwrap:focus-within .composepop { display: block; }
.poptitle { margin: 0 0 8px; font: 600 11.5px/1.3 var(--mono); text-transform: uppercase;
  letter-spacing: .08em; color: var(--muted); }
.popbody { margin: 0 0 8px; font-size: 13px; line-height: 1.5; color: var(--ink-2); }
.popbody:last-child { margin-bottom: 0; }
.popquiet { color: var(--muted); font-size: 12.5px; }

/* The three identity levels inside the From popover. */
.idlevel { padding: 7px 9px; border-radius: var(--r-ctl); margin: 0 -2px; }
.idlevel.current { background: var(--tint); border: 1px solid var(--tint-line); }
.idlevel-name { display: block; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.idlevel-name em { font: 600 10.5px/1 var(--mono); font-style: normal; text-transform: uppercase;
  letter-spacing: .08em; color: var(--accent); margin-left: 6px; }
.idlevel-desc { display: block; font-size: 12.5px; color: var(--ink-2); line-height: 1.45; margin-top: 2px; }

/* To-row info trigger: a quiet circled "?" that reveals the how-else-can-I-
   send-this popover. Hover the icon or focus the field's row. */
.infobtn { width: 26px; height: 26px; margin: 0; padding: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 50%; color: var(--muted); cursor: help; }
.infobtn:hover { background: var(--surface-2); color: var(--ink); }
.infobtn svg { width: 16px; height: 16px; display: block; }

/* Bottom action bar. app#63/#64: the options lead and the primary action sits
   at the RIGHT end of the bar — Pat's read of every mail compose window. The
   shared .optionsbar supplies the hairline top border and wrapping; here the
   hints stay one quiet line.
   The submit is wrapped in .compose-submit so margin-left:auto pushes the pair
   (an optional Cancel + the primary button) over together, and so a wrap on a
   narrow viewport keeps them side by side rather than splitting them. */
.compose-actions { align-items: flex-start; }
.compose-actions .optfield { padding-top: 2px; }
.compose-submit { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.compose-submit .ghost { padding: 10px 14px; font-size: 13.5px; }
@media (max-width: 480px) {
  .compose-submit { width: 100%; margin-left: 0; }
  .compose-submit .optionsbar-submit { flex: 1; }
}

/* ---- Setup step strip (#37/#40, variant B): a compact progress read at the
   top of setup — 5 steps in the radical-B wizard rework. Progression is
   toggled by setup.js via .active/.done. ---- */
.stepstrip { display: flex; align-items: center; gap: 8px; margin: 4px 0 20px;
  font: 600 11.5px/1 var(--mono); text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); flex-wrap: wrap; }
.stepstrip .step { display: inline-flex; align-items: center; gap: 5px; }
.stepstrip .stepnum { display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--line);
  font-size: 10px; color: var(--muted); flex: none; }
.stepstrip .sep { color: var(--line); }
.stepstrip .step.active { color: var(--ink); }
.stepstrip .step.active .stepnum { border-color: var(--accent); color: var(--accent); }
.stepstrip .step.done { color: var(--ink-2); }
.stepstrip .step.done .stepnum { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* ---- Setup wizard steps (SPEC-RADICAL-B 2): one .wiz-step visible at a
   time (setup.js's setStep toggles [hidden]), each a single concern + why. -- */
.wiz-q { font: 700 20px/1.25 var(--sans); letter-spacing: -.01em; color: var(--ink); margin: 2px 0 8px; }
.wiz-actions { display: flex; align-items: center; gap: 12px; margin-top: 22px; flex-wrap: wrap; }
.wiz-actions .btn { width: auto; margin-top: 0; padding: 11px 22px; }
.wiz-actions-right { display: flex; gap: 10px; margin-left: auto; flex-wrap: wrap; }
#wiz-2 button#go.btn { margin-top: 18px; }

/* Revealed-secret box (#9): reserve room so wrapped text never runs behind
   the copy button — the button's own hover-reveal opacity rule is unchanged. */
.secretbox textarea { padding-right: 40px; }

/* Mobile operator shell chrome (#2, mobile bottom nav + top toggles): match
   the fixed bar's actual rendered height (icon+label+safe-area) exactly so
   content never scrolls up underneath it, on any device. */
@media (max-width: 767.98px) {
  body.shell-active .opmain { padding-top: 64px; padding-bottom: calc(70px + env(safe-area-inset-bottom, 0px)); }
  .opbottombar { padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px)); }
}

/* ---- Mailbox (refactor#83): the ONE table merging arrivals/asks/sends.
   Reuses .dtable/.tablewrap/.emptycard/.reveal-row/.st/.pkhint/.row-between/
   .linkrow/.phrase/.chip from the rest of the app — only what's unique to
   this view (the checkbox column — the first checkbox in the app, so its
   base rule lives here — per-type icon, bulk-action bar) gets new rules. ---- */
input[type="checkbox"] { accent-color: var(--accent); width: auto; margin: 0; cursor: pointer; }
.mailbox-th-check, td.mailbox-td-check { width: 34px; text-align: center; vertical-align: middle; }
.mailbox-type { display: inline-flex; align-items: center; justify-content: center; color: var(--ink-2); }
.mailbox-row { cursor: pointer; }
.mailbox-bulkbar { display: flex; align-items: center; gap: 12px; }
.mailbox-detail { padding-top: 4px; padding-bottom: 16px; }
.mailbox-detail .linkrow { display: flex; gap: 8px; margin: 0 0 10px; }
.mailbox-detail .linkrow input[readonly] { flex: 1; min-width: 0; margin-top: 0; }
.mailbox-detail .linkrow button, .mailbox-detail .linkrow a.copybtn { width: auto; flex: none; margin-top: 0; }
.mailbox-th-refresh { text-align: right; }
