/* WCE ARC — components.
 *
 * Built on theme.css, which is the forked token layer. Between them these two
 * files are the whole design system: there is no vendored stylesheet any more
 * and nothing to re-pull from anywhere.
 *
 * The grammar, ported from the app family this was forked from:
 *
 *   - A card is a `--surface` panel on the `--bg` ground, hairline `--line`
 *     border, `--r-lg` corners, `--shadow-card`. That IS the container. (The
 *     system this replaced forbade cards and used rules instead; if you find a
 *     comment anywhere still saying "there are no cards", it is stale.)
 *   - A label is mono, uppercase, 11px, tracked wide. It names a block; it is
 *     never a sentence.
 *   - Display type is serif. Everything else is sans. Mono is for labels,
 *     numerals and anything that behaves like data.
 *   - One accent, used for the primary action, the current nav item and text
 *     that is genuinely a link. Not for decoration.
 *   - Hierarchy comes from the ink ramp: --head, --body, --muted, --faint. Each
 *     step is a real colour, not an opacity, so every one is measurable against
 *     its ground.
 *
 * No hex values below, and no font names: everything comes from the tokens.
 */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--body);
  font: 400 var(--t-body)/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
}

h1, h2, h3, h4 { color: var(--head); font-family: var(--serif); font-weight: 600; line-height: 1.2; }
h1 { font-size: var(--t-h1); letter-spacing: -.01em; margin: 0 0 var(--s-4); }
h2 { font-size: var(--t-h2); margin: 0 0 var(--s-4); }
h3 { font-size: var(--t-h3); margin: 0 0 var(--s-3); }
p { margin: 0 0 var(--s-4); }
a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm); }
hr { border: 0; border-top: 1px solid var(--line); margin: var(--s-7) 0; }

.page { max-width: var(--column); margin: 0 auto; padding: var(--s-8) var(--margin) var(--s-10); }
.page-wide { max-width: var(--column-wide); }

/* ── the eyebrow label ────────────────────────────────────────────────────── */
.label {
  display: block; font: 500 var(--t-eyebrow)/1.4 var(--mono);
  letter-spacing: .18em; text-transform: uppercase; color: var(--faint);
}
.meta, .note { font: 400 var(--t-index)/1.6 var(--mono); color: var(--muted); }
.note { margin: var(--s-3) 0 0; }
.lede { font-size: var(--t-lede); line-height: 1.55; color: var(--body); }
.body { font-size: var(--t-body); line-height: 1.6; color: var(--body); max-width: 68ch; }
.h3 { font-family: var(--serif); font-size: var(--t-h3); font-weight: 600; color: var(--head); line-height: 1.25; }
/* Kept because the templates carry it. Secondary text is `.muted` ink already;
   this exists so a stray class name is not a broken selector. */
.text-muted { color: var(--muted); }

/* ── the card ─────────────────────────────────────────────────────────────── */
.block {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-card); padding: var(--s-6); margin-bottom: var(--s-6);
}
.block > .label { margin-bottom: var(--s-4); }
.block > h2, .block > h3 { margin-top: 0; }
.block > p:last-child { margin-bottom: 0; }
.block-flag { border-color: var(--danger); }
.block-flag > p { color: var(--ink); }

/* "Saved." is one word of confirmation. Given a full card it takes 24px of
   padding on four sides and a shadow, and reads as though something needs
   dealing with. A rule down one side says the same thing in one line. */
.flash {
  display: flex; align-items: baseline; gap: var(--s-3);
  font-size: var(--t-body-s); color: var(--body);
  background: var(--sunk); border-left: 3px solid var(--accent);
  border-radius: var(--r-sm); padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-5);
}
.flash-bad { border-left-color: var(--danger); }
.flash p { margin: 0; }

.doc-head { margin-bottom: var(--s-7); }
/* Title on the left, the one action on the right, sitting above the map's own
   tool row. Wraps to two rows on a phone rather than squeezing the heading. */
.doc-head-act { display: flex; align-items: flex-end; justify-content: space-between;
                gap: var(--s-5); flex-wrap: wrap; }
.doc-head-act h1 { margin-bottom: 0; }
.doc-head > .label { margin-bottom: var(--s-3); }
.doc-head h1 { margin-bottom: var(--s-3); }
.doc-meta { display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: baseline; }

/* ── marks ────────────────────────────────────────────────────────────────── */
.tag {
  display: inline-block; padding: 2px var(--s-3); border-radius: 999px;
  background: var(--sunk); border: 1px solid var(--line);
  font: 500 var(--t-eyebrow)/1.7 var(--mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
}
.tag-on { background: var(--accent-tint); border-color: var(--accent-tint-border); color: var(--accent-ink); }

/* ── buttons ──────────────────────────────────────────────────────────────── */
.btn, .btn-2 {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font: 600 var(--t-body-s)/1 var(--sans); border-radius: var(--r);
  padding: 11px var(--s-5); cursor: pointer; border: 1px solid transparent;
  text-decoration: none;
}
.btn { background: var(--accent); color: var(--on-accent); }
.btn:hover { background: var(--accent-ink); text-decoration: none; }
.btn-2 { background: var(--surface); border-color: var(--line-strong); color: var(--ink); }
.btn-2:hover { border-color: var(--accent); color: var(--accent-ink); text-decoration: none; }
.btn[disabled], .btn-2[disabled] { opacity: .5; cursor: not-allowed; }

/* Destructive. The border and the text carry it, not a filled red block: a
   filled button reads as the thing you are meant to press, and Delete never is.
   Colour alone is not the signal either, the word says what it does. */
.btn-warn { color: var(--danger); border-color: var(--danger); }
.btn-warn:hover { border-color: var(--danger); color: var(--danger);
                  background: color-mix(in srgb, var(--danger) 8%, transparent); }
.btn-warn[disabled]:hover { background: var(--surface); }

/* A compact table row. The default padding is set for tables you read a few
   rows of; a settings list is one you scan twenty of, and the air between rows
   stops being generous and starts being scrolling. */
.table-tight th, .table-tight td { padding-top: var(--s-2); padding-bottom: var(--s-2); }
.table-tight td { vertical-align: middle; line-height: 1.45; }

/* Columns, stated rather than guessed at. Left to itself the browser gave the
   description most of the width and squeezed the name column until "Structures"
   broke across two lines, which the site-wide `overflow-wrap: anywhere` on table
   cells lets it do. That rule is there for email addresses and URLs, and a
   category name is neither. */
.cat-table { table-layout: fixed; }
.cat-name { width: 10rem; }
.cat-num  { width: 5.5rem; }
.cat-acts { width: 9rem; }
.cat-table .cat-name, .cat-table .cat-num, .cat-table .row-acts {
  overflow-wrap: normal; word-break: keep-all; white-space: nowrap;
}
/* A name long enough to genuinely not fit gets an ellipsis rather than either a
   broken word or a column that grows and shoves the actions off the edge. */
.cat-table .cat-name a { display: block; overflow: hidden; text-overflow: ellipsis; }

/* Row actions sit on one line. They wrap only in the restacked phone layout,
   where the cell is the full width of the card and there is room. */
.row-acts { display: flex; gap: var(--s-2); align-items: center; }
.row-acts .row-form { display: inline; margin: 0; }
.row-acts .btn-2 { white-space: nowrap; }

/* Row-level buttons, smaller than a page action because there is one per row and
   they are not what you came to the page to press. 30px tall, comfortably above
   the 24px minimum target, and it takes a chunk out of every row's height. */
.btn-row { padding: 8px var(--s-3); font-size: 13px; }

/* ── the meetings table ───────────────────────────────────────────────────── */
/* Same treatment as the categories table, and only once there is room for it:
   below 861px the columns go back to auto and the table restacks into cards at
   560. When and Where hold their content; the agenda takes the slack. */
@media (min-width: 861px) {
  .mt-table { table-layout: fixed; }
  .mt-when  { width: 15rem; }
  .mt-where { width: 13rem; }
  .mt-acts  { width: 6rem; }
  .mt-table .mt-when { overflow-wrap: normal; }
}

/* ── choosing an association ──────────────────────────────────────────────── */
/* One button per association, each its own form so the whole row is the submit
   and there is no separate "continue" to hunt for. */
.assoc-pick { margin: 0 0 var(--s-3); }
.assoc-btn {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4);
  width: 100%; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-md); padding: var(--s-4) var(--s-5); font: inherit; color: var(--ink);
}
.assoc-btn:hover { border-color: var(--accent); }
.assoc-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.assoc-name { font: 600 var(--t-body)/1.3 var(--sans); }
.assoc-role { font-size: var(--t-eyebrow); color: var(--faint); white-space: nowrap; }

/* ── the new-project wizard ───────────────────────────────────────────────── */
/* Steps as a list, numbered, with the current one filled. Not clickable: a step
   you have not reached has no answers to show, and one you have passed is
   reached by the Back button that carries your answers with it. */
.wiz { display: flex; gap: var(--s-3); list-style: none; margin: 0 0 var(--s-5); padding: 0;
       flex-wrap: wrap; counter-reset: none; }
.wiz-step { flex: 1 1 14rem; display: grid; grid-template-columns: auto 1fr;
            grid-template-rows: auto auto; column-gap: var(--s-3);
            background: var(--surface); border: 1px solid var(--line);
            border-radius: var(--r-md); padding: var(--s-3) var(--s-4); }
.wiz-n { grid-row: 1 / 3; align-self: center;
         width: 1.75rem; height: 1.75rem; border-radius: 50%;
         display: grid; place-items: center;
         font: 600 13px/1 var(--sans); background: var(--sunk); color: var(--faint);
         border: 1px solid var(--line-strong); }
.wiz-label { font: 600 var(--t-body-s)/1.3 var(--sans); color: var(--ink); }
.wiz-hint { font-size: var(--t-eyebrow); color: var(--faint); }
.wiz-step.is-here { border-color: var(--accent); }
.wiz-step.is-here .wiz-n { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
/* Outlined rather than filled. Filled with --success and white text it measured
   2.68:1 in dark mode, because --success is a light green there and is a
   FOREGROUND token: it is built to be read against the surface, not to be one.
   Used the way it was meant to be, it passes in both themes. */
.wiz-step.is-done .wiz-n { background: var(--surface); color: var(--success);
                           border-color: var(--success); }

/* ── the status panel ─────────────────────────────────────────────────────── */
/* The first thing on a project and the loudest, because it is the question
   everyone opened the page to answer. A filled accent rule down the side rather
   than a coloured box: it has to read as the state of the thing, not as an
   alert about it. */
.pstatus {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 4px solid var(--accent); border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  padding: var(--s-5); margin-bottom: var(--s-6);
}
.pstatus-set { display: flex; gap: var(--s-4); align-items: flex-end; flex-wrap: wrap; }
.pstatus-set .field { flex: 1 1 16rem; min-width: 0; margin: 0; }
.pstatus-set .btn { flex: 0 0 auto; }
.pstatus .note { margin: var(--s-3) 0 0; }

/* ── the placeholder picker ───────────────────────────────────────────────── */
/* Form on the left, placeholders on the right. minmax(0, …) on the form column
   rather than 1fr: a 1fr track will not shrink below its content, and a long
   unbroken line in the message box pushed the picker off the side once already
   on another screen in this app. */
.tpl-add { display: grid; grid-template-columns: minmax(0, 1fr) 15rem;
           gap: var(--s-5); align-items: start; }
.tpl-add > .block { margin-bottom: 0; }

.ph-picker { padding: var(--s-5); position: sticky; top: var(--s-5); }
.ph-hint { margin: 0 0 var(--s-4); }
.ph-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }

/* A chip is a button that looks like the token it inserts. Grab cursor because
   it is draggable, but it is a real button underneath: click or Enter works, and
   that is the path that exists for anyone not using a mouse. */
.ph-chip {
  display: block; width: 100%; text-align: left; cursor: grab;
  background: var(--sunk); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3); font: inherit; color: var(--ink);
}
.ph-chip:hover { border-color: var(--accent); background: var(--surface); }
.ph-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ph-chip:active { cursor: grabbing; }
.ph-chip.is-dragging { opacity: .4; }
.ph-chip code { display: block; font: 500 13px/1.5 var(--mono); color: var(--accent-ink); }
.ph-what { display: block; font-size: var(--t-eyebrow); color: var(--faint); }

@media (max-width: 860px) {
  /* The picker under the form rather than beside it, and no longer sticky: a
     sticky panel in a single column follows you down the page over the thing
     you are trying to read. */
  .tpl-add { grid-template-columns: minmax(0, 1fr); }
  .tpl-add > .block { margin-bottom: var(--s-5); }
  .ph-picker { position: static; }
  .ph-list { grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); }
}

.actions {
  display: flex; gap: var(--s-4); align-items: center; flex-wrap: wrap;
  margin-top: var(--s-7); padding-top: var(--s-6); border-top: 1px solid var(--line);
}

/* ── fields ───────────────────────────────────────────────────────────────── */
.field { display: flex; flex-direction: column; }
.field > label {
  font: 500 var(--t-eyebrow)/1.4 var(--mono); letter-spacing: .18em;
  text-transform: uppercase; color: var(--faint); margin-bottom: var(--s-2);
}
.input {
  font: 400 var(--t-body)/1.5 var(--sans); color: var(--ink);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r); padding: 10px var(--s-3); width: 100%;
}
.input::placeholder { color: var(--faint); }
.input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
.input[disabled] { background: var(--sunk); color: var(--muted); }
textarea.input { resize: vertical; min-height: 5em; line-height: 1.6; }
select.input { appearance: none; padding-right: var(--s-7);
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: right 18px center, right 13px center;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
input[type="file"].input { padding: var(--s-2); font-size: var(--t-body-s); }
.pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: var(--s-4); }

/* Yes / no, and the four-verdict control. Segmented, the chosen one filled. */
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--r); overflow: hidden; }
.seg-opt {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 9px var(--s-5); font-size: var(--t-body-s); cursor: pointer;
  color: var(--body); background: var(--surface);
}
.seg-opt + .seg-opt { border-left: 1px solid var(--line-strong); }
.seg-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.seg-opt:has(input:checked) { background: var(--accent); color: var(--on-accent); font-weight: 600; }
/* The :not() is load-bearing. Without it this rule wins on order over the one
   above and a CHOSEN but disabled option — every verdict on a closed review —
   renders faint text on the filled accent at 1.47:1. The recorded verdict has to
   stay readable when the review is closed; that is when it is read most. */
.seg-opt:has(input:disabled):not(:has(input:checked)) { color: var(--faint); cursor: not-allowed; }
.seg-opt:has(input:disabled) { cursor: not-allowed; }
.seg-opt:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }

.na { display: inline-flex; align-items: center; gap: var(--s-2); margin-top: var(--s-3);
      font-size: var(--t-body-s); color: var(--muted); cursor: pointer; }
.derived {
  background: var(--sunk); border-radius: var(--r); padding: var(--s-3) var(--s-4);
  font: 400 var(--t-small)/1.6 var(--sans); color: var(--body);
}

/* ── tables ───────────────────────────────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; font-size: var(--t-body-s); }
.table th {
  text-align: left; font: 500 var(--t-eyebrow)/1.4 var(--mono); letter-spacing: .14em;
  text-transform: uppercase; color: var(--faint);
  padding: var(--s-3) var(--s-4) var(--s-3) 0; border-bottom: 1px solid var(--line-strong);
}
.table td {
  padding: var(--s-3) var(--s-4) var(--s-3) 0; border-bottom: 1px solid var(--line);
  color: var(--body); vertical-align: top; overflow-wrap: anywhere;
}
.table tbody tr:hover td { background: var(--sunk); }
.table-pay td { vertical-align: middle; }
/* A formatted date wants to stay on one line where there is room and wrap where
   there is not. Pinning it to nowrap made the history table wider than a phone
   the moment the raw timestamp was replaced by a readable one. */
.when { white-space: nowrap; }
@media (max-width: 620px) { .when { white-space: normal; } }
.pay-in { display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap; }
.pay-in .input { width: auto; min-width: 8rem; }

/* The whole row opens the record: one stretched link, so a click lands wherever
   the pointer is. The action button has to be lifted above it — the BUTTON, not
   its cell, or the space beside it does nothing at all. */
/* ── the review queue's columns ───────────────────────────────────────────── */
/* Stated widths are a wide-screen refinement, not a rule for every size. Applied
   from the restack breakpoint up, the fixed and nowrap columns added to more
   than the viewport at around 700px and the table pushed the page sideways:
   measured at 702px of table in a 685px window. Between the restack and here,
   auto layout and ordinary wrapping do the job they always did.

   The button's nowrap is deliberately NOT in here. It is the one thing that has
   to hold at every width, because it is what was breaking "Review" in half. */
@media (min-width: 861px) {
  .table-queue .q-num    { width: 4.5rem; white-space: nowrap; overflow-wrap: normal; }
  /* Sized to the longest label rather than pinned. Pinned at 9.5rem the longest
     status wrapped to two lines and cost every row 12px of height, which is the
     opposite of the point. `width: 1%` with nowrap is the table-layout idiom for
     "give this column exactly what it needs and no more". */
  .table-queue .q-status { width: 1%; white-space: nowrap; overflow-wrap: normal; }
  .table-queue .q-go     { width: 6.5rem; white-space: nowrap; overflow-wrap: normal; }
  /* The two free-text columns share what is left, and the address gets the
     bigger half. Measured both ways with a 32-character email in the queue: at
     30% the email fits on one line and the address column drops to 161px, at 20%
     the email wraps and the address gets 259px. The TABLE IS THE SAME HEIGHT
     either way, so the question is only which column you would rather be able to
     read, and that is the address. An email only shows here at all until its
     owner signs in and the record learns their name. */
  .table-queue .q-who    { width: 20%; }
  .table-queue .q-addr   { width: auto; }
  /* Numbers line up when they are the same width per digit, which is what makes
     a column of project numbers scannable. */
  .table-queue .q-num, .table-queue .q-status { font-variant-numeric: tabular-nums; }
}

.table-queue tbody tr { position: relative; }
.row-link { position: absolute; inset: 0; z-index: 1; }
.table-queue .row-go .btn-2 { position: relative; z-index: 2; }
.row-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
.row-go { display: flex; gap: var(--s-4); flex-wrap: wrap; }
.row-go .btn-2 { white-space: nowrap; }
.row-form { margin: 0; }
.invite { display: grid; gap: var(--s-4); max-width: 28rem; margin-top: var(--s-4); }

/* ── the checklist ────────────────────────────────────────────────────────── */
.sect { margin-bottom: var(--s-7); }
.sect > h2 { margin-bottom: var(--s-2); }
.sect-note { color: var(--muted); font-size: var(--t-body-s); margin-bottom: var(--s-5); }

.item {
  display: grid; grid-template-columns: 2.25rem 1fr; gap: var(--s-4);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: var(--s-5); margin-bottom: var(--s-3);
}
.item-n { font: 500 var(--t-index)/1.9 var(--mono); color: var(--faint); font-variant-numeric: tabular-nums; }
.item-label { display: block; font-size: var(--t-body); color: var(--head); font-weight: 500; margin-bottom: var(--s-2); }
.item-hint { margin: 0 0 var(--s-3); color: var(--muted); font-size: var(--t-body-s); }
.item-clauses { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-3); }
.item-control { display: grid; gap: var(--s-3); }
.item-review .item-label { font-weight: 600; }
.verdict { display: grid; grid-template-columns: minmax(19rem, 24rem) 1fr; gap: var(--s-4);
           align-items: end; margin-top: var(--s-4); }
.seg-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.seg-4 .seg-opt { padding: 9px var(--s-2); font-size: var(--t-small); }

/* ── an answer, read back ─────────────────────────────────────────────────── */
.ans { background: var(--sunk); border-radius: var(--r); padding: var(--s-3) var(--s-4);
       margin-bottom: var(--s-3); color: var(--ink); font-size: var(--t-body-s); }
.ans-line { display: grid; grid-template-columns: 7rem 1fr; gap: var(--s-3); padding: 1px 0; }
.ans-line:only-child { grid-template-columns: 1fr; }
.ans-k { font: 500 var(--t-eyebrow)/1.8 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }
.ans-none { font: 400 var(--t-index)/1.7 var(--mono); color: var(--muted); }
.ans-files { list-style: none; margin: 0 0 var(--s-3); padding: 0; }
.ans-files li { display: flex; gap: var(--s-3); align-items: baseline; flex-wrap: wrap;
                font-size: var(--t-body-s); padding: 3px 0; }

/* ── collapsible record sections ──────────────────────────────────────────── */
.rec-sect {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-card); margin-bottom: var(--s-4); padding: 0 var(--s-6);
}
.rec-sect > summary { cursor: pointer; list-style: none; padding: var(--s-5) 0; }
.rec-sect > summary::-webkit-details-marker { display: none; }
.rec-sect > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.rec-h { display: flex; align-items: baseline; gap: var(--s-4); margin: 0;
         font: 600 var(--t-h3)/1.3 var(--serif); color: var(--head); }
.rec-n { font: 400 var(--t-index)/1.6 var(--mono); color: var(--muted); }
.rec-mark { margin-left: auto; font: 400 var(--t-h3)/1 var(--mono); color: var(--accent); }
.rec-mark::after { content: "+"; }
.rec-sect[open] > summary .rec-mark::after { content: "\2212"; }
.rec-sect[open] > summary { border-bottom: 1px solid var(--line); }
.rec-sect > .sect-note { margin: var(--s-4) 0; }
.rec-sect .item { border: 0; box-shadow: none; padding: var(--s-5) 0; margin: 0;
                  border-bottom: 1px solid var(--line); border-radius: 0; background: none; }
.rec-sect .item:last-child { border-bottom: 0; }

/* ── the project workspace ────────────────────────────────────────────────── */
/* A rail beside the section, so a project is one place rather than five URLs
   that overlap. Each item carries its own state line, which is the whole reason
   this beats a row of tabs: what is outstanding is legible without opening it. */
.pwork { display: grid; grid-template-columns: minmax(200px, 232px) minmax(0, 1fr);
         gap: var(--s-8); align-items: start; }
.pwork-body { min-width: 0; }

.prail { position: sticky; top: calc(var(--nav-h) + var(--s-5)); min-width: 0; }
.prail-head { padding-bottom: var(--s-4); margin-bottom: var(--s-4);
              border-bottom: 1px solid var(--line); }
.prail-num { display: block; font: 600 var(--t-h3)/1.2 var(--serif); color: var(--head);
             margin-top: var(--s-2); font-variant-numeric: tabular-nums; }
.prail-addr { display: block; font-size: var(--t-body-s); color: var(--muted); margin-top: 2px; }

.prail-items { display: flex; flex-direction: column; gap: 2px; }
.prail-item { display: block; padding: 9px 10px; border-radius: var(--r-sm); color: var(--ink); }
.prail-item:hover { background: var(--sunk); text-decoration: none; }
.prail-item.is-here { background: var(--accent); }
.prail-item.is-here .prail-label { color: var(--on-accent); font-weight: 600; }
.prail-item.is-here .prail-state { color: var(--on-accent); opacity: .85; }
.prail-label { display: block; font-size: var(--t-body-s); }
.prail-state { display: block; font: 400 var(--t-eyebrow)/1.5 var(--mono); color: var(--faint);
               margin-top: 1px; }

.prail-foot { margin-top: var(--s-6); padding-top: var(--s-4); border-top: 1px solid var(--line); }
.prail-foot a { font-size: var(--t-body-s); }
.prail-foot .note { margin-top: var(--s-2); }

/* On a phone the rail becomes a strip above the section. The pattern this came
   from is desktop-only and scrolls sideways below 1120px; that cannot come
   across, because the record has to be readable in a meeting on a phone. */
@media (max-width: 760px) {
  /* minmax(0, 1fr), never plain 1fr. A 1fr track takes min-content as its
     automatic minimum, so the single column refused to shrink below the width of
     the rail's own row of links and the page scrolled sideways on a phone —
     precisely what this breakpoint exists to prevent. */
  .pwork { grid-template-columns: minmax(0, 1fr); gap: var(--s-5); }
  .prail { position: static; min-width: 0; }
  .prail-items { flex-direction: row; overflow-x: auto; gap: var(--s-2);
                 padding-bottom: var(--s-2); }
  .prail-item { flex: none; white-space: nowrap; }
  .prail-state { display: none; }
  .prail-foot { margin-top: var(--s-4); }
}

/* ── the lot map ──────────────────────────────────────────────────────────── */
.lotmap { margin-bottom: var(--s-8); }
.lm-head { display: flex; align-items: flex-end; justify-content: space-between;
           gap: var(--s-6); flex-wrap: wrap; padding-bottom: var(--s-3); }
.lm-legend { display: flex; align-items: baseline; gap: var(--s-5); flex-wrap: wrap; }
.lm-legend h2 { margin: 0; font-family: var(--mono); }
.lm-key { display: inline-flex; align-items: center; gap: 7px;
          font: 500 var(--t-eyebrow)/1.4 var(--mono); letter-spacing: .12em;
          text-transform: uppercase; color: var(--muted); }
.lm-key-off { color: var(--faint); }
/* Literal, and matching the SVG: the legend has to be the same amber the parcels
   are, and the parcels cannot use a token. See src/ui/lotmap.js. */
.lm-sw { width: 11px; height: 11px; flex: none; background: #ededef; border: 1px solid var(--line); }
.lm-sw-open { background: #f2c230; border-color: #f2c230; }
/* The legend's hatched swatch. A gradient rather than an inline SVG so the key
   stays plain markup, at a tighter pitch than the map's because the swatch is
   11px square and needs two or three strokes to read as hatching. */
.lm-sw-new { background-color: #f2c230; border-color: #f2c230;
             background-image: repeating-linear-gradient(45deg,
               #111214 0 1.4px, transparent 1.4px 4.6px); }
.lm-sw-done { background: #1f7a4d; border-color: #1f7a4d; }

.lm-tools { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.lm-find { margin: 0; }
.lm-q { width: 190px; max-width: 100%; border: 0; border-bottom: 1px solid var(--line-strong);
        background: transparent; padding: 6px 0; font: 400 var(--t-body)/1.4 var(--sans);
        color: var(--ink); border-radius: 0; }
.lm-q::placeholder { color: var(--faint); }
.lm-q:focus { outline: none; border-bottom-color: var(--accent); }
.lm-zoom { display: flex; align-items: center; gap: 10px; font: 400 var(--t-index)/1 var(--mono); }
.lm-zb { border: 0; background: none; cursor: pointer; color: var(--muted);
         font: 400 15px/1 var(--mono); padding: 2px 4px; }
.lm-zb:hover { color: var(--accent-ink); }
.lm-zr { min-width: 40px; text-align: center; color: var(--faint);
         font: 400 var(--t-index)/1 var(--mono); font-variant-numeric: tabular-nums; }
.lm-reset { border: 0; background: none; cursor: pointer; margin-left: 4px; padding: 2px 0;
            font: 400 var(--t-eyebrow)/1.4 var(--mono); letter-spacing: .14em;
            text-transform: uppercase; color: var(--ink); border-bottom: 1px solid var(--ink); }
.lm-reset:hover { color: var(--accent-ink); border-bottom-color: var(--accent); }

/* The aspect ratio is required: the SVG uses the default xMidYMid meet, so a box
   of a different shape letterboxes the drawing and every pointer-to-viewBox
   conversion has to allow for an offset that need not exist. */
.lm-canvas { width: 100%; aspect-ratio: 1522 / 729; min-height: 260px; position: relative;
             overflow: hidden; touch-action: none; cursor: grab;
             border-top: 1px solid var(--ink); background: var(--surface); }
.lm-canvas svg { width: 100%; height: 100%; display: block; }
.lm-lot { cursor: pointer; }
.lm-lot:focus { outline: none; }
.lm-lot:focus-visible path { stroke: #e0362a; stroke-width: 2.6; }
/* Non-matching lots dim rather than vanish: the shape of the subdivision stays
   intact and a near miss is one click away instead of another search. */
.lm-lot.is-dim, .lm-n.is-dim { opacity: .16; }
.lm-streets { opacity: 0; visibility: hidden; }
.lm-canvas text { font-family: var(--sans); }

.lm-strip { border-top: 1px solid var(--line); padding-top: var(--s-4); min-height: 34px;
            display: flex; align-items: baseline; gap: var(--s-8); flex-wrap: wrap; margin: 0; }
.lm-hint { display: block; font: 400 var(--t-index)/1.6 var(--mono); color: var(--faint); }
.lm-field { display: inline-flex; align-items: baseline; gap: 10px; }
.lm-field .label { display: inline; }
.lm-v { font-size: var(--t-body); color: var(--ink); }
.lm-lotno { font: 600 22px/1.1 var(--sans); letter-spacing: -.01em; color: var(--head); }
.lm-open { font-size: var(--t-body); color: var(--ink); border-bottom: 1px solid var(--ink);
           padding-bottom: 2px; }
.lm-open:hover { color: var(--accent-ink); border-bottom-color: var(--accent); text-decoration: none; }

/* Dark. A stylesheet rule beats a presentation attribute, which is exactly why
   the attributes can stay literal for export while the screen still follows the
   theme. These are literal too — no var() ever reaches SVG paint. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .lm-canvas { background: #111e2b; }
  :root:not([data-theme="light"]) .lm-lot path { fill: #22303d; stroke: #111e2b; }
  :root:not([data-theme="light"]) .lm-lot.is-open path { fill: #c9a227; }
  :root:not([data-theme="light"]) .lm-lot.is-sel path { fill: #eaf1f8; stroke: #eaf1f8; }
  :root:not([data-theme="light"]) .lm-n { fill: #8495a3; }
  :root:not([data-theme="light"]) .lm-lot.is-open + .lm-n,
  :root:not([data-theme="light"]) .lm-street { fill: #8495a3; }
}
:root[data-theme="dark"] .lm-canvas { background: #111e2b; }
:root[data-theme="dark"] .lm-lot path { fill: #22303d; stroke: #111e2b; }
:root[data-theme="dark"] .lm-lot.is-open path { fill: #c9a227; }
:root[data-theme="dark"] .lm-lot.is-sel path { fill: #eaf1f8; stroke: #eaf1f8; }
:root[data-theme="dark"] .lm-n, :root[data-theme="dark"] .lm-street { fill: #8495a3; }

/* ── dashboard ────────────────────────────────────────────────────────────── */
.proj-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
             gap: var(--s-5); margin-bottom: var(--s-6); }
.proj { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
        box-shadow: var(--shadow-card); padding: var(--s-6); }
.proj > .label { margin-bottom: var(--s-3); }
.proj-actions { display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: center; margin-top: var(--s-5); }

.meter { height: 6px; background: var(--sunk); border-radius: 999px; overflow: hidden; margin: var(--s-4) 0 var(--s-2); }
.meter > span { display: block; height: 100%; background: var(--accent); border-radius: 999px; }

.outstanding { list-style: none; margin: 0 0 var(--s-4); padding: 0; }
.outstanding li { display: grid; grid-template-columns: 2rem 1fr; gap: var(--s-3);
                  border-top: 1px solid var(--line); padding: var(--s-2) 0; font-size: var(--t-body-s); }
.o-n { font: 500 var(--t-index)/1.7 var(--mono); color: var(--faint); font-variant-numeric: tabular-nums; }

.mailbox { font: 400 var(--t-body-s)/1.6 var(--mono); overflow-wrap: anywhere; margin: 0 0 var(--s-3); }

/* ── correspondence ───────────────────────────────────────────────────────── */
.msg { border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--s-5);
       margin-bottom: var(--s-3); background: var(--surface); }
/* A sender is an email address, which is one unbreakable word. On a phone a long
   one runs straight off the screen unless it is allowed to break. */
.msg-head { display: flex; justify-content: space-between; gap: var(--s-4); flex-wrap: wrap;
            font: 400 var(--t-index)/1.6 var(--mono); color: var(--muted);
            overflow-wrap: anywhere; }
.msg-head > * { min-width: 0; }
.msg-head strong { color: var(--head); font-family: var(--sans); font-size: var(--t-body-s); }
.msg-subject { font: 600 var(--t-body)/1.35 var(--serif); color: var(--head); margin: var(--s-2) 0; }
.msg-body { font-size: var(--t-body-s); white-space: pre-wrap; margin: 0; color: var(--body); }
/* The committee's own side of a conversation, set apart from what came in. */
.msg-committee { background: var(--accent-tint); border-color: var(--accent-tint-border); }
.msg-other { border-color: var(--line-strong); border-style: dashed; }
/* Awaiting a reply is the one state that means somebody still has to act, so it
   is the only one that gets a mark. Answered messages are quiet: the fact is in
   the line above them, named and dated. */
.msg-await { font: 400 var(--t-body-s)/1.6 var(--sans); color: var(--ink);
             border-left: 3px solid var(--accent); padding-left: var(--s-4); margin: var(--s-3) 0; }
.msg-answered { border-left: 3px solid var(--line-strong); }
.reply { margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--line); }
.reply .field { margin-bottom: var(--s-3); }

/* ── the inbox ────────────────────────────────────────────────────────────── */
/* List and reading pane. Two columns where there is room, one where there is
   not — and on one column it is the LIST until you pick something and the
   CONVERSATION after, which is how mail has worked on a phone for fifteen years.
   The server decides which, so the right pane is there on first paint. */
.inbox { display: grid; grid-template-columns: minmax(0, 280px) minmax(0, 1fr);
         gap: var(--s-5); align-items: start; }

.ilist { border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
         background: var(--surface); }
.ilist-head { padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--line);
              display: flex; flex-direction: column; gap: var(--s-3); }
.ifilters { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.ifilter { display: inline-flex; align-items: center; gap: 6px; padding: 3px var(--s-3);
           border-radius: 999px; font: 500 var(--t-eyebrow)/1.7 var(--mono);
           letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
           border: 1px solid var(--line); }
.ifilter:hover { border-color: var(--accent); color: var(--accent-ink); text-decoration: none; }
.ifilter.is-on { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.ifilter-n { font-variant-numeric: tabular-nums; opacity: .85; }
.inew { align-self: start; padding: 7px var(--s-4); font-size: var(--t-small); }

.ilist-body { max-height: 70vh; overflow-y: auto; }
.ilist-empty { padding: var(--s-5) var(--s-4); }
.ithread { display: grid; gap: 3px; padding: var(--s-4);
           border-bottom: 1px solid var(--line); color: var(--body); }
.ithread:hover { background: var(--sunk); text-decoration: none; }
.ithread.is-sel { background: var(--accent-tint); }
/* The one state that means somebody has to act gets the only marker. */
.ithread.is-awaiting { border-left: 3px solid var(--accent); padding-left: calc(var(--s-4) - 3px); }
.ithread-top { display: flex; justify-content: space-between; gap: var(--s-3);
               font: 400 var(--t-index)/1.5 var(--mono); color: var(--muted); }
.ithread-who { overflow-wrap: anywhere; }
.ithread-when { flex: none; font-variant-numeric: tabular-nums; }
.ithread-subject { font: 600 var(--t-body-s)/1.35 var(--sans); color: var(--head); }
.ithread-preview { font-size: var(--t-small); color: var(--muted);
                   display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
                   overflow: hidden; }
.ithread-marks { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: 2px; }
.imark { font: 400 var(--t-eyebrow)/1.6 var(--mono); letter-spacing: .06em;
         text-transform: uppercase; color: var(--faint); }
.imark-await { color: var(--accent-ink); }
.imark-held { color: var(--warning); }
.imark-failed { color: var(--danger); }

.iread { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface);
         padding: var(--s-6); min-width: 0; }
.iread-empty { color: var(--muted); }
.iread-head { padding-bottom: var(--s-4); margin-bottom: var(--s-4);
              border-bottom: 1px solid var(--line); }
.iread-head h2 { margin: 0; }
.iback { display: none; font-size: var(--t-body-s); margin-bottom: var(--s-3); }

/* Sticky rather than fixed: on a long thread it holds at the foot of the window
   while the messages scroll under it; on a short one it just sits at the end.
   No height arithmetic and nothing to recompute on resize. */
.icompose { position: sticky; bottom: 0; background: var(--surface);
            border-top: 1px solid var(--line); padding-top: var(--s-4); margin: 0; }
.icompose .field { margin-bottom: var(--s-3); }
.icompose-foot { display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap; }
.icompose-foot .note { margin: 0; }

@media (max-width: 1100px) {
  .inbox { grid-template-columns: minmax(0, 1fr); }
  /* One column: the list, or the conversation, never both half-width. */
  .inbox.is-reading .ilist { display: none; }
  .iback { display: inline-block; }
  .ilist-body { max-height: none; }
}

/* Template picker and its warning. The warning is not a colour on the text: it
   is a bordered note, because "check this reads correctly" has to survive being
   skimmed. */
.tpl-pick { display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap;
            margin: 0 0 var(--s-3); }
.tpl-pick .input { width: auto; min-width: 14rem; flex: 1 1 14rem; }
.tpl-pick .note { margin: 0; }
.tpl-none { margin: 0 0 var(--s-3); }
.tpl-warn { font-size: var(--t-body-s); color: var(--ink); background: var(--sunk);
            border-left: 3px solid var(--warning); border-radius: var(--r-sm);
            padding: var(--s-3) var(--s-4); margin: 0 0 var(--s-3); }
.tpl-form { margin: 0; }
.tpl-actions { display: flex; gap: var(--s-4); align-items: center; flex-wrap: wrap;
               margin-top: var(--s-4); }
.tpl-actions .note { margin: 0; }

/* ── sign in ──────────────────────────────────────────────────────────────── */
.signin { max-width: 30rem; margin: var(--s-9) auto 0; }

/* ── header ───────────────────────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 20; background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.nav .in {
  max-width: var(--column-wide); margin: 0 auto; padding: 0 var(--margin);
  height: var(--nav-h); display: flex; align-items: center; gap: var(--s-6);
}
.mark { font: 600 var(--t-body-s)/1 var(--sans); letter-spacing: .16em; text-transform: uppercase;
        color: var(--head); white-space: nowrap; }
.mark i { color: var(--accent); font-style: normal; }
.mark:hover { text-decoration: none; }
/* Wraps. Five items fit one line on a laptop and do not on a phone: measured at
   375px they came to 430px and pushed the whole page sideways. A nav that grows
   by one item should cost a second row, not a horizontal scrollbar on every
   screen in the app. */
.nav-links { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-6); margin-right: auto; }
.nav-links a { font-size: var(--t-body-s); color: var(--muted); padding: 4px 0;
               border-bottom: 2px solid transparent; }
.nav-links a:hover, .nav-links a[aria-current="page"] { color: var(--head); border-bottom-color: var(--accent); text-decoration: none; }

/* Identity menu. A <details>, so it opens with no script; menu.js only adds
   outside-click and Escape. */
.um { position: relative; }
.um > summary { display: flex; align-items: center; gap: var(--s-3); cursor: pointer; list-style: none; }
.um > summary::-webkit-details-marker { display: none; }
.um-id { display: none; text-align: right; line-height: 1.3; }
@media (min-width: 34rem) { .um-id { display: block; } }
.um-name { display: block; font-size: var(--t-small); color: var(--head); font-weight: 500; }
.um-role { display: block; font: 400 var(--t-eyebrow)/1.4 var(--mono); letter-spacing: .14em;
           text-transform: uppercase; color: var(--faint); }
.um-avatar { display: flex; align-items: center; justify-content: center; width: 34px; height: 34px;
             flex: none; border-radius: 999px; font: 600 var(--t-index)/1 var(--sans);
             color: var(--on-accent); background: var(--accent); }
.um-menu { position: absolute; right: 0; top: calc(100% + var(--s-3)); z-index: 50; width: 16rem;
           background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
           box-shadow: var(--shadow-lift); overflow: hidden; }
.um-head { padding: var(--s-4); border-bottom: 1px solid var(--line); }
.um-email { font: 400 var(--t-index)/1.5 var(--mono); color: var(--muted); overflow-wrap: anywhere; }
.um-menu a { display: block; padding: var(--s-3) var(--s-4); font-size: var(--t-body-s); color: var(--body); }
.um-menu a + a { border-top: 1px solid var(--line); }
.um-menu a:hover { background: var(--sunk); text-decoration: none; }
.um-out { color: var(--danger); }

/* Appearance. In the identity menu when signed in, in the header otherwise, so
   the choice is reachable from the sign-in page too — someone whose machine is
   in dark mode should not have to sign in before they can turn it off. */
.um-theme { padding: var(--s-4); border-top: 1px solid var(--line); }
.theme { display: flex; flex-direction: column; gap: var(--s-2); margin: 0; }
.theme-label { font: 500 var(--t-eyebrow)/1.4 var(--mono); letter-spacing: .18em;
               text-transform: uppercase; color: var(--faint); }
.theme .seg { width: 100%; }
.theme .seg-opt { flex: 1; font: 500 var(--t-index)/1 var(--sans); padding: 7px var(--s-2);
                  border: 0; background: var(--surface); color: var(--body); }
.theme .seg-opt + .seg-opt { border-left: 1px solid var(--line-strong); }
.theme .seg-on { background: var(--accent); color: var(--on-accent); }
/* In the header, signed out: laid out along the bar rather than stacked. */
.nav .theme { flex-direction: row; align-items: center; gap: var(--s-3); }
@media (max-width: 560px) { .nav .theme-label { display: none; } }

/* A label a screen reader needs and the layout does not. */
.vis-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
              overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* ── responsive ───────────────────────────────────────────────────────────── */
@media (max-width: 880px) {
  .item { grid-template-columns: 1fr; gap: var(--s-2); }
  .verdict { grid-template-columns: 1fr; }
}

@media (max-width: 700px) {
  .seg-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .seg-4 .seg-opt:nth-child(odd) { border-left: 0; }
  .seg-4 .seg-opt:nth-child(n + 3) { border-top: 1px solid var(--line-strong); }
}

/* Seven columns do not fit on a phone, and dragging a queue sideways defeats
   scanning, so it becomes one block per project with the heading as a label. */
@media (max-width: 620px) {
  .table-pay, .table-pay tbody, .table-pay tr, .table-pay td { display: block; width: 100%; }
  .table-pay thead { display: none; }
  .table-pay tr { border-top: 1px solid var(--line); padding: var(--s-4) 0; }
  .table-pay tr:hover td { background: none; }
  .table-pay td { border: 0; padding: var(--s-1) 0; }
  .table-pay td:empty { display: none; }
  .pay-in { flex-direction: column; align-items: stretch; margin-top: var(--s-3); }
  .pay-in .input { width: 100%; }
  .pay-in .btn-2 { align-self: start; }
}

@media (max-width: 560px) {
  .table-queue, .table-queue tbody, .table-queue tr, .table-queue td { display: block; width: 100%; }
  .table-queue thead { display: none; }
  .table-queue tr { border: 1px solid var(--line); border-radius: var(--r-md);
                    padding: var(--s-4); margin-bottom: var(--s-3); background: var(--surface); }
  .table-queue tr:hover td { background: none; }
  .table-queue td { border: 0; padding: 2px 0; display: grid;
                    grid-template-columns: 5.5rem 1fr; gap: var(--s-3); align-items: baseline; }
  .table-queue td::before { content: attr(data-label); font: 500 var(--t-eyebrow)/1.9 var(--mono);
                            letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }
  .table-queue .row-go { display: flex; margin-top: var(--s-3); }

  /* Same restack for any table that opts in. A description column pushes the
     categories table to four, and four columns in 375px is three characters
     wide each. Measured before adding this: the actions column alone came out
     at 129px. */
  .table-stack, .table-stack tbody, .table-stack tr, .table-stack td { display: block; width: 100%; }
  .table-stack thead { display: none; }
  .table-stack tr { border: 1px solid var(--line); border-radius: var(--r-md);
                    padding: var(--s-4); margin-bottom: var(--s-3); background: var(--surface); }
  .table-stack tr:hover td { background: none; }
  .table-stack td { border: 0; padding: 2px 0; display: grid;
                    grid-template-columns: 7rem 1fr; gap: var(--s-3); align-items: baseline; }
  .table-stack td::before { content: attr(data-label); font: 500 var(--t-eyebrow)/1.9 var(--mono);
                            letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }
  /* The actions cell carries no label, so it gets the full width rather than an
     empty 7rem gutter it would otherwise sit to the right of. */
  .table-stack .row-acts { display: flex; grid-template-columns: none; margin-top: var(--s-3); }

  .nav .in { height: auto; flex-wrap: wrap; padding-top: var(--s-3); padding-bottom: var(--s-3);
             row-gap: var(--s-3); }
  .nav-links { order: 3; flex-basis: 100%; margin-right: 0; row-gap: var(--s-2); }
}

@media (max-width: 480px) {
  .ans-line { grid-template-columns: 1fr; gap: 0; }
}

/* ── print ────────────────────────────────────────────────────────────────── */
/* The record is a document before it is a page: it goes in a meeting pack and
   into the association's file. */
@media print {
  .nav, .actions, .um { display: none; }
  .page { padding: 0; max-width: none; }
  .block, .item, .rec-sect { break-inside: avoid; box-shadow: none; }
  .sect > h2, .rec-sect > summary { break-after: avoid; }
  .ans-files a { color: var(--ink); }
  /* A collapsed <details> prints collapsed, which would send the record to the
     meeting pack with every item missing. This covers browsers that support it;
     menu.js opens the sections before printing for the ones that do not. */
  .rec-sect::details-content { content-visibility: visible; }
  .rec-mark { display: none; }
  .rec-sect > summary { cursor: auto; }
}
