/* app/web/static/app.css — "Proof" theme
   A colour-proofing sheet for a paper ledger: warm uncoated stock, five riso
   inks doing distinct semantic jobs (indigo=brand/selection, azure=links/info,
   teal=data marks, yellow=highlights, orange=negative/critical), and a
   misregistered two-colour wordmark standing in for the guilloche/rosette
   signature of past themes.
   Display: Unbounded · Body: Work Sans · Figures/labels: Space Mono */

:root{
  --paper:#FBF3E2; --card:#FFFFFF; --card2:#FFFBF2; --ink:#211D18;
  /* The rail follows the theme rather than staying black through both: in
     light mode it is a warmer, deeper cut of the same uncoated stock as the
     page, separated from it by a hairline instead of by a black slab.
     --rail-line and --rail-hi carry the hairlines and the hover ink, which
     used to be hard-coded whites that only worked over a dark rail. */
  --rail:#F2E4C6; --rail2:#E7D5AE; --rail-txt:#4B4235;
  --rail-line:rgba(33,29,24,.14); --rail-hi:#211D18;

  --pink:#1E3FE0; --pink-d:#122A99; --pink-bg:#E2E6FB;
  --blue:#0074D9; --blue-d:#0059AD;
  --yellow:#FFD400; --yellow-d:#8A6A00; --yellow-soft:#FFE58A; --yellow-bg:#FFF6D6;
  --teal:#00A99D; --teal-d:#00726A;
  --orange:#FF5A1F; --orange-d:#C93D0D;

  --line:#EBDFC4; --line2:#DECB9E; --mut:#8B7F66;
  --pos:#00A99D; --neg:#FF5A1F; --danger:#FF5A1F; --danger-bg:#FFE3D4;
  --track:#F1E6CC; --wash:#D6F1EF; --sb-thumb:#DECB9E;
  --dv1:#00726A; --dv2:#00A99D; --dv3:#5FCBC0; --dv4:#C9EEE9;

  --disp:"Unbounded",system-ui,sans-serif;
  --body:"Work Sans",system-ui,sans-serif;
  --mono:"Space Mono",ui-monospace,Menlo,Consolas,monospace;
}
[data-theme="dark"]{
  --paper:#15110B; --card:#1F1912; --card2:#251E15; --ink:#F3E9D6;
  --rail:#0F0C08; --rail2:#1C1610; --rail-txt:#C9BDA9;
  --rail-line:rgba(255,255,255,.14); --rail-hi:#FFFFFF;

  --pink:#5C7CFF; --pink-d:#93A9FF; --pink-bg:#1B2350;
  --blue:#4DA3FF; --blue-d:#8FC4FF;
  --yellow:#FFDE59; --yellow-d:#FFE98C; --yellow-soft:#5C4B1A; --yellow-bg:#332912;
  --teal:#2FCBBD; --teal-d:#7FE0D5;
  --orange:#FF8659; --orange-d:#FFAE8C;

  --line:#332A1E; --line2:#3E3325; --mut:#B0A38A;
  --pos:#2FCBBD; --neg:#FF8659; --danger:#FF8659; --danger-bg:#3B2013;
  --track:#2A2216; --wash:#22392F; --sb-thumb:#5A4B36;
  --dv1:#8FF0E4; --dv2:#4FD0C2; --dv3:#1F8F84; --dv4:#134F49;
}

/* Categorical series inks, for the one place two categories share a scale: a
   currency's bars in the trend and its "+ …" figure on the KPI card above it.
   Built out of the inks already declared, so both themes follow without a
   second list. Teal leads (it is the data mark of this sheet), then indigo —
   far enough apart in both hue and lightness to survive a colour-blind read
   and a greyscale print. Order matters: it is the order the KPI card lists its
   currencies in. -txt is the same ink cut for body-size text on card white. */
:root{
  --ser-1:var(--teal);   --ser-1-txt:var(--teal-d);
  --ser-2:var(--pink);   --ser-2-txt:var(--pink-d);
  --ser-3:var(--yellow); --ser-3-txt:var(--yellow-d);
  --ser-4:var(--orange); --ser-4-txt:var(--orange-d);
}

/* Money out and money in are opposite signs of the same ledger, so the two
   invoice sections do not share one neutral ink: supplier bars are drawn in
   coral, customer bars in green, on the dashboard and on the section pages
   alike. The families remap the four series variables in place rather than
   adding a fifth tone class, so the bar, its legend key and the KPI card's
   "+ …" figure all move together — that colour is the whole tie between the
   card and the chart underneath it, and it has to survive the retint.
   Tone 1 is the named colour the section is about (lightcoral, lightgreen);
   2-4 are cuts of the same hue, spaced in lightness so a second currency is
   still a bar you can tell from the first. --ser-hover is the mark a
   single-series chart wears under the pointer, in the family's own ink
   instead of the sheet's indigo. */
/* --wash is the tint the ranking rows are laid on (see .hbar-fill). It was the
   sheet's teal everywhere, which made every insights panel read as one more
   chart of its own colour; it now follows the family, so a supplier ranking is
   washed in the same coral its bars are drawn in. Palest cut of the hue there
   is: it sits behind body text, so it stays a tint on the card rather than a
   mark on it. */
.tone-spend{
  --ser-1:#F08080; --ser-2:#B84B3C; --ser-3:#7A2A20; --ser-4:#F8BCB0;
  --ser-1-txt:#B03A28; --ser-2-txt:#8E2E20; --ser-3-txt:#6E241A;
  --ser-4-txt:#A15040; --ser-hover:#C0392B; --wash:#FBDFD9;
}
/* The green is lightgreen taken down a step in luminosity (#90EE90 -> #7ED67E,
   same hue and saturation): the paler original sat at ~1.4:1 against the card
   white and the bars read as a wash rather than as marks. */
.tone-earn{
  --ser-1:#7ED67E; --ser-2:#3E9B4E; --ser-3:#1F6B31; --ser-4:#C8F2C4;
  --ser-1-txt:#25703A; --ser-2-txt:#1D5E30; --ser-3-txt:#164A26;
  --ser-4-txt:#357A45; --ser-hover:#2E8B57; --wash:#DDF3DA;
}
/* The order book is neither: it is what was promised, not what was paid or
   collected, so it takes gold rather than either side of the invoice ledger.
   A step deeper than gold itself (#FFD700 -> #E0BD00, same hue): the pure
   colour read as a wash at 1.4:1 against the card white. */
.tone-order{
  --ser-1:#E0BD00; --ser-2:#B98A00; --ser-3:#7A5B00; --ser-4:#FFE98A;
  --ser-1-txt:#8A6A00; --ser-2-txt:#6E5400; --ser-3-txt:#544000;
  --ser-4-txt:#7A5B00; --ser-hover:#C9A227; --wash:#F7EBBB;
}
/* Over dark stock the ramp runs the other way: the named colour still leads,
   but the cuts beneath it are lightened rather than deepened, and the text
   ink has to read light on the card instead of dark on white. */
[data-theme="dark"] .tone-spend{
  --ser-1:#F08080; --ser-2:#FFB4A2; --ser-3:#C75A48; --ser-4:#FFDCD2;
  --ser-1-txt:#F5A899; --ser-2-txt:#FFC4B6; --ser-3-txt:#F08080;
  --ser-4-txt:#FFDCD2; --ser-hover:#FFC4B6; --wash:#3B2620;
}
[data-theme="dark"] .tone-earn{
  --ser-1:#7ED67E; --ser-2:#C2F7BE; --ser-3:#4FB265; --ser-4:#E2FBDF;
  --ser-1-txt:#A6F2A6; --ser-2-txt:#C2F7BE; --ser-3-txt:#90EE90;
  --ser-4-txt:#E2FBDF; --ser-hover:#C2F7BE; --wash:#1E3A28;
}
[data-theme="dark"] .tone-order{
  --ser-1:#E0BD00; --ser-2:#FFE98A; --ser-3:#C9A227; --ser-4:#FFF4C2;
  --ser-1-txt:#FFDE59; --ser-2-txt:#FFE98A; --ser-3-txt:#FFD700;
  --ser-4-txt:#FFF4C2; --ser-hover:#FFE98A; --wash:#3A3117;
}

*{box-sizing:border-box}
/* No root zoom: a zoom factor here multiplies the viewport units too, so
   min-height:100vh resolved to 110% of the window and every full-height page
   (login, the shell, the drawer) started life with a scrollbar it did not
   need. Type sizes below are the real px values — scale with the browser. */
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--body);font-size:13.5px;line-height:1.5;-webkit-font-smoothing:antialiased}
a{color:var(--blue-d);text-decoration:none}
a:hover{text-decoration:underline}
h1,h2,h3{font-family:var(--disp);letter-spacing:-.01em;font-weight:700}
.serif{font-family:var(--disp)}                 /* legacy hook: now the display face */
/* Unbounded sets a 0.21em space against letterforms this wide, so at heading
   sizes two words fuse ("Mostpurchased", "Topcounterparties"). Widen the word
   gap everywhere the display face is used; em-based, so it tracks type size. */
h1,h2,h3,.serif,.panel h2,.panel .h,.bc-name,button{word-spacing:.2em}
.muted,.mut{color:var(--mut)}
.empty{color:var(--mut);font-style:italic;font-size:13px}
table,.num{font-variant-numeric:tabular-nums}

/* ---- form controls (defaults) ---- */
label{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--mut);margin-top:12px}
input,select,textarea{font:inherit;width:100%;height:40px;margin-top:6px;padding:0 12px;
  border:1px solid var(--line2);border-radius:10px;background:var(--card);color:var(--ink);font-size:14px}
input::placeholder{color:var(--mut);opacity:.7}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--pink);
  box-shadow:0 0 0 3px rgba(30,63,224,.16)}
input[type=file]{padding:8px 12px;height:auto}
textarea{height:auto;min-height:200px;padding:10px 12px;line-height:1.5}
button{font-family:var(--disp);font-weight:700;font-size:13px;height:38px;padding:0 20px;
  border:0;border-radius:999px;cursor:pointer;background:var(--pink);color:#fff;margin-top:10px;
  box-shadow:3px 3px 0 var(--blue);transition:transform .12s,box-shadow .12s}
button:hover{background:var(--pink-d)}
button:hover,button:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--blue)}
:focus-visible{outline:2px solid var(--pink);outline-offset:2px;border-radius:4px}
@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ---- chips / small controls ---- */
.chip{font-family:var(--mono);font-size:11px;display:inline-flex;align-items:center;gap:5px;
  border:1px solid var(--line2);background:var(--card);border-radius:999px;padding:6px 12px;
  color:var(--mut);text-decoration:none;cursor:pointer;height:auto;margin:0;font-weight:400;
  box-shadow:none;transform:none}
.chip:hover,.chip:active{color:var(--ink);border-color:var(--pink);text-decoration:none;
  box-shadow:none;transform:none}
/* A chip rendered as a <button> also matches button:hover, whose brand fill
   outranks .chip's own background — so the label above stayed ink and came out
   dark-on-dark indigo (Document Manager's type tabs, "Expand all",
   "Re-extract", and every other chip button on the page). The label takes the
   paper it takes on any other filled surface here, which flips with the theme
   so the dark mode's pale indigo keeps its contrast too. The chips that own
   their fill opt out: a selected tab (.active/.on), a danger action, and the
   user roster's state switch, each of which sets its own pair below. */
button.chip:hover:not(.active,.on,.danger,.state),
button.chip:active:not(.active,.on,.danger,.state){
  color:var(--paper);background:var(--pink-d);border-color:var(--pink-d)}
.chip.active,.chip.on{background:var(--ink);color:var(--paper);border-color:var(--ink);
  box-shadow:2px 2px 0 var(--pink)}
.chip.danger{color:var(--orange-d);border-color:var(--orange)}
.chip.danger:hover{color:#fff;background:var(--orange);border-color:var(--orange)}

/* Included/excluded state — a single coloured dot, in two guises: .state-toggle
   is the control on a row, .state-dot the same mark where it only reports (a
   group header, which is itself a button and can hold no second one). */
.state-toggle,.state-dot{width:16px;height:16px;padding:0;margin:0;border-radius:50%;
  border:1px solid rgba(0,0,0,.18);display:inline-block;vertical-align:middle;
  box-shadow:inset 0 0 0 2px var(--card)}
.state-toggle{cursor:pointer}
.state-toggle.on,.state-dot.on{background:var(--teal)}
.state-toggle.off,.state-dot.off{background:var(--orange)}
.state-toggle:hover{filter:brightness(1.08);transform:scale(1.12)}

/* =========================================================== AUTH (single) */
/* One canvas: a flat orange field, one small card in the middle. No split, no
   wordmark, no theme switch — so the card pins its own inks below rather
   than following whatever theme the shell was left on. */
.topctrls{position:fixed;top:16px;right:18px;display:flex;gap:7px;z-index:5}
.authpage{position:relative;overflow:hidden;min-height:100vh;
  display:flex;align-items:center;justify-content:center;padding:40px 24px 72px;
  background:#F9852B}
.authpage::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;opacity:.45;
  background-image:radial-gradient(circle,rgba(255,255,255,.07) 1px,transparent 1.6px);
  background-size:11px 11px}
/* the auth switches sit on orange, not on paper: the same warm ink as the
   card, over enough white to lift them off the field */
body:has(.authpage) .topctrls .lang{background:rgba(255,255,255,.24);color:#3A1B05;
  backdrop-filter:blur(6px);padding:5px 11px}
body:has(.authpage) .topctrls .lang:hover,
body:has(.authpage) .topctrls .lang.on{color:#2A1305;background:rgba(255,255,255,.5)}

/* Straight transparency, no blur: the orange reads through the whole card and
   warms it. Nothing inside is opaque either — --card is a white veil, so the
   inputs and the hint only stack a second layer over the first and end up a
   shade lighter than the card, which is all the separation they get. */
.authcard{position:relative;z-index:3;width:100%;max-width:340px;
  --card:rgba(255,255,255,.34);--card2:rgba(255,255,255,.28);
  --ink:#2A1305;--line:rgba(255,255,255,.55);--line2:rgba(255,255,255,.68);--mut:#6B4526;
  --pink:rgba(30,63,224,.7);--pink-d:rgba(18,42,153,.82);--blue:rgba(0,116,217,.65);
  --danger:#8F2A08;
  color:var(--ink);background:rgba(255,255,255,.66);border-radius:18px;padding:26px 26px 24px;
  box-shadow:0 22px 46px -14px rgba(84,34,2,.5),0 6px 16px rgba(84,34,2,.26),
    0 0 0 1px rgba(255,255,255,.35)}
/* the crest is the one solid mark left; knock it back so it sits in the glass */
.authcard .authcrest{opacity:.92}
.authfoot{position:absolute;left:0;right:0;bottom:24px;z-index:3;text-align:center;
  padding:0 20px;font-family:var(--mono);font-size:11px;letter-spacing:.02em;
  color:rgba(52,20,3,.88)}
.authcrest{display:block;width:52px;height:auto;margin:0 auto 14px}
.authcard .panel{max-width:none}
.authcard .panel .h{text-align:center;margin:0 0 16px}
/* the card is tight, so its labels breathe less than a full-page form's */
.authcard label{margin-top:10px}

.panel{width:100%;max-width:340px}
.panel h2,.panel .h{font-family:var(--disp);font-weight:800;font-size:21px;margin:6px 0 14px;letter-spacing:-.01em}
.panel label:first-of-type{margin-top:0}
.panel input{height:41px;margin-top:5px;border-radius:11px;font-size:14.5px}
.panel button{width:100%;height:43px;margin-top:16px;border-radius:11px;font-size:14.5px}
.hint{display:flex;gap:8px;align-items:flex-start;margin-top:16px;padding:10px 12px;
  border:1px solid var(--line);background:var(--card);border-radius:11px;
  font-size:12px;color:var(--mut);line-height:1.45}
.error{margin-top:14px;color:var(--danger);font-size:13px;font-weight:500}
/* A skipped duplicate is news, not a fault: the info ink (azure), not danger. */
.notice{margin:0 0 16px;padding:11px 16px;border:1px solid var(--blue);
  border-radius:999px;background:var(--card);color:var(--ink);
  font-size:12.5px;line-height:1.45}
.qr{display:flex;justify-content:center;margin:16px 0;padding:14px;background:#fff;
  border:1px solid var(--line);border-radius:12px}
.qr svg{width:180px;height:180px}

/* ============================================================ APP SHELL */
.shell{display:grid;grid-template-columns:236px 1fr;min-height:100vh}
/* The rail is pinned: sticky at the top of its own grid track, one viewport
   tall, so reading a long invoice table scrolls the content and leaves the
   navigation where the pointer expects it. align-self:start stops the grid
   from stretching the item to the row height, which would make sticky moot. */
.side{position:sticky;top:0;align-self:start;height:100vh;overflow-y:auto;
  background:var(--rail);color:var(--rail-txt);padding:26px 18px;
  display:flex;flex-direction:column;border-right:1px solid var(--rail-line)}
/* the crest replaces the old wordmark: one square mark, centred on the rail.
   One plate for both stocks: the navy line art of the login card. On the
   near-black rail it is knocked out white instead of swapped for a second,
   differently coloured file — brightness(0) flattens every stroke to black and
   invert(1) lifts it to white, both leaving the alpha alone, so the mark keeps
   its antialiased edges and its transparent ground. */
.side-crest{display:flex;justify-content:center;padding:2px 0 4px}
.side-crest img{width:76px;height:auto;display:block}
[data-theme="dark"] .side-crest img{filter:brightness(0) invert(1)}
.nav{margin-top:26px;display:flex;flex-direction:column;gap:3px}
.nav a{display:flex;align-items:center;padding:10px 16px;border-radius:999px;
  color:var(--rail-txt);font-size:13.5px;font-weight:500;text-decoration:none}
.nav a:hover{background:var(--rail2);color:var(--rail-hi);text-decoration:none}
.nav a.active{background:var(--pink);color:#fff;font-weight:600}
/* language / theme / sign-out, moved off the old top bar. They follow the nav
   directly instead of being pushed to the bottom of the rail (margin-top:auto)
   — on a tall viewport that left them a scroll away from the last link. */
.side-tools{margin-top:22px;display:flex;align-items:center;gap:4px;
  padding-bottom:14px}
.side-tools form{margin:0;display:flex}

/* ---- language switch: the flag's inks as a riso dot ---- */
.lang{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.05em;
  display:inline-flex;align-items:center;gap:6px;padding:5px 9px;border-radius:999px;
  border:0;background:none;color:var(--rail-txt);text-decoration:none;
  transition:color .14s,background .14s}
.lang:hover{color:var(--rail-hi);background:var(--rail2);text-decoration:none}
.lang.on{color:var(--rail-hi);background:var(--rail2)}
.flag{width:15px;height:15px;flex:none;border-radius:50%;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.22)}
/* three bands, cut by the circle: green, chalk, red */
.flag-it{background:linear-gradient(90deg,#008C45 0 33.4%,#F7F6F0 33.4% 66.6%,#CD212A 66.6%)}
/* the cross, stacked top-down: red over its white fimbriation over navy */
.flag-uk{background:
  linear-gradient(90deg,transparent 0 38%,#C8102E 38% 62%,transparent 62%),
  linear-gradient(180deg,transparent 0 38%,#C8102E 38% 62%,transparent 62%),
  linear-gradient(90deg,transparent 0 27%,#fff 27% 73%,transparent 73%),
  linear-gradient(180deg,transparent 0 27%,#fff 27% 73%,transparent 73%),
  #012169}
/* the plate you are not reading sits pale; hovering inks it back up */
.lang:not(.on) .flag{filter:saturate(.28) opacity(.8)}
.lang:not(.on):hover .flag{filter:none}

/* ---- theme / sign-out: bare 18px strokes, no chip around them ---- */
.tool-btn{display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;padding:0;margin:0;border:0;border-radius:9px;
  background:none;color:var(--rail-txt);cursor:pointer;
  box-shadow:none;transform:none;transition:color .14s,background .14s}
.tool-btn:hover,.tool-btn:active{background:var(--rail2);color:var(--rail-hi);
  box-shadow:none;transform:none}
.tool-btn .ic{display:block}
/* the toggle shows the theme you are in, so only one of the two is ever drawn */
.tool-btn .theme-icon{display:none}
.tool-btn .theme-icon-light{display:block}
[data-theme="dark"] .tool-btn .theme-icon-light{display:none}
[data-theme="dark"] .tool-btn .theme-icon-dark{display:block}
.side .foot{padding-top:14px;border-top:1px solid var(--rail-line);
  font-family:var(--mono);font-size:11px;color:var(--rail-txt)}

.main{display:flex;flex-direction:column;min-width:0}
.content{padding:30px 32px 56px;max-width:1180px}
.content h1{font-size:clamp(23px,3vw,30px);font-weight:800;margin:0 0 4px}

.card{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:18px}

/* ---- tables (shared) ---- */
table{width:100%;border-collapse:collapse;font-size:13px}
th{text-align:left;font-family:var(--mono);font-size:10px;letter-spacing:.07em;text-transform:uppercase;
  color:var(--mut);font-weight:500;padding:11px 12px;border-bottom:1px solid var(--line)}
td{padding:11px 12px;border-bottom:1px solid var(--line)}
tr:last-child td{border-bottom:0}
tbody tr:hover{background:var(--card2)}
.card table,.dash-panel table{margin-top:2px}

/* ---- Settings · the user roster ----
   A dense edit surface, not a form: the global control sizing (40px fields on
   a 12px top margin, 11px cell padding) spread the editable columns wider than
   any laptop and turned every row into a paragraph of whitespace. */
.user-table th,.user-table td{padding:5px 8px;vertical-align:middle}
.user-table input,.user-table select{height:30px;margin:0;padding:0 9px;
  font-size:12.5px;border-radius:8px}
.user-table select{padding-right:22px}
/* the id, the MFA flag and the switch are as wide as their content and no
   wider, so the two editable columns get the table's slack */
.user-table .u-id,.user-table .u-mfa{font-family:var(--mono);font-size:11px;
  color:var(--mut);width:1%;white-space:nowrap}
.user-table .u-active,.user-table .u-actions{width:1%;white-space:nowrap}
/* one line, continuing the row where the Active switch left off: three stacked
   buttons made the row three buttons tall, which is the one thing a roster of
   ten accounts cannot afford. nowrap, because wrapping is what stacked them. */
.user-table .u-tools{display:flex;flex-wrap:nowrap;align-items:center;gap:5px}
.user-table form{margin:0;display:inline-flex}
.user-table details{display:inline-block;position:relative}
.user-table summary{display:inline-flex}
/* the password field drops out over the row rather than inside it, so opening
   it cannot push Reset MFA off the line the buttons just gained */
.user-table .u-pw{display:flex;gap:6px;position:absolute;top:calc(100% + 6px);
  right:0;z-index:20;padding:8px;border:1px solid var(--line2);border-radius:10px;
  background:var(--card);box-shadow:0 8px 22px rgba(0,0,0,.16)}
.user-table .u-pw input{width:150px}
.user-table .chip{padding:4px 10px;font-size:10.5px}
/* the account's state and the switch that flips it are one control: a dot
   saying where it stands, pressed to move it */
.user-table .chip.state::before{content:"";width:7px;height:7px;border-radius:50%;
  background:var(--mut);flex:none}
.user-table .chip.state.live::before{background:var(--teal)}
/* a chip button otherwise inherits button:hover's brand fill, which on a
   status pill reads as "this is now selected" rather than "this is a switch" */
.user-table .chip.state:hover{background:var(--card2);color:var(--ink)}
/* a switched-off account keeps its row — the audit trail still points at it —
   but stops competing with the live ones. Its switch stays at full strength:
   it is the way back. */
.user-table tr.user-off td{opacity:.5}
.user-table tr.user-off .u-active{opacity:1}

/* ============================================================ DASHBOARD */
.dash-head{display:flex;align-items:flex-end;justify-content:space-between;gap:14px;
  border-bottom:2px solid var(--ink);padding-bottom:14px;margin-bottom:26px}
.dash-head h1{margin:0}
/* The year is this page's one control — it says which ledger every figure
   below belongs to — so it is set in the weight of a heading rather than that
   of a field label. The box itself keeps its size. */
.year-pick{display:flex;align-items:center;gap:10px;font-family:var(--mono);
  font-size:13px;color:var(--mut)}
.year-pick label{margin:0;font-size:13px;font-weight:700;letter-spacing:.12em;
  color:var(--ink)}
.year-pick select{width:auto;height:36px;margin:0;color:var(--blue-d);
  font-size:15px;font-weight:700}
.year-pick option{font-weight:700}
/* ---- the overview strip -----------------------------------------------
   Three books, three inks, one axis, across the whole page before it splits
   into a column each. The sheet this theme is named after is a colour proof,
   so the traces overprint rather than stack: multiply on the light stock,
   where two inks laid over each other darken, and screen on the dark one,
   where two lights add. The bloom around each trace is the same idea — riso
   ink spreading into uncoated paper — and it is the one flourish on the page,
   so everything around it stays a hairline and a caption. */
/* the strip is a card like every other panel on the page — its own sheet, with
   the heading and the hint as its header rule and the traces printed under
   them. It sets the stock the dots are punched out of, hence var(--card). */
.dash-overview{background:var(--card);border:1px solid var(--line);border-radius:16px;
  padding:20px;margin-bottom:34px}
.ov-head{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;
  border-bottom:1px solid var(--line);padding-bottom:10px;margin-bottom:14px}
.ov-head h2{margin:0;font-size:17px;font-weight:700;color:var(--ink)}
.ov-hint{margin:0;font-family:var(--mono);font-size:11.5px;color:var(--mut)}
/* isolate: the inks blend with each other and with the sheet under the chart,
   and nothing further up the page */
.ov-wrap{position:relative;isolation:isolate}
.ov-chart{display:block;width:100%;height:auto}
/* Uniformly scaled, so below about a tablet the type inside the strip would
   shrink faster than it stays readable. It scrolls sideways there instead —
   the same answer the section trends give, and the axis keeps its size. */
@media(max-width:820px){
  .ov-wrap{overflow-x:auto}
  .ov-chart{min-width:760px}
}
.ov-rule{stroke:var(--line);stroke-width:1}
.ov-fig,.ov-lab{font-family:var(--mono);fill:var(--mut)}
.ov-fig{font-size:11px}
.ov-lab{font-size:11.5px}
.ov-ink{mix-blend-mode:multiply}
.ov-line{fill:none;stroke:var(--ov-ink,var(--ser-1));stroke-width:2.6;stroke-linecap:round;
  stroke-linejoin:round;filter:drop-shadow(0 0 7px var(--ov-glow))}
/* the dot is the reading; the curve between two of them is only how they were
   joined up, so the dots are drawn over it and punched out of the sheet */
.ov-dot{fill:var(--card);stroke:var(--ov-ink,var(--ser-1));stroke-width:2}
.ov-area{stroke:none}
.ov-ink.tone-spend{--ov-glow:rgba(240,128,128,.78)}
.ov-ink.tone-earn{--ov-glow:rgba(126,214,126,.72)}
.ov-ink.tone-order{--ov-glow:rgba(224,189,0,.7)}
[data-theme="dark"] .ov-ink{mix-blend-mode:screen}
[data-theme="dark"] .ov-ink.tone-spend{--ov-glow:rgba(240,128,128,.8)}
[data-theme="dark"] .ov-ink.tone-earn{--ov-glow:rgba(126,214,126,.75)}
[data-theme="dark"] .ov-ink.tone-order{--ov-glow:rgba(255,222,89,.7)}
/* One target per column, the height of the plot: the question is "what
   happened in March", and its answer names all three books at once. The
   guide only appears under the pointer. */
.ov-hit{fill:transparent}
.ov-guide{stroke:var(--ink);stroke-width:1;opacity:0;stroke-dasharray:3 4}
.ov-col:hover .ov-guide{opacity:.35}

/* Both tracks are minmax(0,1fr) and both sections min-width:0, stacked as much
   as side by side. A `1fr` track is minmax(auto,1fr), and `auto` there is the
   item's min-content width — which on a section holding a twelve-month trend is
   the whole series laid out (~500px), not what the trend's own overflow-x can
   scroll. On a phone that floored the single column at 500px and pushed
   everything from here down off the right of the screen, while the head above
   (a plain block) stayed on it. The 0 lets the column take the width it is
   given; min-width:0 lets the section inside do the same, since a grid item's
   automatic minimum size would otherwise spill it out of that column anyway.
   The trend then scrolls sideways in its panel, which is what it is built for. */
.dash-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:32px;align-items:start}
.dash-grid .dash-section{margin-bottom:0;min-width:0}
@media(max-width:1024px){.dash-grid{grid-template-columns:minmax(0,1fr)}}
.dash-section{margin-bottom:42px}
.dash-section:nth-of-type(1){--hero:var(--pink)}
.dash-section:nth-of-type(2){--hero:var(--blue)}
.dash-section:nth-of-type(3){--hero:var(--teal)}
.dash-section:nth-of-type(4){--hero:var(--orange)}
.dash-section h2{color:var(--ink);font-size:17px;font-weight:700;margin:0 0 18px;
  display:flex;align-items:center;gap:12px}
.dash-section h2::after{content:"";flex:1;height:1px;background:var(--line)}

.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(195px,1fr));gap:16px;margin-bottom:22px}
.kpi{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:18px;
  text-align:center}
.kpi-cur{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--pink-d)}
.kpi-label,.kpi-cur{display:inline-block;margin:0 4px}
.kpi-label{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--mut)}
.kpi-main{font-family:var(--body);font-weight:700;font-size:27px;margin:8px 0 4px;color:var(--ink);letter-spacing:-.01em}
.kpi-sub{font-size:12px;color:var(--mut)}
/* The headline figures are marked, not just laid out: the same treatment an
   active filter pick wears (.pick-btn.on) — ink border, small offset shadow in
   the accent. On the dashboard --hero is the section's own colour (set above),
   so each section's totals are stamped in its hue; elsewhere it falls back to
   pink. The 2px margin keeps the offset shadow clear of whatever sits right. */
.kpi-hero{position:relative;border-color:var(--ink);
  box-shadow:2px 2px 0 var(--hero,var(--pink));margin-right:2px}
/* A second currency is added to the card, not given a card of its own: one
   total, plus what else was billed. It is quieter than the headline (about
   two-thirds of it) and printed in its series ink, which is the same ink its
   bars wear in the trend below — that colour is the whole tie between the two.
   The rule above it does the separating, so the figures need no box. */
.kpi-add{margin-top:12px;padding-top:11px;border-top:1px solid var(--line)}
.kpi-plus{font-family:var(--body);font-weight:700;font-size:18px;
  letter-spacing:-.01em;margin:0 0 4px;color:var(--ser-1-txt)}
.kpi-plus .kpi-cur{color:inherit;vertical-align:.12em}
.kpi-add.ser-2 .kpi-plus{color:var(--ser-2-txt)}
.kpi-add.ser-3 .kpi-plus{color:var(--ser-3-txt)}
.kpi-add.ser-4 .kpi-plus{color:var(--ser-4-txt)}

/* relative so the trend legend can be pinned to the panel's top corner; the
   bar tooltips hang off their own cells and are unaffected */
.dash-panel{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:20px;margin-bottom:16px;
  position:relative}
.dash-panel h3{margin:0 0 18px;color:var(--ink);font-size:14px;font-weight:700;font-family:var(--disp)}
.cur-tag{display:inline-block;font-family:var(--mono);font-size:10px;color:var(--blue-d);
  text-transform:uppercase;letter-spacing:.08em;margin-bottom:8px}
.trend-block,.cur-block{margin-bottom:10px}

/* vertical monthly trend (trend_chart). Columns shrink to fit as many-month
   series get wide; past a floor width (enough for the bar + its date label)
   they stop shrinking and the row scrolls horizontally instead of spilling
   out of .dash-panel. */
/* The scrollbar must stay visible the whole time the series overflows: it is
   the only sign that there are more months to the right. No native scrollbar
   can promise that — under overlay scrollbars it fades out at rest, and
   `overflow-x:scroll` and `scrollbar-color` were both measured not to opt out.
   So trendbar.js draws the bar below, and the native one is suppressed once
   that script has taken over (`.sb-js`), leaving it untouched with JS off.
   `.sb-js` says the script is driving; `.sb-on` says it found an overflow to
   drive. Suppressing the native bar on `.sb-on` alone left it live in the very
   case where nothing should ever scroll, and a hovered tooltip reaching past
   the last column was enough overflow to flash it into view. */
/* --trend-gut reserves the strip the axis figures are printed in, so the first
   column starts clear of them instead of sitting on top of the scale. */
/* --t-bar is the width of every bar on every trend, grouped or not. 14px is
   the widest a bar can be and still let a grouped chart show twelve months
   without scrolling in a half-width dashboard panel: a column has to hold the
   pair plus their 3px gap, and twelve of those plus the axis gutter is exactly
   what such a panel has. Seeing the whole year beats a thicker mark. */
/* --t-head is the strip above the chart's ceiling. Normally it is only the
   breathing room a full-height bar needs; a chart that turns the year opens it
   up so the year figures can be printed *above* the top gridline instead of
   hanging inside the plot under it. It lives on the wrapper because both the
   columns and the fixed axis overlay have to be padded by the same figure or
   the gridlines stop landing where the bars are measured from. */
.trend-wrap{position:relative;--trend-gut:48px;--t-bar:14px;--t-head:6px}
.trend-wrap.has-years{--t-head:17px}
/* The section pages — suppliers, customers, orders — give their trend the
   page's full measure, twice the room the dashboard's half-width panel has, so
   their bars are drawn at twice the width. All three, or the same chart in the
   same room would read as three different ones from section to section.
   It has to be set on the wrapper itself: --t-bar is declared there,
   and a value inherited from the panel would never be seen. The grouped floor
   below follows it up (2x28 + 3 = 59px a column), which a full-width panel has
   for a year and a quarterly axis outgrows into the chart's own scroll. */
.trend-wide .trend-wrap{--t-bar:28px}
.trend{position:relative;z-index:1;display:flex;align-items:flex-end;
  --t-gap:6px;gap:var(--t-gap);height:150px;
  padding:var(--t-head) 0 10px var(--trend-gut);overflow-x:auto;overflow-y:hidden}
/* JS-off fallback: ::-webkit-scrollbar does force a classic, always-reserved
   bar even under overlay scrollbars — but only as long as `scrollbar-width` is
   never set on this element, which would make Chrome discard these rules. */
.trend::-webkit-scrollbar{height:7px}
.trend::-webkit-scrollbar-track{background:var(--track);border-radius:4px}
.trend::-webkit-scrollbar-thumb{background:var(--sb-thumb);border-radius:4px}
.sb-js .trend{scrollbar-width:none}
.sb-js .trend::-webkit-scrollbar{display:none}
/* only a chart that really scrolls gives up its bottom padding to the track */
.sb-on .trend{padding-bottom:2px}
.trend-sb{display:none}
.sb-on .trend-sb{display:block;position:relative;height:7px;margin:3px 0 0 var(--trend-gut);
  border-radius:4px;background:var(--track);cursor:pointer}
.trend-sb-thumb{position:absolute;top:0;left:0;height:100%;border-radius:4px;
  background:var(--sb-thumb);cursor:grab}
.trend-sb-thumb:hover{background:var(--mut)}
.trend-sb-thumb.drag{background:var(--pink);cursor:grabbing}
/* position:relative so a column that opens a new year can hang its mark off
   its own leading edge — see .t-yr. */
.t-col{position:relative;flex:1 1 32px;min-width:32px;height:100%;
  display:flex;flex-direction:column;align-items:center;gap:7px}
/* The bar's height:% must resolve against the space actually left once the
   label below has taken its share — not the whole column. Without this slot,
   any value within ~15% of the max resolved to a height beyond what was
   visually available and got silently clipped to the same height as the true
   max, making near-top values indistinguishable from it. */
/* The gap between a column's own bars stays under .trend's gap between
   columns, or the pair stops reading as one month. */
.t-slot{flex:1 1 auto;min-height:0;width:100%;position:relative;display:flex;
  align-items:stretch;justify-content:center;gap:3px}
/* One cell per currency, so a column can hold two bars side by side. The cell,
   not the bar, is the flex item: it stretches to the slot's full height, which
   gives the absolutely-positioned bar inside it a containing block with a
   height a percentage can actually resolve against. A bar sized in % as a flex
   item itself would be resolving against an auto height. */
/* A bar is one width, --t-bar, everywhere: the cell is sized to it rather than
   left to share out whatever the column has spare. Elastic cells made the bar
   a function of how many currencies the section happened to bill in — the
   dashboard drew 24px bars for a one-currency supplier trend next to 14px ones
   for a two-currency customer trend, and the two panels no longer looked like
   two readings of the same thing. The column's floor below is what buys the
   fixed cell its room. */
.t-cell{position:relative;flex:0 0 var(--t-bar);max-width:var(--t-bar)}
.t-bar{position:absolute;left:0;right:0;bottom:0;background:var(--ser-1);
  border-radius:4px 4px 0 0;min-height:3px}
.t-bar.ser-2{background:var(--ser-2)}
.t-bar.ser-3{background:var(--ser-3)}
.t-bar.ser-4{background:var(--ser-4)}
/* short series (the all-years view): keep columns bar-sized and grouped left,
   so three years do not float in a third of the panel each */
.trend.few{justify-content:flex-start;--t-gap:26px;
  padding-left:calc(var(--trend-gut) + 4px)}
.trend.few .t-col{flex:0 0 44px}
/* Two bars need a column that can hold two bars: the floor is exactly the pair
   plus the gap between them, so a grouped chart keeps the same bar width as a
   single one instead of thinning to fit. At --t-bar that floor lands just under
   the 32px a single column already asks for, so both charts settle on the same
   column width and twelve months still fit a half-width panel — the two
   dashboard sections line up month for month, and neither scrolls. */
.trend.multi .t-col{flex:1 1 42px;min-width:calc(var(--t-bar) * 2 + 3px)}
.trend.multi.few .t-col{flex:0 0 58px}
/* Hovering a column marks its bars. A single-series chart can afford to recolour
   them outright; a grouped one cannot — the colour IS which currency it is — so
   there the mark is a lift in the bar's own ink instead. */
.trend:not(.multi) .t-col:hover .t-bar{background:var(--ser-hover,var(--pink))}
.trend.multi .t-col:hover .t-bar{filter:brightness(1.14) saturate(1.2)}
.t-lab{font-family:var(--mono);font-size:9.5px;color:var(--mut);white-space:nowrap}
/* Where the axis turns the year. A column's own label carries the year in two
   digits — "Q1/25", "01/25" — which says which year that column is in but
   never where one year stopped and the next began; over twenty quarters, or
   over two years of months, that is a reading rather than a mark. So the
   boundary gets a rule of its own, dashed because it divides the chart rather
   than measuring anything on it, and the two years are printed either side of
   it saying which stretch is which.
   It hangs off the leading edge of the column that opens the new year and is
   pulled back half a column gap, so it lands in the space between the two
   years instead of shaving the first bar of the new one. Zero width, so both
   labels can be positioned against the line itself. The rule runs from the
   baseline up through the header strip, which is what carries it clear of the
   plot and gives the years somewhere to sit. */
.t-yr{position:absolute;top:calc(var(--t-head) * -1);bottom:0;
  left:calc(var(--t-gap) / -2);width:0;
  border-left:1px dashed var(--line2);pointer-events:none;z-index:2}
/* The years read above the chart's top gridline rather than inside the plot
   under it: up there nothing can ever be drawn behind them, so the boundary is
   named in clear air whatever the bars either side of it are doing. The line
   height is set rather than inherited — the strip above is sized to it, and a
   figure taller than the room reserved for it would be clipped by the
   scroller. The card's own stock stays behind them all the same, for the bar
   that overshoots its ceiling. */
.t-yr em{position:absolute;top:0;font-style:normal;font-family:var(--mono);
  font-size:9px;line-height:12px;letter-spacing:.04em;color:var(--mut);
  background:var(--card);border-radius:3px;padding:0 3px;white-space:nowrap}
.t-yr .ty-a{right:4px}
.t-yr .ty-b{left:4px}

/* Legend: which ink is whose money. Only drawn when more than one currency is
   on the chart — with one series the panel heading already said it.

   It rides on the heading's own line, pinned to the far corner of the panel:
   `top` is the panel's padding and `line-height` is the h3's line box (14px at
   the body's 1.5), so the two sit on one band. Below the chart it would have
   made a two-currency panel taller than a one-currency one, and two such panels
   side by side on the dashboard ended on different baselines. */
.trend-legend{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;
  gap:6px 16px;font-family:var(--mono);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mut);
  position:absolute;top:20px;right:20px;line-height:21px;max-width:55%;
  justify-content:flex-end}
.trend-legend li{display:flex;align-items:center;gap:7px}
.tl-key{width:10px;height:10px;border-radius:3px;flex:none;background:var(--ser-1)}
.tl-key.ser-2{background:var(--ser-2)}
.tl-key.ser-3{background:var(--ser-3)}
.tl-key.ser-4{background:var(--ser-4)}

/* Reference axis: a fixed (non-scrolling) overlay so the price scale stays
   on screen while a long series scrolls beneath it. Its slot mirrors .t-col's
   own box model (same padding/gap, a spacer standing in for .t-lab) so its
   0%/100% lines land exactly on the baseline and ceiling the bars use. */
.trend-grid{position:absolute;top:0;left:0;right:0;z-index:0;height:150px;
  padding:var(--t-head) 0 10px;display:flex;flex-direction:column;
  align-items:stretch;gap:7px}
.tg-slot{flex:1 1 auto;min-height:0;position:relative}
.tg-lab-spacer{height:9.5px}
/* Lines start where the columns do; their figure is printed in the gutter to
   the left of that, centred on the line it belongs to. The figure keeps an
   opaque background because a scrolled series slides its leading padding out
   of view and lets bars pass beneath the gutter. */
.tg-line{position:absolute;left:var(--trend-gut);right:0;height:1px;background:var(--line)}
.tg-line em{position:absolute;right:100%;bottom:-5px;font-style:normal;font-family:var(--mono);
  font-size:9.5px;color:var(--mut);background:var(--card);padding-right:6px}

/* Custom tooltip: shows on hover with no delay, unlike the native title tip
   it sits alongside for keyboard/assistive access. Pinned just inside the
   bar's own top edge rather than floating above it — .trend clips its
   vertical overflow (needed so a long series can still scroll sideways
   without spilling out top/bottom), so a bar at or near the max would have
   nowhere to float a tooltip above it without that tooltip being clipped. */
.t-bar[data-tip]:hover::after,
.t-cell[data-tip]:hover::after,
.t-slot[data-tip]:hover::after{content:attr(data-tip);position:absolute;top:4px;left:50%;
  transform:translateX(-50%);background:var(--ink);color:var(--card);
  font:11px/1.4 var(--mono);white-space:nowrap;padding:3px 8px;border-radius:6px;
  pointer-events:none;z-index:5}
/* an empty month has no bar to pin the tip inside, so it prints on the
   baseline — where the missing bar would have started */
.t-cell[data-tip]:hover::after,
.t-slot[data-tip]:hover::after{top:auto;bottom:2px}
/* Centred on its bar, the tip runs past the chart's own edge at either end of
   the axis: .trend clips it there, and while the pointer rests on that column
   the overhang counts as horizontal overflow — the scroller became scrollable
   over a tooltip. The end columns anchor their tip inside the chart instead. */
.trend .t-col:first-child [data-tip]:hover::after{left:0;transform:none}
.trend .t-col:last-child [data-tip]:hover::after{left:auto;right:0;transform:none}

/* ============================================================ INVOICES LIST */
.filters{display:flex;flex-wrap:wrap;gap:10px;align-items:center;background:var(--card);
  border:1px solid var(--line);border-radius:16px;padding:14px 16px;margin-bottom:18px}
/* A bar that is narrowing the page says so as a whole box, in the selection
   ink of the note at its foot — everything below it, the figures as much as
   the rows, is a slice. Off, it is the plain card it always was. */
.filters.on{border-color:var(--pink);background:var(--pink-bg)}
.filters input,.filters select{height:34px;margin:0;width:auto;font-size:12.5px;background:var(--paper)}
.filters input:focus,.filters select:focus{background:var(--card)}
.filters input[type=date]{width:150px}
/* wide enough for "Min amount" / "Importo min" to sit in the field without the
   placeholder being clipped, spinner and all */
.filters input[type=number]{width:124px;font-family:var(--mono)}
.filters input[type=text]{flex:1;min-width:150px}
.filters select{min-width:104px;color:var(--blue-d)}
/* .filters button is the <noscript> fallback only — the picks apply themselves */
.filters button,.filters .btn-reset{margin:0;height:34px}
/* the picks apply themselves, so the bar's one control is the reset link; it
   wears the button skin — anchors need the box model and the colours spelled
   out, the rest matches the base button rule */
.filters .btn-reset{display:inline-flex;align-items:center;text-decoration:none;
  font-family:var(--disp);font-weight:700;font-size:13px;word-spacing:.2em;padding:0 20px;
  border:0;border-radius:999px;cursor:pointer;background:var(--pink);color:#fff;
  box-shadow:3px 3px 0 var(--blue);transition:transform .12s,box-shadow .12s}
.filters .btn-reset:hover{background:var(--pink-d);color:#fff;text-decoration:none}
.filters .btn-reset:hover,.filters .btn-reset:active{transform:translate(2px,2px);
  box-shadow:1px 1px 0 var(--blue)}
/* Nothing is filtered, so there is nothing to reset: the button is spent and
   reads that way before it is pressed. The outline is inset so losing the
   filled skin costs no height beside the 34px fields. */
.filters .btn-reset.off,.filters .btn-reset.off:hover{background:var(--card2);
  color:var(--mut);box-shadow:inset 0 0 0 1px var(--line2);transform:none;
  cursor:default;text-decoration:none}
/* Excel-style autofilter: a summary button opening a checkbox panel */
.pick{position:relative;flex:1;min-width:192px}
.pick-btn{display:flex;align-items:center;gap:8px;height:34px;padding:0 26px 0 10px;
  border:1px solid var(--line2);border-radius:10px;background:var(--paper);cursor:pointer;
  font-size:12.5px;color:var(--ink);list-style:none;white-space:nowrap}
.pick-btn::-webkit-details-marker{display:none}
.pick-btn::after{content:"▾";position:absolute;right:9px;top:9px;font-size:10px;color:var(--mut)}
.pick-btn:hover{border-color:var(--pink)}
.pick-lab{font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--mut)}
.pick-sum{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pick-btn.on{border-color:var(--ink);box-shadow:2px 2px 0 var(--pink)}
.pick-btn.on .pick-sum{font-weight:600}
.pick[open] .pick-btn{border-color:var(--ink)}
.pick-panel{position:absolute;z-index:40;top:calc(100% + 6px);left:0;min-width:240px;max-width:340px;
  background:var(--card);border:1px solid var(--line2);border-radius:12px;padding:10px;
  box-shadow:4px 4px 0 var(--blue)}
/* The panel opens on one field, not three controls: the search box carries the
   select-all and clear squares inside its own border, at the right edge where
   an autofilter menu puts them. The wrapper is the field — it holds the border
   and takes the focus ring — and the input inside it is stripped bare. */
.pick-find{display:flex;align-items:center;gap:1px;height:32px;margin:0 0 8px;padding-right:3px;
  border:1px solid var(--line2);border-radius:9px;background:var(--paper)}
.pick-find:focus-within{border-color:var(--pink);box-shadow:0 0 0 3px rgba(30,63,224,.16)}
.filters .pick-find .pick-search{flex:1;min-width:0;height:30px;margin:0;padding:0 9px;
  font-size:12.5px;border:0;background:transparent;box-shadow:none}
.filters .pick-find .pick-search:focus{background:transparent;box-shadow:none}
/* the field's own clear cross would sit next to two other squares and read as a
   third control; Esc and deleting the text still empty it */
.pick-search::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.pick-tools{display:flex;align-items:center;gap:1px;flex:none}
/* hidden until filters.js is running: these do nothing without it */
.pick-tools[hidden]{display:none}
.filters .pick-tools button{display:grid;place-items:center;width:25px;height:25px;margin:0;
  padding:0;border:0;border-radius:6px;background:transparent;color:var(--mut);
  box-shadow:none;transform:none}
.filters .pick-tools button:hover,.filters .pick-tools button:active{background:var(--card2);
  color:var(--pink);transform:none;box-shadow:none}
.pick-tools svg{display:block;width:15px;height:15px}
.pick-list{list-style:none;margin:0;padding:0;max-height:250px;overflow-y:auto}
.pick-list li{margin:0}
/* these labels carry data, not field names: undo the global form-label styling
   (mono, uppercase, letter-spaced) or every counterparty reads as a heading */
.pick-list label{display:flex;align-items:flex-start;gap:8px;margin:0;padding:5px 4px;
  font-family:var(--body);font-size:12.5px;font-weight:400;letter-spacing:0;
  text-transform:none;color:var(--ink);cursor:pointer;border-radius:6px}
.pick-list label:hover{background:var(--card2)}
.pick-list input{width:14px;height:14px;margin:2px 0 0;flex:none;accent-color:var(--pink)}
.pick-none{padding:6px 4px;font-size:12px;color:var(--mut)}
.filters-end{margin-left:auto;display:flex;align-items:center;gap:8px}
/* count and note sit over the middle of the table they describe, not off in the
   left margin — text-align carries the wrapped lines that justify-content cannot */
.summary{display:flex;align-items:baseline;justify-content:center;gap:18px;
  margin:0 2px 14px;text-align:center;
  font-family:var(--mono);font-size:12px;color:var(--mut)}
/* The count keeps the middle of the table it describes while the grouping
   control sits at the right edge: two equal side tracks, so the empty one on
   the left pays for the select on the right and nothing shifts off centre. */
.inv-toolbar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:14px;margin:0 2px 14px}
.inv-toolbar .summary{margin:0}
.inv-toolbar .group-by{justify-self:end}
/* the left track, when the table is grouped: it holds the fold-everything
   control and pays for the grouping select opposite it, so the count between
   them keeps the middle either way */
.inv-toolbar .toolbar-lead{justify-self:start}
@media(max-width:760px){
  .inv-toolbar{grid-template-columns:1fr}
  .inv-toolbar .group-by{justify-self:center;margin:0}
  .inv-toolbar .toolbar-lead{justify-self:center}
  .inv-toolbar .toolbar-gap{display:none}
}
/* tells the truth about whether the table below is the whole set or a slice */
.filter-note{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:6px;text-align:center;
  font-family:var(--mono);font-size:11.5px;color:var(--mut);margin:0 2px 10px}
.filter-note strong{color:var(--ink);font-weight:700;text-transform:uppercase;
  font-size:10px;letter-spacing:.06em}
.filter-note.all strong{color:var(--teal-d)}
.fn-chip{border-color:var(--line2);background:var(--card2);color:var(--ink);
  cursor:default;padding:4px 10px;font-size:11px}
.fn-chip:hover{border-color:var(--line2);color:var(--ink)}
/* The same note again, as the first line of the filter bar itself: not a card
   over it but its head, so what is applied is read off the same box as the
   controls that applied it, and read before them. Full-basis to take its own
   row, hairline below, and no side padding — the bar's own 16px already holds
   the margin. */
.filter-note.bar{flex-basis:100%;justify-content:flex-start;text-align:left;
  gap:8px;margin:0;padding:0 0 9px;border-bottom:1px solid var(--line2);
  font-size:12px;color:var(--ink)}
.filters.on .filter-note.bar{border-bottom-color:var(--pink)}
.filter-note.bar strong{font-size:10.5px;letter-spacing:.08em;color:var(--pink-d)}
.filter-note.bar .fn-chip{background:var(--card);border-color:var(--pink);
  font-size:11.5px;font-weight:700}
/* Nothing is being narrowed, and then the line is only that one phrase: with no
   chips to lead it can be read at its own size rather than as a chip label.
   .filter-note.all strong is defined above and ties with .filter-note.bar
   strong, which would take the teal on source order. */
.filter-note.bar.all strong{font-size:14px;letter-spacing:.06em;color:var(--teal-d)}
/* the page numbers are centred under (and over) the table, so the jump target
   sits where the eye already is after reading a row */
.pager{display:flex;flex-wrap:wrap;gap:6px;justify-content:center;align-items:center}
.pager.top{margin:0 0 14px}
.pager.bottom{margin-top:18px}
.pager .chip{font-size:12px;padding:6px 12px}
/* The step arrows carry you past the ends of the printed window, so they are
   the pager's real controls and read a little heavier than the numbers they
   flank. At the ends of the run they stay put, spent rather than gone — the
   same treatment a used-up Reset gets — so the row never shifts under the
   pointer just as you reach for it. */
.pager .step{font-size:14px;line-height:1;padding:5px 11px;color:var(--ink)}
.pager .step.off{color:var(--line2);border-color:var(--line);cursor:default;
  pointer-events:none}

/* ---- the plate ---------------------------------------------------------
   The rows are what these pages exist for — everything above them (filters,
   figures, insight panels) is there to decide which rows to look at — so the
   block that holds them is printed as its own plate: a sheet on the sheet,
   outlined in ink, with a second plate of the section's own colour slipped out
   of register behind it. That misregistration is this theme's signature; the
   wordmark does it, the KPI cards do it at 2px, and here it runs at 14px
   because this is the thing on the page that should be seen first.

   The offset is taken out of the right margin rather than added to the page,
   so the shadow lands inside the content column instead of pushing a
   horizontal scrollbar onto every list. */
.inv-plate{background:var(--card);border:1.5px solid var(--ink);border-radius:20px;
  padding:20px 20px 10px;margin:0 15px 30px 0;
  box-shadow:14px 14px 0 0 var(--ser-1),14px 14px 0 1.5px var(--ink)}
/* the toolbar and the pagers sit inside the plate now, so the first of them no
   longer needs the gap that separated it from the sheet */
.inv-plate>.inv-toolbar:first-child,.inv-plate>.filter-note:first-child{margin-top:0}
.inv-plate table{margin-bottom:2px}
@media(max-width:900px){
  .inv-plate{padding:14px 14px 6px;margin-right:9px;border-radius:16px;
    box-shadow:8px 8px 0 0 var(--ser-1),8px 8px 0 1px var(--ink)}
}
/* Ink on paper is a print, not a light source: over the dark sheet the plate
   behind the rows is the same colour but has to sit back a step, or a slab of
   full-strength coral reads as the subject and the rows as its frame. */
[data-theme="dark"] .inv-plate{box-shadow:14px 14px 0 0 var(--ser-3),
  14px 14px 0 1.5px var(--line2)}
@media(max-width:900px){
  [data-theme="dark"] .inv-plate{box-shadow:8px 8px 0 0 var(--ser-3),
    8px 8px 0 1px var(--line2)}
}

/* ============================================================ DOCUMENT MANAGER
   Dropzone: replaces the OS-rendered "Choose files / No file chosen" input
   with a paper tray you can drag a PDF onto — the hairline dashes read as
   a cut line, and hovering lifts it the same way buttons press down. */
.dropzone{display:flex;flex-direction:column;align-items:center;gap:4px;
  text-align:center;margin-top:6px;padding:34px 20px;cursor:pointer;
  border:2px dashed var(--line2);border-radius:16px;background:var(--card);
  color:var(--mut);transition:border-color .15s,background .15s,transform .15s,box-shadow .15s}
.dropzone input[type=file]{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.dropzone:hover{border-color:var(--pink);color:var(--ink)}
.dropzone:focus-within{border-color:var(--pink);box-shadow:0 0 0 3px rgba(30,63,224,.16)}
.dropzone.drag{border-style:solid;border-color:var(--blue);background:var(--card2);
  color:var(--ink);transform:translate(-2px,-2px);box-shadow:4px 4px 0 var(--blue)}
.dropzone-icon{color:var(--mut)}
.dropzone:hover .dropzone-icon,.dropzone.drag .dropzone-icon{color:inherit}
.dropzone-title{font-family:var(--disp);font-weight:700;font-size:15px;letter-spacing:.02em;color:var(--ink)}
.dropzone-hint{font-family:var(--mono);font-size:10.5px;letter-spacing:.04em;color:var(--mut)}
/* label{} sets uppercase globally for form hints — the filename is real
   content, not chrome, so it keeps its actual case in here */
.dropzone-files{display:flex;flex-wrap:wrap;gap:6px;justify-content:center;margin-top:10px;
  text-transform:none}
.dropzone-files:empty{margin-top:0}
.dropzone-files .chip{cursor:default}
#upload-form{margin-bottom:32px}
/* the tray is centred, so the button under it is too — off in the left margin
   it read as belonging to the page rather than to the drop zone above it */
.upload-actions{display:flex;justify-content:center}
/* No file picked is nothing to upload: the button is spent before it is
   pressed, and says so — same treatment as the filter bar's Reset. */
#upload-form button[disabled],#upload-form button[disabled]:hover{
  background:var(--card2);color:var(--mut);box-shadow:inset 0 0 0 1px var(--line2);
  transform:none;cursor:default}

/* One tab per document class. Chips, not a underlined tab bar: the page
   already speaks in chips, and the count is the thing you scan for. The rail is
   its own row: the tabs choose which table you are looking at, which is a
   different kind of decision from the two controls that act on that table.
   Centred, because the rail is the only thing on its line: three or four chips
   left-aligned under a full-measure dropzone read as the start of a row that
   never arrives, and the tabs are a heading for the whole table rather than a
   control that belongs at the edge the table starts from. */
.doc-tabs{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin:0 0 12px}
.doc-tabs .doc-tab{font-size:11.5px;padding:7px 14px}
/* The row under the tabs, read left to right the way the invoice lists' toolbar
   is: fold-everything at the left edge where the table below starts, the
   grouping select opposite it. .group-by's auto margin is what parts them. */
.doc-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin:0 0 14px;
  border-bottom:1px solid var(--line);padding-bottom:12px}
/* how the rows are bucketed — a setting for the table, so it sits at the far
   end of its rail: whatever shares the row with it is what acts on the rows */
.group-by{display:flex;align-items:center;gap:8px;margin:0 0 0 auto;
  font-family:var(--mono);font-size:10px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--mut)}
.group-by label{margin:0}
.group-by select{width:auto;height:30px;margin:0;padding:0 26px 0 10px;
  font-size:11.5px;letter-spacing:0;text-transform:none;border-radius:8px;
  color:var(--blue-d)}
.tab-count{font-family:var(--mono);font-size:10px;margin-left:7px;padding:1px 6px;
  border-radius:999px;background:var(--track);color:var(--mut)}
.doc-tab.active .tab-count{background:rgba(255,255,255,.18);color:inherit}
/* hovering a tab fills it the same way selecting it does, so its count pill
   takes the same translucent treatment instead of staying a cream pill */
.doc-tab:hover:not(.active) .tab-count{background:rgba(255,255,255,.18);color:inherit}
.doc-panel .empty{margin:18px 2px}

/* Excel-style dense grid: every control shrinks to row height instead of
   pushing it — the default 40px select and 38px button are what made this
   table sprawl in the first place. */
.doc-table{font-size:12.5px}
/* Counterparty rail: the group header already names the company, so the
   per-row copy stays quiet and never out-shouts the filename next to it.
   It is also the column that pays for the date one — the row budget is fixed,
   and an echo of the group header can ellipsize where a filename cannot. */
.doc-table .doc-party{color:var(--mut);max-width:14ch;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
/* Each company is its own tbody, so folding one is a class on the group and
   the borders/zebra of the others stay intact. The invoice lists group their
   rows the same way and share everything below except the .doc-table bits. */
.doc-group.collapsed .doc-row,.doc-group.collapsed .doc-head,
.doc-group.collapsed .inv-row{display:none}
/* The column titles live inside the group, so folding every group leaves the
   group names alone on the page instead of a header row over nothing. Quieter
   than a page-level thead — it repeats, and it labels rather than announces.
   Shared with the grouped invoice lists, sort links and all. */
.doc-head th{padding:4px 10px 3px;font-size:9px;color:var(--mut);opacity:.85;
  border-bottom:1px solid var(--line)}
/* the titles are quieter here, but the sortable ones keep the link colour they
   have in a flat table — the row is smaller, not less clickable */
.doc-head:hover{background:none}
.grp-row td{padding:0;background:var(--card2);
  border-bottom:1px solid var(--line);border-top:1px solid var(--line)}
.grp-row:hover td{background:var(--track)}
.doc-group:first-of-type .grp-row td{border-top:0}
.grp-toggle{display:flex;align-items:center;gap:8px;width:100%;height:auto;
  margin:0;padding:7px 10px;background:none;color:var(--ink);border-radius:0;
  box-shadow:none;transform:none;text-align:left;font-family:var(--disp);
  font-weight:700;font-size:11.5px;letter-spacing:.01em}
.grp-toggle:hover{background:none;box-shadow:none;transform:none;color:var(--pink-d)}
.grp-caret{color:var(--mut);flex:none;transition:transform .15s}
.doc-group.collapsed .grp-caret{transform:rotate(-90deg)}
/* One control for the whole table — the tab's groups here, the grouped list's
   over on the invoice pages. It reads as a setting for the table rather than
   an action on it, so it takes the mono label the controls beside it wear. */
.grp-all{font-family:var(--mono);font-size:10.5px;letter-spacing:.04em;
  text-transform:uppercase;white-space:nowrap}
/* .chip sets display, which outranks the UA's [hidden] rule — without this the
   button JS has not revealed yet would paint anyway */
.grp-all[hidden]{display:none}
.grp-all.folded .grp-caret{transform:rotate(-90deg)}
.grp-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.grp-count{font-family:var(--mono);font-weight:400;font-size:10px;color:var(--mut);
  border:1px solid var(--line2);border-radius:999px;padding:0 7px}
/* Invoice date: mono figures so the column reads as a single ruled edge, and
   quiet — it dates the document, it is not what you scan the table for. */
.doc-table .doc-date{font-family:var(--mono);font-size:11px;color:var(--mut);
  white-space:nowrap}
/* The total is a figure to compare down the column, so mono and right-aligned —
   but it keeps the ink the date gives up: it is the number the row is about. */
.doc-table .doc-total{font-family:var(--mono);font-size:11px;white-space:nowrap;
  text-align:right}
/* How far the document's own arithmetic backed up what was read off it. A
   perfect read is the norm here, so it is printed as quietly as the date is:
   what this column is scanned for is the row that fell short. All three bands
   wear the same pill so the figures line up down the column whatever they say —
   only the ink changes, and only the two short bands take any. */
.doc-table .doc-score{font-family:var(--mono);font-size:11px;white-space:nowrap;
  text-align:right}
.score{display:inline-block;border-radius:20px;padding:1px 7px;color:var(--mut)}
.score.fair{color:var(--yellow-d);background:var(--yellow-bg)}
.score.poor{color:var(--danger);background:var(--danger-bg)}
.doc-table th,.doc-table td{padding:5px 10px}
.doc-table td{vertical-align:middle}
/* not display:flex — that strips the td of its table-cell behaviour and the
   two action columns collapse onto each other instead of sitting side by side */
.doc-table .doc-actions{white-space:nowrap}
.doc-table .doc-actions form + form{margin-left:6px}
.doc-table .chip{padding:3px 10px;font-size:10.5px}
.doc-table .state-toggle{width:13px;height:13px}
/* filename drills into the review page — same treatment as the invoice line
   descriptions: a hairline underline in ink, not a shouting blue link */
.doc-table .file-link{color:inherit;text-decoration:underline;
  text-decoration-color:var(--line2);text-underline-offset:2px;
  text-decoration-thickness:1px}
.doc-table .file-link:hover,.doc-table .file-link:focus-visible{
  color:var(--blue-d);text-decoration-color:currentColor}
/* marks a document whose extracted JSON was hand-edited by a user, so it can
   be spotted at a glance in the list without opening every review page */
.pencil-icon{color:var(--orange-d);margin-left:5px;vertical-align:-2px}
/* the same marks on the group header: the header is a flex row whose gap already
   spaces them, and neither must be the item that gives way when a long company
   name runs the row out of width. The dot's inner ring is cut from the header's
   own stock, not the white a table row sits on. */
.grp-toggle .pencil-icon{margin-left:0;flex:none}
.grp-toggle .state-dot{width:12px;height:12px;flex:none;
  box-shadow:inset 0 0 0 2px var(--card2)}

/* ---- JSON review: badge on the editable JSON when it was hand-edited ---- */
.json-edited-badge{display:inline-flex;align-items:center;font-family:var(--mono);
  font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--danger);
  background:var(--danger-bg);border:1px solid var(--danger);border-radius:20px;
  padding:2px 8px}

/* ============================================================ INVOICE DETAIL */
.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;
  background:var(--card);border:1px solid var(--line);border-radius:16px;padding:20px;margin:16px 0}
.detail-grid > div{font-size:13.5px}
.detail-grid b{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mut);font-weight:500;margin-bottom:3px}
.detail-grid .muted{color:var(--mut);font-size:12px;grid-column:1/-1}
table.lines{background:var(--card);border:1px solid var(--line);border-radius:16px;overflow:hidden}
table.lines tr.hit{background:var(--yellow-bg)}
/* Line descriptions drill down to every invoice with that product. Kept in ink
   with a hairline underline: a whole column of blue links would shout louder
   than the numbers it sits next to. */
table.lines .line-drill{color:inherit;text-decoration:underline;
  text-decoration-color:var(--line2);text-underline-offset:3px;
  text-decoration-thickness:1px}
table.lines .line-drill:hover,table.lines .line-drill:focus-visible{
  color:var(--blue-d);text-decoration-color:currentColor}
.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
mark{background:var(--yellow-soft);color:var(--ink);padding:0 3px;border-radius:3px}

/* ============================================================ REVIEW */
.review{margin-top:16px}
/* the source column is a stack of proof sheets, one per page; the gap spaces
   them, so the figures drop their default margin */
.review-source{display:flex;flex-direction:column;gap:14px}
.page-sheet{margin:0}
/* Each sheet reserves A4 space before its image arrives — `auto` hands the ratio
   back to the real page once it loads — so pages streaming in never shove the
   ones below them down. */
.page-sheet img{display:block;width:100%;height:auto;aspect-ratio:auto 1/1.414;
  background:var(--track);border:1px solid var(--line);border-radius:12px}
/* the registration slip: which sheet of how many, in the label face used for
   every other counter in the app. Only earns its place on multi-page documents */
.page-sheet figcaption{font-family:var(--mono);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mut);padding:0 0 4px 2px}
.page-sheet figcaption span{color:var(--line2)}
.review-fields .h,.review-form{max-width:520px}

/* ============================================================ PLAYGROUND */
/* the playground's own bare lists only — `:not([class])` keeps these off the
   chart lists (.hbars, .bkt-legend, .methods), which lay themselves out and
   were being overridden here by mere element-selector specificity */
.dash-panel ul:not([class]){list-style:none;margin:0;padding:0;display:flex;
  flex-direction:column;gap:8px}
.dash-panel ul:not([class]) li{display:flex;align-items:center;gap:10px;font-size:13.5px}
.pg-msg{padding:12px 15px;border-radius:14px;margin-bottom:10px;font-size:13.5px;line-height:1.55;max-width:75ch}
.pg-user{background:var(--card2);border:1px solid var(--line)}
.pg-bot{background:var(--card);border:1px solid var(--line);border-left:3px solid var(--teal)}
.pg-tool{font-family:var(--mono);font-size:11.5px;color:var(--mut);padding:7px 12px;
  background:var(--yellow-bg);border:1px solid var(--yellow-soft);border-radius:10px;margin-bottom:10px}

/* ============================================================ INSIGHTS */
/* One card now, and it takes the whole width the row always had: this is the
   page's headline figure, so it leads across the full measure rather than
   being penned into one column of the grid below it. */
.insights{display:grid;grid-template-columns:1fr;gap:16px;margin:18px 0 27px}
/* The oversized figure is this row's alone: a section leads on its own total,
   while the dashboard's cards sit four sections to a page in half-width
   columns, where 48px would not fit the amounts. The added currencies scale
   with it — smaller than the headline, larger than the line beneath. */
.insights .kpi-hero .kpi-main{font-family:var(--body);font-weight:700;font-size:48px;
  font-variant-numeric:normal;line-height:1.05;margin:6px 0 4px}
.insights .kpi-plus{font-size:29px;line-height:1.1;margin-bottom:5px}
.ins-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;
  align-items:start;margin-bottom:22px}
/* same floor, same fix as .dash-grid above: the customers grid carries a trend
   panel of its own, and its min-content is the whole series */
@media(max-width:1024px){.ins-grid{grid-template-columns:minmax(0,1fr)}}
.ins-grid .dash-panel{margin-bottom:0;min-width:0}
.ins-grid h3{display:flex;align-items:center;gap:10px}

/* nominal categories as a two-column table: label left, number right. The
   outer grid owns both column widths and every row borrows them through
   `subgrid`, so the numbers share one left edge and one right edge no matter
   how wide each row's own text is. The magnitude rides behind the row as a
   proportional wash instead of taking a column. */
.hbars{list-style:none;margin:0;padding:0;display:grid;
  grid-template-columns:minmax(0,1fr) auto;gap:2px 0}
.hbars .hbar{display:grid;grid-column:1/-1;grid-template-columns:subgrid;
  align-items:baseline;position:relative;isolation:isolate;
  padding:6px 9px;border-radius:6px;font-size:12.5px}
/* no min-width: on a skewed scale a floored sliver reads as a stray tick next
   to the label rather than as a quantity, and the number beside it already
   tells the truth */
.hbars .hbar-fill{position:absolute;z-index:-1;top:0;bottom:0;left:0;
  background:var(--wash);border-radius:6px}
.hbar-lab{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-align:left;padding-right:14px}
.hbar-val{font-family:var(--mono);font-size:11.5px;color:var(--ink);
  font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right}
.hbar-meta{color:var(--mut);font-size:10px;margin-left:7px}

/* due-date buckets: ordinal ramp + reserved status tone */
.bkt{display:flex;flex-direction:column;gap:14px}
.bkt-bar{display:flex;gap:2px;height:18px}
.bkt-seg{display:block;height:100%;border-radius:3px;min-width:3px}
.bkt-legend{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.bkt-legend li{display:flex;align-items:center;gap:8px;font-size:12.5px;
  font-variant-numeric:tabular-nums}
.bkt-key{width:10px;height:10px;border-radius:3px;flex:none}
.bkt-icon{color:var(--neg)}
/* The two had been swapped: what is overdue was drawn in the head of the
   ordinal ramp and what is not yet due in the critical ink, so the panel said
   the opposite of what it meant — and the ⚠ beside "Overdue", which takes
   --neg, sat next to a green segment. The status tone is the negative ink; the
   ramp starts at its own first step and runs dv1..dv4 through the ageing. */
.tone-crit{background:var(--neg)}
.tone-1{background:var(--dv1)}
.tone-2{background:var(--dv2)}
.tone-3{background:var(--dv3)}
.tone-4{background:var(--dv4)}
.methods{list-style:none;margin:14px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.methods li{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--mut);
  font-variant-numeric:tabular-nums}

/* ============================================================ ORDERS */
/* An order is a longer document than an invoice: a specification per cloth
   quality, a paragraph of shipping instructions, and a goods table eleven
   columns wide. So the detail view is a stack of small sections rather than
   one grid, and each keeps its own shape at the widths the app is read at. */
.ord-h{font-family:var(--disp);font-size:14px;font-weight:700;letter-spacing:-.01em;
  margin:24px 0 10px}
/* Label left, value right, with the value free to run to several lines: the
   entries range from "EX WORKS" to a full paragraph of instructions. */
.ord-terms{display:grid;grid-template-columns:minmax(120px,190px) minmax(0,1fr);
  gap:2px 18px;background:var(--card);border:1px solid var(--line);
  border-radius:16px;padding:18px 20px;margin:16px 0;font-size:13px}
.ord-terms dt{font-family:var(--mono);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mut);padding-top:3px}
.ord-terms dd{margin:0;padding-bottom:6px}
.ord-specs{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:12px}
.ord-spec{background:var(--card);border:1px solid var(--line);border-radius:16px;
  padding:16px 18px}
.ord-spec h4{margin:0 0 10px;font-family:var(--mono);font-size:13px;font-weight:700;
  letter-spacing:.04em}
.ord-spec dl{display:grid;grid-template-columns:minmax(84px,auto) minmax(0,1fr);
  gap:2px 12px;margin:0;font-size:12.5px}
.ord-spec dt{font-family:var(--mono);font-size:9.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--mut);padding-top:2px}
.ord-spec dd{margin:0;padding-bottom:4px}
/* Eleven columns will not fold: on a narrow screen the table scrolls inside
   its own box rather than pushing the page sideways. */
.ord-scroll{overflow-x:auto;border-radius:16px}
.ord-lines{width:100%;font-size:12.5px}
.ord-lines td,.ord-lines th{white-space:nowrap}
.ord-links,.ord-add{margin-top:10px}
.ord-add{padding-top:14px;border-top:1px dashed var(--line2)}
.ord-search{display:flex;gap:8px;margin-bottom:12px}
.ord-search input{flex:1;min-width:0}
/* The link/unlink buttons sit in table cells; the form around each must not
   add a line box of its own or the row grows a step taller than its siblings. */
.ord-links form,.ord-add form{display:inline;margin:0}
/* Which side of the business a document belongs to, at a glance: the two inks
   the rest of the app already uses for bought and sold.
   The class is read off the document, never picked, so these chips report:
   no pointer, and the hover ink of a control would be a lie. */
.chip[class*="cls-"]{cursor:default}
.chip.cls-supplier_invoice,.chip.cls-supplier_invoice:hover{color:var(--blue-d);
  border-color:var(--blue)}
.chip.cls-customer_invoice,.chip.cls-customer_invoice:hover{color:var(--teal-d);
  border-color:var(--teal)}
/* An order is not on either side of the ledger yet, and an unclassified
   document is where extraction gave up — the first takes the highlight ink,
   the second stays as quiet as the page's other unknowns. */
.chip.cls-order,.chip.cls-order:hover{color:var(--yellow-d);border-color:var(--yellow)}
.chip.cls-unclassified,.chip.cls-unclassified:hover{color:var(--mut);
  border-color:var(--line2)}
/* How many invoices an order was settled on. A count is a fact about the
   order, not a control, so it does not take the chip's hover ink. */
.chip.lk-count{cursor:default;color:var(--teal-d);border-color:var(--teal)}
.lk-none{color:var(--mut)}
.pad{padding:16px 2px}
@media(max-width:760px){
  .ord-terms{grid-template-columns:minmax(0,1fr);padding:16px}
  .ord-terms dd{padding-bottom:10px}
  .ord-search{flex-wrap:wrap}
}

/* ============================================================ INVOICE DRAWER */
.inv-row{cursor:pointer}
.inv-row.sel{background:var(--pink-bg)}
.inv-row.sel td:first-child{box-shadow:inset 3px 0 0 var(--pink)}
/* the uploads list opens the same drawer from its filename column, so the open
   row is marked the same way — only the row is not clickable as a whole there */
.doc-row.sel{background:var(--pink-bg)}
.doc-row.sel td:first-child{box-shadow:inset 3px 0 0 var(--pink)}
/* top/bottom rather than height:100vh, so the drawer tracks the real viewport
   (100vh also ignores a mobile browser's collapsing address bar) */
.inv-drawer{position:fixed;top:0;bottom:0;right:0;z-index:40;width:min(560px,100%);
  overflow-y:auto;overscroll-behavior:contain;background:var(--card);
  border-left:1px solid var(--line);
  box-shadow:-18px 0 40px rgba(0,0,0,.10);padding:20px 22px 40px}
.dw-head{display:flex;align-items:flex-start;gap:14px;padding-bottom:14px;
  margin-bottom:6px;border-bottom:2px solid var(--ink)}
.dw-head h2{margin:0;font-size:17px;font-weight:700}
.dw-tools{margin-left:auto;display:flex;gap:7px;flex:none}
.dw-tools button{height:auto;margin:0}
.dw-body .detail-grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  padding:16px;margin:14px 0}
.dw-body table.lines{font-size:12px}
.dw-backdrop{display:none}
@media(max-width:900px){
  .inv-drawer{width:100%;border-left:0}
  .dw-backdrop{display:block;position:fixed;inset:0;z-index:39;
    background:rgba(0,0,0,.45)}
}

@media(max-width:760px){
  /* Not a one-column grid: a grid item can only stick inside its own grid
     area, and stacked that area is just the bar's own row — nowhere to travel.
     As a block the bar's containing block is the whole shell, so it can ride
     the page down. */
  .shell{display:block}
  /* the rail folds into a top bar and stays pinned there: the nav is the only
     way off a page, and it was scrolling away from the first screenful.
     height:auto undoes the desktop 100vh, which would otherwise leave a
     full-screen bar. z-index sits under the drawer backdrop (39). */
  .side{position:sticky;top:0;z-index:30;height:auto;overflow-y:visible;
    flex-direction:row;align-items:center;gap:14px;padding:10px 16px;
    overflow-x:auto;white-space:nowrap;
    border-right:0;border-bottom:1px solid var(--rail-line);
    box-shadow:0 2px 12px rgba(0,0,0,.14)}
  .side-crest{padding:0;flex:none}
  .side-crest img{width:34px}
  .nav{margin-top:0;flex-direction:row;gap:6px;flex:none}
  .nav a{padding:8px 14px;white-space:nowrap}
  .side-tools{margin-top:0;margin-left:auto;padding-bottom:0;flex:none}
  .side .foot{display:none}
  table{display:block;overflow-x:auto}
  /* The roster is an editable table; sideways scrolling to reach the save
     button is not a phone interface. Each row folds into a labelled card
     instead — the header row is dropped and every cell names itself from the
     data-lab the template put on it. */
  .user-table,.user-table tbody,.user-table tr,.user-table td{display:block;
    overflow:visible;width:auto}
  .user-table thead{display:none}
  .user-table tr{border:1px solid var(--line2);border-radius:12px;
    background:var(--card2);padding:6px 10px;margin-bottom:10px}
  .user-table tbody tr:hover{background:var(--card2)}
  .user-table td{display:grid;grid-template-columns:76px minmax(0,1fr);
    align-items:center;gap:10px;padding:4px 0;border-bottom:0}
  /* the content-width columns of the wide table would starve as grid rows */
  .user-table .u-id,.user-table .u-mfa,
  .user-table .u-active,.user-table .u-actions{width:auto;white-space:normal}
  .user-table td::before{content:attr(data-lab);font-family:var(--mono);
    font-size:9.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--mut)}
  /* the action row spans the card and drops its (empty) label column */
  .user-table .u-actions{grid-template-columns:minmax(0,1fr);padding-top:8px}
  .user-table .u-actions::before{display:none}
  /* a folded card has no row height to protect: the buttons may wrap onto a
     second line, and the password field goes back to sitting under its summary
     instead of floating over the card below */
  .user-table .u-tools{flex-wrap:wrap}
  .user-table .u-pw{position:static;margin-top:6px;padding:0;border:0;
    border-radius:0;background:none;box-shadow:none}
  .user-table .u-pw input{width:100%}
  .authpage{padding:28px 18px 64px}
  .authfoot{bottom:18px;font-size:10px}
  .authcard{padding:22px 20px 20px;border-radius:16px}
  .authcrest{width:46px;margin-bottom:12px}
  .content{padding-left:18px;padding-right:18px}
}
