/* Servicing Console — typography and scale taken from Servicing Console
   Mockup.html verbatim, not reinterpreted:
     body 13.5px · h1 19px · table 12.7px · th 10.5px/700/uppercase/.3px
     td padding 9px 14px · card radius 12px · chip 700 weight, radius 20px
   Palette is the finalized brand (sampled from the logo), which replaces the
   mockup's #2E4A3A green. Everything else visual follows the mockup. */
:root{
  --olive:#444733; --olive2:#565a40; --sage:#B5C696; --mint:#DAEEEB; --gold:#c79a3e;
  --bg:#eef3f0; --paper:#fff; --ink:#233029; --muted:#6a776f; --line:#e2ebe5;
  --pos:#2f7d54; --posbg:#e3f1e7; --red:#b4442f; --redbg:#fbe0e0;
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  /* THE APP TILE. What the family shares is the LINE-ART LANGUAGE and the
     tile geometry -- Front Porch's 64-unit square with rx=14, 14/64 = 21.9%,
     and a mark inset 9 -- not the fill. Each app keeps its own colour:
     Front Porch olive, the Sales CRM gold, the Console green. So the tile
     stays the sage it has always been.

     THE MARK IS FILLED, so it carries its own two colours rather than
     inheriting one. --tile-fg is gone with the stroke it drove. The mountain
     is 9.52:1 on sage; the sun is 1.12:1 by luminance and reads on HUE -- a
     saturated yellow on a desaturated green -- which is why the test below
     measures the mountain and checks the sun by its distance in hue and
     saturation rather than pretending a contrast ratio describes it. */
  --tile-bg:var(--sage); --tile-radius:21.9%;
  --mark-rock:#1a1a1a; --mark-sun:#F5C518;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--font);
  -webkit-font-smoothing:antialiased;font-size:13.5px}
/* ---- shell ---- */
.top{background:var(--olive);color:#fff;display:flex;align-items:center;gap:12px;padding:11px 18px}
.top img{width:28px;height:auto;display:block}
.brand{font-weight:700;font-size:15px}
.top .sep{opacity:.4}
/* Same weight as the wordmark beside it: bold to bold. */
.top .sub{opacity:.85;font-size:13px;font-weight:700}
.top .right{margin-left:auto;display:flex;align-items:center;gap:10px;font-size:11.5px}
.pill{border-radius:20px;padding:4px 11px;font-size:11px;font-weight:700}
.search{margin-left:auto;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.22);
  border-radius:8px;padding:6px 12px;color:#eaf3ef;font-size:12.5px;width:230px}
.search::placeholder{color:rgba(255,255,255,.6)}
.avatar{width:26px;height:26px;border-radius:50%;background:rgba(255,255,255,.2);display:flex;
  align-items:center;justify-content:center;font-size:12px;font-weight:700}
.pill.live{background:#7fb08e;color:#12301f}
.pill.dry{background:var(--gold);color:#fff}
.wrap{display:flex;min-height:calc(100vh - 50px)}
/* Sidebar — the mockup's .rail, matched rule for rule. */
.rail{width:196px;background:#fff;border-right:1px solid var(--line);padding:12px 8px;flex-shrink:0}
/* HIERARCHY, THE RIGHT WAY UP. The group headings were 10px, normal weight
   and muted, sitting above items at 13px, weight 600 and near-black -- so
   SERVICING read as a caption for the list rather than the name of it, and
   every submenu was louder than its own heading. The heading is now the
   largest and heaviest thing in the rail; the items are lighter and indented
   under it, so the level is visible from shape as well as from weight. */
.rail .grp{font-size:13px;text-transform:uppercase;letter-spacing:.6px;
  font-weight:800;color:var(--olive);margin:18px 10px 6px}
.rail .grp:first-child{margin-top:4px}
.rail a{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:8px;margin-left:8px;color:#3a463e;
  text-decoration:none;font-size:13px;cursor:pointer;font-weight:500}
.rail a.on{background:#e7f0ea;color:var(--olive);font-weight:650}
.rail a:hover{background:#f1f6f2}
/* THE ICON HAS A SIZE WHEREVER IT IS USED.
   `.ic` was only sized under `.rail`, and an <svg> with a viewBox and no
   width falls back to the replaced-element default -- so the export hub's
   section icons rendered enormous. Rose reported them as "too big"; they were
   not styled at all. This is the base rule; the rail keeps its own size. */
.ic{width:15px;height:15px;flex-shrink:0;display:inline-flex;align-items:center;
    justify-content:center;vertical-align:-2px;color:var(--olive2)}
.ic svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:1.7;
        stroke-linecap:round;stroke-linejoin:round}
/* A section heading's icon sits with the words, not above them. */
.panel-hd h3 .ic,.hd h3 .ic{margin-right:7px;color:var(--olive)}
.rail .ic{width:17px;height:17px;flex-shrink:0;display:flex;align-items:center;justify-content:center;color:var(--olive2)}
.rail a.on .ic{color:var(--olive)}
.rail .ic svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.main{flex:1;padding:22px 24px 60px;min-width:0;max-width:1180px}
h1{font-size:19px;margin:0 0 3px;color:var(--ink);font-weight:700}
.lede{color:var(--muted);margin:0 0 16px;font-size:13px}
h2{margin:0;font-size:14px;font-weight:700}
/* ---- cards & tables ---- */
/* A ROW OF DISTINCT CARDS. auto-fit with a 180px floor collapsed to one
   column whenever the main area was narrow, which read as four stacked bands
   rather than four figures — the distinction between them is the point.
   auto-fill with a smaller floor keeps them side by side, and the shadow and
   heavier border make each one read as its own card at a glance. */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr));
  gap:12px;margin-bottom:16px;align-items:stretch}
.kpi{background:#fff;border:1px solid var(--line);border-radius:12px;padding:14px 16px;
  box-shadow:0 1px 2px rgba(20,24,18,.05);display:flex;flex-direction:column}
.kpi .n{font-size:22px;font-weight:700;line-height:1.15}
.kpi .l{font-size:10px;font-weight:700;letter-spacing:.5px;color:var(--muted);margin-top:5px;text-transform:uppercase}
.kpi .n{font-size:26px}
/* A CARD MAY NOT SHEAR ITS CONTENTS.
   This was overflow:hidden, which clips to the rounded corners -- and clips
   anything wider than the card too, with no scrollbar to say so. A table one
   column too wide simply lost its right-hand columns: on a 1440px window the
   late-notice table was 1365px of content inside a 1130px box, so 235px of it
   -- the amounts and the action -- were not on the screen and nothing
   indicated they existed. overflow-x:auto keeps the corners and scrolls
   instead of hiding. Nothing on any screen can be invisible now; the worst
   case is a scrollbar. */
.card{background:#fff;border:1px solid var(--line);border-radius:12px;padding:0;overflow-x:auto;overflow-y:visible;margin-bottom:16px}

/* ...and the notice panels are sized to FIT at a normal window width, so that
   fallback never has to engage. Fixed layout so long addresses wrap inside
   their column instead of widening the table. */
#ln-out table,#pf-out table{table-layout:fixed;width:100%}
/* td is white-space:nowrap globally, so a long address does not wrap — it
   just runs under the next column. overflow-wrap alone cannot help while
   nowrap stands. Same opt-in as .wrapcell, applied to the whole panel. */
#ln-out td,#pf-out td,#ln-out th,#pf-out th{white-space:normal}
/* Only the address column may break mid-token. An email has no spaces, so it
   needs it; a loan account has hyphens to break at and looks wrong chopped
   through the middle of MCC-LOT1-5. */
#ln-out td.mono,#pf-out td.mono{overflow-wrap:anywhere}
/* Columns are: 1 tick, 2 loan, 3 borrower, 4 status, 5 goes-to, then the
   per-type ones, then the letter button. Widths are named by position, so
   they have to move when a column is added -- these were one out after the
   tick column arrived, which put 20% on the loan number and squeezed the
   address into three lines. */
#ln-out th:nth-child(3),#pf-out th:nth-child(3){width:17%}
#ln-out th:nth-child(5),#pf-out th:nth-child(5){width:21%}
#ln-out th:last-child,#pf-out th:last-child{width:13%}
#ln-out td:last-child .btn,#pf-out td:last-child .btn{width:100%;padding-left:6px;padding-right:6px}
.card .hd{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;
  border-bottom:1px solid var(--line);gap:10px;flex-wrap:wrap}
.card .hd h3{margin:0;font-size:14px;color:var(--olive);font-weight:700}
.card .hd .r{font-size:12px;color:var(--muted)}
.exp{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
/* CONTROLS GO TO THE RIGHT, NOT THE MIDDLE.
   `.hd` is space-between. With two children -- a title and its controls --
   that puts the controls on the right, which is what every non-collapsible
   card does. A COLLAPSIBLE header has a third child, the caret, so
   space-between spread three items evenly and stranded the controls in the
   middle of the bar: on The Book that is Active / Paid off / + New loan,
   floating between "Loans" and the caret. Rose reported them as centred
   because they were.
   margin-left:auto alone was not enough: space-between then split what was
   LEFT between the controls and the caret, so they landed at 418px on a
   1280px header -- still the middle, measured. A collapsible header drops
   space-between entirely and lets the auto margin absorb all the slack. */
.panel-hd{justify-content:flex-start;position:relative;padding-right:34px}
.panel-hd > .exp,.panel-hd > .r{margin-left:auto}
/* THE CARET IS PINNED TOP-RIGHT, not carried along by the flex row.
   `.hd` wraps, and For Paper Bill's header carries a date, a filter and three
   buttons -- so on any width where that row wrapped, the caret was pushed onto
   the SECOND line and sat under the controls, below the rest of the section.
   Rose reported it as awkwardly placed; it was in a different place from every
   other section's, and only at some widths, which is the kind of difference
   nobody can describe but everybody notices.
   Absolute takes it out of the wrapping entirely: top-right, level with the
   title, identical on every section whatever its header holds. The padding
   above reserves the space so a long title cannot run underneath it. */
.panel-caret{position:absolute;right:14px;top:14px}
.exp select,.exp input{width:auto}
/* Segmented Active / Paid off control */
.seg{display:inline-flex;border:1px solid var(--line);border-radius:8px;overflow:hidden}
.seg a{padding:6px 13px;font-size:12.5px;font-weight:700;color:var(--muted);cursor:pointer;background:#fff}
.seg a.on{background:var(--olive);color:#fff}
/* Autopay-enrolled marker */
.bolt{color:var(--gold);font-weight:800}
.overdue{color:var(--red);font-weight:700}
.card .bd{padding:14px}
table{width:100%;border-collapse:collapse;font-size:12.7px}
th{text-align:left;color:var(--muted);font-weight:700;font-size:10.5px;text-transform:uppercase;
  letter-spacing:.3px;padding:9px 14px;border-bottom:1.5px solid var(--line)}
td{padding:9px 14px;border-bottom:1px solid #eef2ee;white-space:nowrap}
tr:last-child td{border-bottom:0}
tbody tr.clk{cursor:pointer}
tbody tr.clk:hover{background:var(--bg)}
.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.acct{font-weight:700}
.wrapcell{white-space:normal}
/* ---- collapsible rail groups ----------------------------------------------
   The caret used to be a 10px glyph at 55% opacity, which nobody saw. The
   whole header is the target, it says it is one on hover, and the chevron is
   large enough to read as a control rather than punctuation. */
.rail .grp[data-grp]{display:flex;align-items:center;justify-content:space-between;
  cursor:pointer;user-select:none;border-radius:8px;padding-right:8px;
  transition:background .12s,color .12s}
.rail .grp[data-grp]:hover{background:rgba(20,24,18,.06)}
.rail .grp[data-grp]:focus-visible{outline:2px solid var(--olive);outline-offset:2px}
.rail .grp[data-grp] .caret{font-size:13px;line-height:1;opacity:.75;
  transition:transform .15s ease;display:inline-block}
/* The glyph itself is set in index.html; this only animates the turn. */
.rail .grp[data-grp] .caret{font-weight:700}

/* ---- status chips: Title Case with the aging bucket, sized to read ---- */
.chip{display:inline-block;font-size:11.5px;font-weight:700;padding:3px 10px;border-radius:20px;white-space:nowrap}
.s0{background:#e3f1e7;color:#2f7d54}
.s1{background:#fbf4e0;color:#a9832a}
.s2{background:#fbead0;color:#b5701f}
.s3{background:#fbe2d6;color:#b8542a}
.s4{background:#fbe0e0;color:#b23b3b}
.s5{background:#f0d2d2;color:#8f2f2f}
/* ---- controls ---- */
button{font-family:var(--font);font-size:13px;border-radius:8px;border:1px solid var(--line);
  background:#fff;padding:8px 14px;cursor:pointer;font-weight:600}
button:hover{background:var(--bg)}
button.btn{background:var(--olive);color:#fff;border:none;font-weight:700}
button.btn.ghost{background:#fff;color:var(--olive);border:1.5px solid var(--olive)}
button.btn.sm{padding:6px 12px;font-size:12.5px}
button.btn:hover{background:var(--olive2)}
button.danger{background:var(--red);color:#fff;border:none;font-weight:700}
button.sm{padding:6px 11px;font-size:12px}
button:disabled{opacity:.45;cursor:not-allowed}
input,select,textarea{font-family:var(--font);font-size:13px;padding:8px 10px;border:1px solid var(--line);
  border-radius:8px;background:#fff;width:100%}
label{display:block;font-size:10.5px;font-weight:700;letter-spacing:.3px;color:var(--muted);
  margin:0 0 4px;text-transform:uppercase}
.field{margin-bottom:13px}
.row{display:grid;gap:13px}
.row.c2{grid-template-columns:1fr 1fr}
.row.c3{grid-template-columns:1fr 1fr 1fr}
.row.c4{grid-template-columns:repeat(4,1fr)}
/* ---- tabs ---- */
.tabs{display:flex;gap:2px;border-bottom:1px solid var(--line);padding:0 14px;flex-wrap:wrap}
.tab{padding:9px 13px;font-size:12.5px;font-weight:600;color:var(--muted);cursor:pointer;
  border-bottom:2px solid transparent;margin-bottom:-1px}
.tab.on{color:var(--ink);border-bottom-color:var(--olive);font-weight:700}
.tab:hover{color:var(--ink)}
/* ---- notes ---- */
.note{border-left:3px solid var(--sage);background:#fff;padding:11px 14px;border-radius:0 8px 8px 0;
  font-size:12.5px;color:var(--muted);margin:14px 0}
.note.warn{border-left-color:var(--gold);background:#fdf8ec;color:#6b5316}
.note.stop{border-left-color:var(--red);background:#fdeeeb;color:#7c2d1c}
.mono{font-family:var(--mono);font-size:12px}
.right{text-align:right}.muted{color:var(--muted)}
.spin{display:inline-block;width:12px;height:12px;border:2px solid var(--line);border-top-color:var(--olive);
  border-radius:50%;animation:s .7s linear infinite;vertical-align:-2px}
@keyframes s{to{transform:rotate(360deg)}}
.actions{display:flex;gap:8px;flex-wrap:wrap;padding:14px}

/* Notice composer — the mockup's checkbox row and button row. */
.chks{display:flex;gap:16px;align-items:center;padding-top:6px}
.chks label{display:flex;gap:6px;align-items:center;font-size:12.7px;font-weight:400;letter-spacing:0;text-transform:none;color:var(--ink)}
.acts{display:flex;gap:8px;justify-content:flex-end;margin-top:14px}

/* ---- staff sign-in ---------------------------------------------------- */
/* THE SIGN-IN CARD IS CENTRED IN THE VIEWPORT, vertically as well as across.
   It sat high with a wide gap beneath it, and the cause was not this rule --
   it was that `.main` wraps this in 22px of top padding and 60px of bottom,
   so a 100vh box started 22px down and ran 22px off the end. Measured before
   the fix: 393px above the card, 349px below, on a page that scrolled because
   .main came out 1094px tall in a 1012px viewport.
   So the padding is dropped when the container is bare -- see .wrap.bare
   .main below -- and this owns the height.
   100dvh first, because on a phone 100vh is the viewport WITH the URL bar
   retracted: the card is pushed below the fold at rest and settles as you
   scroll. The vh line stays underneath it for anything that does not know
   dvh. */
.signin-wrap{min-height:100vh;min-height:100dvh;
  display:flex;align-items:center;justify-content:center;
  padding:24px;background:var(--bg);box-sizing:border-box}
.signin{background:var(--paper);border:1px solid var(--line);border-radius:12px;
  padding:26px 24px;width:100%;max-width:340px;box-shadow:0 1px 3px rgba(20,40,30,.04)}
.signin img{display:block;margin:2px auto 10px;width:56px;height:auto}
.signin h2{margin:0 0 2px;font-size:16px;text-align:center}
.signin .sub{text-align:center;color:var(--muted);font-size:12.5px;margin:0 0 18px}
.signin .out{margin-top:14px;padding:11px 13px;border-radius:9px;font-size:12.5px;line-height:1.5}
.signin .out.ok{background:#eef5f0;border:1px solid var(--line)}
.signin .out.err{background:#fbeceb;border:1px solid #e6c9c6;color:var(--bad)}

/* ---- signed-in identity in the top bar -------------------------------- */
.me{margin-left:auto;display:flex;align-items:center;gap:9px;font-size:12.5px}
.me .nm{font-weight:700}
.me .rl{font-size:10.5px;font-weight:700;letter-spacing:.3px;text-transform:uppercase;
  padding:2px 8px;border-radius:20px;background:#e7f0ea;color:var(--green)}
.me .rl.viewer{background:#eef0ec;color:var(--muted)}
.me .rl.admin{background:#e3f1e7;color:#2f7d54}

/* An action a role cannot perform is hidden to spare a click. The engine
   refusing the call is the guarantee; this is not it. */
[data-needs]{}
.role-note{font-size:12px;color:var(--muted);margin-top:10px}

/* `hidden` loses to a display rule. The sign-in screen relies on this to take
   the shell off the page, and role-hiding relies on it for buttons. */
[hidden]{display:none !important}
/* THE SIGN-IN SCREEN'S CONTAINER. Written as .shell.bare until now, and
   there is no .shell in this Console: the rule matched nothing, and the
   line that added the class found nothing to add it to. */
.wrap.bare{display:block;min-height:0}
/* The sign-in screen is the whole page, not a page with a margin: the rail
   and the top bar are hidden above it, so .main's padding is the only thing
   between this and the viewport edges. .signin-wrap carries its own. */
.wrap.bare .main{padding:0;max-width:none}

/* ---- the app mark on its tile ----------------------------------------- */
/* The mark carries its own fills; the tile carries the background. */
.mark-tile{display:inline-flex;align-items:center;justify-content:center;
  background:var(--tile-bg);
  border-radius:var(--tile-radius);line-height:0;
  /* A MARK NEVER SHRINKS. In the top bar it is a flex item beside a search
     box that wants the room, and an SVG sized in percentages has a
     min-content width of zero -- so the default flex-shrink:1 collapsed it to
     0px wide while keeping its height, and the bar showed nothing at all. */
  flex:0 0 auto}
.mark-tile svg{width:72%;height:72%;display:block}
/* 72% is Front Porch's inset: a 46-unit mark in a 64-unit tile. */
/* display:flex, not the inherited inline-flex: auto margins do not centre an
   inline box, so the tile sat against the left edge of the card. */
.signin .mark-tile{display:flex;width:56px;height:56px;margin:2px auto 10px}
/* THE TOP BAR SHOWS THE TILE, not a bare mark. The line-art version could be
   white on the olive bar because it inherited a colour; a filled black
   mountain directly on that bar is 1.82:1 and vanishes. On its own tile it is
   the 9.52:1 it is everywhere else, and the bar carries the same icon as the
   dock and the tab. */
.top .mark-tile{width:28px;height:28px}
.btn.danger{background:#a6342b}
.note.ok{background:#eef5f0;border-color:#cfe0d4}

/* ---- combobox ----
   One control, not two. The old loan picker was a text box that filtered a
   separate list box below it, which reads as two questions ("what do I type?"
   then "what do I pick?") for one answer. This is the single control: click to
   see everything, type to narrow, pick to answer. */
.combo{position:relative}
.combo .combo-in{width:100%;padding-right:30px}
.combo .combo-in.picked{font-weight:600}
.combo .combo-caret{position:absolute;right:11px;top:50%;transform:translateY(-50%);
  pointer-events:none;color:var(--muted);font-size:10px;line-height:1}
.combo .combo-list{position:absolute;z-index:40;left:0;right:0;top:calc(100% + 3px);
  max-height:260px;overflow-y:auto;background:#fff;border:1px solid var(--line);
  border-radius:8px;box-shadow:0 8px 24px rgba(35,48,41,.14);padding:4px}
.combo .combo-opt{padding:7px 10px;border-radius:6px;cursor:pointer;font-size:13px;
  display:flex;align-items:baseline;gap:8px}
.combo .combo-opt .lbl{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.combo .combo-opt .tag{font-size:9.5px;font-weight:700;letter-spacing:.3px;text-transform:uppercase;
  border-radius:20px;padding:2px 7px;flex-shrink:0}
.combo .combo-opt .tag.arc{background:#eef1ec;color:var(--muted)}
.combo .combo-opt.on{background:var(--mint)}
.combo .combo-opt .lbl b{font-weight:700}
.combo .combo-none{padding:9px 10px;color:var(--muted);font-size:12.5px}

/* Per-field validation message. Under the box it belongs to, because a list of
   thirteen problems at the bottom of a five-tab form is a list nobody can act
   on — the operator cannot see which box each one is about. */
.err{display:block;color:var(--red);font-size:11.5px;line-height:1.35;margin-top:4px}
.field input.bad,.field select.bad{border-color:var(--red)}

/* ---- THE BOOK's table fits its card, at any width -------------------------
   The last-payment column made it ten columns wide: 1167px of content in a
   968px card, so 199px -- the Status chip and half of Land type -- sat off
   the right edge behind a horizontal scrollbar. The card's overflow-x:auto
   means it scrolls rather than clips, which is better than the shear it
   replaced, but a table you have to scroll sideways to read is a table whose
   last columns nobody reads.

   table-layout:fixed is the guarantee: the table is exactly 100% of the card
   and can never exceed it, whatever the content. The percentages then decide
   who gives way, and ellipsis handles the overrun -- td is white-space:nowrap
   globally, so without it a long borrower name runs under the next column
   instead of stopping. Borrower is the widest and the most tolerant of
   truncation, because the account number beside it is the identifier people
   actually scan for. */
#bk-table{table-layout:fixed;width:100%}
#bk-table th,#bk-table td{padding:9px 8px;overflow:hidden;text-overflow:ellipsis}
#bk-table th:nth-child(1),#bk-table td:nth-child(1){width:3%}
#bk-table th:nth-child(2),#bk-table td:nth-child(2){width:10%}
#bk-table th:nth-child(3),#bk-table td:nth-child(3){width:14%}
#bk-table th:nth-child(4),#bk-table td:nth-child(4){width:10%}
#bk-table th:nth-child(5),#bk-table td:nth-child(5){width:10%}
#bk-table th:nth-child(6),#bk-table td:nth-child(6){width:9%}
#bk-table th:nth-child(7),#bk-table td:nth-child(7){width:10%}
#bk-table th:nth-child(8),#bk-table td:nth-child(8){width:12%}
#bk-table th:nth-child(9),#bk-table td:nth-child(9){width:14%}
#bk-table th:nth-child(10),#bk-table td:nth-child(10){width:8%}
/* The chip must not be the thing that forces the width back open. */
#bk-table td:nth-child(9) .chip{max-width:100%;overflow:hidden;text-overflow:ellipsis}

/* ---- the shared section component (console/panel.js) ---------------------
   FIT IS THE POINT. table-layout:fixed makes a table exactly 100% of its card
   and unable to exceed it, whatever the content; the per-column widths in the
   column definitions decide who gives way. Declared with the columns rather
   than here, because a column added in JS and a width added in CSS drift, and
   the drift shows up as a sheared table nobody can explain.

   Ellipsis rather than wrap: td is white-space:nowrap globally, so without it
   a long value runs under the next column instead of stopping. */
.fit-table{table-layout:fixed;width:100%}
.fit-table th,.fit-table td{padding:9px 8px;overflow:hidden;text-overflow:ellipsis}
.fit-table td .chip{max-width:100%;overflow:hidden;text-overflow:ellipsis}

/* A collapsible section header reads as a control: the whole bar is the
   target, it says so on hover, and the caret is large enough to be punctuation
   nobody misses. */
.panel-hd{cursor:pointer;user-select:none;align-items:center}
.panel-hd:hover{background:var(--bg)}
.panel-hd:focus-visible{outline:2px solid var(--olive);outline-offset:-2px}
.panel-caret{color:var(--muted);font-size:12px;line-height:1}
.panel-section .panel-body[hidden]{display:none}

/* The pinned snapshot never collapses, so it never sits inside a section. */
.kpis+.panel-section{margin-top:16px}

/* --- per-column type-to-search, in the shared table -----------------------
   The glyph is quiet until it is used. A column carrying a filter keeps a
   mark in its heading, because a table that is silently hiding rows is how a
   count gets read wrong -- and the row at the top of the body says how many
   are hidden, in words. */
.fit-table th .col-filter-on { color: var(--acc, #2563eb); opacity: 1; font-size: 12px; }

/* THE FILTER ROW, directly beneath the headings and aligned to them.
   One cell per column including the ones that cannot be filtered, so nothing
   shifts out of line; the row is quiet until a box is used. The boxes used to
   replace a column's label in its own cell, which hid the heading exactly
   when a reader needed it and resized the cell under the cursor. */
.fit-table tr.filter-row th {
  padding: 3px 6px 5px; background: var(--bg-soft, #fafafa);
  border-bottom: 1px solid var(--line); font-weight: 400;
}
.fit-table tr.filter-row .col-filter {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 11.5px;
  padding: 2px 6px; border: 1px solid var(--line); border-radius: 4px;
  background: var(--bg, #fff); color: var(--fg); opacity: .75;
}
.fit-table tr.filter-row .col-filter::placeholder { color: var(--muted); opacity: .6; }
.fit-table tr.filter-row .col-filter:hover { opacity: 1; }
.fit-table tr.filter-row .col-filter:focus {
  outline: none; opacity: 1; border-color: var(--acc, #2563eb);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc, #2563eb) 18%, transparent);
}
/* A box carrying a filter stays visibly on even when nothing is focused --
   the row is otherwise quiet enough to overlook, and a table that is silently
   hiding rows is how a count gets read wrong. */
.fit-table tr.filter-row .col-filter.on {
  opacity: 1; border-color: var(--acc, #2563eb);
  background: color-mix(in srgb, var(--acc, #2563eb) 6%, var(--bg, #fff));
}
.fit-table tr.filter-note td {
  background: var(--warn-bg, #fffbe6); font-size: 12px; padding: 6px 10px;
  border-bottom: 1px solid var(--line);
}
.fit-table tr.filter-note .col-filter-clear {
  background: none; border: 1px solid var(--line); border-radius: 4px;
  padding: 1px 8px; margin-left: 6px; cursor: pointer; font: inherit; font-size: 11px;
}

/* The TMO bolt is NOT the Usio bolt. Same glyph, different fact: one means
   money is being drafted, the other means it was in TMO and the mandate did
   not come with it. Hollow and amber rather than solid, so the difference is
   visible at a glance and not only on hover. */
.bolt.tmo { color: var(--warn, #b45309); opacity: .85; }
