/* ==========================================================================
   PCB Transactions — the house style.

   Lifted from pcb-prototype.html, which is the source of truth for how this
   system looks as well as how it behaves. Values are the prototype's: the
   palette is sampled from the PCBMG logo and David approved it on 2026-07-29,
   so they are copied rather than reinterpreted.

   Everything here is shared. A new screen that uses .card, .pill, table and
   .sec inherits the look without adding any CSS of its own, which is the point
   of having this file at all.
   ========================================================================== */

:root{
  /* Sampled from the PCBMG logo. */
  --brand:#DC2544; --brand-d:#B81C37; --brand-l:#FBE9EC;
  --ink:#231F20; --ink2:#56514F; --ink3:#8B8482; --ink4:#B5AFAC;
  --line:#E7E2DE; --line2:#F2EEEB;
  --bg:#FAF8F6; --card:#FFFFFF;
  --ok:#1D6B45; --ok-bg:#E9F3ED;
  --pos:#437D14; --pos-bg:#F1F7E9; --pos-line:#BFD9A0;
  --warn:#8A5A18; --warn-bg:#FBF2E2;
  --info:#1D4E7A; --info-bg:#EAF1F7;
  --bad:#A61E32; --bad-bg:#FBEBEE;
  --mute-bg:#F2EEEB; --calc-bg:#F7F4F1;

  --serif:'Cormorant Garamond',Georgia,'Iowan Old Style',serif;
  --sans:'Poppins','Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;
  --display:var(--serif);
  --sh:0 1px 2px rgba(35,31,32,.04),0 4px 14px rgba(35,31,32,.05);
}

*{box-sizing:border-box;margin:0;padding:0}

body{
  background:var(--bg);
  color:var(--ink);
  font:15px/1.6 var(--sans);
  -webkit-font-smoothing:antialiased;
}

a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}

/* Figures line up in columns only if the digits are the same width. Every
   money and date cell in the system carries one of these. */
.mono,.money{font-variant-numeric:tabular-nums;font-feature-settings:'tnum' 1;letter-spacing:.01em}
/* True identifiers -- APN, escrow number, licence number -- are read character
   by character, which is the one place a monospace face earns its keep. */
.code{font-family:ui-monospace,'SF Mono',Menlo,Consolas,monospace;font-size:.94em;letter-spacing:0}

/* ---------- header ---------- */

.topbar{
  background:#fff;border-bottom:1px solid var(--line);
  padding:13px 30px;display:flex;align-items:center;gap:24px;flex-wrap:wrap;
}
.logo{display:flex;align-items:center;text-decoration:none;flex:0 0 auto}
.logo img{display:block;height:48px;width:auto}
@media(max-width:1100px){.logo img{height:40px}}
.spacer{flex:1}
.who{font-size:13px;text-align:right;line-height:1.4;font-weight:600}
.who .role{font-weight:400;color:var(--ink3)}
/* Somebody licensed for both jobs carries two titles. Separated by a middot on
   one line rather than stacked, so the topbar keeps its height whether a person
   holds one title or three. */
.who .role-sep{font-weight:400;color:var(--ink4);margin:0 4px}

/* The nav is its own band under the header, as in the prototype, so the
   current section is marked by a rule directly above the page it opens. */
/* Wraps rather than scrolling sideways. The prototype's nav was written when a
   broker saw five sections; at eleven the row is wider than the 1260px page on
   any normal laptop, and a horizontal scrollbar hides whole sections behind a
   gesture nobody thinks to try. Each item still stays on one line. */
.nav{
  background:#fff;border-bottom:1px solid var(--line);
  padding:0 30px;display:flex;gap:4px;flex-wrap:wrap;
}
.nav a{
  color:var(--ink2);padding:13px 16px;font-size:13.5px;font-weight:600;
  border-bottom:2px solid transparent;white-space:nowrap;transition:.12s;
}
.nav a:hover{color:var(--ink);text-decoration:none}
.nav a.on{color:var(--brand);border-bottom-color:var(--brand)}

/* ---------- page ---------- */

.wrap{max-width:1260px;margin:0 auto;padding:32px 30px 90px}
.wrap.narrow{max-width:430px}
/* The file list. Measured on 2026-09-05 with the 34 anonymised records: the
   table needs 1304px and a 1260px page offers it 1198px, whatever the window
   -- David: "my screen isn't the limit, the container is". 1440px: the full
   width of the window David asked about, so that window's own edge is the
   only limit there, and a cap rather than none so a 1920px monitor does not
   stretch every card to 1860px and hand the slack to the address column.
   Opted into per page through the `wrap_class` block, the way the sign-in
   pages opt into `narrow`, so no other screen moves. */
.wrap.wide{max-width:1440px}

.page-h{display:flex;align-items:baseline;gap:14px;margin-bottom:22px;flex-wrap:wrap}
h1{font-family:var(--display);font-size:33px;font-weight:600;letter-spacing:-.005em;line-height:1.1}
h2{font-family:var(--display);font-size:19px;font-weight:600}
.sub{color:var(--ink3);font-size:13.5px}
.tiny,.muted{font-size:12.5px;color:var(--ink3)}
.flag{color:var(--bad);font-size:12.5px;font-weight:600}
.back{display:inline-block;color:var(--ink3);font-size:13px;font-weight:600;margin-bottom:14px}
.back:hover{color:var(--brand);text-decoration:none}

/* ---------- cards ---------- */

/* No padding of its own: a card is a frame, and .card-b is what holds content
   away from the edge. That is what lets a table sit flush inside one. */
.card{
  background:var(--card);border:1px solid var(--line);border-radius:14px;
  margin-bottom:18px;box-shadow:var(--sh);overflow:hidden;
}
.card-h{padding:16px 20px;border-bottom:1px solid var(--line2);display:flex;align-items:center;gap:12px}
.card-h h2{font-family:var(--display);font-size:19px;font-weight:600}
.card-b{padding:20px}
.sec-edit{margin-left:auto;font-size:12.5px;font-weight:600}

/* ---------- forms ---------- */

/* Every textual control, named by what it is *not*.

   This was a list of the eight input types that happened to be in use, so any
   type not on it silently rendered as the browser's own box -- Arial, 13.3px,
   no padding, square corners, 19px tall against the 40px of the field beside
   it. `type=tel` on the participant phone and `type=search` on the lender
   filter were both missing, and both looked exactly like the unstyled
   commission readout reported on 2026-08-09. The same defect twice is a
   defective rule, not two defective fields.

   Stated as an exclusion, so a control added later is styled by default and
   only the genuinely different ones -- boxes, buttons, sliders -- opt out.

   `:where()` carries no specificity, so this selector weighs the same as a bare
   `input`. That is deliberate and load-bearing: `input[readonly]`, `input.calc`
   and `.field input` all sit above it and must keep winning. Spelling the
   `:not()`s out directly would have raised this to nine classes' worth and
   quietly repainted every readout on the site. */
input:where(:not([type=checkbox], [type=radio], [type=submit], [type=button],
  [type=reset], [type=image], [type=range], [type=color], [type=hidden])),
select,textarea{
  font:inherit;font-size:14px;padding:8px 11px;
  border:1px solid #DBD5D1;border-radius:8px;background:#fff;color:var(--ink);
}
input:focus,select:focus,textarea:focus{
  outline:0;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-l);
}
input[readonly]{background:var(--calc-bg);color:var(--ink2);border-color:var(--line)}
/* A disabled field looks disabled. It had no rule at all, so a read-only
   section rendered identically to an editable one -- the same white boxes, the
   same cursor -- and the only thing saying otherwise was the word "read-only"
   in the summary. Found on 2026-08-22 while building the Final Closing freeze,
   whose whole point is that the reader can tell.

   The same tint the calculated readouts wear, because it says the same thing:
   this is a figure to read, not a box to type in. `cursor:default` because the
   text caret over a field nothing can be typed into is an invitation. */
input:disabled,select:disabled,textarea:disabled{
  background:var(--calc-bg);color:var(--ink2);border-color:var(--line);
  cursor:default;opacity:1;
}
select{cursor:pointer}
textarea{width:100%}

.field{margin-bottom:18px}
.field>label{
  display:block;font-size:9.5px;text-transform:uppercase;letter-spacing:.16em;
  color:var(--ink3);font-weight:700;margin-bottom:6px;
}
.field input:not([type=checkbox]),.field select,.field textarea{width:100%}

/* A money box wears its dollar sign beside it rather than in its value, so what
   is typed and what is stored are only ever digits. David, 2026-08-22.
   The wrapper is what carries the field's full width now, since the input
   inside it is no longer the `.field`'s direct child. */
.money-box{display:flex;align-items:center;gap:7px;width:100%}
.money-box .pfx{color:var(--ink3);font-size:14px;font-weight:600;flex:0 0 auto}
.money-box input{flex:1 1 auto;min-width:0}

/* Two tiers of required. Red is what a file needs to count as open; amber is
   what it needs before a reviewer's hour is spent on it, and only appears once
   the red is cleared. Different hues, not different shades: an agent has to be
   able to tell them apart at a glance and one in ten cannot see red-green. */
.req{color:var(--brand);font-weight:700}
.req2{color:#C47B0A;font-weight:800}
/* Needed before the file can be cleared to disburse. A third marker rather
   than reusing the amber one: since 2026-09-05 a review no longer waits on
   the closing figures, so one asterisk cannot mean both without the legend
   telling an agent their review is blocked on a figure nobody needs yet. */
.req3{color:var(--info);font-weight:800}
.legend{
  display:flex;gap:18px;flex-wrap:wrap;align-items:center;
  font-size:12.5px;color:var(--ink2);
  padding:10px 14px;margin-bottom:18px;
  background:#FCFBFA;border:1px solid var(--line2);border-radius:9px;
}

.btn{
  background:var(--ink);color:#fff;border:0;padding:9px 18px;border-radius:9px;
  font:inherit;font-size:13.5px;font-weight:600;cursor:pointer;transition:.12s;
  display:inline-block;text-decoration:none;
}
.btn:hover{background:#000;text-decoration:none;color:#fff}
.btn.pri{background:var(--brand)}
.btn.pri:hover{background:var(--brand-d)}
/* .plain is this project's older name for the prototype's .ghost. Both are
   accepted so a template does not have to be rewritten to be restyled. */
.btn.ghost,.btn.plain{background:#fff;color:var(--ink);border:1px solid #DBD5D1}
.btn.ghost:hover,.btn.plain:hover{background:#FBF9F8;border-color:var(--ink4);color:var(--ink)}
.btn.sm{padding:6px 13px;font-size:12.5px;border-radius:7px}
.btn:disabled{opacity:.4;cursor:not-allowed}

.bar{display:flex;gap:10px;align-items:center;flex-wrap:wrap}

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

table{width:100%;border-collapse:collapse}
th{
  text-align:left;font-size:9.5px;text-transform:uppercase;letter-spacing:.16em;
  color:var(--ink3);font-weight:700;padding:12px 14px;
  border-bottom:1px solid var(--line);background:#FCFBFA;white-space:nowrap;
}
td{padding:13px 14px;border-bottom:1px solid var(--line2);vertical-align:middle;color:var(--ink)}
tbody tr:last-child td{border-bottom:0}
td.tiny,td .tiny,td.muted,td .muted{font-size:13px;color:var(--ink2)}
td.r,th.r{text-align:right}
td.mono{font-size:13.5px;color:var(--ink2);font-variant-numeric:tabular-nums}
td .money,td.money{font-size:14.5px;font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums}
tbody tr:hover{background:#FCFBFA}

.tblwrap{overflow-x:auto}
.txtbl{min-width:760px}
/* The file list's gutters, 10px a side rather than 14px. Thirteen columns
   carry 28px of padding each, 364px of the table's width, and trimming them
   is the one lever that leaves the type, the row height and every column in
   place. On this table only: `.txtbl` is shared with four others. */
.filelist th,.filelist td{padding-left:10px;padding-right:10px}

/* The approved lender list, tightened on David's instruction of 2026-08-08 so
   more of a lender fits on one line. Two steps: name, loan types and A/E come
   down a little, and email and phone come down further -- they are the longest
   values in the row and the ones that were wrapping. */
.lendertbl td{padding:9px 12px}
.lendertbl .l-name{font-size:13px;font-weight:600}
.lendertbl .l-types{font-size:12px}
.lendertbl .l-types .pill{font-size:10px;padding:2px 7px}
.lendertbl td.l-ae{font-size:12px}
.lendertbl td.l-phone,.lendertbl td.l-email{font-size:11.5px}
.lendertbl td.l-email{word-break:break-all}
.lendertbl td.l-web{font-size:12px}
/* Borrower Info: one row per person.

   It replaced a `<dl>` per borrower, which carried no margin -- so the gap
   between one person's last row and the next person's name matched the gap
   between two rows of the same person, and there was no boundary to read.
   David, 2026-08-26.

   A min-width and the wrapper's `overflow-x` rather than squeezing: eight
   columns of real values do not fit a narrow window, and a scrollbar is
   honest where a truncated email is not. */
.btbl{min-width:900px}
.btbl td{vertical-align:top}
.btbl .b-name{font-weight:600;white-space:nowrap}
.btbl .b-email{font-size:12.5px;word-break:break-all}

/* What this account's list opens on. Quiet, but permanently on the screen:
   the state a button used to imply is now simply written down. */
.defaultline{color:var(--ink3);margin:-2px 0 12px 2px}

/* A line under a People group heading, for a group whose name does not explain
   itself. Inside the card, above the table, so it reads as part of the group. */
.grpnote{padding:12px 20px 0;color:var(--ink3)}
.defaultline b{color:var(--ink2);font-weight:600}

.addr{color:var(--brand);font-weight:600}
.addr-sub{font-size:12px;font-weight:400;color:var(--ink3);margin-top:2px}

/* The street on one line, the town underneath it. Two lines per row, not four.

   `nowrap` is the default rather than the rule: an address is the thing a
   reader identifies a file by, so it is **never** clipped and never given an
   ellipsis. A street long enough to overflow wraps to a second line instead --
   David, 2026-08-26: "I'd rather one unusual row be taller than have an
   address I can't fully read." `min-width` is what lets the column take the
   width freed by dropping Pay Date / How and merging the two status pills. */
.txtbl td:first-child{min-width:230px}
.addr-street{white-space:nowrap}
@media(max-width:1180px){
  /* Below this the column cannot hold the longest streets on one line, so the
     wrap is allowed rather than the row being squeezed. Still never clipped. */
  .addr-street{white-space:normal}
}

/* Status and Workflow in one column, stacked, Status always on top. Two facts
   about one file -- where the deal is, and where the paperwork is -- kept
   separately readable rather than run together. */
.statuscell{white-space:nowrap}
.statuscell .pill{display:block;width:fit-content}
.statuscell .pill+.pill{margin-top:5px}

/* The delete control: same place in the row, quieter than a button. It is not
   an action anybody should be drawn to down a list of real files. */
.delx{
  color:var(--ink3);text-decoration:none;font-size:17px;line-height:1;
  padding:2px 6px;border-radius:6px;display:inline-block;
}
.delx:hover{color:var(--bad);background:#FDF2F2}

/* A row breaking a 3-day rule, and a checklist row still missing its document.
   Both are read at a glance down a long list, so the cue is the whole row. */
tr.oob td{background:#fffafa}
tr.oob td:first-child{box-shadow:inset 3px 0 0 var(--bad)}
tr.unmet td{background:#FDF4F4}

.empty{padding:38px;text-align:center;color:var(--ink3)}
.pager{display:flex;align-items:center;justify-content:center;gap:14px;padding:14px}

/* ---------- list controls ---------- */

.listctl{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:12px 16px;border-bottom:1px solid var(--line2);background:#FCFBFA;
}
.seg{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.seg .btn.on{background:var(--brand);border-color:var(--brand);color:#fff}
.seg .btn.on:hover{background:var(--brand-d);border-color:var(--brand-d);color:#fff}

/* ---------- file-list filter bar ----------
   Three rows: period chips (.listctl above), the three most-used controls,
   and the rest behind a disclosure. Tokens only -- no colours of its own --
   so it follows the brand rather than pinning a copy of it. */
.filterbar{padding:12px 16px;border-bottom:1px solid var(--line2);background:#FCFBFA}
.filterrow{display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap}
/* The second, disclosed row. Named `more` rather than `wrap`: `.wrap` is the
   page container, and a row that carried its name inherited its max-width and
   its 90px of bottom padding. 2026-09-05. */
.filterrow.more{padding-top:10px}
.filterbar .f{display:flex;flex-direction:column;gap:4px}
.filterbar .f.grow{flex:1;min-width:220px}
.filterbar .f.actions{flex-direction:row;gap:7px;margin-left:auto}
.filterbar input[type=text],
.filterbar input[type=search],
.filterbar input[type=month],
.filterbar .sel{
  padding:6px 9px;border:1px solid var(--line);border-radius:7px;
  background:#fff;color:var(--ink);font:inherit;font-size:13px;
}
.filterbar input:focus,.filterbar .sel:focus{
  outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-l);
}
.morefilters{margin-top:10px}
.morefilters>summary{
  cursor:pointer;color:var(--ink2);display:flex;align-items:center;gap:7px;
  width:max-content;user-select:none;
}
.morefilters>summary:hover{color:var(--brand)}
.hidden-form{display:none}

/* Narrow screens: the actions stop hugging the right and the search box stops
   being squeezed to nothing beside two dropdowns. */
@media (max-width:720px){
  .filterbar .f.actions{margin-left:0;width:100%}
  .filterbar .f.grow{min-width:100%}
}

/* ---------- stat boxes ---------- */

/* Three or four short facts in a row. Used by the agent's "My Week" strip. */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:13px;margin-bottom:18px}
.stat{
  background:var(--card);border:1px solid var(--line);border-radius:11px;
  padding:15px 17px;box-shadow:0 1px 2px rgba(35,31,32,.04);
}
.stat .k{
  font-size:9.5px;text-transform:uppercase;letter-spacing:.16em;
  color:var(--ink3);font-weight:700;
}
.stat .v{
  font-family:var(--display);font-size:29px;font-weight:600;margin-top:5px;
  font-variant-numeric:tabular-nums;line-height:1;
}
/* A date is longer than a count and would otherwise wrap out of the box. */
.stat .v.date{font-size:19px;padding-top:4px}
.stat .v.bad{color:var(--bad)}
.stat .v.warn{color:var(--warn)}
.stat .d{font-size:11.5px;color:var(--ink4);margin-top:5px}

/* ---------- loan type programs ---------- */

/* Jumped to from the page header, so it should not land flush against the top
   of the window with no air above it. */
#loan-programs{scroll-margin-top:14px}

/* A row each rather than a chip each, because each one is renameable in place
   and a text box does not fit in a chip. */
.proglist{margin-bottom:14px}
.progrow{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:7px 0;border-top:1px solid var(--line);
}
.progrow:first-child{border-top:0}
.progname{display:flex;align-items:center;gap:7px}
.progname input{max-width:230px}
.progcount{color:var(--ink3);font-size:12px;min-width:82px}
/* Retired reads as retired wherever it appears, rather than simply vanishing. */
.progrow.retired .progname input{color:var(--ink3);font-style:italic}

/* ---------- status pills ---------- */

/* Three facts on one line under the title: reviews owed, payouts owed, and
   whether the nightly job is alive. Pills since 2026-09-05; they were three
   full-width cards, and on the usual day -- nothing waiting, job ran -- the
   cards spent 385px saying so and pushed the list below the fold. The row is
   25px tall when quiet, 30px when a pill has something to say (measured).

   The negative top margin tucks the row under the title, inside .page-h's own
   22px margin, so it reads as part of the heading rather than a band of its
   own. */
.statusrow{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:-8px 0 18px}

/* Quiet: the same family as .pill beside the title, outlined rather than
   filled and in grey, because a zero is not news. The value sits a shade
   darker than its label so the eye finds it without the pill shouting. */
.spill{
  display:inline-flex;align-items:center;gap:8px;
  font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.11em;
  color:var(--ink3);border:1px solid var(--line);border-radius:20px;
  padding:4px 12px;background:transparent;text-decoration:none;white-space:nowrap;line-height:1.6;
}
.spill .n{font-variant-numeric:tabular-nums;color:var(--ink2)}
a.spill:hover{border-color:var(--ink3);color:var(--ink2);text-decoration:none}

/* Something to say: filled, bordered, a size up, and a sentence rather than a
   label and a number. Only the pill with the news changes. Three colours for
   three meanings -- red is a rule broken (the compliance pill), blue is work
   waiting, amber is something that stopped running. David, 2026-09-05: work
   waiting must not look like a breach sitting six inches away. */
.spill.act,.spill.late{
  text-transform:none;letter-spacing:0;font-size:12.5px;font-weight:600;padding:4px 14px;
}
.spill.act{background:var(--info-bg);border-color:var(--info);color:var(--info)}
a.spill.act:hover{background:#DCE8F2;border-color:var(--info);color:var(--info)}
.spill.late{background:var(--warn-bg);border-color:#E6D3AC;color:var(--warn)}
a.spill.late:hover{background:#F5E8CB;border-color:var(--warn);color:var(--warn)}

/* How long a cleared file's agent has been owed, under its workflow pill on
   the list. The queue's figure, moved onto the rows when the queue became a
   pill. Amber past the office's threshold -- the same signal the review queue
   uses for a review running out of time: one colour, one meaning. */
.waitline{display:block;margin-top:4px;font-size:11.5px;color:var(--ink3);font-variant-numeric:tabular-nums}
.waitline.over{color:var(--warn);font-weight:700}

/* ---------- my details ---------- */

/* A box the office still needs filled, on the agent's own record. Amber, the
   colour of work waiting, never the red of a rule broken: a blank DRE number
   is a reminder, not a breach. David, 2026-09-05. */
.needs-filling label{color:var(--warn)}
.needs-filling .flag{color:var(--warn);font-weight:600}
.needs-filling input{border-color:#E6D3AC}

/* ---------- period cards ---------- */

/* RE and Loan side by side rather than averaged. They are separate businesses
   under one company, and the mix is the only reason anyone reads these. */
.pcards{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:0 0 18px}
/* Stacked below 1000px, not 820px, because House fees and Paid to associates
   are exact to the cent as of 2026-08-27 and exact figures are longer.

   Measured rather than guessed. Two cards sharing the row leaves this much for
   each of the three figure columns, against $123,456.78 at 80px and
   $1,234,567.89 at 95px in 12.5px tabular-nums:

       1260px viewport -> 141px    1000px -> 98px
       1100px viewport -> 114px     900px -> 81px    830px -> 69px

   So 821-1000px was a band where the figures did not fit and the old
   breakpoint put the worst case -- 69px of column for a 73px number -- right
   above it. Stacking earlier gives a full-width card 197px per column there.
   David asked to be told rather than guessed at if it got tight: it did, this
   is the arithmetic, and the band is now gone rather than narrowed. */
@media(max-width:1000px){.pcards{grid-template-columns:1fr}}
.pcard{
  background:var(--card);border:1px solid var(--line);border-radius:11px;
  padding:15px 17px;box-shadow:0 1px 2px rgba(35,31,32,.04);
}
.pcard .pc-h{
  font-size:12px;font-weight:650;text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink3);margin-bottom:2px;
}
/* What the card counts, in words, under the heading. The card and the list
   disagreed by two files once and nothing on screen said why. */
.pcard .pc-sub{color:var(--ink4);margin-bottom:9px}
.pc-tbl{
  /* 78px holds $89,204.55 with slack. A floor rather than a fixed width: it is
     what stops a long label crushing the figures into each other, and above
     1000px the fraction is what actually applies. */
  display:grid;grid-template-columns:auto repeat(3,minmax(78px,1fr));
  gap:0 8px;font-variant-numeric:tabular-nums;
}
.pc-tbl>div{padding:3px 0;font-size:12.5px;color:var(--ink2);text-align:right}
.pc-tbl>div.l{text-align:left;color:var(--ink3)}
.pc-tbl>div.hd{
  font-size:9.5px;text-transform:uppercase;letter-spacing:.1em;font-weight:700;
  color:var(--ink4);border-bottom:1px solid var(--line2);
  padding-bottom:5px;margin-bottom:2px;
}
/* The Total column, set off by a rule. Named .pctot rather than .tot: an
   earlier version collided with the money-input style and rendered pink. */
.pc-tbl>div.pctot{font-weight:700;color:var(--ink)}
.pc-tbl>div:nth-child(4n){border-left:1px solid var(--line2);padding-left:11px}
.pc-tbl>div.hd:nth-child(4n){padding-left:11px}
/* Every file count is a link to the filters that produced it. Underlined only
   on hover: a card of permanently underlined figures reads as a mistake, and
   the numbers have to stay scannable as numbers. */
.pc-tbl a.pclink{color:inherit;text-decoration:none;border-bottom:1px dotted var(--line2)}
.pc-tbl a.pclink:hover{color:var(--brand);border-bottom-color:var(--brand)}

/* ---------- pipeline board ---------- */

.board{display:grid;grid-template-columns:repeat(5,minmax(178px,1fr));gap:12px;overflow-x:auto}
.col-h{
  font-size:9.5px;text-transform:uppercase;letter-spacing:.16em;color:var(--ink3);
  font-weight:700;padding:0 4px 10px;display:flex;justify-content:space-between;gap:8px;
}
.tile{
  display:block;background:#fff;border:1px solid var(--line);border-radius:11px;
  padding:13px 14px;margin-bottom:10px;box-shadow:var(--sh);transition:.12s;
  color:var(--ink);text-decoration:none;
}
.tile:hover{border-color:var(--ink4);transform:translateY(-1px);text-decoration:none}
.tile .a{font-family:var(--display);font-weight:600;font-size:16px;color:var(--ink);margin-bottom:2px}
.tile .m{
  display:flex;justify-content:space-between;gap:8px;margin-top:8px;
  font-size:12.5px;color:var(--ink2);font-variant-numeric:tabular-nums;font-weight:500;
}
/* Amber edge: a review that has been open too long. Red edge: a 3-day rule
   broken. Red wins -- a file can be both, and the compliance breach is the one
   with a deadline attached. */
.tile.stale{border-left:3px solid var(--warn)}
.tile.oob{border-left:3px solid var(--bad);background:#fffafa;border-color:#f0c9cd}
.tile .oobtag{display:block;margin-top:7px;font-size:11px;font-weight:700;color:var(--bad)}

/* The review queue reuses the board's tiles, laid out as a grid rather than a
   column. Same component, different arrangement. */
.queue{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:12px}
.queue .tile{margin-bottom:0}
.officers{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}
.officers .tile{margin-bottom:0}
.officers .tile .a{font-size:19px;font-weight:700}

/* The × inside a chip. A button rather than a link, because removing something
   is a POST and a link that changes data is a link somebody can be walked into. */
.chipx{
  background:none;border:0;padding:0 0 0 4px;cursor:pointer;
  color:inherit;font-weight:800;font-size:inherit;line-height:1;
}

/* ---------- email chooser ---------- */

/* Most of the office lives in webmail, where a mailto: opens whatever the
   machine was set up with years ago -- usually nothing. */
.emenu{
  position:absolute;z-index:60;background:#fff;border:1px solid var(--line);
  border-radius:10px;box-shadow:0 10px 30px rgba(35,31,32,.17);
  padding:6px;min-width:196px;font-size:13px;
}
.emenu .emenu-h{
  font-size:11px;color:var(--ink3);padding:5px 9px 7px;
  border-bottom:1px solid var(--line2);margin-bottom:4px;
  word-break:break-all;font-weight:600;
}
.emenu a,.emenu button{
  display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  padding:7px 9px;border-radius:7px;color:var(--ink);text-decoration:none;
  background:none;border:0;font:inherit;cursor:pointer;
}
.emenu a:hover,.emenu button:hover{background:#faf9fa;text-decoration:none}

/* ---------- checklist upload panel ---------- */

/* One row per document, opening onto its files, its note and the upload box.
   A <details> rather than script: the browser already does this. */
.doc{border-bottom:1px solid var(--line2)}
.doc:last-child{border-bottom:0}
.doc>summary{
  display:flex;align-items:center;gap:10px;padding:11px 4px;cursor:pointer;
  list-style:none;font-size:13.5px;
}
.doc>summary::-webkit-details-marker{display:none}
.doc>summary::before{
  content:"";flex:0 0 auto;width:0;height:0;
  border:4px solid transparent;border-left-color:var(--ink4);
  transition:transform .12s ease;
}
.doc[open]>summary::before{transform:rotate(90deg) translateX(-1px)}
.doc .dt{flex:1;font-weight:600;color:var(--ink)}
.doc.unmet .dt{color:var(--bad)}
.doc.done .dt{color:var(--ink3);font-weight:500}
/* Drag to reorder a checklist template. The handle is the only draggable
   thing in the row, so selecting a title still selects text. The arrows beside
   it are not hidden: they are the keyboard path and the one that survives a
   page with no scripting. */
.grip{color:var(--ink4);cursor:grab;letter-spacing:-3px;user-select:none;font-size:15px}
tr.dragging{opacity:.45;background:#F4F7FB}

/* Visually hidden, still read aloud. A column of drag handles needs a heading
   that a screen reader can announce and a sighted reader does not need. */
.vh{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

.uppanel{padding:4px 4px 18px 22px}
/* Why a document is where it is, when the importer had to say. Indented under
   the filename so it reads as a note about that document and not as a row of
   its own. */
.docwhy{color:var(--ink3);margin:1px 0 0 34px}

/* The file-type badge. Three characters, so a list of attachments reads as
   what it is before any filename is parsed. */
.ficon{
  display:inline-block;min-width:34px;text-align:center;padding:2px 5px;
  border-radius:5px;background:var(--line2);color:var(--ink3);
  font-size:9.5px;font-weight:800;letter-spacing:.06em;margin-right:7px;
}
.ficon.pdf{background:#FBEAEA;color:#A32B2B}
.ficon.img{background:#EAF1FB;color:#2B5AA3}

/* ---------- list rows ---------- */

/* A plain row with a title, a line of detail and its actions on the right.
   Used by the forms library, where a table would be four columns of nothing. */
.lrow{
  display:flex;gap:14px;align-items:center;
  padding:13px 2px;border-bottom:1px solid var(--line2);
}
.lrow:last-child{border-bottom:0}
.lrow .a{font-weight:650;font-size:14.5px;color:var(--ink)}

/* The play marker beside a training video. YouTube's red, so the row reads as
   a video at a glance rather than as another download. */
.ytmark{
  flex:0 0 42px;height:30px;border-radius:6px;background:#FF0000;
  display:flex;align-items:center;justify-content:center;color:#fff;font-size:15px;
}

/* ---------- review findings ---------- */

.ritems{border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#fff;max-width:680px}
.ritem{
  display:flex;gap:10px;align-items:flex-start;padding:10px 13px;
  border-bottom:1px solid var(--line2);font-size:13px;
}
.ritem:last-child{border-bottom:0}
.ritem.done{background:#F7FAF7;color:var(--ink3)}
.ritem.done>div>div:first-child{text-decoration:line-through}
.ritem form{margin:0}

/* ---------- pills ---------- */

.pill{
  display:inline-block;font-size:9.5px;font-weight:700;text-transform:uppercase;
  letter-spacing:.11em;padding:4px 10px;border-radius:20px;white-space:nowrap;
  background:var(--mute-bg);color:var(--ink3);
}
.p-ok{background:var(--ok-bg);color:var(--ok)}
.p-warn{background:var(--warn-bg);color:var(--warn)}
.p-info{background:var(--info-bg);color:var(--info)}
.p-mute{background:var(--mute-bg);color:var(--ink3)}
.p-bad{background:var(--bad-bg);color:var(--bad)}
.pill.dual{background:var(--warn-bg);color:var(--warn)}
.dualchip{font-size:8px;padding:1px 5px;vertical-align:middle;margin-left:5px}
/* NEW ESCROW. Same geometry as .dualchip and for the same reason: it sits
   inside the address line rather than under it, so it costs no row height.
   Row height on this table is set by the address cell, which is already one
   to three lines; anything that adds a fourth was ruled out. David,
   2026-09-05: "this is a constraint, not a preference". */
.newchip{font-size:8px;padding:1px 5px;vertical-align:middle;margin-left:5px}
td .pill,th .pill{white-space:nowrap}

/* ---------- banners ---------- */

/* One shape for everything the page needs to say before the content: a rule
   down the left, the colour carrying the urgency. */
.banner,.errors,.notice{
  border-radius:0 12px 12px 0;padding:14px 18px;font-size:13.5px;
  margin-bottom:16px;box-shadow:var(--sh);
  background:var(--warn-bg);border:1px solid #E6D3AC;border-left:3px solid var(--warn);color:#6B4512;
}
.banner.bad,.errors{
  background:var(--bad-bg);border-color:#F0C9CD;border-left-color:var(--bad);color:var(--bad);
}
.banner.ok{
  background:var(--pos-bg);border-color:var(--pos-line);border-left-color:var(--pos);color:#2C5A0E;
}
.banner b{font-weight:700}
.banner ul{margin:9px 0 0 18px}
.banner li{margin-bottom:4px}
.banner .muted{color:inherit;opacity:.8}

.note{
  background:#fff;border:1px solid var(--line);border-left:3px solid var(--brand);
  padding:14px 18px;border-radius:0 12px 12px 0;font-size:13.5px;color:var(--ink2);
  margin-bottom:20px;box-shadow:var(--sh);
}

/* ---------- accordion sections ---------- */

.sec{
  border:1px solid var(--line);border-radius:13px;margin-bottom:11px;
  background:#fff;overflow:hidden;box-shadow:var(--sh);
}
.sec>summary{
  padding:15px 19px;cursor:pointer;display:flex;align-items:center;gap:11px;
  list-style:none;font-family:var(--display);font-size:18px;font-weight:600;
}
.sec>summary::-webkit-details-marker{display:none}
.sec>summary:hover{background:#FCFBFA}
.sec[open]>summary{border-bottom:1px solid var(--line2)}
.chev{
  width:7px;height:7px;flex:0 0 auto;
  border-right:1.8px solid var(--brand);border-bottom:1.8px solid var(--brand);
  transform:rotate(-45deg);transition:transform .16s;
}
.sec[open] .chev{transform:rotate(45deg)}
.sec-body{padding:22px 19px}
.sec-body>table:first-child,.sec-body>.tblwrap:first-child{margin-top:-6px}

/* ---------- definition lists ---------- */

/* The read-only counterpart of the prototype's .fields grid: same column,
   same right-aligned label, no inputs. */
dl{display:grid;grid-template-columns:225px 1fr;gap:13px 20px;align-items:baseline;max-width:820px}
dt{font-size:13px;color:var(--ink2);font-weight:500;text-align:right}
dd{color:var(--ink);font-size:14px}
@media(max-width:640px){
  dl{grid-template-columns:1fr;gap:2px 0}
  dt{text-align:left;margin-top:10px}
}

/* ---------- ledger ---------- */

/* The panel fills the section it sits in.

   It was pinned to 560px with `overflow:hidden`, which on a dual file cut the
   second transaction-fee override clean off the right-hand edge -- the row
   carries one per side, and two of them plus a label and a figure do not fit in
   528px of content box. Reported by David on 2026-08-10 as "two Override
   controls, the second clipped".

   Widening rather than shrinking the controls: the section around it is 1160px
   at 1280px of viewport, so the room was always there and the cap was the whole
   defect. `overflow:hidden` stays -- it is what keeps the rounded corners -- and
   with the width free there is nothing left for it to cut. */
.ledger{
  border:1px solid var(--line);border-radius:12px;
  overflow:hidden;margin-top:6px;background:#fff;
}
.ledger .row{
  display:flex;align-items:center;gap:12px;padding:11px 16px;
  border-bottom:1px solid var(--line2);font-size:13.5px;
  flex-wrap:wrap;
}
/* Every override on the panel starts at the same x, whatever the row's label
   says and however many the row carries. A fixed column rather than whatever
   the flex line has left over, which is what made each row's controls land in a
   different place.

   The column is as wide as a *ticked* override, not an untouched one. It was
   268px -- room for the switch and the figure, and none for the written reason
   that appears beside them the moment the switch goes on. So the reason box hung
   413px into a 268px column and the panel's `overflow:hidden` cut its right-hand
   edge off. Reported by David on 2026-08-21 on a loan file's Transaction fee row,
   and it was never about loans: every override on this ledger that carries a
   reason did it, on every file type, and the dual-fee fix of Round 4 measured
   only the unticked state.

   434px is what the row holds: 112 switch + 7 + 118 figure + 7 + 190 reason. The
   label beside it has 511px left at the panel's 1160px, which is four times what
   the longest of them needs. `max-width` keeps the column from outgrowing a
   narrower panel rather than reintroducing the same clipping at a smaller size. */
.ledger .row .ovrs{
  flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-start;
  gap:6px;width:434px;max-width:100%;
}
/* A note belongs under its row rather than beside it: `flex-basis:100%` puts it
   on its own line, and `nowrap` keeps "both sides added together: $12,960.00
   listing + $8,640.00 selling" on one, which is how it reads as one fact. */
.ledger .row .rownote{
  flex:1 0 100%;margin-top:6px;font-size:11.5px;color:var(--ink3);
  white-space:nowrap;overflow-x:auto;
}
.ledger .row .rownote.muted{opacity:.7}
/* What Total deductions is made of, listed under it. Separated by a wide gap
   rather than punctuation, so two parts read as two facts and one part does not
   trail a stray comma. Inherits `nowrap` from `.rownote`, and scrolls inside its
   own row if a description is long -- which is the ledger's existing answer for
   a note wider than the panel, and keeps it out of the panel's own overflow. */
.ledger .row .deduction-parts{display:flex;gap:22px}
.ledger .row .deduction-parts .part{white-space:nowrap}
.ledger .row:last-child{border-bottom:0}
.ledger .row.sum{background:#FCFBFA;font-weight:700;border-top:1px solid var(--ink)}
.ledger .row .op{color:var(--brand);width:13px;text-align:center;font-weight:700;flex:0 0 auto}
.ledger .row .lbl{flex:1;color:var(--ink2)}
.ledger .row.sum .lbl{color:var(--ink)}
/* Fixed rather than a minimum, so the override column beside it starts at the
   same x on every row. With `min-width` a wider figure -- $12,960.00 against
   $598.00 -- pushed its own row's controls further right than the row above,
   which is what "align every Override input to a common column" was about. */
.ledger .row .val{
  font-variant-numeric:tabular-nums;flex:0 0 132px;text-align:right;
  font-size:14.5px;font-weight:500;color:var(--ink);
}
.ledger .row.sum .val{font-weight:700}

/* A calculated readout: the same size and weight as the money it reports, and
   visibly not an input. It had no rule at all, so it rendered as the browser's
   default text box -- small, square and narrower than every field above it,
   while holding the most important figure on the screen.

   The `max-width` that first rule carried is gone. It left the box 260px wide
   against the 1160px of every other field on the section, so the figure still
   read as an afterthought beside the boxes it is the point of -- reported by
   David twice, and measured on the live screen on 2026-08-09. A readout now
   fills its field exactly as an input does; what marks it as calculated is the
   weight, the tinted ground and the absence of a focus ring. */
input.calc{
  font-size:17px;font-weight:700;font-variant-numeric:tabular-nums;
  color:var(--ink);background:var(--calc-bg);
  border:1px solid var(--line);border-radius:9px;
  padding:11px 14px;width:100%;
}

/* The dollars belonging to the rate directly above them. Indented and set a
   size down from the readout it echoes, so it reads as an answer to the box it
   sits under rather than as another question. */
.under{margin-top:8px;padding-left:13px;border-left:2px solid var(--line2)}
.under>label{
  display:block;font-size:9.5px;text-transform:uppercase;letter-spacing:.16em;
  color:var(--ink3);font-weight:700;margin-bottom:5px;
}
.under input.calc{font-size:15px;padding:9px 12px}
/* Read-only, so it takes no focus ring: a ring invites typing into a figure
   that is calculated, and the way to depart from it is the override beside it. */
input.calc:focus{outline:none;border-color:var(--line)}

/* An override sits beside the figure it replaces, behind its own checkbox. It
   is dimmed until the checkbox is ticked, so a row of them reads as "these are
   calculated" rather than as seven boxes asking to be filled in. */
/* `width:100%` fills the column above rather than being sized by whatever the
   browser thinks a text input is worth. That intrinsic width was the other half
   of the clipping: the reason box measured 169px from its `size` attribute, not
   the 190px its own rule allows, so the arithmetic that produced the 268px
   column and the width the box actually took were two different numbers. */
.ovr{display:flex;align-items:center;gap:7px;flex:0 0 auto;width:100%}
/* Fixed, so the box beside it starts in the same place on every row -- and wide
   enough for "Listing side" and "Selling side", which is what the two fees on a
   dual file are called now that they are told apart. */
.ovr .ovr-switch{
  display:flex;align-items:center;gap:4px;white-space:nowrap;
  color:var(--ink3);cursor:pointer;font-weight:600;
  flex:0 0 auto;width:112px;
}
.ovr input:disabled,.ovr textarea:disabled{background:var(--mute-bg);color:var(--ink3)}
.ovr input:not([type="checkbox"]){max-width:118px;font-size:12.5px;padding:4px 7px}
.ovr .ovr-why{display:none}
/* Takes the room the switch and the figure leave, and no more. `min-width:0` is
   what lets it shrink below the input's intrinsic width on a narrow panel --
   without it a flex item refuses to go under its content size and pushes the
   overflow back out through the side of the ledger. */
.ovr.on .ovr-why{display:inline-flex;flex:1 1 auto;min-width:0}
.ovr.on .ovr-why input{width:100%;max-width:190px}
.ovr.on .ovr-switch{color:var(--brand)}
/* Both boxes say what they are. Light gray, so a placeholder reads as a prompt
   and never as a value somebody has already typed. */
.ovr input::placeholder{color:var(--ink3);opacity:.75;font-weight:400}

/* The Save at the head of a section. Set apart from the fields under it by a
   rule, so it reads as belonging to the section rather than as its first row. */
.sec-save{
  margin:0 0 16px;padding-bottom:14px;
  border-bottom:1px solid var(--line2);
}

/* The review's status boxes, as the legacy Review Info panel shows them. Ticked
   by the actions that cause them, never by hand, so these are marks rather than
   inputs -- drawn square to read as the checkboxes they replace. */
.rstates{
  display:flex;flex-wrap:wrap;gap:8px 22px;margin-top:16px;
  padding-top:14px;border-top:1px solid var(--line2);
}
.rstate{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--ink3)}
.rstate-box{
  width:15px;height:15px;flex:0 0 auto;border:1px solid var(--line);border-radius:3px;
  background:#fff;display:flex;align-items:center;justify-content:center;
  font-size:11px;line-height:1;color:var(--ok);font-weight:700;
}
.rstate.on{color:var(--ink);font-weight:600}
.rstate.on .rstate-box{border-color:var(--ok);background:#E4F0E9}

/* Present for screen readers, out of the way visually: the tick alone carries
   no text, so each box states its own yes or no. */
.visually-hidden{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ---------- workflow rail ---------- */

/* Chevrons rather than blocks: the file moves left to right and the shape
   says so without a caption. The arrow is a border triangle hanging off the
   right edge, which is why every step needs the same height. */
.rail{display:flex;align-items:stretch;overflow-x:auto;padding:2px 0;margin:22px 0}
.step{
  flex:1;min-width:112px;min-height:46px;position:relative;
  padding:12px 9px 12px 22px;background:var(--mute-bg);color:var(--ink3);
  font-size:11px;font-weight:700;line-height:1.35;
  text-transform:uppercase;letter-spacing:.07em;display:flex;align-items:center;
}
.step:first-child{border-radius:9px 0 0 9px;padding-left:14px}
.step:last-child{border-radius:0 9px 9px 0}
.step::after{
  content:"";position:absolute;right:-12px;top:0;width:0;height:0;z-index:2;
  border-left:12px solid var(--mute-bg);
  border-top:23px solid transparent;border-bottom:23px solid transparent;
}
.step:last-child::after{display:none}
.step.done{background:#E4F0E9;color:var(--ok)}
.step.done::after{border-left-color:#E4F0E9}
.step.now{background:var(--brand);color:#fff}
.step.now::after{border-left-color:var(--brand)}

/* ---------- reporting charts ----------

   The four charts at the top of admin reporting, from
   `reportingchartoption-a.html`.

   **The series hexes are the mockup's, verbatim.** They are validated for
   colourblind separation against both a light and a dark surface, which is not
   a property that survives being re-picked by eye. Everything around them --
   surfaces, rules, type, spacing -- is the app's own, because the mockup is a
   standalone design study carrying a second design system (Source Sans 3,
   JetBrains Mono, its own accent) and importing that into one page would leave
   this screen looking like a different product.

   **The dark values are defined and deliberately inert.** David asked for dark
   mode on the OS setting and the theme toggle; the app has neither -- there is
   no `prefers-color-scheme` block anywhere in this file and no `data-theme`
   attribute set by any template or script. Wiring these to
   `prefers-color-scheme` alone would hand a reader on a dark OS a dark chart
   panel sitting on the app's light page, which is worse than not doing it. So
   they hang off `[data-theme="dark"]`, which nothing sets today: ready for an
   app-wide dark mode and doing nothing until there is one. */
:root{
  --series-1:#2a78d6;  /* real estate */
  --series-2:#eb6834;  /* loans */
  --series-3:#1baf7a;  /* house fees */
  --series-4:#4a3aa7;  /* paid to associates */
}
:root[data-theme="dark"]{
  --series-1:#3987e5; --series-2:#d95926; --series-3:#199e70; --series-4:#9085e9;
}

/* The page's own card padding, not a number chosen for this card. `.card` itself
   carries none -- `.card-h` and `.card-b` supply it at 20px -- and this section
   has neither of those wrappers, so its contents sat flush against the border
   while every other card on the page was inset. Symmetric on purpose: David,
   2026-08-28, asked for left and right to match rather than be picked apart. */
.chartcard{padding:20px}
.chart-head{margin-bottom:14px}
.chart-head h2{font-family:var(--display);font-size:19px;font-weight:600}
.chart-head .tiny{display:block;margin-top:2px}

.chips{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 16px}
.chips .chip{
  font-size:13px;font-weight:600;padding:6px 14px;border-radius:999px;
  border:1px solid var(--line);background:transparent;color:var(--ink2);
  text-decoration:none;display:inline-block;
}
.chips .chip:hover{border-color:var(--ink4)}
.chips .chip.on{background:var(--brand);border-color:var(--brand);color:#fff}

/* Stands where the chip row would be, so the section keeps its rhythm when
   there is only one period to show. */
.onlyperiod{margin:0 0 16px}

/* The one line an empty year shows, between the totals and the charts. */
.noclosed{margin:0 0 12px;color:var(--ink3)}

/* One row of four above the charts. Two up on a narrow window rather than four
   squeezed: these are the figures the charts are read against. */
.ctotals{
  display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:8px;overflow:hidden;margin:0 0 20px;
}
@media(max-width:820px){.ctotals{grid-template-columns:repeat(2,1fr)}}
.ctot{background:var(--card);padding:12px 15px 11px}
.ctot-l{font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink3);font-weight:700}
.ctot-v{font-size:20px;font-weight:600;font-variant-numeric:tabular-nums;margin-top:3px;color:var(--ink)}
.ctot-s{font-size:12px;color:var(--ink3);margin-top:1px}

.chartgrid{display:grid;grid-template-columns:1fr 1fr;gap:18px}
@media(max-width:820px){.chartgrid{grid-template-columns:1fr}}
.chartbox{min-width:0}
.chart-title{font-size:14.5px;font-weight:600;color:var(--ink)}
.chart-sub{font-size:12.5px;color:var(--ink3);margin-top:1px}

.clegend{display:flex;gap:15px;flex-wrap:wrap;margin:9px 0 6px;min-height:17px}
.clegend span{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--ink2)}
.swatch{width:11px;height:11px;border-radius:2px;display:inline-block}
.swatch.s1{background:var(--series-1)}
.swatch.s2{background:var(--series-2)}
.swatch.s3{background:var(--series-3)}
.swatch.s4{background:var(--series-4)}

.chartbox svg{display:block;width:100%;height:auto;overflow:visible}
.cgrid{stroke:var(--line);stroke-width:1}
.caxis{font-family:var(--sans);font-size:11px;fill:var(--ink3)}
.caxis.mono{font-variant-numeric:tabular-nums}
.cempty{font-family:var(--sans);font-size:12px;fill:var(--ink4)}
.cbar{transition:opacity .12s}
.cbar:hover{opacity:.78}
.cbar.s1{fill:var(--series-1)}
.cbar.s2{fill:var(--series-2)}
.cbar.s3{fill:var(--series-3)}
.cbar.s4{fill:var(--series-4)}

/* Follows the pointer, so it never covers the bar it describes. `position:fixed`
   because the SVG scales and an absolutely positioned tip inside it would scale
   with the bars. */
.ctip{
  position:fixed;pointer-events:none;z-index:60;background:var(--ink);color:var(--bg);
  font-size:12.5px;line-height:1.45;padding:8px 11px;border-radius:6px;opacity:0;
  transition:opacity .1s;white-space:pre-line;box-shadow:0 6px 20px -8px rgba(35,31,32,.5);
}

.cnumbers{margin-top:18px;border-top:1px solid var(--line2);padding-top:12px}
.cnumbers summary{font-size:13px;color:var(--ink2);cursor:pointer}
.cnumbers table{margin-top:10px;font-size:12.5px}
.cnumbers td,.cnumbers th{padding:6px 10px}


/* ---- sortable table headings -------------------------------------------
   The indicator is on the heading rather than in it: a caret added as text
   would be picked up by `textContent`, which is the sorter's fallback key.
   David, 2026-09-03: the sorted column and its direction must be obvious at a
   glance rather than something he has to remember.
------------------------------------------------------------------------- */
th.sortable {
  cursor: pointer;
  user-select: none;
  position: relative;
}
th.sortable:hover {
  color: var(--brand);
}
th.sortable::after {
  content: "\2195";           /* up-down arrow: sortable, not yet sorted */
  opacity: .28;
  margin-left: 5px;
  font-size: .85em;
}
th.sortable[data-sorted="ascending"]::after {
  content: "\2191";
  opacity: 1;
}
th.sortable[data-sorted="descending"]::after {
  content: "\2193";
  opacity: 1;
}
th.sortable[data-sorted] {
  color: var(--brand);
}
th.sortable:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -2px;
}

/* The headline stat that is no longer abbreviated needs to be allowed to be
   longer than the folded figures beside it. */
.stat .v.exact {
  font-size: .92em;
  letter-spacing: -.01em;
}

/* Editing review text in place. Added 2026-09-05, when findings and the review
   notes became correctable after saving -- the notes had been rendered on the
   file screen and writable by nobody since the field was created. */
.finding-text{
  width:100%;font:inherit;font-size:13.5px;line-height:1.45;padding:7px 9px;
  border:1px solid var(--line);border-radius:6px;background:#fff;resize:vertical;
}
.finding-edit{display:flex;flex-direction:column;gap:6px;align-items:flex-start}
