/* The web app's look: mason ui's design system, copied (never imported) from embeddable-hq/mason-data at commit
   9e20f15662c34406d281f5eb1350f6dbacf134a9: src/web/app.css (its @font-face rules, its tokens for light and dark, and the
   few components these pages use: the state's marker, buttons, form controls, a table, a Failure, an empty state, the
   page title's course of bricks, a box titled on its edge, fitted to a page without script), and its fonts from src/web/vendor/, each with its licence
   beside it: Geist and Geist Mono (geist 1.7.2) and Zilla Slab 700 (@fontsource/zilla-slab 5.3.0), SIL OFL 1.1. Served
   by this app itself (src/pages.ts, under style-src 'self' and font-src 'self'): nothing is fetched from elsewhere.
   Rules below "This service's own" are not in mason-data. */

@font-face { font-family: "Geist"; src: url("vendor/geist-1.7.2/Geist-Variable.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: "Zilla Slab"; src: url("vendor/zilla-slab-5.3.0/zilla-slab-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist Mono"; src: url("vendor/geist-1.7.2/GeistMono-Variable.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }

/* ---------------------------------------------------------------- tokens */
:root {
  --bg: #f6f5f2; --surface: #fdfcfb; --sunken: #f2f0ec;
  --line: #e8e5df; --line-strong: #cfcac1; --frame: #dcd8d0;
  --fg: #2d2a27; --muted: #615c56; --subtle: #69645d;
  --accent: #2b6f70; --accent-soft: #e2eeed;
  --ok: #2e7340; --warn: #865600; --bad: #a6344f; --unknown: #69645d;
  --warn-soft: #f7eedb; --bad-soft: #f9e5e8;
  --cta: #2b6f70; --cta-hover: #235d5e; --cta-fg: #ffffff; --cta-line: #255f60;
  --btn: #fdfcfb; --btn-hover: #f2f0ec;
  --bevel: 0 1px 1px rgb(45 42 39 / 0.06);
  --bevel-pressed: inset 0 1px 1px rgb(45 42 39 / 0.08);
  --stone-1: #e6e2db;
  --drop: 1px 1px 0 var(--stone-1), 0 2px 6px -2px rgb(45 42 39 / 0.06);
  --zebra: #f9f8f6;
  --code-bg: #f4f2ee; --code-fg: #36322e;
  --hl-comment: #6e6962; --hl-keyword: #2b6f70; --hl-ident: #7b3f8c; --hl-string: #2e6b3a; --hl-placeholder: #8a5a00; --hl-command: #2f5c9a;
  --brick: #199eaa; --bar-track: #e8e5df;

  --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font-display: "Zilla Slab", "Rockwell", "Roboto Slab", Georgia, serif;
  --text-xs: 12px; --text-sm: 13px; --text-md: 14px; --text-lg: 16px; --text-xl: 26px; --text-2xl: 34px;
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px; --space-6: 32px; --space-7: 48px;
  --radius-sm: 2px; --radius: 0;
  --gutter: 24px;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #16181c; --surface: #1c1f24; --sunken: #191c20;
    --line: #2a2e35; --line-strong: #3f444d; --frame: #30353d;
    --fg: #e7e5e1; --muted: #aaa69f; --subtle: #97938c;
    --accent: #6cbcb8; --accent-soft: #1b3434;
    --ok: #72c48f; --warn: #e2b45e; --bad: #ed8da4; --unknown: #97938c;
    --warn-soft: #2c2517; --bad-soft: #351f26;
    --cta: #5aaba7; --cta-hover: #6cbcb8; --cta-fg: #0d1919; --cta-line: #5aaba7;
    --btn: #22262c; --btn-hover: #2a2f36;
    --bevel: 0 1px 1px rgb(0 0 0 / 0.25);
    --bevel-pressed: inset 0 1px 1px rgb(0 0 0 / 0.3);
    --stone-1: #111316;
    --drop: 1px 1px 0 var(--stone-1), 0 2px 8px -2px rgb(0 0 0 / 0.3);
    --zebra: #1f2227;
    --code-bg: #121417; --code-fg: #dcdad5;
    --hl-comment: #8f8b84; --hl-keyword: #6cbcb8; --hl-ident: #c79fe0; --hl-string: #8fcf9a; --hl-placeholder: #e2b45e; --hl-command: #8fb4ef;
    --brick: #1ea2a8; --bar-track: #2c3038;
    color-scheme: dark;
  }
}

/* ---------------------------------------------------------------- base */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--bg); color: var(--fg); font: var(--text-sm)/1.55 var(--font-mono); -webkit-font-smoothing: antialiased; }
a { color: var(--fg); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { text-decoration-color: var(--accent); text-decoration-thickness: 2px; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 0; }
h1, h2 { font-family: var(--font-display); font-weight: 700; letter-spacing: 0; }
code, pre { font-family: var(--font-mono); font-size: 0.95em; }
code { overflow-wrap: anywhere; }
pre { white-space: pre-wrap; margin: var(--space-2) 0 0; color: var(--muted); }

/* a state's marker, a small stone block: its colour says the state, always beside the state's words; under way, it breathes */
@keyframes pulse { 50% { opacity: 0.35; } }

/* ---------------------------------------------------------------- badges and buttons */
.badge { display: inline-flex; align-items: center; height: 20px; padding: 0 6px; border-radius: 0; font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 600;
  background: var(--sunken); color: var(--muted); border: 1px solid var(--line-strong); white-space: nowrap; }
button { font: inherit; font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 500; height: 32px; padding: 0 var(--space-3); border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong); background: var(--btn); color: var(--fg); box-shadow: var(--bevel); cursor: pointer; white-space: nowrap; }
button:hover { background: var(--btn-hover); }
button:active:not(:disabled) { transform: translate(1px, 1px); box-shadow: var(--bevel-pressed); }
button.primary { background: var(--cta); color: var(--cta-fg); border-color: var(--cta-line); }
button.primary:hover { background: var(--cta-hover); }
button.danger { color: var(--bad); }
button.danger:hover { background: var(--bad-soft); border-color: var(--bad); }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
a.btn { display: inline-flex; align-items: center; height: 32px; padding: 0 var(--space-3); border-radius: var(--radius-sm); font-weight: 500;
  border: 1px solid var(--line-strong); background: var(--btn); color: var(--fg); box-shadow: var(--bevel); white-space: nowrap; text-decoration: none; }
a.btn:hover { background: var(--btn-hover); text-decoration: none; }
a.btn.primary { background: var(--cta); color: var(--cta-fg); border-color: var(--cta-line); }
a.btn.primary:hover { background: var(--cta-hover); }

/* ---------------------------------------------------------------- form controls */
form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: var(--space-3) 0; }
label { font-size: var(--text-sm); color: var(--muted); }
input, select { font: inherit; font-family: var(--font-mono); font-size: var(--text-sm); height: 32px; padding: 0 var(--space-3); border-radius: 0;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--fg); min-width: 14em; }
select { min-width: 0; }
input:hover, select:hover { border-color: var(--subtle); }
/* a field beside its button on one row (the allowlist, delete, mason login's code, the organisation's name): its label
   and field take the row but 10rem, the button's and its busy text's (two fields: half the row but 3rem each). A set
   width, not a growing one: a field that grew would shrink when the busy text shows at mousedown, moving the button from
   under the pointer; this way the busy text fits beside the button or wraps alone. Words too long for the row (a
   63-character replica name to type) wrap, and the field goes under them. A phone puts each label over its field
   instead (below). The gap is about a space, between a label's words and its code */
@media (min-width: 641px) {
  form:not(.stack, .inline, .formcard) > label:has(> input:not([type="radio"], [type="checkbox"])) { display: flex; align-items: center; gap: var(--space-2); flex: 0 1 calc(100% - 10rem); flex-wrap: wrap; }
  form:not(.stack, .inline, .formcard):has(> label ~ label > input) > label:has(> input:not([type="radio"], [type="checkbox"])) { flex-basis: calc(50% - 3rem); }
  form:not(.stack, .inline, .formcard) > label > input:not([type="radio"], [type="checkbox"]) { flex: 1 1 8em; min-width: 8em; }
}
input:focus-visible, select:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
input::placeholder { color: var(--subtle); }

/* ---------------------------------------------------------------- tables: dense, hairline */
table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--text-sm); background: var(--surface);
  border: 1px solid var(--frame); box-shadow: var(--drop); margin: var(--space-3) 0 var(--space-4); }
th, td { text-align: left; vertical-align: top; padding: var(--space-2) var(--space-3); border-top: 1px solid var(--line); font-weight: 400; }
tr:first-child > * { border-top: 0; }
tr:nth-child(even) > * { background: var(--zebra); }

/* ---------------------------------------------------------------- what went wrong, what went right */
.failure { border: 1px solid var(--frame); border-left: 4px solid var(--bad); border-radius: var(--radius); box-shadow: var(--drop); padding: var(--space-3) var(--space-4);
  margin: var(--space-3) 0 var(--space-4); background: var(--surface); }
.done { border: 1px solid var(--frame); border-left: 4px solid var(--ok); border-radius: var(--radius); box-shadow: var(--drop); padding: var(--space-3) var(--space-4);
  margin: var(--space-3) 0 var(--space-4); background: var(--surface); }
.err { color: var(--bad); overflow-wrap: anywhere; }

/* ---------------------------------------------------------------- empty */
.empty { text-align: center; padding: var(--space-6) var(--space-4); color: var(--muted); background: var(--surface);
  border: 1px dashed var(--frame); margin: var(--space-3) 0 var(--space-5); font-family: var(--font-sans); font-size: var(--text-md); }
/* a footing with nothing built on it yet: three stones laid, the courses above them only marked */
.empty::before { content: ""; display: block; width: 18px; height: 7px; margin: 18px auto var(--space-4); transform: translateX(-20px); background: var(--line-strong);
  box-shadow: 20px 0 0 var(--line-strong), 40px 0 0 var(--line-strong), 10px -9px 0 var(--line), 30px -9px 0 var(--line), 20px -18px 0 var(--line); }

/* ---------------------------------------------------------------- a small button */
button.small, a.btn.small { height: 28px; padding: 0 var(--space-2); font-size: var(--text-xs); }

/* ---------------------------------------------------------------- This service's own: the page, its sections, its states */
.top { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--gutter); background: var(--sunken); border-bottom: 1px solid var(--frame); }
.brand { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--fg); text-decoration: none; }
.brand:hover { text-decoration: none; }
.notice { border: 1px solid var(--frame); border-left: 4px solid var(--warn); border-radius: var(--radius); background: var(--warn-soft); padding: var(--space-3) var(--space-4); margin: 0 0 var(--space-4); }
.notice p { margin: 0; overflow-wrap: anywhere; }
.brand-name { font-family: var(--font-display); font-weight: 700; font-size: 22px; line-height: 1; }
.logo { display: inline-flex; width: 24px; height: 24px; background: var(--cta); color: var(--cta-fg); border: 1px solid var(--cta-line); box-shadow: 1px 1px 0 var(--stone-1); flex: none; }
.logo svg { width: 100%; height: 100%; display: block; }
.top .brand, .account form { flex: none; }
/* who is signed in, then Sign out, at the bar's right: a long label is cut short, so the bar never wraps or scrolls */
.account { display: flex; align-items: center; gap: var(--space-3); margin-left: auto; min-width: 0; }
.who { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
.account button { white-space: nowrap; }
main { max-width: 52rem; margin: 0 auto; padding: var(--space-6) var(--gutter) var(--space-7); }
/* a page's title stands on a course of bricks being laid */
main > h1 { font-size: var(--text-2xl); line-height: 1.15; margin: 0 0 var(--space-5); overflow-wrap: anywhere; }
main > h1::after { content: ""; display: block; width: 14px; height: 5px; margin: var(--space-3) 0 2px; background: var(--brick);
  box-shadow: 16px 0 0 var(--brick), 32px 0 0 var(--line-strong), 8px -7px 0 var(--brick), 24px -7px 0 var(--line); }
/* prose reads in the sans; the chrome, labels, codes and tables stay mono */
main p, main li { font-family: var(--font-sans); font-size: var(--text-md); max-width: 78ch; }
main p code, main li code { font-size: var(--text-sm); }
/* a box titled on its top edge, as mason ui's Connect box is */
.box { background: var(--surface); border: 1px solid var(--frame); box-shadow: var(--drop); padding: var(--space-4) var(--space-5); margin: var(--space-6) 0; }
.box > h2 { width: fit-content; max-width: 100%; margin: calc(-1 * var(--space-4) - 0.8em) 0 var(--space-2) calc(-1 * var(--space-2)); padding: 0 var(--space-2);
  background: var(--surface); font-size: 20px; line-height: 1.6; }
.box.danger { border-color: var(--bad); }
/* the page's main action */
.box.primary { border-color: var(--accent); }
.box table { box-shadow: none; }
h2 { font-size: 20px; margin: var(--space-6) 0 var(--space-2); }
/* a section of the creation page */
.step > h2 { font-size: var(--text-lg); }
/* the creation page: the addresses and the db user (.before) above the form, or on a wide screen to its right, wide
   enough for the db user's SQL unwrapped; that SQL scrolls in its box, never the page. Only this page is wider
   (main:has). */
main:has(> .create) { max-width: 80rem; }
.create { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: var(--space-7); align-items: start; }
.create fieldset, .create .sync-panel { min-width: 0; }
.create .before pre { white-space: pre; overflow-x: auto; }
/* what to do on the database first, in a quieter panel than the form, so the form reads as the call to action. No top
   padding: its first heading's own margin spaces it, so that heading lines up with the form's. */
.create > .before { background: var(--sunken); border: 1px solid var(--line); padding: 0 var(--space-5) var(--space-4); }
@media (max-width: 640px) { .create > .before { padding: 0 var(--space-3) var(--space-3); } }
@media (min-width: 70rem) {
  /* 37rem inside the panel, for the widest SQL, plus its padding and border */
  .create { grid-template-columns: minmax(0, 1fr) calc(37rem + 2 * var(--space-5) + 2px); }
  .create > .before { grid-column: 2; grid-row: 1; }
  .create > #connect { grid-column: 1; grid-row: 1; }
}
pre.copy { border-color: var(--line-strong); }
/* with script, a block's Copy button (app.js) sits in its top-right corner, above its first line, so it covers no text */
.copyable { position: relative; margin-top: var(--space-2); }
.copyable > pre { margin-top: 0; padding-top: calc(24px + 2 * var(--space-1)); }
.copyable > button { position: absolute; top: var(--space-1); right: var(--space-1); height: 24px; min-height: 0; padding: 0 var(--space-2);
  font-size: var(--text-xs); white-space: nowrap; user-select: none; }
/* it sends no form, so a click on it never looks busy */
.copyable > button:focus:not(:focus-visible) { opacity: 1; }
.copyable > button:focus:not(:focus-visible)::after { content: none; }
/* the db user's choice of SQL: the checked radio shows its panel, without script (create.ts readerStep) */
fieldset.sync { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin: var(--space-3) 0; }
fieldset.sync > legend { flex-basis: 100%; font-size: var(--text-md); color: var(--fg); font-weight: 700; }
fieldset.sync > label { margin-right: var(--space-3); }
fieldset.sync > .hint, fieldset.sync > .sync-panel { flex-basis: 100%; }
fieldset.sync > .hint { margin: 0; color: var(--muted); font-size: var(--text-sm); }
.sync-panel { display: none; }
#sync-off:checked ~ .sync-off, #sync-poll:checked ~ .sync-poll, #sync-replication:checked ~ .sync-replication { display: block; }
.sync-panel > p { margin: var(--space-2) 0; }
/* at phone width each choice on a line of its own, its radio beside it */
@media (max-width: 640px) { fieldset.sync > label { flex: 1 1 calc(100% - 2.5rem); margin-right: 0; } }
details.notes { font-size: var(--text-sm); }
details.notes > summary { cursor: pointer; }
details.notes p, details.notes li { font-size: var(--text-sm); }
/* a long name in a command (a 63-character replica's, on a phone) breaks where it must, never pushing the page sideways */
main pre { background: var(--code-bg); color: var(--code-fg); border: 1px solid var(--line); padding: var(--space-2) var(--space-3); overflow-wrap: anywhere; }
/* a block's highlighting (src/highlight.ts): its comments recede and its statements stand out; each colour is at least
   4.5:1 on --code-bg in both themes (tests/highlight.test.ts) */
.hl-comment { color: var(--hl-comment); }
.hl-keyword { color: var(--hl-keyword); font-weight: 600; }
.hl-ident { color: var(--hl-ident); }
.hl-string { color: var(--hl-string); }
.hl-placeholder { color: var(--hl-placeholder); }
.hl-command { color: var(--hl-command); font-weight: 600; }
form.inline { display: inline-flex; margin: 0; }
/* a field a line, each as wide as the form: capped at 48rem, where a tablet's one column would make a port field a
   thousand pixels wide (on a wide screen the create page's column is narrower than that already) */
form.stack { flex-direction: column; align-items: stretch; max-width: 48rem; }
form.stack label { display: flex; flex-direction: column; gap: var(--space-1); }
form.stack button { align-self: flex-start; }
/* a choice of one: each radio beside its words */
fieldset { border: 0; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); }
legend { font-size: var(--text-sm); color: var(--muted); padding: 0; margin-bottom: var(--space-1); }
form label.choice { flex-direction: row; align-items: center; gap: var(--space-2); width: auto; color: var(--fg); }
/* a choice shown but not offered here, "contact us" (create.ts soon): muted, still 4.5:1 on --bg and --surface in both themes
   (tests/create.test.ts) */
form label.choice.soon { color: var(--muted); cursor: not-allowed; }
/* the creation form's region and size: a choice a line, so the offered ones read as a list above the contact-us ones */
:is(#create, #credentials) fieldset { flex-direction: column; align-items: flex-start; }
/* the creation form's two parts, the database Mason reads and the replica it makes: each headed by its legend and a
   line, its fields as wide as the form (no side padding or border), and a space between the parts */
:is(#create, #credentials) fieldset.group { align-items: stretch; gap: var(--space-2); }
:is(#create, #credentials) fieldset.group > legend { font-size: var(--text-md); color: var(--fg); font-weight: 700; margin-bottom: 0; }
:is(#create, #credentials) fieldset.group > .hint, :is(#create, #credentials) .bastion-fields > .hint { margin: 0; color: var(--muted); font-size: var(--text-sm); }
:is(#create, #credentials) fieldset.group + fieldset.group { margin-top: var(--space-5); }
:is(#create, #credentials) fieldset.group:last-of-type { margin-bottom: var(--space-2); }
/* The bastion's fields show only while its box is ticked, without script; hidden, they keep their values and take no focus. */
:is(#create, #credentials) .bastion-fields { display: flex; flex-direction: column; gap: var(--space-2); }
:is(#create, #credentials) fieldset.group:has(input[name=via]:not(:checked)) > .bastion-fields { display: none; }
input[type="radio"] { min-width: 0; width: auto; height: auto; margin: 0; accent-color: var(--accent); }
.code-big { font-size: 2rem; letter-spacing: 0.1em; font-family: var(--font-mono); }
.code-big code { font-size: 1em; }
.caution { border-left: 4px solid var(--warn); background: var(--warn-soft); padding: var(--space-2) var(--space-3); }
/* the way back up to the list, above a page's title: quiet, a link and not a button */
.crumbs { margin: 0 0 var(--space-3); font-size: var(--text-xs); color: var(--muted); }
.crumbs a { color: var(--muted); }
/* a Failure: what happened, then what to do next */
.failure p, .done p { margin: 0 0 var(--space-2); }
.failure > :last-child, .done > :last-child { margin-bottom: 0; }

/* a state line: its marker beside its words, never colour alone */
.state { display: flex; gap: var(--space-2); align-items: baseline; }
.state::before { content: ""; width: 10px; height: 6px; flex: none; background: var(--unknown); transform: translateY(-2px); }
.state.ok::before { background: var(--ok); } .state.warn::before { background: var(--warn); animation: pulse 1.6s ease-in-out infinite; }
.state.bad::before { background: var(--bad); }
.state > p { margin: 0; }
.status { background: var(--surface); border: 1px solid var(--frame); box-shadow: var(--drop); padding: var(--space-3) var(--space-4); margin: 0 0 var(--space-5); }
.status .state > p { font-size: var(--text-lg); font-family: var(--font-mono); }
.status > p { margin: var(--space-2) 0 0; color: var(--muted); font-size: var(--text-sm); }
@media (prefers-reduced-motion: reduce) { .state.warn::before, ul.replicas li.warn::before, .waiting .track { animation: none; } }

/* a creation's steps: a mark beside each, its state in words too; the current one bold, later ones greyed */
ol.steps { list-style: none; padding: 0; margin: var(--space-3) 0 0; font-size: var(--text-sm); }
ol.steps > li { padding-left: 20px; text-indent: -20px; margin: 2px 0; max-width: none; }
ol.steps > li::before { display: inline-block; width: 20px; text-indent: 0; content: "·" / ""; color: var(--subtle); }
ol.steps > li.ticked::before { content: "✓" / ""; color: var(--ok); }
ol.steps > li.now { font-weight: 600; } ol.steps > li.now::before { content: "▸" / ""; color: var(--warn); }
ol.steps > li.stopped { font-weight: 600; } ol.steps > li.stopped::before { content: "✗" / ""; color: var(--bad); }
ol.steps > li.later { color: var(--subtle); }

/* the home page's replicas: one row each, its state's marker first */
ul.replicas { list-style: none; padding: 0; margin: var(--space-3) 0 var(--space-5); background: var(--surface); border: 1px solid var(--frame); box-shadow: var(--drop); }
ul.replicas li { display: block; max-width: none; padding: var(--space-3) var(--space-4); border-top: 1px solid var(--line); }
ul.replicas li:first-child { border-top: 0; }
ul.replicas li::before { content: ""; display: inline-block; width: 10px; height: 6px; margin-right: var(--space-2); vertical-align: middle; background: var(--unknown); }
ul.replicas li.ok::before { background: var(--ok); } ul.replicas li.bad::before { background: var(--bad); }
ul.replicas li.warn::before { background: var(--warn); animation: pulse 1.6s ease-in-out infinite; }
ul.replicas strong { font-family: var(--font-mono); }
/* an older Mason's Upgrade (replicas.ts replicaList), after its state */
ul.replicas a.btn { margin-left: var(--space-2); vertical-align: middle; }
/* a ready replica's name opens Mason UI by a form (replicas.ts openMason): a button, looking like the link it stands for */
button.link { height: auto; padding: 0; border: 0; background: none; box-shadow: none; font: inherit; color: var(--fg); text-decoration: underline;
  text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
button.link:hover { background: none; text-decoration-color: var(--accent); text-decoration-thickness: 2px; }
/* its "…" once pressed sits just past the name, never over it, and never changes its size */
button.link::after { right: auto !important; left: 100%; }
/* the load balancer's note, under where it stands, muted */
.addresses .dim { color: var(--muted); }

/* Mason's checks of the database, a line each, the word beside its marker */
ul.checks { list-style: none; padding: 0; }
ul.checks > li { padding-left: 18px; text-indent: -18px; margin: var(--space-1) 0; }
ul.checks > li::before { content: ""; display: inline-block; width: 10px; height: 6px; margin-right: 8px; vertical-align: middle; background: var(--unknown); }
ul.checks > li.ok::before { background: var(--ok); } ul.checks > li.warn::before { background: var(--warn); } ul.checks > li.bad::before { background: var(--bad); }
ul.checks ul { list-style: disc; margin: 0; padding-left: 1.25em; text-indent: 0; color: var(--muted); }
/* a check's way out, folded until asked for */
details { margin: var(--space-2) 0; }
details > summary { cursor: pointer; font-weight: 600; text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
details > p { margin: var(--space-2) 0 0; }

/* waiting on the replica's machine: a quiet shimmer of an empty track, gone once the answer is on the page */
.waiting { margin: var(--space-4) 0; }
.waiting .track { display: block; width: 100%; max-width: 30rem; height: 6px; border-radius: 3px; background: var(--bar-track); margin-top: var(--space-2); animation: bar-wait 1.6s ease-in-out infinite; }
@keyframes bar-wait { 50% { opacity: 0.45; } }
main:has(.outcome) .waiting { display: none; }

/* a form's button once clicked says it is working; a button reached by keyboard is :focus-visible, not this. It still
   takes clicks: focus comes at mousedown, so taking pointer events away there would swallow the click itself. A second
   submit is answered by the server with the first one's answer (src/pages.ts replyOnce). */
button:focus:not(:focus-visible) { opacity: 0.7; }
/* the ellipsis sits in the button's right padding, so the button keeps its size: one that grew at mousedown could wrap
   to the next line, away from the pointer, before mouseup */
button { position: relative; }
button:focus:not(:focus-visible)::after { content: "…"; position: absolute; right: 2px; }
.busy { display: none; color: var(--muted); font-size: var(--text-sm); }
button:focus:not(:focus-visible) ~ .busy { display: inline; }
/* the same look once the form is sent, until its answer is shown (src/web/app.js data-busy): focus is lost with the
   window, this is not. The form's other buttons (Change the details, Cancel) are put away meanwhile */
button[data-busy] { opacity: 0.7; }
button[data-busy]::after { content: "…"; position: absolute; right: 2px; }
button[data-busy] ~ .busy { display: inline; }
form[data-busy] button:not([data-busy]), form[data-busy] a.btn { visibility: hidden; }
/* in a row of fields the busy text is a flex item of its own, so when it shows at mousedown it wraps alone: were the
   button and it one item, the pair would wrap together and move the button from under the pointer before mouseup */
form:not(.stack) > span:has(> .busy) { display: contents; }
/* a form the browser holds back (a required field empty) sent nothing, so its button never says it is working */
form:invalid .busy { display: none !important; }
form:invalid button:focus:not(:focus-visible) { opacity: 1; }
form:invalid button:focus:not(:focus-visible)::after { content: none; }
/* Turbo's bar while a page loads: its own <style> is refused by the CSP (style-src 'self'), so it is drawn here */
.turbo-progress-bar { position: fixed; top: 0; left: 0; height: 3px; background: var(--accent); z-index: 2147483647;
  transition: width 300ms ease-out, opacity 150ms 150ms ease-in; transform: translate3d(0, 0, 0); }

/* ---------------------------------------------------------------- a phone */
@media (max-width: 640px) {
  :root { --gutter: 16px; }
  main { padding-top: var(--space-5); }
  main > h1 { font-size: var(--text-xl); }
  /* room for who is signed in */
  .top { gap: var(--space-2); }
  .top .badge { display: none; }
  .box { padding: var(--space-4) var(--space-3); }
  input { min-width: 0; }
  /* a field's label over its control, the control its width, never its height */
  form label { display: flex; flex-direction: column; gap: var(--space-1); width: 100%; }
  form label input { flex: none; width: 100%; }
  /* a label with code in it (delete's "Type <name> to confirm", mason login's code) reads as one line, not a line a part */
  form label:has(> code) { display: block; }
  form label:has(> code) > input { display: block; margin-top: var(--space-1); }
  form.inline label { width: auto; }
  table { display: block; overflow-x: auto; }
  /* a long label wraps on a phone, never past the page */
  button { white-space: normal; height: auto; min-height: 32px; padding-top: 6px; padding-bottom: 6px; text-align: left; }
}
/* a checkbox in the design's own look, as a radio takes the accent: a square stone, filled with the accent and ticked
   once checked. The input itself stays, so the keyboard, its label and a screen reader work as they always do */
input[type="checkbox"] { appearance: none; flex: none; display: inline-grid; place-content: center; width: 16px; height: 16px; min-width: 0; margin: 0;
  padding: 0; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); box-shadow: var(--bevel); cursor: pointer; }
input[type="checkbox"]::before { content: ""; width: 9px; height: 5px; border: solid var(--cta-fg); border-width: 0 0 2px 2px;
  transform: translateY(-1px) rotate(-45deg); visibility: hidden; }
input[type="checkbox"]:hover:not(:disabled) { border-color: var(--accent); }
input[type="checkbox"]:checked { background: var(--accent); border-color: var(--cta-line); }
input[type="checkbox"]:checked::before { visibility: visible; }
input[type="checkbox"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: none; }
input[type="checkbox"]:disabled { background: var(--sunken); border-color: var(--line); box-shadow: none; cursor: not-allowed; }

/* the picker shown while a replica is made (picks.ts): its progress at the top, then the tables to tick */
.creation [hidden], .picks [hidden] { display: none !important; }
.creation > p[data-step] { color: var(--fg); font-size: var(--text-md); font-family: var(--font-sans); }
/* the bar is the bricks of the page's title being laid */
.creation progress { display: block; width: 100%; max-width: 30rem; height: 8px; margin: var(--space-2) 0 0; appearance: none; border: 0; border-radius: 0;
  background: var(--bar-track); color: var(--brick); }
.creation progress::-webkit-progress-bar { background: var(--bar-track); }
.creation progress::-webkit-progress-value { background: var(--brick); transition: width 0.6s ease; }
.creation progress::-moz-progress-bar { background: var(--brick); }
@media (prefers-reduced-motion: reduce) { .creation progress::-webkit-progress-value { transition: none; } }
/* a failed creation has no tables to choose */
.creation[data-state="failed"] ~ .box.primary { display: none; }
/* the search and the count above the list, on one line where they fit */
form.picks .find { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
form.picks .find input { flex: 1 1 14rem; min-width: 0; max-width: 24rem; }
.picks .count { color: var(--muted); }
/* a table a row, the whole row its box's label; a long list scrolls in its frame, so the button stays near */
ul.tables { list-style: none; padding: 0; margin: 0; background: var(--surface); border: 1px solid var(--frame); max-height: min(60vh, 32rem); overflow-y: auto; }
ul.tables > li { margin: 0; max-width: none; border-top: 1px solid var(--line); }
ul.tables > li:first-child { border-top: 0; }
ul.tables label.choice { display: flex; flex-direction: row; align-items: flex-start; gap: var(--space-3); padding: var(--space-2) var(--space-3); cursor: pointer; color: var(--fg); }
ul.tables label.choice:hover { background: var(--sunken); }
ul.tables li:has(input:checked) label.choice { background: var(--accent-soft); }
ul.tables label.choice:has(input:disabled) { color: var(--muted); cursor: not-allowed; background: none; }
ul.tables input[type="checkbox"] { margin-top: 2px; }
ul.tables .what { min-width: 0; }
/* the letters the search matched: the accent's tint, underlined in the accent so it still shows on a ticked row's tint */
ul.tables mark { background: var(--accent-soft); color: inherit; box-shadow: inset 0 -2px 0 var(--accent); }
ul.tables li:has(input:checked) mark { background: var(--surface); }
ul.tables .note { display: block; margin-top: 2px; color: var(--muted); font-family: var(--font-sans); font-size: var(--text-sm); }
form.picks .send { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
/* once pressed, a calm line in the place of the button (and Skip, so a second press lands on neither): nothing is sent yet */
form.picks[data-waiting]:not([data-busy]) .send { display: none; }
p.calm { margin: 0; border-left: 4px solid var(--accent); background: var(--accent-soft); padding: var(--space-2) var(--space-3); }
/* the send's answer: "Syncing N tables" and the way to Mason UI on one line */
.synced .head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-4); }
.synced .head p { margin: 0; font-size: var(--text-lg); }
.synced ul { margin: var(--space-2) 0 0; padding-left: 1.25em; }
