:root {
  color-scheme: light dark;
  --bg: #ffffff;
  --surface: #f4f4f5;
  --ink: #18181b;
  --muted: #52525b;
  --line: #c9c9ce;
  --line-strong: #6b7280;
  --accent: #1d4ed8;
  --accent-ink: #ffffff;
  --danger: #a01b1b;
  --ok: #17632f;
  --warn-bg: #fdf3d0;
  --warn-ink: #5c4600;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d0d10;
    --surface: #17171c;
    --ink: #ededf0;
    --muted: #a1a1aa;
    --line: #3a3a42;
    --line-strong: #8b8b96;
    --accent: #7aa2f7;
    --accent-ink: #0d0d10;
    --danger: #f08a8a;
    --ok: #6ec98a;
    --warn-bg: #3a2f08;
    --warn-ink: #f3dc95;
  }
}

* { box-sizing: border-box; border-radius: 0; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
}

a { color: var(--accent); }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

header.bar {
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.bar-inner, main, footer.foot {
  max-width: 62rem;
  margin: 0 auto;
  padding: 1rem;
}

.bar-inner { display: flex; flex-wrap: wrap; gap: 0.75rem 1.25rem; align-items: baseline; }
.brand { font-weight: 600; letter-spacing: 0.01em; }
nav.nav { display: flex; flex-wrap: wrap; gap: 1rem; }
nav.nav a { text-decoration: none; }
nav.nav a[aria-current="page"] { text-decoration: underline; text-underline-offset: 0.25em; font-weight: 600; }
.bar-end { margin-left: auto; display: flex; gap: 1rem; align-items: baseline; }

h1 { font-size: 1.5rem; margin: 0 0 1rem; font-weight: 600; }
h2 { font-size: 1.125rem; margin: 2rem 0 0.75rem; font-weight: 600; }
p { margin: 0 0 1rem; }
.muted { color: var(--muted); }
.mono { font-family: var(--mono); }

.panel {
  border: 1px solid var(--line);
  background: var(--surface);
  padding: 1rem;
  margin: 0 0 1.5rem;
}

.banner {
  border: 1px solid var(--danger);
  color: var(--danger);
  background: var(--bg);
  padding: 0.75rem 1rem;
  margin: 0 0 1.5rem;
}

.notice { border: 1px solid var(--line); background: var(--warn-bg); color: var(--warn-ink); padding: 0.75rem 1rem; margin: 0 0 1.5rem; }
.bad { color: var(--danger); }
.good { color: var(--ok); }

/* Any stack of fields, not only one inside a form. The password and salt on
   the download page sit outside the form on purpose, so that they cannot be
   posted, and without this they were the only fields on the panel stretched
   to the full width of their box. */
.stack { display: flex; flex-direction: column; gap: 1rem; max-width: 26rem; }
label { display: block; font-weight: 600; margin: 0 0 0.25rem; }
.hint { display: block; font-weight: 400; color: var(--muted); font-size: 0.875rem; }

input[type="text"], input[type="email"], input[type="password"], input[type="date"], input[type="number"] {
  width: 100%;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink);
  font: inherit;
}

input.code { font-family: var(--mono); letter-spacing: 0.25em; }

button {
  padding: 0.5rem 1rem;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

button.secondary { background: transparent; color: var(--ink); border-color: var(--line-strong); }
button.danger { background: transparent; color: var(--danger); border-color: var(--danger); }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 0.5rem; border-bottom: 1px solid var(--line); vertical-align: top; }
th { font-weight: 600; }

ol.codes { font-family: var(--mono); columns: 2; margin: 0; padding-left: 1.5rem; }
ol.codes li { break-inside: avoid; padding: 0.125rem 0; }

.qr { border: 1px solid var(--line); padding: 0.75rem; display: inline-block; background: var(--bg); color: var(--ink); }
.qr svg { display: block; width: 13rem; height: 13rem; }

footer.foot { border-top: 1px solid var(--line); color: var(--muted); font-size: 0.875rem; }

@media (max-width: 40rem) {
  .bar-inner { flex-direction: column; align-items: stretch; }
  .bar-end { margin-left: 0; }
  ol.codes { columns: 1; }
  /* A table scrolls sideways inside its own box rather than stacking. Stacking
     it put every heading in one block and every value in another, so a reader
     had to count rows to learn which value belonged to which heading: the file
     versions page showed six headings and then six unlabelled values. Making
     the table a scrolling block keeps each value under its own heading, and
     keeps the page itself the width of the phone. */
  table { display: block; overflow-x: auto; max-width: 100%; }
}

/* The frame the templates page renders a message in. Without a background of
   its own the frame is transparent, so an empty or slow frame showed the dark
   page through it and read as a black box. A message is a document of its own
   and keeps whatever look it has; the surface behind it is white, which is
   what an inbox is. */
iframe.preview {
  display: block;
  width: 100%;
  background: #ffffff;
  border: 1px solid var(--line);
}

/* The first thing in the document, so a keyboard reaches the page content
   without walking the whole navigation on every page. It is off screen until
   it is focused, and then it sits over the bar. */
a.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  padding: 0.5rem 1rem;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--accent);
}
a.skip:focus { left: 0; }

/* Text that only a screen reader reads. Not display none, which would take it
   out of the accessibility tree along with the rest. */
.offscreen {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* A numeric column lines up on its digits. The tabular figures keep the digits
   one width, so two rows of the same magnitude are the same length. */
.num { text-align: right; font-variant-numeric: tabular-nums; }
td.num, th.num { text-align: right; }

/* A long value, shortened, with the button that copies the whole of it. */
.hashcell { display: inline-flex; gap: 0.5rem; align-items: baseline; }
.hashcell code { font-family: var(--mono); font-size: 0.8125rem; }
button.copy {
  padding: 0.125rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line-strong);
}
button.copy:hover { border-color: var(--accent); }

/* A moment and its hint each stay on one line. Without this a narrow column
   broke "21 Sep 2026, 05:14" across five lines and made a table of twenty
   entries four times taller than it needed to be. */
time { white-space: nowrap; }

/* The hint under a moment. Never the only thing said about it. */
.ago { display: block; color: var(--muted); font-size: 0.8125rem; white-space: nowrap; }

/* What is wrong with a form, said twice: once at the top of the page and once
   beside the field itself. */
.errors { border: 1px solid var(--danger); color: var(--danger); background: var(--bg); padding: 0.75rem 1rem; margin: 0 0 1.5rem; }
.errors h2 { margin: 0 0 0.5rem; font-size: 1rem; }
.errors ul { margin: 0; padding-left: 1.25rem; }
.errors a { color: var(--danger); }
.field-error { display: block; color: var(--danger); font-weight: 600; font-size: 0.875rem; margin: 0.25rem 0 0; }
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--danger); }

/* Nothing in the panel moves, fades, glows or casts a shadow. */
* { transition: none !important; animation: none !important; box-shadow: none !important; text-shadow: none !important; }

/* ---- status: a word, with colour as the second channel ---- */
.st { font-weight: 600; }
.st-ok { color: var(--ok); }
.st-warn { color: var(--warn-ink); }
.st-bad { color: var(--danger); }
.st-muted { color: var(--muted); font-weight: 400; }
.st-info { color: var(--ink); }

@media (prefers-color-scheme: dark) {
  .st-warn { color: #e6b800; }
}

/* ---- wide tables scroll inside their own box, never the page ---- */
/* Paint containment is not decoration. Without it the wide table inside the
   scroller still counted towards the document's own scrolling area, so at
   phone width the Backups page could be dragged 331 pixels sideways even
   though the scroller itself was clipping correctly. Found by measuring the
   document in a real browser at 390 pixels. */
.tw { overflow-x: auto; border: 1px solid var(--line); contain: paint; }
.tw table { min-width: 44rem; }
.tw:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
table.facts { min-width: 0; }
table.facts th { width: 14rem; white-space: nowrap; }

/* ---- counts on the Overview ---- */
.tiles { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1.5rem; }
.tile {
  flex: 1 1 9rem;
  border: 1px solid var(--line);
  background: var(--surface);
  padding: 0.75rem;
  color: inherit;
  text-decoration: none;
  display: block;
}
a.tile:hover, a.tile:focus-visible { border-color: var(--accent); }
.tile-n { display: block; font-size: 1.75rem; font-weight: 600; line-height: 1.1; }
.tile-l { display: block; font-size: 0.875rem; color: var(--muted); }

/* ---- what needs attention, at the top of the Overview ---- */
.attention { border: 1px solid var(--danger); background: var(--surface); padding: 1rem; margin: 0 0 1.5rem; }
.attention h2 { margin: 0 0 0.75rem; font-size: 1.125rem; }
.attention ul { margin: 0; padding-left: 1.25rem; }
.attention li { margin: 0 0 0.5rem; }
.attention li:last-child { margin-bottom: 0; }
.attention .st { margin-right: 0.5rem; }
.allclear { border: 1px solid var(--line); background: var(--surface); padding: 1rem; margin: 0 0 1.5rem; }
.allclear p { margin: 0; }

/* ---- filter bar above a list ---- */
.filters { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: flex-end; margin: 0 0 1rem; }
.filter { display: flex; flex-direction: column; gap: 0.25rem; }
.filter label { font-size: 0.875rem; margin: 0; }
.filter input, .filter select { width: 12rem; }
.filter-actions { display: flex; gap: 0.75rem; align-items: baseline; }

select, textarea {
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  width: 100%;
}
textarea { resize: vertical; }
select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- pager ---- */
.pg { display: flex; flex-wrap: wrap; gap: 1rem; align-items: baseline; margin: 1rem 0 0; font-size: 0.875rem; }
.pg-at { color: var(--muted); }
.pg-note { color: var(--muted); flex-basis: 100%; }

/* ---- row actions and decision cards ---- */
.row-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.row-actions form { display: inline; }
.decision { border: 1px solid var(--danger); background: var(--surface); padding: 1rem; margin: 0 0 1.5rem; }
.decision h2 { margin-top: 0; }
.decide { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-start; }
.decide form { flex: 1 1 18rem; border: 1px solid var(--line); padding: 0.75rem; }
.once { border: 1px solid var(--accent); background: var(--surface); padding: 1rem; margin: 0 0 1.5rem; }
.once .key { font-family: var(--mono); font-size: 1.25rem; letter-spacing: 0.08em; word-break: break-all; }
.fp { font-family: var(--mono); font-size: 0.8125rem; word-break: break-all; }
.js-only { color: var(--muted); font-size: 0.875rem; }

/* The plain text part of an email, and anything else preformatted. A mail line
   is longer than a phone is wide, and without this the line widens the whole
   document rather than the block: the templates page measured 939 CSS pixels
   inside a 390 pixel viewport. The block scrolls on its own instead. */
pre {
  margin: 0 0 1rem;
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.45;
  max-width: 100%;
  overflow-x: auto;
  padding: 0.75rem;
  border: 1px solid var(--line);
  background: var(--bg);
}

@media (max-width: 40rem) {
  /* Inside the scroller the table keeps its own minimum width and lays out as
     a table. The rule above makes a bare table scroll on its own; this one
     stops it doing that twice. */
  .tw table { display: table; overflow-x: visible; max-width: none; }
  .filter input, .filter select { width: 100%; }
  .filter { flex: 1 1 100%; }
}
