/* Ecoterra — the Phase 2 authenticated surfaces.
 *
 * A SECOND stylesheet, on purpose. `base.css` is the site's, it is being worked on by
 * somebody else right now, and the standing rule on this project is "do not append to
 * the stylesheet" — three bugs came from rules appended in later edits silently
 * overriding earlier ones. So the trustee portal and the buyer's account sub-pages link
 * this file after `base.css` and add to it, rather than editing it.
 *
 * Two rules this file keeps to:
 *
 *   - **It defines no design tokens.** Every colour, radius, shadow and font here is a
 *     custom property `base.css` and the token package already publish. Nothing is
 *     redefined and no literal colour appears anywhere in the file; a test in
 *     test/portal.test.js scans the whole assets tree for hex literals.
 *   - **No sizing rule decides visibility, and no container rule colours a button.**
 *     Nothing here sets `display` alongside a width or height, so a sizing rule can
 *     never outrank the rule meant to show or hide something — that is how the header
 *     came to render two logos at once. And every rule that colours links inside a
 *     container carries `:not(.btn)`, because `.nav a` capturing the Sign in button is
 *     how it came to be dark green on dark green.
 *
 * ---------------------------------------------------------------- the trustee pass
 *
 * Reworked 16 August 2026 for the independent trustee desks — regulated firms holding
 * other people's house money, often ₦100m at a time. What the surface was missing was
 * not decoration; it was *rank*. Everything carried the same weight, so a ₦40m release
 * waiting on a second signature looked exactly like a settled row from last month.
 *
 * The four ideas the whole sheet is built on:
 *
 *   1. **State is carried by the card, not only by a chip in its corner.** A record
 *      waiting on this firm is raised, has an accent edge and sits on the panel colour;
 *      a settled or refused one is flat, on the tint, and recedes. `:has()` reads the
 *      status pill the template already prints, so no template had to learn a new
 *      vocabulary of classes and the two can never disagree.
 *   2. **Money is typographically its own thing.** Amounts are body-font, weighted,
 *      tabular-lining and slightly tightened, so a column of them lines up digit for
 *      digit and reads as a figure rather than as a sentence. They are NOT set in
 *      `--font-display`: its naira sign reads as a struck-through N at card sizes,
 *      which on a payment record is the one misreading you cannot afford.
 *   3. **A form is a decision, so it looks like one.** `.act` is a recessed well rather
 *      than a dashed rule, and the wells that carry an irreversible act — the ones
 *      whose submit is a solid `.btn` — are raised out of it again.
 *   4. **A long list needs somewhere to put your eye.** Tables are hairline-ruled with
 *      a stronger rule every fifth row, which is what makes 200 rows countable.
 *
 * Two things deliberately NOT done, so nobody re-proposes them:
 *
 *   - **No sticky table headers.** A horizontal scroller (`overflow-x:auto`) computes
 *     `overflow-y` to `auto` as well, which makes the wrapper the scroll container a
 *     sticky header would stick inside — and it has no height limit, so it never
 *     scrolls and the header never detaches. The honest fix is a max-height on the
 *     wrapper, and a ledger you have to scroll inside a page you also scroll is worse
 *     than no sticky header. Wide tables scroll sideways in their own box; the page
 *     body never does.
 *   - **No organisation name on every page.** `orgName` is a local on the overview
 *     route alone and `me.trusteeName` on three others; printing the firm elsewhere
 *     would mean changing routes, which this pass does not do. The identity is carried
 *     instead by the brand rule down the left of every masthead, and by the overview's
 *     own `<h1>` — which IS the firm's name — being treated as one.
 *
 * `--on-surface-subtle` fails WCAG AA in light mode, and this pass moved everything a
 * trustee has to READ off it: field labels, `dt`s, column headings, record references,
 * `.act` headings and `.act-note` — which carries "This is the one irreversible write
 * on this platform" — are all `--on-surface-muted` now. What is left on subtle is
 * genuinely ornamental: a stage number, a bullet, a placeholder.
 */

/* ---------------------------------------------------------------- the surface */

/* Longhands, not `padding:34px 0 96px`. Every one of these pages is `<main class="wrap
   surface">`, and `.wrap`'s gutter is `padding:0 24px` — so a shorthand here, being
   later in the cascade at the same specificity, was setting the horizontal padding back
   to zero and putting every heading, table and card hard against the glass on anything
   narrower than 1188px. base.css carries a comment about the identical bug being fixed
   on `.pad`; this file had reintroduced it. */
.surface{padding-top:34px;padding-bottom:96px}

/* The masthead. `align-items:flex-start` rather than baseline: the ledger puts a
   balance card in the right-hand slot, and a card whose first line of text is aligned
   to a 30px heading's baseline hangs off the top of the page. */
.surface-head{display:flex;flex-wrap:wrap;gap:18px 24px;align-items:flex-start;
  justify-content:space-between}
.surface-head h1{font-family:var(--font-display);font-size:30px;line-height:1.14;
  letter-spacing:-.024em;margin-top:10px}
/* The letter reader's title block: reference and state as a wrapping row, and room under
   it so the state pill does not touch whatever notice follows. */
.letter-meta{display:flex;flex-wrap:wrap;gap:8px 12px;align-items:center}
.letter-head{margin-bottom:18px}
.surface-sub{font-size:13px;color:var(--on-surface-muted);margin-top:8px;max-width:64ch;
  line-height:1.7}
.surface-sub strong{color:var(--on-surface);font-weight:600}
/* The eyebrow is a brand chip from base.css; a link inside one must not be a second,
   louder green on top of it. */
.eyebrow a:not(.btn){color:var(--on-brand-soft)}

/* The sub-navigation. Tracked-out capitals read as a label; a portal's own navigation
   should read as navigation, so this is sentence case at a normal measure with the
   current page carried by weight AND an underline rather than by colour alone. */
.surface-nav{display:flex;flex-wrap:wrap;gap:2px;margin:24px 0 28px;
  border-bottom:1px solid var(--border)}
.surface-nav a{position:relative;padding:10px 13px 11px;font-size:12.5px;font-weight:500;
  text-decoration:none;border-radius:var(--radius-small) var(--radius-small) 0 0}
.surface-nav a:not(.btn){color:var(--on-surface-muted)}
.surface-nav a:hover{background:var(--surface-muted)}
.surface-nav a:not(.btn):hover{color:var(--on-surface)}
.surface-nav a:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.surface-nav a.is-here{font-weight:600}
.surface-nav a.is-here:not(.btn){color:var(--on-surface)}
.surface-nav a.is-here::after{content:"";position:absolute;left:11px;right:11px;
  bottom:-1px;height:2px;border-radius:2px 2px 0 0;background:var(--brand)}

/* ---------------------------------------------------------- section rhythm */

/* `.details`, `.section-heading`, `.section-sub`, `.note`, `.what` and `.buttons` were
   used on every one of these pages and styled on none of them — they fell through to
   browser defaults, which is why a page of six sections read as one undifferentiated
   column. `workspace.css` loads after this file and keeps its own, heavier, card
   treatment for the workspace; these are the portal's. */
.details{margin-top:36px}
.details h2{font-family:var(--font-display);font-size:18px;line-height:1.3;
  letter-spacing:-.014em}
.details > h2{margin-bottom:4px}
.section-heading{font-family:var(--font-display);font-size:17px;line-height:1.3;
  letter-spacing:-.012em;margin:28px 0 12px}
.details > .section-heading{margin-top:0}
.section-sub{font-size:12.5px;color:var(--on-surface-muted);line-height:1.7;
  margin-bottom:14px;max-width:72ch}
.section-sub code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;
  padding:1px 5px;border-radius:var(--radius-small);background:var(--surface-muted)}

.note{font-size:12.5px;color:var(--on-surface-muted);line-height:1.7;margin-top:14px;
  max-width:78ch}
.note strong{color:var(--on-surface);font-weight:600}
.note a:not(.btn){color:var(--brand)}
/* A reference in a table that opens its record has to look like it does: on the firm's
   and Ecoterra's Process pages the version refs were body-coloured text. */
.datatable td a:not(.btn){color:var(--brand);text-decoration:underline;
  text-decoration-color:color-mix(in srgb,var(--brand) 35%,transparent);text-underline-offset:3px}
.datatable td a:not(.btn):hover{text-decoration-color:currentColor}
.records .buttons{margin-top:12px}

/* The paragraph that explains what a record MEANS, as opposed to what it says. It is
   load-bearing copy on most of these pages — "a finding informs the client's acceptance
   and never replaces it" is a `.what` — so it is set at reading size and its emphasis
   is at full contrast. */
.what{font-size:13px;color:var(--on-surface-muted);line-height:1.75;margin-top:16px;
  max-width:74ch}
.what strong{color:var(--on-surface);font-weight:600}
.what a:not(.btn){color:var(--brand)}

.buttons{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-top:18px}

/* ---------------------------------------------------------------- money */

/* Body font, not display. Tabular lining figures so a column of amounts lines up digit
   for digit, and a little negative tracking so a nine-figure sum still scans as one
   number rather than as a queue of commas. */
.money{font-variant-numeric:tabular-nums;font-weight:600;letter-spacing:-.014em;
  color:var(--on-surface)}
/* Qualified with `.record-head` so it outranks that container's own display-serif rule
   for headings. A `h3.money` at (0,1,1) loses to `.record-head h3` at (0,2,1), which is
   how the amount on every deposit and release card kept the serif — and with it a naira
   sign that reads as a struck-through N. */
.record-head h3.money{font-family:var(--font-body);font-size:22px;line-height:1.25;
  letter-spacing:-.018em;margin-top:3px}

/* -------------------------------------------------------- honest degradation */

/* The band that says the page is showing less than the truth, or that something was
 * refused. It is never used to announce a success — a success is stated by the record
 * the service sent back, and there is no markup here that can print one without it.
 *
 * The state edge is a `::before` rather than a fat `border-left`, so the band keeps a
 * true 1px frame all the way round and the colour reads as a marker on it rather than
 * as three-quarters of a box. */
.band{position:relative;overflow:hidden;border:1px solid var(--border);
  border-radius:var(--radius);padding:18px 22px 18px 26px;margin-bottom:22px;
  background:var(--gradient-panel);box-shadow:var(--shadow-1)}
/* A band carries its own space BELOW because it usually opens a page. One that follows a
   section had none above, and sat hard against the last line of whatever preceded it
   (the firm's overview, "You administer this organisation", 18 Sep 2026). */
section + .band{margin-top:28px}
/* TWO THINGS ARE CALLED .band. base.css has the public site's page sections, and its
   `.band + .band{padding-top:0}` (so two sections do not double their 56px) reached every
   NOTICE band here that follows another: the second one's heading sat 1px under its top
   border — "Nothing is waiting on your organisation", "Before you can publish". Measured
   in a browser, 18 Sep 2026. This sheet loads after base.css, so restating the notice
   band's own padding is enough. */
.band + .band{padding-top:18px}
.band::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  background:var(--border-strong)}
.band h2{font-family:var(--font-display);font-size:16px;line-height:1.35;
  letter-spacing:-.012em;margin-bottom:7px}
.band p{font-size:13px;color:var(--on-surface-muted);line-height:1.7;max-width:82ch}
.band p + p{margin-top:9px}
.band code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;
  padding:1px 5px;border-radius:var(--radius-small);background:var(--surface-muted)}
.band a:not(.btn){color:var(--brand)}
.band .buttons{margin-top:14px}
.band.attention::before{background:var(--status-attention)}
.band.attention{border-color:color-mix(in srgb,var(--status-attention) 26%,var(--border))}
.band.waiting::before{background:var(--accent)}
.band.done::before{background:var(--status-complete)}

/* --------------------------------------------------------------- record lists */

.records{display:flex;flex-direction:column;gap:16px;margin-top:16px}
.record{position:relative;border:1px solid var(--border);border-radius:var(--radius);
  padding:20px 22px;background:var(--surface-panel);box-shadow:var(--shadow-1)}
.record-head{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:flex-start;
  justify-content:space-between}
.record-head h3{font-family:var(--font-display);font-size:17px;line-height:1.3;
  letter-spacing:-.014em}
/* A reference is not ornament — it is what a trustee quotes to their own back office,
   so it is legible rather than merely present. */
.record-head .ref{display:block;font-size:10.5px;letter-spacing:var(--micro-tracking);
  text-transform:uppercase;font-weight:600;color:var(--on-surface-muted)}
.record-head .ref a:not(.btn){color:var(--on-surface-muted)}
.record-head .ref a:not(.btn):hover{color:var(--brand)}

/* Facts as ruled rows rather than as a gapped grid: a label left, a value hard right,
   a hairline between. Twelve of these on a release card is a table, and it should look
   like one. */
.record dl{display:grid;grid-template-columns:auto minmax(0,1fr);margin-top:14px;
  font-size:12.5px}
.record dt{color:var(--on-surface-muted);padding:7px 18px 7px 0;
  border-top:1px solid var(--border)}
.record dd{text-align:right;color:var(--on-surface);overflow-wrap:anywhere;padding:7px 0;
  border-top:1px solid var(--border);font-variant-numeric:tabular-nums}
.record dl > dt:first-child{border-top:0}
.record dl > dt:first-child + dd{border-top:0}
/* The property a viewing is about, on its card (walkthrough P-15, 14 Oct 2026). */
.viewing-shot{width:160px;height:107px;object-fit:cover;border-radius:var(--radius);margin:10px 0 2px;vertical-align:top}
.record dd strong{font-weight:600}
.record dd .small{display:block;margin-top:3px}
.record .note{max-width:none}
/* A card whose only action is a link — an appointment's "Open this appointment" — gets
   a footer rule and a weighted link, so the one thing you can do with the card is not
   the quietest thing on it. */
.record > .note:last-child{margin-top:16px;padding-top:14px;
  border-top:1px solid var(--border)}
.record > .note a:not(.btn){font-weight:600}
/* `max-width:none` matters: the rule above this paragraph is its own border, and a
   72-character measure would draw it three-quarters of the way across the card. */
.record .what{padding-top:14px;border-top:1px solid var(--border);margin-top:14px;
  max-width:none}
/* ...but not as the record's FIRST line, where it is a rule over nothing (U-13). */
.record > .what:first-child{padding-top:0;border-top:0;margin-top:0}
/* The trail of what a firm has already recorded against a request. */
.record > h4{font-size:10.5px;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  font-weight:700;color:var(--on-surface-muted);margin-top:20px}
.record > ul{list-style:none;margin-top:9px;display:grid;gap:7px}
.record > ul li{position:relative;padding-left:17px;font-size:12.5px;line-height:1.6;
  color:var(--on-surface-muted)}
.record > ul li::before{content:"";position:absolute;left:2px;top:7px;width:5px;height:5px;
  border-radius:50%;background:var(--border-strong)}
/* A panel nested inside a record — the site inspection already recorded against a
   release — is a quieter inset, not a second card floating on the first. */
.record .review{max-width:none;margin-top:18px;background:var(--tint);box-shadow:none}

/* A status, said in words. Never colour alone — a pill that means something only by
 * being green is a pill a colour-blind trustee cannot read. The dot is a second,
 * non-verbal channel; the words are still the answer. */
.pill{display:inline-flex;align-items:center;gap:7px;padding:4px 11px;font-size:10px;
  font-weight:700;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  white-space:nowrap;border-radius:var(--radius-pill);color:var(--on-surface-muted);
  border:1px solid var(--border-strong);background:var(--surface)}
/* A pill that is a sentence ("Default — new buy projects are dealt this version") may wrap;
   unwrapped it pushed the template page 28px past a phone. eco-dev F122, 16 Oct 2026. */
.pill.sentence{white-space:normal;max-width:100%}
.pill::before{content:"";width:6px;height:6px;border-radius:50%;flex:0 0 auto;
  background:var(--on-surface-subtle)}
.pill.live{color:var(--on-surface);
  border-color:color-mix(in srgb,var(--status-complete) 48%,transparent);
  background:color-mix(in srgb,var(--status-complete) 10%,transparent)}
.pill.live::before{background:var(--status-complete)}
.pill.holding{color:var(--on-surface);
  border-color:color-mix(in srgb,var(--accent) 52%,transparent);
  background:color-mix(in srgb,var(--accent) 13%,transparent)}
.pill.holding::before{background:var(--accent)}
.pill.stopped{color:var(--on-surface);
  border-color:color-mix(in srgb,var(--status-attention) 48%,transparent);
  background:color-mix(in srgb,var(--status-attention) 10%,transparent)}
.pill.stopped::before{background:var(--status-attention)}

/* ----------------------------------------------------------------- the tables */

/* Wide on a desktop, scrollable rather than squashed on a phone. A ledger that wraps
 * is a ledger nobody can add up. `.tablewrap` was in six templates and in no
 * stylesheet at all, so the clients, people, overview and record tables were rendering
 * as bare browser tables with nothing to stop them running off a narrow screen. Both
 * wrappers are one thing now.
 * `position:relative` so the scroller is the containing block of anything absolutely
 * positioned inside it — a `.visually-hidden` header ("Act") or caption otherwise sits
 * at its static place past the table's right edge, escapes `overflow-x`, and scrolls the
 * whole page sideways at 390px (suite 10, 14 Oct 2026). */
.datatable,.tablewrap{position:relative;width:100%;overflow-x:auto;margin-top:16px;
  border:1px solid var(--border);border-radius:var(--radius);
  background:var(--surface-panel);box-shadow:var(--shadow-1)}
.datatable table,.tablewrap table{width:100%;border-collapse:collapse;font-size:12.5px;
  min-width:560px}
/* Headings wrap rather than nowrap. "May counter-authorise" held on one line pushes the
   people table three hundred pixels past the column and puts a scrollbar under a table
   that would otherwise have fitted. */
.datatable th,.tablewrap th{text-align:left;padding:11px 14px;font-size:10px;
  letter-spacing:var(--micro-tracking);text-transform:uppercase;font-weight:700;
  line-height:1.4;color:var(--on-surface-muted);background:var(--tint);
  border-bottom:1px solid var(--border-strong);vertical-align:bottom}
.datatable td,.tablewrap td{padding:12px 14px;border-top:1px solid var(--border);
  vertical-align:top}
.datatable tbody tr:first-child td,.tablewrap tbody tr:first-child td{border-top:0}
.datatable td.num,.tablewrap td.num{text-align:right;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.datatable th.num,.tablewrap th.num{text-align:right}
/* A money column, weighted so a run of amounts is the thing you see down a page of
   references and dates. */
.datatable td.money,.tablewrap td.money{font-size:13px}
.datatable tbody tr:hover,.tablewrap tbody tr:hover{background:var(--tint)}
/* Somewhere to put your eye in two hundred rows: every fifth boundary is drawn a shade
   stronger, so a trustee can count down a ledger in fives without losing the line. */
.datatable tbody tr:nth-child(5n+1) td,.tablewrap tbody tr:nth-child(5n+1) td{
  border-top-color:var(--border-strong)}
/* Weight only, no colour: the client name in a cell is usually wrapped in a link, and a
   colour here would repaint it and take the only affordance the row has with it. */
.datatable td strong,.tablewrap td strong{font-weight:600}
.datatable td .small,.tablewrap td .small{line-height:1.5}
/* Controls that belong to one row. `inline-flex` on the forms rather than `flex` on the
   cell: a `<td>` whose display is changed stops being a table cell and takes the column
   widths with it. */
.rowacts form{display:inline-flex;margin:0 8px 6px 0}
/* A row's own picker (the firm's seat, People page) in the theme's surface — it was the
   browser's white box on a dark page until 16 Oct 2026 (FINDINGS F125). */
.rowacts select{font-family:inherit;font-size:13.5px;padding:8px 10px;margin-right:6px;
  border:1px solid var(--border-strong);border-radius:var(--radius-small);
  background:var(--surface);color:var(--on-surface)}
.rowacts select:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}
/* A granted power and a withheld one, down a column of four-letter answers. The word is
   still the answer — weight is the second channel, not the only one. */
.yn{font-weight:600;color:var(--on-surface)}
.yn.is-no{font-weight:400;color:var(--on-surface-muted)}

/* The stage list on a single deposit or release. A stage that has not happened is still
   printed — leaving it out would read as "we did not look" — and simply recedes. */
.stages tr.is-pending td{color:var(--on-surface-muted)}
.stages tr.is-pending td strong{font-weight:500;color:var(--on-surface-muted)}

/* The overview's queue. Four rows, and the whole point of the page: how many things
   are waiting on this firm and what they are worth. The counts and the values are
   figures, so they are set as figures rather than as body text in a cell. */
.queue table{min-width:520px}
.queue td{padding:16px 14px;vertical-align:middle}
.queue .q-what{max-width:44ch}
.queue .q-what strong{font-size:13.5px}
.queue .q-count{font-size:23px;font-weight:600;letter-spacing:-.022em;
  color:var(--on-surface);line-height:1.1}
.queue .q-value{font-size:15px;font-weight:600;letter-spacing:-.014em;
  color:var(--on-surface)}
.queue .q-act{text-align:right;white-space:nowrap}
/* Nothing waiting is not the same as something waiting, and must not shout as loudly.
   The row stays, in full, and simply stops asking for attention. */
.queue tr.is-idle .q-count,.queue tr.is-idle .q-value{color:var(--on-surface-muted);
  font-weight:400}
.queue tr.is-idle .q-what strong{font-weight:500;color:var(--on-surface-muted)}

/* ------------------------------------------------------------------- the acts */

/* Every one of these is a plain form. Nothing on this surface needs JavaScript, and a
 * money decision least of all.
 *
 * A dashed rule above a form does not say "this is a decision"; it says "the content
 * carries on". So an act is a recessed well with a labelled head — visibly a place
 * where something is DONE rather than read. */
.act{margin-top:18px;padding:16px 18px;border:1px solid var(--border);
  border-radius:var(--radius-small);background:var(--tint)}
.act + .act{margin-top:12px}
.act h4{font-size:10.5px;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  font-weight:700;margin-bottom:12px;color:var(--on-surface-muted)}
.act-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:14px;align-items:start}
.act-fields label{display:block;font-size:10px;letter-spacing:var(--micro-tracking);
  text-transform:uppercase;font-weight:700;margin-bottom:6px;color:var(--on-surface-muted)}
/* The controls explicitly undo the label's capitals and tracking. Without this the
   caps inherit into the field and a trustee types their statement reference in
   letter-spaced upper case — which is not what they typed and not what is sent. */
.act-fields input,.act-fields select,.act-fields textarea{width:100%;font-family:inherit;
  font-size:13.5px;font-weight:400;text-transform:none;letter-spacing:normal;
  line-height:1.5;padding:10px 12px;border:1px solid var(--border-strong);
  border-radius:var(--radius-small);background:var(--surface);color:var(--on-surface)}
.act-fields textarea{resize:vertical;min-height:76px}
.act-fields input:focus,.act-fields select:focus,.act-fields textarea:focus{
  outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}
.act-fields input::placeholder,.act-fields textarea::placeholder{
  color:var(--on-surface-subtle);text-transform:none;letter-spacing:normal}
/* A tick box is a sentence with a control in front of it, not a caption above one. */
/* A version's words, to read (partials/definitionwords.ejs): the letter as text. */
.defwords{margin-top:14px;display:flex;flex-direction:column;gap:10px}
.defwords-one{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}
.defwords-one summary{cursor:pointer;padding:12px 16px;font-weight:600;font-size:13.5px;
  display:flex;flex-wrap:wrap;gap:4px 12px;align-items:baseline}
.defwords-one[open] summary{border-bottom:1px solid var(--border)}
.defwords-text{white-space:pre-wrap;padding:18px 20px;font-size:14px;line-height:1.7;
  max-width:74ch;color:var(--on-surface)}
/* What a colleague may do with money, on the firm's People table: the two ticks and
   their Save on one line under the role control. */
.rowperms{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:center;margin-top:8px}
.rowperms label.inline{display:inline-flex;gap:6px;align-items:center;font-size:12.5px;margin:0}
/* The definition editor (partials/definitionedit.ejs) — a firm's terms and packs, and
   Ecoterra's samples. Each document is a card; its letter runs the card's full width. */
.defedit-meta{margin-bottom:6px}
.defedit .hint{display:block;margin-top:6px;font-size:12px;letter-spacing:0;text-transform:none;
  font-weight:400;color:var(--on-surface-subtle)}
.defdoc{border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px 20px;
  margin:18px 0 0;background:var(--surface);min-width:0}
.defdoc legend{font-family:var(--font-display);font-size:17px;padding:0 8px;margin-left:-8px;
  color:var(--on-surface)}
.defdoc-when{font-size:12.5px;color:var(--on-surface-muted);margin:0 0 14px}
.defdoc .act-fields{align-items:end}
.defdoc-words{margin-top:16px}
.defdoc-words textarea{min-height:300px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:12.5px;line-height:1.65}
.defdoc-add{border-style:dashed;background:transparent}
.defedit > .act-buttons{margin-top:20px}
.act-fields label.inline{display:flex;align-items:flex-start;gap:10px;font-size:12.5px;
  font-weight:400;line-height:1.6;text-transform:none;letter-spacing:normal;
  color:var(--on-surface);margin-bottom:0}
.act-fields label.inline input{width:auto;flex:0 0 auto;margin-top:3px}
/* A `<legend>` inside a `display:grid` fieldset becomes an ordinary grid item and
   lands on top of the border it is meant to interrupt. The group is its own element
   now and the grid lives inside it. */
.act-group{border:1px solid var(--border);border-radius:var(--radius-small);
  padding:12px 16px 16px;margin-top:14px}
.act-group legend{font-size:10px;letter-spacing:var(--micro-tracking);
  text-transform:uppercase;font-weight:700;color:var(--on-surface-muted);padding:0 6px}
.act-buttons{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:16px}
/* TWO DECISIONS IN ONE WELL — 7 September 2026, at the user's asking: a rule between
   Approve and the reason field, *"so the user knows the send it back is for the text
   box"*. They were reading it exactly as the layout said. Approving takes no input and
   sending back REQUIRES one, and stacked with nothing between them the field's label sat
   directly under the Approve button and read as a caption on it.
   A hairline with the word set INTO it rather than a bare rule: a line says "something
   else follows", and "or" says these are two ways out of the same decision, which is the
   fact a reader needs. Decorative — the sub-heading beneath it carries the same meaning
   for anyone not seeing the page, which is why the word itself is hidden from them. */
.act-split{display:flex;align-items:center;gap:14px;margin:20px 0 2px;
  font-size:9.5px;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  /* `muted`, not `subtle`: at 9.5px, subtle is 4.27:1 on the well's tint in light —
     under AA for text this size. Muted is 7.68 light, 8.59 dark. */
  font-weight:700;color:var(--on-surface-muted)}
.act-split::before,.act-split::after{content:"";flex:1 1 auto;height:1px;
  background:var(--border-strong)}
/* Carries "This is the one irreversible write on this platform." Muted, never subtle. */
.act-note{font-size:12px;margin-top:12px;line-height:1.7;color:var(--on-surface-muted);
  max-width:78ch}
.act-note strong{color:var(--on-surface);font-weight:600}

/* --------------------------------------------------------- review and outcome */

/* The page between pressing a button and anything happening. It exists so that no
 * single click can settle a release. */
.review{max-width:620px;border:1px solid var(--border);border-radius:var(--radius);
  padding:26px 28px;background:var(--surface-panel);box-shadow:var(--shadow-1)}
/* The same markup used as a section of a wide page rather than as the confirmation
   dialogue it was written for. A 620px box adrift in a 1140px column reads as an
   unfinished layout, and a 1140px box with two rows of facts in it reads as an empty
   one — so at full width the outer card goes and the facts table becomes the panel.
   The section's own heading is doing the work the card frame was doing badly. */
.review.full{max-width:none;border:0;padding:0;background:none;box-shadow:none}
.review.full dl{margin-top:0}
.review.full .what{margin-top:14px}
.review h1{font-family:var(--font-display);font-size:24px;line-height:1.15;
  letter-spacing:-.022em}
.review h2{font-family:var(--font-display);font-size:16px;line-height:1.3;
  letter-spacing:-.012em;margin-bottom:4px}
.review h4{font-size:10.5px;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  font-weight:700;color:var(--on-surface-muted);margin-bottom:4px}
.review .lede{margin-top:10px;max-width:66ch}
.review .small{margin-top:16px;max-width:70ch}
.review dl{display:grid;grid-template-columns:auto minmax(0,1fr);margin:18px 0;
  font-size:13px;padding:2px 16px;border:1px solid var(--border);
  border-radius:var(--radius-small);background:var(--tint)}
.review dt{color:var(--on-surface-muted);padding:9px 18px 9px 0;
  border-top:1px solid var(--border)}
.review dd{text-align:right;overflow-wrap:anywhere;padding:9px 0;
  border-top:1px solid var(--border);font-variant-numeric:tabular-nums}
.review dl > dt:first-child{border-top:0}
.review dl > dt:first-child + dd{border-top:0}
.review dd .small{display:block;margin-top:3px}
.review .buttons{margin-top:6px}
/* "What this is for", inside the confirmation itself. A quieter inset rather than a
   second card stacked on the first — it is context for the decision, not a rival to it.
   The margin used to be an inline style on the template. */
.review .review{max-width:none;margin:20px 0;padding:20px;background:var(--tint);
  box-shadow:none}
.review .review dl{background:var(--surface-panel)}
.review .buttons a:not(.btn){font-size:13px;color:var(--on-surface-muted)}
.review .err{margin-top:16px}

/* What a firm is holding, as a row of figures rather than as a paragraph in a box.
   These are the numbers a trustee opens the page for. */
.review.holdings dl{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);
  grid-template-rows:auto auto;gap:7px 30px;padding:18px 20px;align-items:start;
  margin:16px 0 0}
.review.holdings dt{border-top:0;padding:0;font-size:10px;font-weight:700;
  letter-spacing:var(--micro-tracking);text-transform:uppercase;
  color:var(--on-surface-muted)}
.review.holdings dd{border-top:0;padding:0;text-align:left;font-size:18px;font-weight:600;
  letter-spacing:-.016em;line-height:1.35;color:var(--on-surface)}
.review.holdings dd .small{margin-top:6px;font-size:11.5px;font-weight:400;
  letter-spacing:normal}
.review.holdings a:not(.btn){color:var(--brand)}

.outcome{max-width:640px}
.outcome .what{margin-top:16px}

/* ---------------------------------------------------------------- the buyer's */

.countdown{margin-top:6px;padding:16px 20px;border:1px solid var(--border);
  border-radius:var(--radius);background:var(--tint);box-shadow:var(--shadow-1)}
.countdown .figure{font-family:var(--font-body);font-size:26px;font-weight:600;
  letter-spacing:-.022em;line-height:1.2;font-variant-numeric:tabular-nums}
.countdown .caption{font-size:11.5px;margin-top:7px;color:var(--on-surface-muted);
  max-width:30ch;line-height:1.55}
.countdown.gone{border-color:var(--status-attention)}

.choices{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px;
  margin-top:18px}
.choice{border:1px solid var(--border);border-radius:var(--radius);padding:20px;
  background:var(--surface-panel);display:flex;flex-direction:column;gap:10px;
  box-shadow:var(--shadow-1)}
.choice h3{font-family:var(--font-display);font-size:17px;letter-spacing:-.014em}
.choice .kind{font-size:10px;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  font-weight:700;color:var(--on-surface-muted)}
/* ~~`.choice .fee`~~ removed 12 September 2026. It styled ONE fee for the whole firm, and
   a firm is now approved per service and prices each one separately — the catalogue card
   renders `.svcitem-fee` per service instead, from base.css, which is the same control the
   public `/providers` cards use so the two catalogues cannot quote a firm differently. */
.choice .regulator{font-size:12.5px;color:var(--on-surface-muted);line-height:1.6}
.choice .fixture{font-size:11.5px;line-height:1.6;padding-top:10px;
  border-top:1px solid var(--border);color:var(--status-attention)}

/* The chooser's well is a CARD, like the record above it — same ground, same border,
   same radius, same padding — because two boxes in one column that differ only slightly
   read as a mistake rather than as a distinction. Only the legend marks it as a
   question rather than a statement. */
[data-surface="account"] .act-group:has(.pick-list){
  background:var(--surface-panel);border-color:var(--border);
  border-radius:var(--radius);padding:18px 22px 22px;box-shadow:var(--shadow-1)}

/* PICKING ONE OF SEVERAL — 10 September 2026, reported on the running site: *"the ask
   a provider section does not look clean and slick, no proper margins."* It was right,
   and for the reason `.checklist` was wrong on the workspace an hour earlier: the markup
   borrowed `.choice`, which above is the CARD on the public /providers grid — 20px of
   padding, a display font `h3`, its own `.fee` and `.regulator`. A `<label>` wearing it
   got the card's border and padding and none of its structure, so the tick box floated
   to the far right of a 1030px row, five hundred pixels from the firm it belonged to,
   and the name sat under it rather than beside it.

   A pickable ROW is its own control: the box on the left, everything the choice is made
   on to the right of it, one column so two firms read as two options rather than two
   cards. The whole row is the hit target — a name is easier to press than a 13px box —
   and the checked state is drawn, because a tick alone at this size is not enough
   signal that money is about to be asked for on your behalf. */
/* The list to ask more firms, folded once a request is out (F-8): one line until opened. */
.ask-more{margin-top:18px;border:1px solid var(--border);border-radius:var(--radius-small);padding:12px 16px}
.ask-more > summary{cursor:pointer;font-weight:600;font-size:13.5px}
.ask-more[open] > summary{margin-bottom:12px}
.pick-list{display:flex;flex-direction:column;gap:10px;margin-top:14px}
.pick{display:grid;grid-template-columns:20px minmax(0,1fr);gap:14px;align-items:start;
  padding:16px 18px;border:1px solid var(--border);border-radius:var(--radius);
  /* A shade BACK from the well it sits in, not the same white: the well is now a card
     of the same family as the record above it, and rows painted `--surface-panel`
     inside a `--surface-panel` card would have no edge at all except a hairline. */
  background:var(--surface-muted);cursor:pointer;
  transition:border-color .12s ease, background-color .12s ease}
.pick:hover{border-color:var(--border-strong);background:var(--surface)}
.pick:focus-within{outline:2px solid var(--brand);outline-offset:2px}
.pick:has(input:checked){border-color:var(--brand);
  background:color-mix(in srgb, var(--brand) 5%, var(--surface-panel))}
/* The control keeps its own size against the surface's field reset, which stretches an
   input to the width of its cell — that reset is what put a checkbox in the far corner. */
.pick > input{width:18px;height:18px;flex:0 0 auto;margin:2px 0 0;accent-color:var(--brand)}
.pick-body{display:flex;flex-direction:column;gap:5px;min-width:0}
/* A name and its badge on one line, wrapping together rather than the badge alone. */
.pick-name{display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  font-weight:600;font-size:14.5px;line-height:1.35;color:var(--on-surface)}
.pick-line{font-size:12.5px;line-height:1.6;color:var(--on-surface-muted)}
.pick-line.strong{color:var(--on-surface)}
/* One line of times reads as a row of options, not a stack of cards. */
.pick-list.tight{flex-direction:row;flex-wrap:wrap}
.pick-list.tight .pick{padding:11px 15px;align-items:center}
.pick-list.tight .pick-name{font-size:13.5px}

.tracker{display:flex;flex-direction:column;gap:10px;margin-top:16px}
/* `align-items:start`, not `center`: an accepted phase carries a name, a sentence and a
   stack of site photographs, and centring against all that put the phase number level
   with the word "Cancelled." two hundred pixels below the title it numbers. A number
   belongs beside the first line of the thing it counts. */
.stage{display:grid;grid-template-columns:34px 1fr auto;gap:14px;align-items:start;
  padding:14px 16px;border:1px solid var(--border);border-radius:var(--radius);
  background:var(--surface-panel)}
.stage .n{font-family:var(--font-display);font-size:15px;text-align:center;
  color:var(--on-surface-subtle)}
.stage h3{font-size:14px}
.stage .said{font-size:12px;color:var(--on-surface-muted);margin-top:3px;line-height:1.55}
.stage.reached{border-color:var(--status-complete)}
/* A phase whose WORK is accepted but whose MONEY has not been paid out.
 *
 * `reached` alone was drawing a green-bordered card for a tranche that had gone nowhere,
 * which is the same misinformation as a green tick: the eye reads the border, decides the
 * row is finished, and never reaches the sentence. `owed` overrides the green — it is
 * listed after `reached` and both are single-class selectors, so the later rule wins — and
 * adds a left edge, so the state is carried by position and weight rather than by hue
 * alone for anyone who cannot separate the two colours. */
.stage.owed{border-color:var(--status-attention);border-left-width:4px}

/* THE CLIENT'S STAGE CARD (project/phases.ejs). Not the grid above: a head, then its body
   in reading order. The evidence grid and its figures had no rules at all until
   19 Sep 2026, so one photograph rendered at the full width of the page. */
.tracker-case .stage{display:block;padding:18px 20px}
.tracker-case .stage-head{display:flex;flex-wrap:wrap;gap:8px 14px;align-items:center;
  justify-content:space-between;margin-bottom:10px}
.tracker-case .stage-head h3{font-family:var(--font-display);font-size:17px;line-height:1.3}
.tracker-case > .what{margin-top:0}
.tracker-case > .note{margin-top:6px;max-width:68ch}
.stage-evidence-h{margin-top:18px;font-size:10.5px;letter-spacing:var(--micro-tracking);
  text-transform:uppercase;color:var(--on-surface-subtle)}
.stage-evidence{margin-top:10px}
.tracker-case .act-buttons{margin-top:16px}
.evidence-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));
  gap:12px;margin-top:12px}
.evidence-shot{margin:0}
.evidence-shot img{vertical-align:top;width:100%;aspect-ratio:4/3;object-fit:cover;
  border-radius:var(--radius-small);border:1px solid var(--border)}
.evidence-shot figcaption{margin-top:6px;font-size:11.5px;line-height:1.5;
  color:var(--on-surface-muted)}

.trail{margin-top:10px;padding-left:16px;border-left:2px solid var(--border)}
.trail li{font-size:12px;color:var(--on-surface-muted);line-height:1.6;margin-top:5px}
.trail li:first-child{margin-top:0}

/* ------------------------------------------------------- the ways past a password */

/* The two links under the sign-in form — "Forgotten your password?" and "Email me a
 * link instead" — and the same list on the pages they lead to.
 *
 * They are a list rather than a sentence because they are two separate destinations
 * with nothing in common but where they sit, and because a visitor reaches for them at
 * the moment the form has just refused them, which is the worst moment to be reading
 * prose. `:not(.btn)` on the colour rule, as everywhere else in this file: without it a
 * button placed in this list would be brand-on-brand. */
.auth-ways{list-style:none;display:flex;flex-wrap:wrap;gap:6px 22px;justify-content:center;
  margin-top:18px;padding-top:16px;border-top:1px solid var(--border)}
.auth-ways li{font-size:13px}
.auth-ways a:not(.btn){color:var(--brand)}

/* ------------------------------------------------------------------ empties */

/* "You have none" and "we could not ask" are different sentences and must never share
 * one. This is only ever the first; the second is a .band above it. */
.nothing{border:1px dashed var(--border-strong);border-radius:var(--radius);
  padding:34px 26px;font-size:13.5px;line-height:1.75;text-align:center;
  color:var(--on-surface-muted);background:var(--gradient-tint);margin-top:16px}
.nothing p{max-width:66ch;margin-left:auto;margin-right:auto}
.nothing p + p{margin-top:9px}
.empty p + p{margin-top:9px}

/* ------------------------------------------------- site evidence, client side

   The photographs a client is asked to accept a phase on. Above the accept control, never
   below it — the decision must not be offered before the evidence for it. */
.evidence{margin-top:14px;padding-top:12px;border-top:1px solid var(--border)}
.evidence-head{font-family:var(--font-display);font-size:14px;margin-bottom:10px}
.step{margin-top:14px}
.step h5{font-size:13px;font-weight:600;color:var(--on-surface)}
.step p.small{margin-top:2px}

/* Wide enough that a crack in a lintel is visible. A thumbnail grid would make the
   evidence unreadable, which on this screen means unusable. */
/* `auto-fill` reserves every track it can fit whether anything occupies it or not, so a
   step with two photographs in a 1035px panel put them in the left 45% and left two empty
   columns — half the panel blank, once per step, four steps down a phase. `auto-fit`
   collapses the tracks nothing is in, so two photographs share the width instead of
   hugging the left edge of it. That also serves the reason above: these are the pictures a
   client accepts a phase on, and two of them at 500px are more use than two at 250px
   beside a void. Four still land at 250px each, which is what the 220px floor is for. */
.shots{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:10px;margin-top:8px}
.shot{margin:0}
/* `vertical-align` rather than `display:block` to kill the inline gap under the image.
   A sizing rule here must not also decide display: a (0,3,0) sizing rule that did once
   outranked a (0,2,0) swap rule and put two logos in the header, and `phase2.test.js`
   asserts the separation. Declaring the selector twice is equally refused, so the answer
   is to not need `display` at all. */
.shot img{width:100%;height:auto;vertical-align:top;border-radius:var(--radius-small);
  border:1px solid var(--border);background:var(--surface-muted)}
.shot figcaption{margin-top:5px;display:flex;flex-direction:column;gap:1px;
  font-size:11.5px;color:var(--on-surface-muted);line-height:1.45}
/* A missing capture time is a weaker claim than a stated one, and says so rather than
   rendering as an absence nobody notices. */
.shot figcaption .unstated{color:var(--status-attention)}

.papers{margin-top:8px;padding-left:16px}
.papers li{font-size:12.5px;line-height:1.7}
/* `:not(.btn)` so this cannot capture a button dropped inside the list. */
.papers a:not(.btn){color:var(--brand)}

/* The client's own project list on their account landing page. Added 16 August 2026,
   when that panel stopped being a hardcoded "you have no projects yet" and started
   rendering what the client actually has.

   `a:not(.btn)` deliberately: a container that colours its links captures any button
   inside it, which phase2.test.js holds the whole stylesheet to. */
.projectlist{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:8px}
.projectlist a:not(.btn){display:grid;gap:2px;padding:12px 14px;
  border:1px solid var(--border);border-radius:var(--radius-small);
  text-decoration:none;color:inherit;background:var(--surface)}
.projectlist a:not(.btn):hover{border-color:var(--border-strong)}
.projectlist .ref{font-size:11.5px;letter-spacing:.06em;color:var(--on-surface-muted)}
.projectlist .name{font-weight:600;color:var(--on-surface)}
/* The line under a project's name is two things joined: enum values the service stores
   in lower case — `build`, `active`, `on hold` — and then a sentence counting phases.
   `text-transform:capitalize` made the enums read as labels and wrecked the sentence
   along with them, so every row on the client's front door said "0 Of 4 Phases
   Accepted". Lowercasing the whole line and raising only its first letter gets both,
   because the enum is always the first thing on it. Safe here precisely because these
   rows carry no names — which is why the waiting panel further down opts out of it
   rather than sharing it. */
.projectlist .meta{font-size:12.5px;color:var(--on-surface-muted);text-transform:lowercase}
.projectlist .meta::first-letter{text-transform:uppercase}

/* ------------------------------------- what is waiting, on the client's front door

   C1. The panel is the first thing in the client's right-hand column and the only
   part of that page that asks something of the reader, so it is the one panel allowed
   to carry the accent edge — the same device the trustee's overview uses for a record
   holding money, for the same reason and to the same rule.

   The second half is deliberately quieter than the first. "Waiting on you" is a list
   of things to do; "waiting on somebody else" is a list of things NOT to do, and
   giving them equal weight would turn a page about two actions into a page about
   twenty-six. Muted, not hidden: a client whose every project is stalled must still
   be able to see that, which is the whole reason the half exists. */
/* News — what happened while they were not looking. Sits above "what is waiting" and
   is deliberately lighter than it: this panel reports, that one asks. */
.news-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap}
.news-head h2{display:flex;align-items:center;gap:8px}
.newslist{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:8px}
.newslist a:not(.btn){display:grid;gap:3px;padding:12px 14px;
  border:1px solid var(--border);border-left:3px solid var(--status-complete);
  border-radius:var(--radius-small);text-decoration:none;color:inherit;
  background:var(--surface)}
.newslist a:not(.btn):hover{border-color:var(--border-strong)}
/* A decline needs them to do something; an acceptance does not. One border carries
   the whole distinction — see the `severity` note on notification_inbox.json. */
.newslist li.is-attention a:not(.btn){border-left-color:var(--status-attention)}
.newslist .name{font-weight:600;color:var(--on-surface)}
.newslist .meta{font-size:12.5px;color:var(--on-surface-muted);line-height:1.6}
.newslist .when{font-size:11.5px;color:var(--on-surface-subtle)}

.waiting-panel{border-left:3px solid var(--accent);box-shadow:var(--shadow-2)}
/* These rows carry SENTENCES, and names inside them — "Sterling Trust Nominees Limited
   (fixture) has not accepted · asked 20 hours ago" — so they opt out of the case
   handling above entirely. The `capitalize` that rule used to carry produced "Accepted
   Automatically In 13 Days 3 Hours If You Do Nothing"; the `lowercase` it carries now
   would take the firm's name down with the rest of the line, and the first-letter rule
   would raise a name that begins in lower case. Both are refused here. Caught by looking
   at the page; the markup and the words were already correct. */
.waiting-panel .projectlist .meta{text-transform:none}
.waiting-panel .projectlist .meta::first-letter{text-transform:none}
.waiting-head{font-size:13px;letter-spacing:.04em;text-transform:uppercase;
  color:var(--on-surface-muted);margin-top:20px;font-weight:600}
.waiting-panel > .waiting-head:first-of-type{margin-top:12px}
.quiet-list a:not(.btn){background:var(--tint);border-style:dashed}
.quiet-list .name{font-weight:500;color:var(--on-surface-muted)}

/* --------------------------------------- rhythm on the client's front door itself

   The panels are right and their order is right; what the page was missing was air
   between them.

   `.panel` in base.css carries no margin of its own, and on /account only the last
   panel had an inline `margin-top`. So the four answers down the right-hand column —
   what you were told, what is waiting, your projects, payments — sat flush against one
   another, hairline touching hairline, and the front door read as one long slab with
   rules across it rather than as four separate things one of which wants you. The gap
   belongs to the column rather than to any one panel, which is why it is set here and
   not added to `.panel`: `.panel` is also the profile card, a form aside and half the
   workspace, none of which are stacked. */
.acct > div > .panel + .panel{margin-top:18px}

/* The profile card has four facts and a sign-out button in it, and the column beside it
   runs to three thousand pixels, so a desktop showed a metre of empty page down the
   left of everything. Sticky rather than stretched: a card that has said everything it
   has to say is allowed to be short, and it now follows the reader down the panels
   instead. `.acct` already sets `align-items:start`, so nothing here needs to fight the
   grid for the height. Unstuck below 820px — see the breakpoints. */
.acct > aside{position:sticky;top:20px}

/* Money on the client's own pages. Same reason as `.money` at the top of this file:
   `--font-display`'s naira sign renders as a capital N with one bar through it, and
   "₦52,000,000" under a suggested plot reads as a struck-out figure — a cancelled
   price, on the one number the reader came for. Body font, weighted, tabular.
   `.tile .price` carries the same defect on /properties and /land, which are on
   base.css alone and out of this stylesheet's reach. */
[data-surface="account"] .tile .price{font-family:var(--font-body);font-weight:600;
  letter-spacing:-.018em;font-variant-numeric:tabular-nums}

/* ------------------------------------------------- a client's form is not a desk

   `.act-fields` is `auto-fit` from `minmax(210px,1fr)`, which is correct on a trustee's
   desk: a release has a dozen facts across it and the width is the whole point. The
   client's forms have five short fields, and on a 1140px page auto-fit dealt all five
   into one row — a name, an email and a phone number each 250px wide, the last of them
   900px away from the sentence that introduced it, and the form reading as a
   spreadsheet rather than as a question. Nothing this surface asks anybody for is longer
   than a name, a date or a way to be reached, so the form is held to a reading measure
   and the fields pair up inside it.

   620px, which is `.review`'s measure rather than a new number of its own. On the payment
   page an `.act` sits directly beneath a `.review` card, and a 720px form under a 620px
   card reads as two blocks that failed to line up; the client's decision column is one
   width all the way down. Wells nested inside a `.review` are already narrower than this
   and are unaffected. */
[data-surface="account"] .act{max-width:620px}

/* ============================================ A FIRM'S OWN ENTRY — /trustee/organisation

   29 August 2026, at the user's direction: "this view does not look clean and
   professional." It was not. Two causes, and neither was a colour.

   `.act-fields` is `auto-fit` from `minmax(210px,1fr)`, which is right on a trustee's
   DESK — a release has a dozen facts across it and width is the whole point. This page is
   not a desk. It is seven questions in three unrelated groups, and on a wide screen
   auto-fit dealt all seven into one line: the regulator's name in a 210px box, "YOUR FEE,
   IN BASIS POINTS" wrapping onto two lines above a field the width of a word, and the fee
   sitting 900px from the licence it has nothing to do with.

   And `.plain li` carries a bottom rule. Inside a bordered band, five short phrases became
   five empty-looking input rows — a checklist that reads as a form on a page that is
   mostly a form.

   `[data-surface="account"]` reached the same conclusion for the client's forms and
   records the reasoning beside it in portal.css. This is that decision, for this page. */

/* A GROUP is one question somebody can answer in a sitting. The border is the grouping —
   no card, no shadow: four stacked cards on one page is a filing cabinet, and the reader
   has to decide which drawer matters. */
/* ONE MEASURE for everything in this section. The checklist band ran the full page width
   while the form sat at 760px, so the two read as separate documents that failed to line
   up — the same complaint `[data-surface="account"] .act` records above. */
.orgcol{max-width:760px}
.orgform{margin-top:16px}
.orgset{border:0;padding:0;margin:0 0 30px;min-width:0}
.orgset > legend{padding:0;font-family:var(--font-display);font-size:15px;
  line-height:1.35;color:var(--on-surface);letter-spacing:-.01em}
.orgset-note{margin:6px 0 0;font-size:12.5px;line-height:1.65;
  color:var(--on-surface-muted);max-width:62ch}
.orgset-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:16px 18px;margin-top:14px}
/* A field whose content is a URL gets the whole row — nothing else here is long enough
   to need it. The regulator's name looked like it did and does not: at half of 760px a
   box holds "Securities and Exchange Commission" with room to spare, and spanning it
   pushed the licence reference onto a row of its own with half the page empty beside it.
   Two related questions belong on one line. */
.orgset-fields > label.wide{grid-column:1 / -1}
/* The fee pair is ONE answer in two boxes; neither means anything without the other, so
   they stay side by side and stay narrow rather than stretching to fill a row. */
.orgset-fields.narrow{grid-template-columns:repeat(2,minmax(0,220px))}
.orgset-fields > label{display:block;min-width:0;font-size:10px;
  letter-spacing:var(--micro-tracking);text-transform:uppercase;
  color:var(--on-surface-muted);font-weight:600}
.orgset-fields > label em{font-style:normal;text-transform:none;letter-spacing:0;
  font-weight:400;color:var(--on-surface-subtle)}
/* `.feeopt-input input` is in this list because it is the same kind of box in the same
   form — it simply lives inside a radio option rather than in the field grid. Left out, it
   fell back to the browser's own control: white on a dark page, 85px wide, with the unit
   suffix stranded 180px away from it. */
.orgset-fields input,.orgset-fields select,
.feeopt-input input,
.orgset textarea{width:100%;margin-top:7px;font-family:inherit;font-size:14px;
  color:var(--on-surface);background:var(--surface);border:1px solid var(--border-strong);
  border-radius:var(--radius-small);padding:10px 12px}
.orgset textarea{margin-top:14px;resize:vertical;min-height:150px;line-height:1.65}
/* THE SELECT, drawn like the other fields. Left alone it renders as the platform's own
   control — on Safari a grey bevelled box with a blue arrow, sitting beside seven fields
   that share a border, a radius and a background. One native control in a styled form
   looks like a bug rather than a convention, and in dark mode it is a light grey slab.
   Seen on the running site, 29 August 2026.

   `appearance:none` takes the arrow with it, so one is drawn: two lines, in the muted
   text colour, at the size the rest of the form is written in. */
.orgset-fields select{appearance:none;-webkit-appearance:none;padding-right:34px;
  background-image:linear-gradient(45deg,transparent 50%,var(--on-surface-muted) 50%),
    linear-gradient(135deg,var(--on-surface-muted) 50%,transparent 50%);
  background-position:calc(100% - 17px) calc(50% + 1px),calc(100% - 12px) calc(50% + 1px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.orgset-fields select:disabled{background-image:none}

.orgset-fields input:focus,.orgset-fields select:focus,
.feeopt-input input:focus,
.orgset textarea:focus{outline:2px solid var(--brand);outline-offset:1px;
  border-color:var(--brand)}
.orgset-fields input::placeholder,.feeopt-input input::placeholder,
.orgset textarea::placeholder{color:var(--on-surface-subtle)}
/* Read-only for a manager or client administrator. Legible, and visibly not editable —
   a greyed box somebody cannot read is worse than one they cannot type in. */
.orgset-fields input:disabled,.orgset-fields select:disabled,
.feeopt-input input:disabled,
.orgset textarea:disabled{background:var(--tint);color:var(--on-surface-muted);
  border-color:var(--border);cursor:not-allowed}

/* TWO WAYS TO CHARGE, as two options rather than a dropdown that hides one of them.

   The choice and the amount belong together: a select saying "flat fee" above a box
   labelled only "amount" makes the reader hold the unit in their head while typing it.
   Each option carries its own field, so what is being answered is never more than a line
   away from the answer. Both fields are on the page because there is no JavaScript here —
   the radio decides which is kept, and the route ignores the other.

   ## Making the CHOSEN one obvious — 29 August 2026, at the user's direction

   The first version leaned on `--tint` for the selected background and on `accent-color`
   for the dot, and in dark mode neither carried:

     `--tint` and `--surface` are three points of luminance apart in the dark palette.
     A background change nobody can see is not a background change.

     `accent-color` gave the checked radio a small green dot on a dark ring while the
     UNCHECKED control stayed a filled white circle. The unselected option was the
     brighter of the two, which is worse than no signal: it points the wrong way.

   So the state is now said four times over, and none of them is a hue somebody has to
   compare against its neighbour: `--brand-soft` for the ground, which is clearly lighter
   than `--surface` in the dark palette and clearly darker in the light one — a difference
   either way round — plus a 2px brand border, a brand rail down the left edge, and a
   hand-drawn radio that is filled when chosen and a plain outline when not. */
.feechoice{display:grid;gap:12px;margin-top:16px}
.feeopt{position:relative;display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:0 14px;align-items:start;padding:16px 18px;border:2px solid var(--border);
  border-radius:var(--radius-small);background:var(--surface);cursor:pointer;
  overflow:hidden;transition:border-color .15s ease,background .15s ease}
.feeopt:hover{border-color:var(--border-strong)}

/* The chosen one. `:has` is in every browser this platform supports; where it is not,
   the drawn radio below still fills, so the state is never invisible. */
.feeopt:has(input:checked){border-color:var(--brand);background:var(--brand-soft)}
/* A rail down the edge — the one cue that survives being glanced at rather than read,
   and the same device `.band` uses to mark which notice matters. */
.feeopt:has(input:checked)::before{content:"";position:absolute;left:0;top:0;bottom:0;
  width:4px;background:var(--brand)}
.feeopt:has(input:focus-visible){outline:2px solid var(--brand);outline-offset:3px}

/* THE RADIO, drawn rather than accented. `accent-color` styles the dot and leaves the
   ring to the platform, which is how the unchecked control ended up the brighter of the
   two in Safari's dark mode. */
.feeopt > input[type=radio]{appearance:none;-webkit-appearance:none;margin:1px 0 0;
  width:20px;height:20px;flex:0 0 auto;border-radius:50%;
  border:2px solid var(--border-strong);background:var(--surface);cursor:pointer}
.feeopt > input[type=radio]:checked{border-color:var(--brand);
  /* The dot is the border's own inner shadow, so it can never be a pixel out of centre. */
  box-shadow:inset 0 0 0 4px var(--surface),inset 0 0 0 20px var(--brand)}
.feeopt > input[type=radio]:disabled{cursor:default;opacity:.7}

.feeopt-body{display:block;min-width:0}
.feeopt-name{display:block;font-size:14.5px;font-weight:600;color:var(--on-surface)}
/* The chosen option's name reads at full strength; the other stays quiet. Two greys
   apart is enough once the ground and the rail have already said it. */
.feeopt:has(input:checked) .feeopt-name{color:var(--on-brand-soft)}
.feeopt-hint{display:block;margin-top:3px;font-size:12.5px;line-height:1.6;
  color:var(--on-surface-muted)}
.feeopt-input{margin-top:12px;max-width:210px}
.feeopt-input input{margin-top:0}
/* The amount that is NOT being used recedes rather than disappearing — it still holds a
   figure somebody typed, and hiding it would lose their work without saying so. */
.feeopt:not(:has(input:checked)) .feeopt-input{opacity:.55}
.feeopt:not(:has(input:checked)):hover .feeopt-input{opacity:1}
/* Read-only for a manager, not invisible: they still need to see what their firm charges. */
.feeopt:has(input:disabled){cursor:default}

/* A UNIT the reader can see while typing. "0.5" in a bare box is a number somebody has
   to remember the meaning of; "0.5 %" is a fee. The suffix is decoration — `aria-hidden`,
   because the label already says what the field is and a screen reader announcing "per
   cent" after the value would read it twice. */
.suffixed{position:relative;display:block}
.suffixed input{padding-right:34px}
/* A prefix reads before the number — ₦250,000, not 250,000₦. */
.suffixed.prefixed input{padding-right:12px;padding-left:28px}
.suffixed .prefix{position:absolute;left:12px;top:50%;transform:translateY(-50%);
  font-size:13px;color:var(--on-surface-muted);pointer-events:none}
.suffixed .suffix{position:absolute;right:12px;top:50%;transform:translateY(-50%);
  font-size:13px;color:var(--on-surface-muted);pointer-events:none}
/* The spinner would sit under the suffix. Nobody nudges a fee one basis point at a time. */
.suffixed input::-webkit-outer-spin-button,
.suffixed input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.suffixed input[type=number]{-moz-appearance:textfield;appearance:textfield}

.orgform-foot{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;
  padding-top:20px;border-top:1px solid var(--border)}
.orgform-foot .note{margin:0;font-size:12px;color:var(--on-surface-muted)}

/* THE CHECKLIST. A marker and a phrase — no rules, because a rule per row inside a
   bordered band is what made these look like empty fields. Two columns where there is
   room: five short phrases stacked is a tall block saying very little. */
.needlist{list-style:none;margin:12px 0 0;padding:0;display:grid;
  /* TWO columns, not `auto-fit`. Five short phrases dealt across a 1300px band became a
     row of five, which reads as a toolbar — a thing you press — rather than as a list of
     what is outstanding. Two columns keeps them a list and still halves the height. */
  grid-template-columns:repeat(2,minmax(0,1fr));gap:2px 28px;max-width:560px}
.needlist li{position:relative;padding:3px 0 3px 18px;font-size:13px;line-height:1.6;
  color:var(--on-surface)}
.needlist li::before{content:"";position:absolute;left:2px;top:11px;width:5px;height:5px;
  border-radius:50%;background:var(--status-attention)}


/* THE MEASURE GOES ON THE PROSE, NEVER ON THE CARD — corrected 10 September 2026, the
   same hour it was introduced. Capping the WELL at 760px made the chooser narrower than
   the declarations card directly above it, and the section stopped lining up: *"the card
   does not look uniform on the page any more."* Right — a card's width is the page's
   rhythm and is not one section's to change. So the well runs to the section's edge like
   every sibling, and the line length is held where it actually matters: on the sentence
   and on a firm's description. */
[data-surface="account"] .act-group > .note{max-width:68ch;margin-bottom:2px}
[data-surface="account"] .pick-line{max-width:88ch}

/* The measure is on the field grid as well as on the well, because not every client form
   has a well: /account/viewings puts a bare `.act-fields` inside a `.record`, where the
   rule above cannot reach it, and seven fields were dealt 4 + 3 across a 1090px card with
   an empty cell in the corner. */
[data-surface="account"] .act-fields{grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
  max-width:620px}

/* A short list of choices is a list. "In person" and "Video call" were grid items in
   the rule above, which put them at opposite ends of a 1030px fieldset — 500px apart,
   with the question above them and nothing between them, which is not something anybody
   reads as one choice. `:has(> label.inline)` picks out the grids that hold radios and
   tick boxes rather than fields, so a real field grid in the same well is untouched. */
[data-surface="account"] .act-fields:has(> label.inline){
  grid-template-columns:minmax(0,1fr);gap:10px}

/* Sentence case on the client's forms, capitals kept on the trustee's.
   Tracked-out capitals label a column of figures well, and that is what they do on the
   desks. On a form that asks a buyer their name they set "(REQUIRED)" and "(OPTIONAL)"
   shouting beside every field — and this codebase writes prose. `:not(.inline)` because
   a radio's label is a sentence and already has its own treatment; without it the two
   rules tie on specificity and this one, being later, would win and re-weight it. The
   controls' own reset inside `.act-fields` is what keeps any of this from inheriting
   into what somebody types. */
[data-surface="account"] .act-fields label:not(.inline){font-size:12.5px;
  letter-spacing:normal;text-transform:none;font-weight:600}
[data-surface="account"] .act-group legend{font-size:13px;letter-spacing:normal;
  text-transform:none;font-weight:600;color:var(--on-surface)}
/* A well's `h4` names the act inside it — "End this appointment", "Have your trustee
   inspect stages for you" — which is the same job the legend above does in different
   markup. Leaving one in capitals and sentence-casing the other put both treatments on
   the same page. */
[data-surface="account"] .act h4{font-size:13px;letter-spacing:normal;
  text-transform:none;font-weight:600;color:var(--on-surface)}

/* The band that explains what a form does has to be the same width as the form, or the
   pair reads as two unrelated blocks that happen to be stacked — which is what holding
   the form to a measure above had just made of "What this does" on the viewing request,
   left edge aligned and 470px longer. Matched by context rather than surface-wide:
   `:has()` restricts this to a band that follows a section containing a form, which is
   the only shape where the two are one thought. A band above a table or a grid of
   trustees is a page-wide notice and keeps the page's width. */
[data-surface="account"] .details:has(> .act) + .band{max-width:620px}

/* ----------------------------------------------------- the missing button weight

   `.btn.secondary` is in six templates and in no stylesheet — not base.css, not this
   file, not workspace.css. Every one of them therefore fell through to `.btn` itself and
   rendered as a full brand primary with the green cast under it. On the client's project
   page that put "Something is not right" — raising a dispute — beside "Accept" in
   identical glowing green, on the one screen where accepting releases somebody's money.
   On the watchlist it made "Stop watching", which is destructive, the loudest thing on
   the page. base.css states the rule this broke in its own comment above `.btn.outline`:
   two glowing buttons side by side is two primary actions.

   Aliased onto `.outline` rather than given a fourth look. A template asking for
   `secondary` means "a real second action, not the primary one", which is exactly what
   `.outline` already is; inventing a new weight would put a distinction on the page that
   no template intends. Element-qualified for base.css's reason: a button must outrank
   whatever colours the links around it.

   NOT closed by this file: `views/public/listing.ejs` uses the same class for "Watch this
   home", and public pages load base.css alone. The rule has to be repeated there. */
a.btn.secondary, button.btn.secondary, .btn.secondary{background:var(--surface);
  color:var(--brand);border:1px solid var(--border-strong);box-shadow:var(--shadow-1)}
.btn.secondary:hover{border-color:var(--brand);background:var(--brand-soft);
  color:var(--on-brand-soft);filter:none}

/* ------------------------------------------------------- cards without a card head

   The watchlist builds its cards out of `.record` but without the `.record-head` wrapper
   every other card in the portal carries, so the rules that give a card its title and
   its figure never matched it. The title fell through to a browser-default bold sans
   `h3` while every other card title on the surface is display serif at 17px, and the
   price — the number the card exists for — rendered as 13px body copy, because `.price`
   is only ever styled inside a `.tile`. Said here rather than by rewrapping the markup:
   the card is correct HTML and it was the stylesheet that had the hole in it.

   Direct children only, so a card that DOES have a `.record-head` keeps its own rules
   and the two can never disagree about the same heading. */
/* The bottom margin is part of the same hole: with none, "Ask to see a property" on
   /account/viewings sat directly on the first field's label, heading and label reading as
   one line of text. */
.record > h3{font-family:var(--font-display);font-size:17px;line-height:1.3;
  letter-spacing:-.014em;margin-bottom:10px}
.record > h3 a:not(.btn){color:var(--on-surface);text-decoration:none}
.record > h3 a:not(.btn):hover{color:var(--brand)}
/* Body font and tabular, for the reason `.money` gives at the top of this file: the
   display face's naira reads as a struck-through N, and a struck-out price is the one
   misreading a watchlist cannot afford. */
.record > .price{font-family:var(--font-body);font-size:20px;font-weight:600;
  letter-spacing:-.018em;font-variant-numeric:tabular-nums;color:var(--on-surface);
  margin-top:4px}
/* The form holding "Stop watching" had no rules at all, so the button sat in default
   flow hard against the bottom of the facts panel above it. */
.inline-form{margin-top:16px}

/* ------------------------------------------- the client's project page, put in rank

   Its four section headings — "Your money", "Phases", "Inspections", "Details" — are
   `<h2 class="surface-sub">`, and `.surface-sub` is the 13px muted paragraph that sits
   under an `<h1>`. So every heading was smaller and fainter than the 17px display-serif
   card titles underneath it, and a page with four clear sections read as one stack of
   unrelated cards. Corrected for `h2` alone: on a `<p>`, which is what the class was
   written for, it is still the subline it was written as. */
h2.surface-sub{font-family:var(--font-display);font-size:18px;line-height:1.3;
  letter-spacing:-.014em;color:var(--on-surface);max-width:none}

/* A client's project card carries three facts. `.record dl`'s label-left, value-hard-
   right is right on a trustee's release card, where twelve facts have to line up down a
   column — but on a card the full width of the page it put "Type" at one end and "Build"
   at the other with 800px of nothing between a label and the word it labels, three times
   a card and twenty-five cards down /account/projects. The pattern stays; the measure is
   held to something one pair of eyes can span without moving. */
[data-surface="account"] .record dl{max-width:56ch}

/* `.step` is base.css's /build entry card: 26px of padding, a tint ground, a border and
   a lift on hover. The project page uses the same class name for a group of site
   photographs inside `.evidence`, so each group rendered as a marketing card that rose
   under a cursor it could not respond to, nested three deep inside the phase card that
   already frames it. This file's own `.step h5` rule shows what was meant: a plain
   labelled block. Scoped to the evidence, so /build keeps its cards. */
[data-surface="account"] .evidence .step{padding:0;border:0;background:none;
  box-shadow:none}
[data-surface="account"] .evidence .step:hover{box-shadow:none}

/* ------------------------------------------------------ the trustee's own desk

   Everything above is shared with the buyer's account pages and, through
   `workspacehead.ejs`, with the Ecoterra workspace. What follows is scoped to
   `data-surface="trustee"`, which every one of the seventeen trustee templates already
   sets on `<html>`, so the trustee portal can be opinionated about rank without
   deciding anything for the other two surfaces.

   The state of a record is read off the pill the template already printed. That matters:
   the alternative was a second set of classes on the article, which is a second source of
   truth about the same fact and free to disagree with the first. */

/* One brand rule down the left of every trustee masthead, and only there. On the
   overview the heading beside it is the firm's own name — the one place on this surface
   a trustee sees their organisation set as a title — so it is set as one, and the rule
   carries that treatment across to the other sixteen pages so the portal reads as one
   place rather than as sixteen. Scoped, because half the account surface has a
   `.surface-head` and half does not, and a mark that appears on some pages of a surface
   and not others is noise rather than identity. */
[data-surface="trustee"] .surface-head{position:relative;padding-left:20px}
[data-surface="trustee"] .surface-head::before{content:"";position:absolute;left:0;
  top:3px;bottom:3px;width:3px;border-radius:var(--radius-pill);
  background:var(--gradient-brand-soft)}

/* Waiting on this firm: raised, on the panel colour, with an accent edge. */
[data-surface="trustee"] .record{border-left:3px solid var(--border-strong)}
[data-surface="trustee"] .record:has(.pill.holding){border-left-color:var(--accent);
  box-shadow:var(--shadow-2)}
/* Settled or refused: flat, on the tint, and out of the way. The words and the figures
   are untouched — a finished record is still completely readable, it simply stops
   competing with the one that needs a signature. */
[data-surface="trustee"] .record:has(.pill.live){border-left-color:var(--status-complete);
  background:var(--tint);box-shadow:none}
[data-surface="trustee"] .record:has(.pill.stopped){
  border-left-color:var(--status-attention);background:var(--tint);box-shadow:none}

/* The irreversible acts — confirming a deposit, counter-authorising, recording a
   settlement, sending an invitation — are the ones whose submit is a solid button.
   Those wells come back out of the recess so the decision is visibly the decision, and
   the notes and inspections around them stay recessed. */
[data-surface="trustee"] .act:has(.btn:not(.outline):not(.quiet)){
  background:var(--surface-panel);border-color:var(--border-strong);
  box-shadow:var(--shadow-1)}
[data-surface="trustee"] .act:has(.btn:not(.outline):not(.quiet)) h4{
  color:var(--on-surface)}

/* The overview's lead band is the most important sentence on the surface — how much is
   held up, and whose. It is allowed to be bigger than the rest. */
[data-surface="trustee"] .band.attention h2{font-size:19px}
[data-surface="trustee"] .band.done h2{font-size:19px}

/* ------------------------------------------------------------- breakpoints */
/* Last in the file, always: a media query above the rule it overrides loses the
 * cascade at equal specificity, silently. */

/* ---- a draft's journey ----------------------------------------------------- */
/* Where a project that has no phases yet has actually got to. The list markup is the
   drawer's `.process`, so a step looks the same wherever somebody meets it. */
.draft-journey{border:1px solid var(--border);border-radius:var(--radius);
  background:var(--gradient-panel);padding:20px 22px;margin-top:14px}
.draft-journey .note{margin-top:0;margin-bottom:16px}
.draft-journey .process{margin-bottom:0}
.process-when{display:block;font-size:11.5px;color:var(--on-surface-subtle);margin-top:2px}
.process-do{display:inline-block;margin-top:4px;font-size:12.5px;font-weight:600}

/* ---- the conversation about a project -------------------------------------- */
/* A thread reads top to bottom, oldest first, like every other conversation somebody
   has ever had. Ecoterra's messages sit left and the client's are tinted and indented —
   but each is NAMED as well, because "which of these did I write" is not a question a
   colour should be the only answer to. */
.thread{border:1px solid var(--border);border-radius:var(--radius);
  background:var(--gradient-panel);padding:18px 20px;margin-top:14px}
.thread-head{font-size:13px;font-weight:600;color:var(--on-surface);margin-bottom:12px}
.thread-ref{font-size:10px;letter-spacing:.12em;text-transform:uppercase;font-weight:700;
  color:var(--on-surface-subtle);margin-left:8px}
.msg{padding:10px 13px;border-radius:var(--radius-small);margin-bottom:9px;max-width:80%}
.msg-them{background:var(--surface);border:1px solid var(--border)}
.msg-me{background:color-mix(in srgb,var(--brand) 9%,transparent);
  border:1px solid color-mix(in srgb,var(--brand) 22%,transparent);margin-left:auto}
.msg-who{font-size:10px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;
  color:var(--on-surface-subtle);margin-bottom:4px}
.msg-body{font-size:13px;line-height:1.6;color:var(--on-surface);white-space:pre-wrap}
.msg-form{display:flex;gap:10px;align-items:flex-end;margin-top:12px}
.msg-form textarea{flex:1 1 auto;font-family:inherit;font-size:14px;padding:10px 12px;
  border:1px solid var(--border-strong);border-radius:var(--radius-small);
  background:var(--surface);color:var(--on-surface);resize:vertical;line-height:1.5}
.msg-form textarea:focus{outline:2px solid var(--brand);outline-offset:1px;
  border-color:var(--brand)}
.msg-form .btn{flex:0 0 auto}

/* ---- the project's own head ------------------------------------------------ */
/* A status strip that never hides, and tabs that are real links. The strip is the
   condition on which tabs are safe here: the first question on this page is "does
   anything need me?", and an answer behind a tab is an answer nobody sees. */
.statstrip{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:1px;margin:18px 0 0;padding:0;background:var(--border);
  border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
.statstrip li{background:var(--surface);padding:13px 16px}
/* The accent is for a cell that WANTS something. A strip that shouted about everything
   would be a strip nobody reads. */
.statstrip li.is-live{background:color-mix(in srgb,var(--brand) 7%,var(--surface))}
.statstrip-n{display:block;font-family:var(--font-display);font-size:19px;line-height:1.15;
  color:var(--on-surface)}
.statstrip li.is-live .statstrip-n{color:var(--brand)}
.statstrip-k{display:block;font-size:11px;color:var(--on-surface-subtle);margin-top:3px}

.ptabs{display:flex;gap:2px;margin-top:20px;overflow-x:auto;
  border-bottom:1px solid var(--border);scrollbar-width:none}
.ptabs::-webkit-scrollbar{display:none}
/* Layout here, colour below. Two rules because this sheet forbids one rule doing both
   sizing and display, AND forbids defining a selector twice — so they are different
   selectors, not the same one written out again. */
.ptabs a{flex:0 0 auto;display:flex;align-items:center;gap:7px;
  padding:11px 15px;font-size:13.5px;font-weight:600;white-space:nowrap;
  border-bottom:2px solid transparent;margin-bottom:-1px}
/* Colouring links inside a container must exclude buttons, or it captures them. */
.ptabs a:not(.btn){color:var(--on-surface-muted)}
.ptabs a:not(.btn):hover{color:var(--on-surface);text-decoration:none}
.ptabs a.is-on:not(.btn){color:var(--brand)}
.ptabs a.is-on{border-bottom-color:var(--brand)}
.ptab-pill{display:inline-flex;align-items:center;justify-content:center;
  padding:1px 6px;border-radius:9px;font-size:10.5px;font-weight:700;line-height:1.5;
  background:var(--brand);color:var(--on-hero)}

/* ---- the property, on the project ------------------------------------------ */
.pgallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));
  gap:10px;margin-top:14px}
/* A flex container, so the photograph inside needs no `display` of its own — which is
   what lets its sizing rule be a sizing rule and nothing else. */
.pgallery-shot{display:flex;overflow:hidden;border-radius:var(--radius-small);
  border:1px solid var(--border);background:var(--surface-muted);aspect-ratio:4/3}
/* The first photograph earns two cells: a grid of identical squares says nothing about
   which one is the picture of the house. */
.pgallery-shot.is-lead{grid-column:span 2;grid-row:span 2}
.pgallery-shot img{width:100%;height:100%;object-fit:cover;
  transition:transform .6s cubic-bezier(.2,.7,.3,1)}
.pgallery-shot:hover img{transform:scale(1.03)}

/* ---- documents and the timeline -------------------------------------------- */
.doclist{list-style:none;margin:14px 0 0;padding:0}
.doclist li{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:13px 0;border-bottom:1px solid var(--border)}
.doc-name{font-size:14px;font-weight:600;color:var(--on-surface)}
.doc-meta{font-size:11.5px;color:var(--on-surface-subtle);margin-top:2px}

.timeline{list-style:none;margin:14px 0 0;padding:0}
.timeline li{display:grid;grid-template-columns:165px minmax(0,1fr);gap:4px 16px;
  padding:12px 0;border-bottom:1px solid var(--border)}
.timeline-when{font-size:11.5px;color:var(--on-surface-subtle);padding-top:2px}
.timeline-what{font-size:13.5px;color:var(--on-surface)}
.timeline li.is-done .timeline-what{font-weight:600}
.timeline-detail{font-size:12px;color:var(--on-surface-muted);margin-top:3px;grid-column:2}

/* A call, on the CLIENT's own conversation: an event that happened off the
   platform, not a bubble somebody typed at them (28 August 2026). */
.msg-event{margin:12px 0;padding:10px 14px;border:1px dashed var(--border-strong);
  border-radius:var(--radius-small);background:transparent}
.msg-event-head{font-size:12px;letter-spacing:.04em;opacity:.75}
.msg-event-note{font-size:13.5px;line-height:1.6;margin-top:6px}
.msg-event-by{font-size:11.5px;opacity:.7;margin-top:6px}


/* THE AUDIT TRAIL — one list

   `.audit`, not ~~`.trail`~~: portal.css already owns that name for the document
   status trail a few hundred lines above, and the suite refused the duplicate. Two
   components, two names — the same rule the drawers learned this morning., on the client's project page and the staff one.

   A rule down the left rather than a card per row: this is read as a sequence, and
   twenty bordered boxes make twenty separate things out of one history. The mark is
   coloured by the FAMILY of the event (`trail-viewing`, `trail-reservation`) so a page
   somebody is scanning under pressure groups before it is read. */
.audit{list-style:none;margin:14px 0 0;padding:0 0 0 22px;position:relative}
.audit::before{content:"";position:absolute;left:5px;top:6px;bottom:6px;width:1px;
  background:var(--border)}
.audit-row{position:relative;padding:0 0 20px}
.audit-row:last-child{padding-bottom:4px}
.audit-mark{position:absolute;left:-22px;top:5px;width:11px;height:11px;border-radius:50%;
  background:var(--surface);border:2px solid var(--border-strong)}
.audit-enquiry,.audit-client{border-color:var(--brand-muted)}
.audit-viewing{border-color:var(--status-progress)}
.audit-reservation{border-color:var(--accent)}
.audit-phase,.audit-evidence{border-color:var(--status-complete)}
/* WHO ELSE READS THIS ROW — staff surfaces only. Quiet on purpose: it is a property of
   the row, not a status, and a coordinator scanning a history should read the history. */
/* One rule, one selector: the suite refuses a selector defined twice AND a rule that does
   both sizing and visibility. `inline-block` here is neither — it is the box the padding
   needs, with no width or height beside it. */
.audit-who{display:inline-block;font-size:9.5px;letter-spacing:var(--micro-tracking);
  text-transform:uppercase;font-weight:700;padding:2px 7px;
  border-radius:var(--radius-pill);margin-left:8px;vertical-align:1px}
.audit-who.is-shared{color:var(--status-complete);
  background:color-mix(in srgb,var(--status-complete) 10%,transparent)}
.audit-who.is-internal{color:var(--on-surface-subtle);background:var(--surface-muted)}
.audit-call{border-color:var(--status-due)}
.audit-what{font-size:14px;line-height:1.5;color:var(--on-surface);font-weight:600}
.audit-detail{font-size:13px;line-height:1.65;color:var(--on-surface-muted);margin-top:3px;
  max-width:78ch}
.audit-meta{font-size:11.5px;line-height:1.6;color:var(--on-surface-subtle);margin-top:5px}
.audit-meta .ref{font-size:10.5px;letter-spacing:var(--micro-tracking);
  text-transform:uppercase;color:var(--on-surface-subtle)}
.audit-pages{display:flex;align-items:center;gap:14px;margin-top:18px;flex-wrap:wrap}
.audit-pages .note{margin:0}

/* The letter reader — TEMPLATE-SPEC §5, 5 Sep 2026. The letter reads as a LETTER:
   a paper frame, measured line length, the platform's own type. */
.letter-frame{background:var(--surface);border:1px solid var(--border);
  border-radius:var(--radius-small);padding:40px 44px;margin:20px 0;max-width:680px;
  font-size:16px;line-height:1.65;color:var(--on-surface)}
.letter-frame p{margin:0 0 1em;max-width:62ch}
.letter-end{color:var(--on-surface-muted);font-size:12px;letter-spacing:.12em;
  text-transform:uppercase;text-align:center;margin-top:28px}
/* The reader's layout (redesigned 6 Sep 2026): the letter as a sheet with a
   letterhead, the signing card beside it in three numbered steps. */
.letter-layout{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:24px;
  align-items:start;margin-top:8px}
.letter-sheet{margin:0;max-width:none;padding:48px 52px 40px;
  box-shadow:0 18px 40px -28px var(--shadow)}
.letter-letterhead{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
  padding-bottom:18px;margin-bottom:28px;border-bottom:1px solid var(--border)}
.letter-brand{font-family:var(--font-display);font-size:15px;letter-spacing:.02em;
  color:var(--brand)}
.letter-issued{font-size:11.5px;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  color:var(--on-surface-subtle);align-self:center}
.letter-signature{display:flex;gap:12px;align-items:baseline;margin-top:28px;padding-top:16px;
  border-top:1px solid var(--border);font-size:13px;color:var(--on-surface-muted)}
.letter-signature-mark{font-family:var(--font-display);font-size:18px;color:var(--brand)}
.sign-card{position:sticky;top:20px;background:var(--surface-panel);border:1px solid var(--border);
  border-radius:var(--radius);padding:22px 22px 18px;box-shadow:0 14px 32px -26px var(--shadow)}
.sign-card-quiet{background:var(--tint)}
.sign-lead{font-size:13.5px;line-height:1.55;color:var(--on-surface);margin:6px 0 14px}
.sign-steps{list-style:none;margin:0;padding:0;display:grid;gap:14px}
.sign-step{display:grid;grid-template-columns:28px minmax(0,1fr);gap:12px;align-items:start;
  opacity:.55;transition:opacity .2s ease}
.sign-step[data-step="read"],.sign-step.is-open{opacity:1}
.sign-step strong{display:block;font-size:13.5px;margin:4px 0 2px;color:var(--on-surface)}
.sign-step-n{display:inline-flex;align-items:center;justify-content:center;
  border-radius:50%;border:1px solid var(--border-strong);font-size:12px;font-weight:600;
  color:var(--on-surface-muted);background:var(--surface)}
.sign-step > .sign-step-n{width:28px;height:28px}
.sign-step.is-done .sign-step-n{background:var(--brand);border-color:var(--brand);
  color:var(--on-brand)}
.sign-step.is-ready .sign-step-n{border-color:var(--brand);color:var(--brand)}
.sign-step-hint{font-size:12.5px;line-height:1.5;color:var(--on-surface-muted);margin:0 0 8px}
.sign-form{display:grid;gap:8px;margin-top:6px}
.sign-code-label{font-size:12px;color:var(--on-surface-muted)}
.sign-code{font-size:24px;letter-spacing:.42em;text-align:center;font-variant-numeric:tabular-nums;
  padding:10px 0 10px .42em;border:1px solid var(--border-strong);border-radius:var(--radius-small);
  background:var(--surface);color:var(--on-surface);width:100%}
.sign-code:focus{outline:2px solid var(--brand);outline-offset:1px}
.sign-submit{width:100%;justify-content:center}
.sign-submit[disabled]{opacity:.45;cursor:not-allowed}
.sign-fine{font-size:11.5px;line-height:1.5;color:var(--on-surface-subtle);margin:16px 0 0;
  padding-top:12px;border-top:1px solid var(--border)}
.sign-record{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:6px 12px;
  font-size:13px;margin:8px 0 12px}
.sign-record dt{color:var(--on-surface-muted)}
.sign-record dd{margin:0;color:var(--on-surface)}

.letter-frame h3{font-family:var(--font-display);font-size:19px;margin:1.2em 0 .4em;
  color:var(--on-surface)}
.letter-frame ul,.letter-frame ol{margin:0 0 1em;padding-left:1.4em;max-width:62ch}
.letter-frame li{margin:0 0 .35em}
.letter-frame p a:not(.btn),.letter-frame li a:not(.btn){color:var(--brand);text-decoration:underline}

/* A document type's form, drawn for whoever completes it (TEMPLATE-SPEC §10) */
.docform{margin-top:10px}
.docform-field{margin-bottom:10px}
.docform-field label{display:block;font-size:13px;font-weight:600;margin-bottom:4px}
.docform-field .opt{font-weight:400;color:var(--on-surface-muted);margin-left:6px}
.docform-field .hint{display:block;font-size:12px;color:var(--on-surface-muted);margin-top:3px}
.docform-compact .docform-field{margin-bottom:6px}
.answers{display:grid;grid-template-columns:max-content 1fr;gap:4px 14px;margin:10px 0 0;font-size:13px}
.answers dt{color:var(--on-surface-muted)}
.answers dd{margin:0}

/* An onboarding checklist inside a band (TEMPLATE-SPEC §11) */
.checklist{margin:8px 0 6px;padding-left:1.2em;font-size:13px;line-height:1.6}
.checklist li{margin:0 0 .3em}
.checklist a:not(.btn){font-weight:600;color:var(--brand)}

/* ------------------------------------------------- the document inbox, 6 Sep 2026

   One delivery is one row; its documents are attachments on it; each opens a drawer.
   At the user's direction, replacing a card-per-document list that ran three screens
   deep for one mint of three. `views/partials/documentbatch.ejs` and
   `src/app/documentbatches.js` carry the reasoning.

   Shared by all four document lists, so nothing here is scoped to a surface. */
.batches{display:flex;flex-direction:column;gap:10px;margin-top:16px}
.batch{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}
.batch.wants{border-left:3px solid var(--accent)}
.batch-head{display:flex;align-items:center;gap:12px;padding:13px 16px;cursor:pointer}
.batch-head::-webkit-details-marker{display:none}
.batch-head:hover{background:var(--tint)}
.batch-head:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.batch-mark{position:relative;flex:0 0 auto;width:9px;height:9px;
  border-right:2px solid var(--on-surface-subtle);border-bottom:2px solid var(--on-surface-subtle);
  transform:rotate(-45deg);transition:transform .18s ease}
.batch[open] .batch-mark{transform:rotate(45deg)}
.batch-said{flex:1 1 auto;min-width:0}
.batch-title{display:block;font-family:var(--font-display);font-size:15px;line-height:1.3;
  color:var(--on-surface)}
.batch-meta{display:block;font-size:11.5px;line-height:1.5;color:var(--on-surface-muted);
  margin-top:2px}
.batch-count{flex:0 0 auto;font-size:10px;letter-spacing:var(--micro-tracking);
  text-transform:uppercase;font-weight:600;padding:4px 10px;border-radius:var(--radius-pill)}
.batch-count.is-done{color:var(--on-surface-muted);background:var(--surface-muted)}
.batch-count.is-wanting{color:var(--on-brand-soft);background:var(--brand-soft)}
/* Neither finished nor anybody's move — see the partial. Muted like `is-done` but in the
   surface's own ink, so it reads as "nothing here for you" rather than as an
   achievement. */
.batch-count.is-waiting{color:var(--on-surface-subtle);background:var(--tint)}

.attachments{list-style:none;margin:0;padding:0 16px 8px;border-top:1px solid var(--border)}
.attachment{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding:9px 0;border-bottom:1px solid var(--border)}
.attachment:last-child{border-bottom:0}
.att-name{flex:1 1 220px;font-size:13px;line-height:1.45;font-weight:600;
  color:var(--on-surface);text-decoration:none}
.att-name:hover{color:var(--brand);text-decoration:underline}
.att-state{flex:0 0 auto;font-size:11px;letter-spacing:.02em;color:var(--on-surface-muted)}
.attachment.is-wants .att-state{color:var(--accent);font-weight:600}
.attachment.is-refused .att-state{color:var(--status-attention);font-weight:600}
.att-note{flex:1 1 100%;font-size:11.5px;line-height:1.5;color:var(--on-surface-subtle)}

/* The status marks. Shape says what happened, colour says whether it still wants you;
   the word sits beside every one of them, so these are decorative and marked so. */
.att-icon{position:relative;flex:0 0 auto;width:14px;height:14px;align-self:center}
.att-icon::after{content:"";position:absolute;left:50%;top:50%}
.icon-read::after,.icon-signed::after,.icon-checked::after{width:4px;height:8px;
  margin:-6px 0 0 -3px;border-right:2px solid var(--status-complete);
  border-bottom:2px solid var(--status-complete);transform:rotate(42deg)}
.icon-sign::after,.icon-form::after,.icon-toread::after{width:8px;height:8px;
  margin:-4px 0 0 -4px;border-radius:50%;background:var(--accent)}
.icon-sent::after{width:7px;height:7px;margin:-4px 0 0 -4px;border-radius:50%;
  border:2px solid var(--on-surface-subtle)}
.icon-refused::before{content:"";position:absolute;left:50%;top:50%;width:11px;height:2px;
  margin:-1px 0 0 -5px;background:var(--status-attention);transform:rotate(45deg)}
.icon-refused::after{width:11px;height:2px;margin:-1px 0 0 -5px;
  background:var(--status-attention);transform:rotate(-45deg)}

/* The state, restated at the top of the document's own drawer. */
.att-state-line{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:600;
  color:var(--on-surface-muted);margin-bottom:14px}
.att-state-line.is-wants{color:var(--accent)}
.att-state-line.is-refused{color:var(--status-attention)}
.drawer-sub{font-size:10.5px;letter-spacing:var(--micro-tracking);text-transform:uppercase;
  color:var(--on-surface-muted);margin:20px 0 8px}

/* CHOOSING A TRUSTEE, IN CARDS — 7 September 2026, at the user's direction: the request
   drawer shows the firms "in card view" and the client may tick several.

   Cards rather than a list of radio buttons because this is a COMPARISON. Regulator,
   licence and fee across four firms is what the client is weighing, and a stack of plain
   labels makes them open four pages to find the fee — which is how somebody ends up not
   comparing at all and picking the first name.

   The whole card is the label, so the hit area is the card rather than a 13px box. */
.firm-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));
  gap:12px;margin:4px 0}
.firm-card{display:flex;flex-direction:column;gap:3px;padding:14px;
  border:1px solid var(--border);border-radius:var(--radius-small);
  background:var(--surface);cursor:pointer}
/* The tick sits with the NAME, on its own row. Floated beside a body column it landed
   level with the regulator line and read as a tick against that line. */
.firm-card-pick{display:flex;align-items:flex-start;gap:9px}
.firm-card-pick input{margin:2px 0 0;flex:0 0 auto}
.firm-card:hover{border-color:var(--border-strong)}
/* Ticked changes the border AND the ground. A card that barely changes when ticked is one
   people tick twice and then untick by accident. */
.firm-card:has(input:checked){border-color:var(--brand);background:var(--brand-soft)}
.firm-card:focus-within{outline:2px solid var(--brand);outline-offset:2px}
.firm-card-name{font-weight:700;font-size:13.5px;color:var(--on-surface)}
.firm-card-line{font-size:11.5px;color:var(--on-surface-muted)}
.firm-card-note{font-size:12px;line-height:1.5;color:var(--on-surface-muted)}
.firm-card-fee{margin-top:4px;font-size:11.5px;font-weight:700;color:var(--brand)}
/* A seeded firm, said quietly but said. */
.firm-card-fixture{margin-top:6px;font-size:11px;line-height:1.45;color:var(--status-due)}

/* The client surface has no `.drawer-acts` of its own — it lives in workspace.css, which
   an account page does not load. Same shape, so a drawer looks the same on both sides. */
.drawer-acts{display:flex;align-items:center;gap:10px;margin-top:14px}

/* THE PROPERTY THIS CASE IS ABOUT — 8 September 2026.
   Photographs on one side, the facts on the other, and the facts are the half that
   answers "which property is this?" — so they do not collapse to a caption under an
   image. In `portal.css` rather than `workspace.css`: this is the CLIENT's project page,
   and the staff surface has its own. */
.propertycard{margin-top:28px}
.propertycard-body{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);
  gap:24px;align-items:start}
/* ~~`.propertycard-cover`, `.propertycard-strip`.~~ Gone the same day they were written:
   a hand-rolled hero and thumbnail row is a PICTURE of a gallery, and the user asked for
   the gallery — *"I am unable to click on the picture and view the pictures as a carousel
   like in the listing detail."* The card now renders `partials/gallery.ejs`, which brings
   its own `.gallery*` and `.shot*` rules from `base.css` — the sheet every surface loads,
   which is why this needed no new styles at all. */
.propertycard-facts h3{font-family:var(--font-display);font-size:19px;margin:0 0 6px}
.propertycard-price{font-size:20px;font-weight:700;color:var(--on-surface);margin:0 0 14px}
.propertycard-facts .act-buttons{margin-top:16px}

/* The firm's Decline in a Requests row: the reason as a real field above its button,
   under Accept rather than squeezed beside it (walkthrough U-14, 15 Oct 2026). */
.decline-act{margin-top:10px;padding:0;border:0;background:none;min-width:220px}
.decline-act .act-fields{margin-bottom:8px}
/* A strip of words reads label first (detailhead `labelFirst`, U-13). */
.statstrip.label-first .statstrip-k{margin:0 0 4px;font-size:10px;font-weight:700;
  letter-spacing:var(--micro-tracking);text-transform:uppercase}
/* A plain list of rows in a records section: no browser bullets (U-13). */
.records ul.rows{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:8px}
.records ul.rows li{padding:10px 12px;background:var(--tint);border-radius:var(--radius-small)}


@media (max-width:900px){
  .propertycard-body{grid-template-columns:1fr}
  .review.holdings dl{grid-auto-flow:row;grid-template-rows:none;gap:14px 0}
  .review.holdings dd{font-size:17px}
}

@media (max-width:720px){
  .record dl{grid-template-columns:minmax(0,1fr)}
  .record dt{padding-bottom:0}
  .record dd{text-align:left;border-top:0;padding-top:2px}
  .review dl{grid-template-columns:minmax(0,1fr)}
  .review dt{padding-bottom:0}
  .review dd{text-align:left;border-top:0;padding-top:2px}
  .stage{grid-template-columns:26px 1fr}
  [data-surface="trustee"] .surface-head{padding-left:16px}
  .surface-head h1{font-size:24px}
  .surface-nav{gap:0}
  .surface-nav a{padding-left:10px;padding-right:10px}
  .act{padding:14px}
  .queue .q-count{font-size:20px}
}



@media (max-width:820px){
  /* base.css collapses `.acct` to one column here, and a sticky first block in a single
     column does not sit beside anything — it rides over the panels underneath it as you
     scroll. The card goes back to being an ordinary first block. */
  .acct > aside{position:static}
}

@media (max-width:620px){
  .shots{grid-template-columns:minmax(0,1fr)}
  .record{padding:16px 18px}
  .review{padding:20px}
}

/* The firm's own entry, stacked. One column below the measure where two fit — see
   `.orgset-fields` above. Down here with the other breakpoints, because a media query
   sitting above the rule it overrides loses the cascade silently; the suite asserts it. */
@media (max-width:620px){
  .orgset-fields,.orgset-fields.narrow{grid-template-columns:minmax(0,1fr)}
  /* The checklist too. Two columns of short phrases at 480px is two cramped columns,
     which is the crowding this rewrite existed to remove, reintroduced on a phone. */
  .needlist{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:900px){
  .letter-layout{grid-template-columns:1fr}
  .letter-sheet{padding:28px 22px 24px}
  .sign-card{position:static}
}

/* A decision trail on a phone: the date over the line, not beside it. */
@media (max-width:560px){
  .timeline li{grid-template-columns:minmax(0,1fr)}
  .timeline-detail{grid-column:auto}
}
