/* =====================================================================
   Integrated Accounting System - interface styles
   ===================================================================== */
:root {
  /* ACCOVA identity: ink and teal on mist.
     INK  #102B36  primary text and dark panels
     TEAL #00A995  the accent, and every action
     MIST #F3F7F7  the page behind the cards
     The brand board names three colours and nothing else, so everything below
     is either one of them, a tint of one, or a status colour that has to stay
     what it is - a red that meant "wrong" cannot become teal because the logo
     changed. */
  --bg: #F3F7F7;
  --surface: #ffffff;
  --surface-2: #f8fbfb;
  --border: #dfe7e8;
  --border-strong: #c3d0d2;
  --text: #102B36;
  --text-dim: #4a5f68;
  /* Darkened from #8d867d, which measured 3.2:1 on the page and 3.6:1 on a
     card - below the 4.5:1 a body of text needs to be read reliably. It is the
     colour of .muted, .hint, .empty and every metric label, so it was the most
     widespread readability fault in the product. Now 4.9:1 and 5.5:1. */
  --text-faint: #5b7079;
  /* Teal is the accent the brand board gives to actions, but the pure #00A995
     measures 2.4:1 on white - far under the 4.5:1 a link or a small label needs.
     So the token is a darkened teal of the same hue for anything that has to be
     read, and the pure brand teal is kept for fills and rules, where contrast is
     not a reading matter. */
  --brand: #00776A;
  --brand-pure: #00A995;
  --brand-dark: #005A50;
  --brand-soft: #e6f6f3;
  /* The same teal again, but for things that are PAINTED teal with white on
     them - buttons and badges - rather than written in teal. In the light
     theme the two are identical. They part in the dark one: text teal has to
     turn light to be read on a dark card, and a light teal button with white
     lettering on it cannot be read at all. */
  --brand-fill: #00776A;
  --brand-fill-hover: #005A50;
  --green-fill: #16794a;
  /* The second teal: focus rings, the info alert, the chosen tick, the edge of
     a toast. This was called --gold, after the identity it replaced, and
     pointed at a teal - a name that lied to anybody editing the stylesheet.
     Darkened from #0E7C8C, which read at 4.30:1 on its own soft background. */
  --accent: #0A6E7C;
  --accent-soft: #e7f2f4;
  --accent-line: #c3dde2;
  --green: #16794a;
  --green-soft: #e4f4ec;
  --red: #b4232a;
  --red-soft: #fceaeb;
  /* Was #96690d, 4.4:1 on its own soft background - just under the line, and
     it carries the Draft chip and every warning in the system. */
  --amber: #8a5f09;
  --amber-soft: #fdf3dc;
  --slate: #35506b;
  --slate-soft: #e8eef5;
  /* The edge each alert is drawn with - its own colour, faded to a line. */
  --green-line: #b9e2cd;
  --red-line: #f2c3c5;
  --amber-line: #f0dcae;
  --sidebar: #102B36;
  --sidebar-2: #17394a;

  /* The panel's own words. The menu was coloured with ten one-off greys, three
     of which the eye cannot tell apart (#8fa8b1, #85a0a9, #94adb6), and its
     foot with a separate warm family - rose and crimson left over from the old
     maroon identity, on the opposite side of the colour wheel from the teal
     above it. One cool family now, named for what each one does. The panel is
     dark in both themes, so none of these change with the theme. */
  --side-strong: #eaf4f6;          /* hover, the active entry, names      10.4+ */
  --side-text: #cbdbe0;            /* the links themselves                10.4:1 */
  --side-label: #a7bcc4;           /* open section headings                7.5:1 */
  --side-muted: #8fa8b1;           /* icons, folded headings, hints        5.9:1 */
  --side-edge: #56727d;            /* the outline of a button on the panel 3.0:1 */
  --side-line: rgba(255, 255, 255, .08);
  --side-hover: rgba(255, 255, 255, .055);

  /* Chart series. Six, chosen by measurement: every pair stays apart for
     normal sight (dE >= 23) and for red-green colour blindness (dE >= 14.6),
     and every one stands at 3:1 or better against the card. The old palette
     had ten, and under colour blindness the brand teal and the rose became
     the same colour, as did the second teal and the slate. Past six no
     palette stays apart; a chart that needs more folds the rest into grey. */
  --chart-teal: #009987;
  --chart-ink: #102B36;
  --chart-amber: #B67A08;
  --chart-blue: #3565B0;
  --chart-clay: #C4552F;
  --chart-grey: #4F5F67;
  --chart-grid: #e2eaeb;
  --chart-axis: #5b7079;
  --chart-dot: #ffffff;

  --radius: 8px;
  --shadow: 0 1px 2px rgba(16, 43, 54, .06), 0 4px 16px rgba(16, 43, 54, .08);
  --topbar-glass: rgba(255, 255, 255, .86);

  /* ---------------------------------------------------------------------
     The rest of the system, not just the colours.

     Colour was tokenised from the start; spacing, type and corners were not,
     so every new screen solved layout with a one-off number and the stylesheet
     drifted to fourteen corner radii and twenty font sizes. These are the
     values it actually converged on, named.
     --------------------------------------------------------------------- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;

  --r-sm: 4px; --r-md: 6px; --r-lg: 8px; --r-pill: 999px;

  /* A fixed ladder, one step per job. The old one started at 11px and a set of
     books is read for six hours at a time, not glanced at - every step below
     went up by a point, and the two that carry meaning (the page you are on
     and the figure you came for) were given sizes of their own. */
  --fs-xs: 12px;                 /* labels, chips */
  --fs-sm: 13px;                 /* secondary text under a figure */
  --fs-base: 14px;               /* body, tables, forms */
  --fs-md: 15px;                 /* card and section titles */
  --fs-lg: 16px;
  --fs-xl: 23px;                 /* the page title */
  --fs-kpi: 29px;                /* the four figures on the front page */

  /* Three weights, because Segoe UI has three. 550, 650 and 680 were rounded
     by the browser to 600, 700 and 700 anyway - precision that existed only in
     the stylesheet. */
  --fw-normal: 400; --fw-medium: 600; --fw-bold: 700;

  --font-ui: "Segoe UI", Inter, Roboto, system-ui, -apple-system, sans-serif;
  --font-mono: "Cascadia Mono", Consolas, "SF Mono", monospace;
}

* { box-sizing: border-box; }

/* The `hidden` attribute must beat any display rule below - the modal backdrop
   is display:flex, which would otherwise keep it permanently visible. */
[hidden] { display: none !important; }

html, body {
  margin: 0; height: 100%;
  font-family: "Segoe UI", Inter, Roboto, system-ui, -apple-system, sans-serif;
  font-size: 14px; color: var(--text); background: var(--bg);
}

/* Links were left to the browser, which paints them blue and then purple once
   visited - two colours nothing else in the product uses, appearing on nearly
   every card. They are the brand colour now, and they stay it after a visit. */
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }
a:visited { color: var(--brand); }
/* The sidebar and anything wearing a button keep their own colour. */
.nav a, .nav a:visited, .btn, a.btn, a.btn:visited { color: inherit; text-decoration: none; }
.nav a:hover, a.btn:hover { text-decoration: none; }

#app { display: flex; height: 100vh; overflow: hidden; }
/* Out of sight until the session is known - see index.html. Visibility, not
   display, so nothing is laid out twice when the cover comes off. */
#app.booting { visibility: hidden; }

/* ------------------------------- Sidebar ------------------------------ */
/* A faint arabesque, the kind cut into a mashrabiya screen, drawn once as a
   data URI so the page still works with no network at all. */
/* The arabesque is still there, at a third of its old strength. It was drawn
   at 0.035 opacity across the whole panel, which is faint on a designer's
   monitor and a texture you read *through* on an ordinary one - thirty menu
   links sat on top of a moving background all day. Branding is worth a little
   readability, not this much: the pattern now only shows at the top, behind
   the mark, and the list itself is on flat colour. */
.sidebar {
  width: 224px; flex: 0 0 224px; color: var(--side-text);
  display: flex; flex-direction: column; overflow: hidden;
  background: linear-gradient(176deg, #17394a 0%, var(--sidebar) 38%, #0b1f28 100%);
}
/* The mark gets room to breathe: stacked and centred, large enough to read the
   bars inside the A rather than squinting at a 40px thumbnail. */
/* The block is deliberately compact. At its old size the mark and the wordmark
   took a fifth of the panel, and the panel's job is the menu: what was gained
   in presence was paid for in links you had to scroll to. The mark is still
   large enough to read the arrow inside the A. */
.brand {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: 14px 14px 11px; border-bottom: 1px solid var(--side-line);
  background:
    url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'>\
<g fill='none' stroke='%23ffffff' stroke-opacity='0.016' stroke-width='1'>\
<path d='M28 2 L54 28 L28 54 L2 28 Z'/><path d='M28 14 L42 28 L28 42 L14 28 Z'/>\
<path d='M0 0 L14 14 M56 0 L42 14 M0 56 L14 42 M56 56 L42 42'/></g></svg>") 0 0/56px 56px,
    radial-gradient(120% 90% at 50% 0%, rgba(0,169,149,.09), transparent 62%),
    linear-gradient(180deg, rgba(0,169,149,.06), transparent);
}
.brand-mark {
  /* The artwork is wider than it is tall, so it is fitted inside the square
     rather than stretched to it. */
  width: 58px; height: 58px; display: block; object-fit: contain;
  /* The lockup carries its own ink background, which sits close to the panel
     behind it. A faint teal halo lifts it off; the dark shadow underneath is
     kept for depth. Both are stronger now that the pattern behind them is
     fainter - the mark stands out by being lit, not by shouting over texture. */
  filter: drop-shadow(0 0 9px rgba(0,169,149,.34))
          drop-shadow(0 4px 10px rgba(0,0,0,.45));
}
.brand-name {
  color: #fff; font-weight: var(--fw-bold); font-size: 19px; letter-spacing: 4px;
  line-height: 1.1; margin-top: 9px; padding-left: 4px;  /* optical centring */
}
.brand-tagline {
  font-size: 10px; letter-spacing: .8px; text-transform: uppercase;
  /* The pure brand teal, not the darkened one: this line sits on the ink panel,
     where the darkened teal meant for white backgrounds goes nearly invisible. */
  color: var(--brand-pure); margin-top: 5px;
}
.brand-sub { font-size: 11px; color: var(--side-muted); margin-top: 7px;
  padding-top: 7px; border-top: 1px solid var(--side-line);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 200px; }

/* ---------------------------- The folded menu -------------------------
   Folded, the panel keeps only its icons: the module is still one click away
   and the table gets back 168px. What it must not become is a guessing game,
   so each icon carries its own entry's name beside it on hover, and the choice
   is remembered - somebody who lives in payroll should not have to fold the
   menu again every morning. */
.rail-toggle {
  flex: 0 0 auto; height: 22px; border: none; cursor: pointer;
  background: rgba(255,255,255,.04); color: var(--side-muted); line-height: 1;
  border-bottom: 1px solid rgba(255,255,255,.06);
}
.rail-toggle::before { content: "\00AB \00A0 NARROW"; letter-spacing: 1px; font-size: 9.5px; }
/* The word is the stylesheet's, so the dictionary never saw it and Arabic
   read NARROW. Written as escapes - "تضييق القائمة" - so the file's encoding
   cannot mangle it; no letter-spacing, which pulls Arabic letters apart. The
   arrow is the same character: in a right-to-left line it turns round by
   itself and points at the edge the menu folds towards. */
[dir="rtl"] .rail-toggle::before {
  content: "\00AB\00A0\00A0\062A\0636\064A\064A\0642\00A0\0627\0644\0642\0627\0626\0645\0629";
  letter-spacing: 0; font-size: 11px;
}
.rail-toggle:hover { background: rgba(0,169,149,.16); color: var(--side-strong); }
#app.rail .rail-toggle::before { content: "\00BB"; font-size: 13px; letter-spacing: 0; }
#app.rail .sidebar { width: 56px; flex: 0 0 56px; }
#app.rail .brand { padding: 10px 4px 8px; }
#app.rail .brand-mark { width: 34px; height: 34px; }
#app.rail .brand-name,
#app.rail .brand-tagline,
#app.rail .brand-sub,
#app.rail .nav-group,
#app.rail .session-text,
#app.rail .session-actions { display: none; }
#app.rail .nav a { padding: 9px 0; justify-content: center; gap: 0; position: relative; }
#app.rail .nav a .badge { display: none; }
#app.rail .nav a::before { font-size: var(--fs-base); width: auto; }
/* Every section is shown while folded - there are no headings left to open. */
#app.rail .nav-links { display: block !important; }
#app.rail .sidebar-foot { padding: 8px 4px; }
/* The entry's own words, beside the icon, on hover. */
#app.rail .nav a:hover::after {
  content: attr(data-label); position: absolute; inset-inline-start: 100%;
  margin-inline-start: 8px; white-space: nowrap; z-index: 40;
  background: var(--sidebar-2); color: var(--side-strong); padding: 5px 10px;
  border-radius: var(--r-sm); font-size: var(--fs-sm); font-weight: var(--fw-normal);
  box-shadow: 0 6px 18px rgba(0,0,0,.45);
}

.nav { flex: 1; overflow-y: auto; padding: 8px 0 16px; }
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-thumb { background: #2c4b58; border-radius: 3px; }
/* Each heading folds its own section, so thirty links still fit on a laptop
   screen without scrolling past the half of the system you are not using. */
/* Gold on every one of ten headings turned the accent into wallpaper. The
   headings are now quiet stone and the gold is spent where it earns its
   keep: the bar beside the page you are actually on. */
.nav-group {
  display: flex; align-items: center; gap: 7px;
  padding: 12px 16px 6px; font-size: var(--fs-xs); text-transform: none;
  letter-spacing: .2px; color: var(--side-label); opacity: 1; font-weight: var(--fw-bold);
  cursor: pointer; user-select: none;
}
.nav-group:hover { color: var(--side-strong); }
.nav-group:focus-visible { outline: 2px solid var(--brand-pure); outline-offset: -2px; }
.nav-group::after {
  content: "\2039";                 /* a chevron, pointing down when open */
  margin-left: auto; font-size: 15px; line-height: 1; opacity: .7;
  transform: rotate(-90deg); transition: transform .15s ease;
}
.nav-group.collapsed::after { transform: rotate(90deg); }
.nav-group.collapsed { color: var(--side-muted); }
/* A heading whose links this account cannot reach folds away with them,
   rather than opening onto nothing. */
.nav-group[hidden] { display: none !important; }
.nav a {
  display: flex; align-items: center; gap: 9px; padding: 7px 16px;
  color: var(--side-text); text-decoration: none; font-size: var(--fs-base);
  border-left: 3px solid transparent;
}
.nav a::before { content: attr(data-icon); font-size: var(--fs-sm); color: var(--side-muted);
  width: 14px; text-align: center; }
.nav a:hover { background: var(--side-hover); color: #fff; }
/* Where you are, said properly: the brand colour behind it and a teal bar down
   the edge, rather than a thin outline that read as a focus ring. */
.nav a.active {
  background: linear-gradient(90deg, rgba(0,169,149,.55), rgba(0,169,149,.18));
  color: #fff; border-left-color: var(--brand-pure); font-weight: var(--fw-medium);
}
.nav a.active::before { color: var(--brand-pure); }
.badge {
  margin-left: auto; background: var(--brand-fill); color: #fff; border-radius: 9px;
  padding: 1px 7px; font-size: 10px; font-weight: var(--fw-bold); min-width: 18px; text-align: center;
}
.badge:empty { display: none; }
.sidebar-foot { padding: 10px 16px; border-top: 1px solid var(--side-line);
  font-size: 11px; color: var(--side-muted); }

/* -------------------------------- Main -------------------------------- */
/* Warm stone with a whisper of the brand in the corners - enough to feel
   designed, faint enough that a page of figures still reads first. */
.main {
  flex: 1; display: flex; flex-direction: column; overflow: hidden;
  background:
    radial-gradient(900px 520px at 100% 0%, rgba(0,169,149,.10), transparent 60%),
    radial-gradient(760px 480px at 0% 100%, rgba(16,43,54,.07), transparent 62%),
    var(--bg);
}
/* The letterhead for paper. Print hides the sidebar and the title bar, so
   without this a printed report carried no logo and nothing saying whose
   figures these were. Hidden on screen; @media print brings it out. */
.print-head { display: none; }

.topbar {
  min-height: 56px; flex: 0 0 auto; background: var(--topbar-glass);
  backdrop-filter: blur(6px); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-5);
}
.topbar h1::before {
  content: ""; display: inline-block; width: 3px; height: 17px; margin-right: 9px;
  background: linear-gradient(180deg, var(--accent), var(--brand));
  border-radius: 2px; vertical-align: -3px;
}
/* The title gives way, the buttons do not. A quotation toolbar carries six of
   them next to a long document number; with a locked height and permission to
   wrap, the second row wrapped into space that did not exist and Convert to
   Invoice became unclickable. */
.topbar h1 { font-size: var(--fs-xl); margin: 0; font-weight: var(--fw-bold);
  letter-spacing: -.3px;
  flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
/* The line under the title on the front page: the day, and who is reading. */
.topbar .page-sub { font-size: var(--fs-sm); color: var(--text-dim); margin-top: 1px; }
.topbar .title-block { display: flex; flex-direction: column; min-width: 0; }
.topbar .title-block h1 { line-height: 1.15; }
.topbar-actions { margin-left: auto; display: flex; gap: var(--sp-2);
  align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.menu-toggle { display: none; }
.content { flex: 1; overflow-y: auto; padding: 20px; }
.loading { padding: 40px; text-align: center; color: var(--text-faint); }

/* The public demonstration says so on every screen. */
.demo-bar {
  flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 4px 12px;
  align-items: center; justify-content: center; text-align: center;
  padding: 7px 20px; font-size: var(--fs-sm); color: var(--text);
  background: var(--surface-2); border-bottom: 1px solid var(--border);
}
.demo-bar a { color: var(--brand); font-weight: 600; }

/* Sits between the title bar and the page, so it survives every redraw and
   is read before anything below it. Empty unless there is something to say. */
.licence-bar { flex: 0 0 auto; padding: 0 20px; }
.licence-bar:empty { display: none; }
.licence-bar .alert { margin-top: 14px; }
.code-block {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); font-family: var(--font-mono);
  padding: var(--sp-3); font-size: var(--fs-sm); overflow-x: auto;
  margin: var(--sp-2) 0;
}

/* The first paragraph in a panel should not push the panel open, and the last
   should not leave a gap at the bottom. Twenty-two screens were each saying
   style="margin-top:0" to arrange this one sentence at a time. */
.card-body > p:first-child, .modal-body > p:first-child,
.card-body > .alert:first-child, .modal-body > .alert:first-child,
.alert > p:first-child { margin-top: 0; }
.card-body > p:last-child, .modal-body > p:last-child,
.alert > p:last-child { margin-bottom: 0; }

/* A row of buttons under a form or a list. */
.button-row { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); flex-wrap: wrap; }

/* A metric that has to carry a long value rather than a figure. */
.metric.compact .value { font-size: var(--fs-lg); }

/* ------------------------------- Buttons ------------------------------ */
button, .btn {
  font: inherit; font-weight: var(--fw-medium); padding: 7px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
  cursor: pointer; display: inline-flex; align-items: center; gap: var(--sp-2);
  white-space: nowrap; text-decoration: none; line-height: 1.4;
}
button:hover, .btn:hover { background: var(--surface-2); border-color: var(--text-faint); }
/* A button that is working is not a button you may press again. Dimming alone
   still invites the second click that files the journal entry twice. */
button:disabled, .btn[aria-disabled="true"] {
  opacity: .55; cursor: not-allowed; filter: saturate(.4); pointer-events: none;
}

/*
   One focus ring, everywhere.

   Before this the only thing with a visible focus style was a text field, and
   even that was a recoloured border - which a checkbox does not have. Anyone
   working by keyboard, which on a reconciliation screen is everyone, had no
   way of telling where they were. The ring is drawn outside the control so it
   is visible on a maroon button as well as on white.
*/
button:focus-visible, .btn:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
a:focus-visible, .tree-toggle:focus-visible,
table.grid tbody tr.clickable:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(0, 169, 149, .20);
}
/* On the ink panel the page's focus teal all but vanishes; the bright brand
   teal is the one that reads there (5.0:1). */
.nav a:focus-visible, .nav-group:focus-visible,
.sidebar-foot button:focus-visible {
  outline: 2px solid var(--brand-pure); outline-offset: -2px; box-shadow: none;
}
table.grid tbody tr.clickable:focus-visible { outline-offset: -2px; }
.btn-primary { background: var(--brand-fill); border-color: var(--brand-fill); color: #fff; }
.btn-primary:hover { background: var(--brand-fill-hover); border-color: var(--brand-fill-hover); }
.btn-danger { background: var(--surface); border-color: var(--red); color: var(--red); }
.btn-danger:hover { background: var(--red-soft); }
.btn-success { background: var(--green-fill); border-color: var(--green-fill); color: #fff; }
.btn-success:hover { filter: brightness(1.1); }
.btn-sm { padding: 4px 9px; font-size: 12px; }
.icon-btn { border: none; background: none; padding: 5px 8px; font-size: 17px; color: var(--text-dim); }
.icon-btn:hover { background: var(--surface-2); }

/* -------------------------------- Cards ------------------------------- */
.card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); margin-bottom: 16px; overflow: hidden;
}
.card-head {
  padding: 12px 16px; border-bottom: 1px solid var(--border); display: flex;
  align-items: center; gap: 10px; flex-wrap: wrap; background: var(--surface);
}
/* A card heading is the label on a drawer: it should read at a glance from
   across a desk. At 600 weight in the body colour it sank into the table
   under it, and a screen of fifteen cards became one grey wall. */
.card-head h2 { font-size: 15px; margin: 0; font-weight: var(--fw-bold);
  color: var(--text); letter-spacing: -.1px; }
.card-head .spacer { margin-left: auto; }
.card-body { padding: 16px; }
.card-body.tight { padding: 0; }

/* ----------------------- Logo, stamp and signature --------------------
   Shown as they will print. A file name tells nobody whether a signature
   came out upside down; the picture does, which is the whole point of
   putting them on the screen rather than in a folder. The frame keeps a
   pale chequer behind it so a transparent PNG can be told from a white
   rectangle - the difference that decides whether a signature sits on the
   page or in a box on it. */
.art-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px; }
.art-slot { border: 1px solid var(--line); border-radius: 8px; padding: 12px;
  display: flex; flex-direction: column; gap: 8px; }
.art-label { font-weight: var(--fw-bold); font-size: 13px; }
.art-frame { height: 96px; display: flex; align-items: center; justify-content: center;
  border-radius: 6px; padding: 6px;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #eceff3 25%, transparent 25%, transparent 75%, #eceff3 75%),
    linear-gradient(45deg, #eceff3 25%, transparent 25%, transparent 75%, #eceff3 75%);
  background-size: 14px 14px; background-position: 0 0, 7px 7px; }
.art-frame img { max-width: 100%; max-height: 100%; object-fit: contain; }
.art-note { font-size: 12px; line-height: 1.45; }
.art-actions { display: flex; gap: 8px; margin-top: auto; }

/* ------------------------------- Metrics ------------------------------ */
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px;
  margin-bottom: 16px; }
.metric {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px 16px; box-shadow: var(--shadow);
}
.metric { display: flex; flex-direction: column; }
.metric .label { font-size: var(--fs-xs); text-transform: none; letter-spacing: 0;
  color: var(--text-dim); font-weight: var(--fw-medium); }
.metric .value { font-size: 22px; font-weight: var(--fw-bold); margin-top: 6px;
  font-variant-numeric: tabular-nums; letter-spacing: -.4px; }
.metric .sub { font-size: var(--fs-sm); color: var(--text-dim); margin-top: 3px;
  margin-top: auto; padding-top: 4px; }
/* A coloured edge was on roughly half the tiles, which made it decoration
   rather than a signal. It is now kept for the two states that mean something:
   something is wrong, or something needs doing. */
.metric.good .value { color: var(--green); }
.metric.bad .value { color: var(--red); }
.metric.warn { border-left: 3px solid var(--amber); }
.metric.risk { border-left: 3px solid var(--red); }

/* ------------------------- The four that matter ---------------------- */
/* Everything above the fold answers one question each, in a figure big enough
   to read from a standing position, with one line underneath and no more. */
.kpi-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px; margin-bottom: 18px; align-items: stretch;
}
.kpi {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 16px 18px 14px; display: flex; flex-direction: column; min-height: 118px;
}
.kpi .kpi-label { font-size: var(--fs-xs); color: var(--text-dim);
  font-weight: var(--fw-medium); letter-spacing: .1px; }
.kpi .kpi-value {
  font-size: var(--fs-kpi); font-weight: var(--fw-bold); line-height: 1.08;
  margin-top: 8px; font-variant-numeric: tabular-nums; letter-spacing: -.8px;
  color: var(--text);
}
/* The fils and the currency are there when you need them and out of the way
   when you are scanning four figures for their order of magnitude. */
.kpi .kpi-value .dec { font-size: .56em; font-weight: var(--fw-medium);
  color: var(--text-dim); letter-spacing: 0; }
.kpi .kpi-value .cur { font-size: .42em; font-weight: var(--fw-medium);
  color: var(--text-faint); margin-left: 5px; letter-spacing: .4px; }
.kpi .kpi-note { font-size: var(--fs-sm); color: var(--text-dim);
  margin-top: auto; padding-top: 8px; }
.kpi.is-good .kpi-value { color: var(--green); }
.kpi.is-bad .kpi-value { color: var(--red); }
.kpi.is-flagged { border-left: 3px solid var(--amber); }

/* ---------------------------- Dashboard bands -------------------------
   Twelve tiles in one run is a wall, not a dashboard: the eye has nowhere to
   stop and no idea which three belong together. Naming the groups - what the
   company is worth, what it earned, who owes whom - turns the same figures
   into a page that can be read in order. */
.band { margin: 0 0 18px; }
.band > .band-head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 0 2px 10px; padding-bottom: 7px;
  border-bottom: 2px solid var(--border-strong);
}
/* Sentence case, not shouted. Capitals across every heading is the look of a
   terminal from 1994; the same words set normally read faster and date less. */
.band > .band-head h2 {
  margin: 0; font-size: var(--fs-md); font-weight: var(--fw-bold); color: var(--text);
  text-transform: none; letter-spacing: -.1px;
}
.band > .band-head h2::before {
  content: ""; display: inline-block; width: 3px; height: 14px; margin-right: 9px;
  background: var(--brand-fill); border-radius: 2px; vertical-align: -2px;
}
.band > .band-head .band-note { font-size: var(--fs-sm); color: var(--text-dim);
  margin-left: auto; }
.band .metrics { margin-bottom: 0; }

/* The statement block: a short balance sheet or trading summary, ruled the
   way one is ruled on paper, with the total carrying a double line. */
.figures { width: 100%; border-collapse: collapse; font-size: var(--fs-base); }
.figures td { padding: 7px 4px; border-bottom: 1px solid var(--border); }
.figures td.num { text-align: right; font-variant-numeric: tabular-nums;
  font-weight: var(--fw-medium); white-space: nowrap; }
.figures tr.sum td { border-top: 1px solid var(--border-strong); border-bottom: none;
  font-weight: var(--fw-bold); }
.figures tr.sum td.num { font-size: 15px; }
.figures tr.rule td { border-bottom: 2px double var(--border-strong); }
.figures tr:last-child td { border-bottom: none; }
.figures td.indent { padding-left: 18px; color: var(--text-dim); }

/* ---------------------------- Fiscal periods -------------------------- */
.period-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 10px; }
.period-tile { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px;
  background: var(--surface); display: flex; flex-direction: column; gap: 4px; min-height: 96px; }
.period-tile.closed { background: var(--surface-2); }
.period-tile .period-name { font-weight: var(--fw-medium); display: flex; align-items: center;
  justify-content: space-between; gap: 6px; }
.period-tile .period-counts { font-size: 12px; color: var(--text-dim); }
.period-tile .period-actions { margin-top: auto; display: flex; gap: 4px; flex-wrap: wrap; }

/* A figure on its own says little. The move since last month is the part
   anyone actually reads, so it sits beside the number, not under it. */
.metric .value-row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.trend { font-size: 12px; font-weight: var(--fw-medium); white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.trend.up { color: var(--green); }
.trend.down { color: var(--red); }
.trend.flat { color: var(--text-faint); }

/* ----------------------------- Action centre --------------------------
   Everything waiting on a person, in one place and in priority order, so
   the first question the dashboard answers is "what do I have to do today".
   -------------------------------------------------------------------- */
.actions-card .card-body { padding: 0; }
.quick-create { display: flex; gap: var(--sp-2); margin-right: var(--sp-3);
  padding-right: var(--sp-3); border-right: 1px solid var(--border); }
.action-more { margin-left: var(--sp-2); }
.actions-card { margin-bottom: 18px; }

.action-row {
  display: flex; align-items: center; gap: 12px; padding: 10px 16px;
  border-bottom: 1px solid var(--border); font-size: var(--fs-base);
}
.action-row:last-child { border-bottom: none; }
.action-row .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; }
.action-row .dot.high { background: var(--red); }
.action-row .dot.medium { background: var(--amber); }
.action-row .dot.low { background: var(--text-faint); }
.action-row .what { flex: 1; min-width: 0; }
.action-row .what strong { font-weight: var(--fw-bold); }
.action-row .detail { color: var(--text-dim); font-size: var(--fs-sm); margin-top: 2px; }
.action-row .count {
  font-variant-numeric: tabular-nums; font-weight: var(--fw-bold); font-size: 15px;
  min-width: 2ch; text-align: right;
}
.action-clear { padding: 22px 16px; text-align: center; color: var(--green);
  font-size: 13px; font-weight: var(--fw-medium); }

/* -------------------------------- Tables ------------------------------ */
/*
   The header row has to stay put while a long report scrolls, or six columns
   of figures end up unlabelled halfway down a general ledger.

   `position: sticky` only sticks inside a box that actually scrolls. With
   `overflow-x: auto` and no height the wrapper never scrolls vertically, so
   the header stuck to a box that never moved - which is to say it did nothing,
   on every screen in the product except the one that set a height by hand.
   The height is what makes it real, and the totals row is worth pinning too:
   it is the line an accountant is looking for.
*/
/* max() keeps a short window from collapsing the table to nothing: on a
   450px-tall screen the subtraction goes negative and the rows disappear. */
.table-wrap { overflow: auto; max-height: max(260px, calc(100vh - 232px)); }
.table-wrap.short { max-height: max(220px, 44vh); }
.table-wrap.full { max-height: none; overflow: visible; overflow-x: auto; }
table.grid { width: 100%; border-collapse: collapse; font-size: var(--fs-base); }
table.grid thead th {
  background: var(--surface-2); text-align: left; padding: 9px 12px;
  font-weight: var(--fw-medium);
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .5px;
  color: var(--text-dim);
  white-space: nowrap; position: sticky; top: 0; z-index: 2;
  /* A sticky cell drops its border when it detaches, so the line under the
     header is drawn as an inset shadow instead. */
  box-shadow: inset 0 -1px 0 var(--border);
}
table.grid tfoot td { position: sticky; bottom: 0; z-index: 2; }
table.grid tbody td { padding: 9px 12px; border-bottom: 1px solid var(--border); vertical-align: middle; }
table.grid tbody tr:hover { background: var(--surface-2); }
table.grid tbody tr.clickable { cursor: pointer; }
/* A list of names with no bullets and no indent, for a result that is read
   rather than counted - who received their payslip and who did not. */
ul.plain { list-style: none; margin: 4px 0 10px; padding: 0; }
ul.plain li { padding: 3px 0; border-bottom: 1px solid var(--border); }
ul.plain li:last-child { border-bottom: 0; }

/* The row you are standing on, in a list that includes it - the revision
   history shows every round of an offer, and one of them is the page you are
   already reading. */
table.grid tbody tr.row-highlight { background: var(--accent-soft); }
table.grid tbody tr.row-highlight td:first-child { box-shadow: inset 3px 0 0 var(--brand); }
table.grid tfoot td {
  padding: 10px 12px; font-weight: var(--fw-bold); border-top: 2px solid var(--border-strong);
  background: var(--surface-2);
}
/* A search that narrows what is already on the screen, sitting in the card's
   own heading rather than above it - it belongs to that table. */
.table-search {
  width: 232px; max-width: 42vw; margin-inline-end: 12px;
  padding: 5px 10px; font-size: var(--fs-sm); font-family: inherit;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--text);
}
.table-search:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(0, 169, 149, .16);
}

/* ------------------------- Wide tables, made readable -------------------
   A payroll run is nineteen columns. Two things make one of those legible on a
   screen: rows that do not waste half their height on wrapped job titles, and
   the name staying in place while the figures scroll past it. */
table.grid.dense thead th { padding: 6px 10px; }
table.grid.dense tbody td { padding: 5px 10px; }
table.grid.dense tfoot td { padding: 7px 10px; }
/* Text columns hold one line each; the whole value is on the cell's tooltip.
   Figures were never allowed to wrap. */
table.grid.dense tbody td:not(.num) {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* A pinned cell has to paint over the one sliding under it, so it carries its
   own background rather than inheriting the row's. */
.pinned-grid table.grid tbody td.pinned { background: var(--surface); z-index: 1; }
.pinned-grid table.grid tbody tr:hover td.pinned { background: var(--surface-2); }
.pinned-grid table.grid thead th.pinned { background: var(--surface-2); z-index: 3; }
.pinned-grid table.grid tfoot td.pinned { background: var(--surface-2); z-index: 3; }
/* The join where the pinned block ends, so the eye can see what is held. */
.pinned-grid table.grid td.pinned-last,
.pinned-grid table.grid th.pinned-last { box-shadow: 1px 0 0 var(--border-strong); }
[dir="rtl"] .pinned-grid table.grid td.pinned-last,
[dir="rtl"] .pinned-grid table.grid th.pinned-last { box-shadow: -1px 0 0 var(--border-strong); }

.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* A figure is read against its heading, so the heading has to sit over it. The
   rules above align every header left, which beats .num on specificity and
   leaves the amount stranded under the column before it — these put it back. */
table.grid thead th.num,
table.grid tfoot td.num,
table.lines th.num { text-align: right; }
.mono { font-family: var(--font-mono); font-size: var(--fs-sm); }
.muted { color: var(--text-faint); }
.strong { font-weight: var(--fw-medium); }
.pos { color: var(--green); }
.neg { color: var(--red); }
.empty { padding: 34px; text-align: center; color: var(--text-faint); }
.row-actions { display: flex; gap: 5px; justify-content: flex-end; }

/* ---------------------------- Account tree ---------------------------- */
.tree-name { display: flex; align-items: center; gap: 6px; }
.tree-toggle {
  width: 16px; height: 16px; border: none; background: none; padding: 0; cursor: pointer;
  color: var(--text-faint); font-size: 10px; line-height: 1;
}
.tree-toggle.leaf { visibility: hidden; }
tr.group-row > td { background: var(--surface-2); font-weight: var(--fw-medium); }
tr.hidden-row { display: none; }

/* -------------------------------- Chips ------------------------------- */
.chip {
  display: inline-block; padding: 2px 9px; border-radius: 11px; font-size: 11px;
  font-weight: var(--fw-medium); letter-spacing: .2px; white-space: nowrap;
}
.chip-draft { background: var(--amber-soft); color: var(--amber); }
.chip-registered { background: var(--slate-soft); color: var(--slate); }
.chip-posted { background: var(--green-soft); color: var(--green); }
.chip-cancelled { background: var(--red-soft); color: var(--red); }
.chip-neutral { background: var(--surface-2); color: var(--text-dim); border: 1px solid var(--border); }
.chip-brand { background: var(--brand-soft); color: var(--brand-dark); }

/* -------------------------------- Forms ------------------------------- */
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 13px; }
.form-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.field { display: flex; flex-direction: column; gap: 4px; }
.field.span-2 { grid-column: span 2; }
.field.span-all { grid-column: 1 / -1; }
.field label { font-size: 12px; font-weight: var(--fw-medium); color: var(--text-dim); }
.field label .req { color: var(--red); }
input, select, textarea {
  font: inherit; padding: 7px 10px; border: 1px solid var(--border-strong);
  border-radius: 6px; background: var(--surface); color: var(--text); width: 100%;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(0, 169, 149, .16);
}
input[readonly], input:disabled, select:disabled {
  background: var(--surface-2); color: var(--text-dim); cursor: not-allowed;
}
textarea { min-height: 62px; resize: vertical; }
input[type="checkbox"] { width: auto; accent-color: var(--brand); }

/* A figure must always be fully readable. The browser's spinner arrows eat
   about 17px on the right — exactly the room the digits need — and nobody
   clicks an arrow to reach 1,000,000, so they go. Tabular figures keep the
   columns of an amount aligned as it is typed. */
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
  font-variant-numeric: tabular-nums;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.check-field { flex-direction: row; align-items: center; gap: 8px; }
.check-field label { font-size: 13px; color: var(--text); }
.filters { display: flex; gap: 9px; align-items: flex-end; flex-wrap: wrap; }
.filters .field { min-width: 145px; }
.hint { font-size: 11px; color: var(--text-faint); }

/* --------------------------- Document lines --------------------------- */
table.lines { width: 100%; border-collapse: collapse; font-size: 13px; }
table.lines th {
  background: var(--surface-2); padding: 7px 8px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .4px; color: var(--text-dim); border-bottom: 1px solid var(--border);
  text-align: left; font-weight: var(--fw-medium);
}
table.lines td { padding: 4px 6px; border-bottom: 1px solid var(--border); }
table.lines input, table.lines select { padding: 5px 7px; font-size: 13px; }
table.lines td.num input { text-align: right; }
/* The description box, sized by the script to exactly the text it holds: one
   line until there is a second one, so a table of short descriptions still
   reads as a table. Without the override the general textarea rule opens every
   row 62px tall. */
table.lines textarea.line-desc {
  padding: 5px 7px; font-size: 13px; line-height: 1.45; font-family: inherit;
  min-height: 0; resize: none; display: block;
  /* Not `hidden`: if the measured height is ever wrong the text must still be
     reachable by scrolling rather than silently cut off. */
  overflow-y: auto;
}
/* Wherever a stored description is shown back, the line breaks in it are shown
   too - the grid, the document view, the printed page. */
.pre-line { white-space: pre-line; }
.line-total { padding: 6px 8px; font-variant-numeric: tabular-nums; font-weight: var(--fw-medium); }
/* Says whether a line touches stock at all, right where the item is chosen. */
.line-note { display: block; margin-top: 3px; font-size: 11px; color: var(--text-dim); }
.line-note.service { color: var(--green); }

.doc-totals { display: flex; justify-content: flex-end; margin-top: 12px; }
.doc-totals table { border-collapse: collapse; min-width: 260px; }
.doc-totals td { padding: 5px 10px; }
.doc-totals td.label { color: var(--text-dim); }
.doc-totals td.num { font-variant-numeric: tabular-nums; font-weight: var(--fw-medium); }
.doc-totals tr.grand td {
  border-top: 2px solid var(--border-strong); font-size: 16px; font-weight: var(--fw-bold); padding-top: 8px;
}

/* -------------------------------- Modal ------------------------------- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(16, 24, 40, .45);
  display: flex; align-items: flex-start; justify-content: center; padding: 40px 16px;
  z-index: 100; overflow-y: auto;
}
.modal {
  background: var(--surface); border-radius: 10px; width: 100%; max-width: 560px;
  box-shadow: 0 12px 48px rgba(16, 24, 40, .28); display: flex; flex-direction: column;
}
.modal.wide { max-width: 900px; }
.modal-head { padding: 14px 18px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; }
.modal-head h2 { font-size: 15px; margin: 0; font-weight: var(--fw-medium); }
.modal-head .icon-btn { margin-left: auto; }
.modal-body { padding: 18px; }
.modal-foot { padding: 12px 18px; border-top: 1px solid var(--border);
  display: flex; gap: 8px; justify-content: flex-end; background: var(--surface-2);
  border-radius: 0 0 10px 10px; }

/* -------------------------------- Toasts ------------------------------ */
.toasts { position: fixed; bottom: 20px; right: 20px; display: flex;
  flex-direction: column; gap: 8px; z-index: 200; }
.toast {
  background: var(--sidebar); color: #fff; padding: 11px 16px; border-radius: 7px;
  box-shadow: 0 6px 22px rgba(16, 24, 40, .28); font-size: 13px; max-width: 420px;
  border-left: 3px solid var(--brand); animation: slidein .18s ease-out;
}
.toast.error { border-left-color: var(--red); }
.toast.success { border-left-color: #34d399; }
@keyframes slidein { from { transform: translateX(20px); opacity: 0; } }

/* An update is not an error and not a passing message: it stays until it is
   dealt with, because ignoring it means working on a stale copy. */
.update-bar {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px; z-index: 210;
  background: var(--sidebar); color: #fff; padding: 12px 16px; border-radius: 9px;
  box-shadow: 0 10px 30px rgba(16, 24, 40, .34); font-size: 13px;
  border-left: 3px solid var(--accent); max-width: min(680px, calc(100vw - 40px));
  animation: slidein .18s ease-out;
}
.update-bar span { flex: 1; }
.update-bar button { flex: 0 0 auto; }

/* ------------------------------- Sections ----------------------------- */
.section-title {
  font-size: 12px; text-transform: uppercase; letter-spacing: .7px; color: var(--text-dim);
  font-weight: var(--fw-bold); margin: 18px 0 8px; padding-bottom: 5px; border-bottom: 1px solid var(--border);
}
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.alert {
  padding: 11px 14px; border-radius: 6px; font-size: 13px; margin-bottom: 14px;
  border: 1px solid transparent;
}
.alert-warn { background: var(--amber-soft); color: var(--amber); border-color: var(--amber-line); }
/* Brown text on a teal ground: the gold identity's info alert with only its
   background changed. It is one teal family now, and reads at 5.2:1. */
.alert-info { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.alert-error { background: var(--red-soft); color: var(--red); border-color: var(--red-line); }
.alert-ok { background: var(--green-soft); color: var(--green); border-color: var(--green-line); }
/* The header of a document: dates, references and amounts. The amounts have to
   line up on the decimal like every other column of money in the system. */
.kv { display: grid; grid-template-columns: auto 1fr; gap: 5px 14px;
  font-size: var(--fs-base); }
.kv dt { color: var(--text-dim); }
.kv dd { margin: 0; font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.tabs button {
  border: none; background: none; border-bottom: 2px solid transparent; border-radius: 0;
  padding: 8px 14px; color: var(--text-dim); font-weight: var(--fw-medium);
}
.tabs button.active { color: var(--brand); border-bottom-color: var(--brand); }

@media (max-width: 980px) {
  .sidebar { position: fixed; inset: 0 auto 0 0; z-index: 90; transform: translateX(-100%);
    transition: transform .2s; }
  .sidebar.open { transform: none; }
  .menu-toggle { display: inline-flex; }
  .two-col { grid-template-columns: 1fr; }
  .form-grid.cols-2 { grid-template-columns: 1fr; }
}

/*
   Printing a screen.

   The old rule hid the obvious furniture and stopped there, which left three
   things on the paper that had no business being there: .main kept its
   flex-and-hidden layout, so Chromium clipped everything past the first
   screenful; the Excel and PDF buttons live inside card headings, which were
   never hidden, so a printed statement said "Excel PDF" in the middle of it;
   and the fixed update bar printed across the first page. Status chips also
   lost their backgrounds, which on a mono printer made Posted and Cancelled
   identical - so they are told to keep their colour.
*/
@media print {
  /* Most of this system's tables are wider than an upright sheet of A4, which
     gives 704px between its margins: a trial balance wants 909, a guarantee
     register 1001, the asset register 1148. Printed upright they arrive with
     the account name crushed into a hundred pixels, every row broken over
     three lines, and the last columns cut off at the edge of the paper.
     A sheet turned on its side gives 1033, which is where nearly all of them
     fit. The table says which it needs by carrying `wide`, set in grid() from
     the number of columns that reach the paper, so a narrow report still
     prints upright and nobody has to remember to change the dialog. */
  @page { size: A4 portrait; margin: 14mm 12mm; }
  @page wide { size: A4 landscape; margin: 12mm 14mm; }
  body:has(table.grid.wide) { page: wide; }
  /* The widest of them - payroll at seventeen columns - do not fit even turned
     round. A point smaller buys about 120px, which is the difference for all
     but that one. */
  table.grid.wide { font-size: 11px; }
  table.grid.wide thead th { font-size: 10px; }
  html, body { height: auto; background: #fff; overflow: visible !important; }
  /* The screen keeps the shell at one viewport tall and clips what spills out
     of it - that is what makes the app scroll rather than the window. On paper
     the same rule threw away everything past the first page, which read as
     "this report prints nothing". Every box in the chain has to let go. */
  #app { display: block; height: auto; overflow: visible !important; }
  .main { display: block; overflow: visible !important; height: auto; background: none; }
  .content { padding: 0; overflow: visible !important; height: auto; }
  .sidebar, .topbar, .filters, .row-actions, .toasts,
  .update-bar, .modal-backdrop, .licence-bar, .demo-bar,
  .card-head button, .card-head .btn, .action-row button { display: none !important; }
  /* Hiding the filters left the card around them behind: an empty ruled box
     above every printed report. Take the whole card with them. */
  .card:has(> .card-body > .filters) { display: none !important; }

  /* The letterhead, repeated by nothing: one block at the top of the run. */
  .print-head {
    display: flex; align-items: center; gap: 14px;
    padding-bottom: 8px; margin-bottom: 14px;
    border-bottom: 2px solid #102B36;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .print-head img { height: 46px; width: auto; max-width: 190px; }
  .print-head-text { flex: 1; min-width: 0; }
  .print-company { font-size: 14px; font-weight: 700; color: #102B36;
    letter-spacing: -.2px; }
  .print-title { font-size: 12px; color: #4a5f68; margin-top: 2px; }
  .print-stamp { font-size: 10px; color: #5b7079; white-space: nowrap;
    align-self: flex-end; }
  /* A card must NOT refuse to be broken. It was asked to stay whole so a small
     panel would not be split across two sheets - but a report's card holds the
     whole report, which is taller than a sheet, and a box that may not be
     broken and does not fit has to start on a fresh one. That is where the
     blank first page came from: the letterhead, then nothing, then the report
     beginning overleaf. The rows below keep their own promise not to split,
     which is the one that was actually wanted. */
  .card { box-shadow: none; border: none; break-inside: auto; margin-bottom: 10px; }
  .table-wrap { max-height: none !important; overflow: visible !important; }
  table.grid thead th, table.grid tfoot td { position: static; }
  table.grid { break-inside: auto; }
  table.grid tr { break-inside: avoid; }
  /* A report that runs to four sheets had column headings on the first one
     only; from the second sheet on, a reader had four columns of figures and
     nothing saying which was the debit. */
  table.grid thead { display: table-header-group; }
  table.grid tfoot { display: table-footer-group; }
  .chip, table.grid thead th, table.grid tfoot td, .alert, .metric,
  /* The shading is what shows a group from an account it contains. Dropped by
     the printer, a chart of accounts arrives as one flat list of names. */
  table.grid tr.group-row > td {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }

  /* The last column of a list is its row of buttons. Hiding the buttons left
     the column standing - an empty ruled strip down the side of the paper,
     and the width it held was taken from the column that needed it most. */
  table.grid:has(.row-actions) thead th:last-child,
  table.grid:has(.row-actions) tbody td:last-child,
  table.grid:has(.row-actions) tfoot td:last-child { display: none; }

  /* The open/close arrows of the account tree are controls, not content; the
     indent stays and goes on saying which account sits under which. */
  .tree-toggle { display: none !important; }

  /* On paper the type column says "Liability" on all forty of the accounts
     sitting under Liabilities - a hundred and forty-five repetitions of what
     the group above each one already says. The width it costs is the width
     the longest account name is short of, and a name broken over three lines
     is what makes the page look thrown together. It stays on the screen,
     where nothing is competing for the room. */
  #accountTree .acc-type { display: none; }

  /* Column widths are set in pixels for a screen a good deal wider than a
     sheet of paper. On A4 the fixed ones hold their size and the one that
     flexes - the name - is squeezed to nothing, so every account wraps onto
     two lines and the page reads as a mess. On paper the table sizes itself
     to what is in it. Dense tables keep their widths: they clip long text on
     purpose, and left to themselves they would run off the page. */
  table.grid:not(.dense) { table-layout: auto; }
  table.grid:not(.dense) thead th,
  table.grid:not(.dense) tbody td { width: auto !important; }

  a[href^="#"] { text-decoration: none; color: inherit; }
}

/* =========================== Right to left ===========================
   Arabic reads the other way, and so does the layout: the menu moves to the
   right, every edge marker swaps side, every chevron turns round.

   One thing does NOT turn round, and it is the important one. A figure is
   still 1,318,912.05 read left to right, a date is still 2026-09-15, and an
   account code is still 5213. Those keep direction: ltr inside a page that is
   otherwise rtl - the column they sit in moves, the characters in them do
   not. An accounting screen that flips its numbers is unreadable, and it is
   the usual way this is got wrong.
   ===================================================================== */
[dir="rtl"] .sidebar { order: 2; }
[dir="rtl"] .main { order: 1; }

[dir="rtl"] .nav a { border-left: none; border-right: 3px solid transparent; }
[dir="rtl"] .nav a.active {
  border-right-color: var(--brand-pure);
  background: linear-gradient(270deg, rgba(0,169,149,.55), rgba(0,169,149,.18));
}
[dir="rtl"] .nav-group::after { margin-left: 0; margin-right: auto; }
[dir="rtl"] .badge { margin-left: 0; margin-right: auto; }

[dir="rtl"] .topbar h1::before { margin-right: 0; margin-left: 9px; }
[dir="rtl"] .topbar-actions { margin-left: 0; margin-right: auto; }
[dir="rtl"] .quick-create {
  margin-right: 0; margin-left: var(--sp-3);
  padding-right: 0; padding-left: var(--sp-3);
  border-right: none; border-left: 1px solid var(--border);
}

[dir="rtl"] .band > .band-head h2::before { margin-right: 0; margin-left: 9px; }
[dir="rtl"] .band > .band-head .band-note { margin-left: 0; margin-right: auto; }

[dir="rtl"] .metric.warn, [dir="rtl"] .metric.risk,
[dir="rtl"] .kpi.is-flagged, [dir="rtl"] .ai-answer {
  border-left: none; border-right: 3px solid;
}
[dir="rtl"] .metric.warn { border-right-color: var(--amber); }
[dir="rtl"] .metric.risk { border-right-color: var(--red); }
[dir="rtl"] .kpi.is-flagged { border-right-color: var(--amber); }
[dir="rtl"] .ai-answer {
  border-right-color: var(--brand);
  border-radius: var(--r-md) 0 0 var(--r-md);
}

[dir="rtl"] .kpi .kpi-value .cur { margin-left: 0; margin-right: 5px; }
[dir="rtl"] .figures td.indent { padding-left: 0; padding-right: 18px; }
[dir="rtl"] .card-head .spacer { margin-left: 0; margin-right: auto; }
[dir="rtl"] .pw-wrap input { padding-right: 10px; padding-left: 42px; }
[dir="rtl"] .pw-peek { right: auto; left: 4px; }
[dir="rtl"] .auth-help { justify-content: flex-start; }
[dir="rtl"] .insight-row .chip { margin-top: 1px; }

/* Columns move; the characters inside them do not. */
[dir="rtl"] .num, [dir="rtl"] td.num, [dir="rtl"] th.num,
[dir="rtl"] .mono, [dir="rtl"] .value, [dir="rtl"] .kpi-value,
[dir="rtl"] .figures td.num, [dir="rtl"] input[type="number"],
[dir="rtl"] input[type="date"], [dir="rtl"] input[type="month"],
[dir="rtl"] .code-block, [dir="rtl"] .print-stamp {
  direction: ltr;
}
/* A right-aligned figure column in an rtl table aligns to the left edge of
   the page, which is where the eye now expects the end of a number. */
[dir="rtl"] td.num, [dir="rtl"] th.num, [dir="rtl"] .figures td.num {
  text-align: left;
}

/* Text the company wrote decides its own direction.

   A customer called "Example Real Estate Co." dropped into a right-to-left
   cell otherwise renders as ".Example Real Estate Co" - the full stop is
   neutral, so it takes the direction of the paragraph and jumps to the
   front. plaintext lets each run take the direction of its own first
   letter instead, which is right for a screen holding both languages at
   once: Arabic names read right to left, Latin ones left to right, in the
   same column. */
[dir="rtl"] td, [dir="rtl"] .brand-tagline, [dir="rtl"] .brand-sub,
[dir="rtl"] .card-head h2, [dir="rtl"] .modal-head h2,
[dir="rtl"] .tree-name, [dir="rtl"] .chip, [dir="rtl"] option,
[dir="rtl"] .metric .label, [dir="rtl"] .metric .sub,
[dir="rtl"] .detail, [dir="rtl"] dd, [dir="rtl"] .sub,
/* A box somebody types into holds whichever language they typed. The reminder
   letter is the clearest case: the same textarea carries an Arabic letter to
   one customer and an English one to the next. */
[dir="rtl"] textarea, [dir="rtl"] input {
  unicode-bidi: plaintext;
}

/* Arabic has no small-caps and no letter-spacing tradition; the uppercase
   tracking that flatters English here makes Arabic look broken. */
[dir="rtl"] .brand-tagline, [dir="rtl"] .suggest-label,
[dir="rtl"] .band-head h2 {
  letter-spacing: normal; text-transform: none;
}

.lang-toggle {
  font-weight: var(--fw-bold); min-width: 38px;
  border: 1px solid var(--border-strong); background: var(--surface);
}
.lang-toggle:hover { border-color: var(--brand); color: var(--brand); }

/* A first-time user meets the sign-in card before anything else, so the
   switch has to be reachable from there too. */
.auth-lang {
  position: absolute; top: 12px; right: 12px;
  padding: 3px 9px; border-radius: 7px; font-size: var(--fs-xs);
  line-height: 1.6; cursor: pointer;
}
[dir="rtl"] .auth-lang { right: auto; left: 12px; }

/* Paper is decided by the document, not by the screen: an invoice going to a
   bank keeps the letterhead's own direction whichever way the app was left. */
@media print {
  [dir="rtl"] .print-head { direction: ltr; }
}

/* ------------------------------ Insights ------------------------------ */
/* A finding is a claim and its reason, side by side. The reason is set
   quieter than the claim but not so quiet it goes unread - it is the part
   that decides whether the claim is worth acting on. */
.insight-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 11px 0; border-bottom: 1px solid var(--border);
}
.insight-row:last-child { border-bottom: none; }
.insight-row .chip { flex: 0 0 auto; margin-top: 1px; }
.insight-main { flex: 1; min-width: 0; }
.insight-why { color: var(--text-dim); font-size: 12.5px; line-height: 1.5; margin-top: 2px; }
.insight-where { flex: 0 0 auto; }

.proposal { border: 1px solid var(--border); border-radius: 8px;
  padding: 12px 14px; margin-bottom: 12px; background: var(--surface-2); }
.proposal-head { display: flex; align-items: center; gap: 10px;
  justify-content: space-between; margin-bottom: 4px; }
.proposal .table-wrap { margin-top: 8px; background: var(--surface); border-radius: 6px; }

/* Offered, never applied: the row sits under the field and stays quiet until
   there is something to say. */
.suggest-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  min-height: 0; }
.suggest-strip:empty { display: none; }
.suggest-label { font-size: 11.5px; color: var(--text-faint);
  text-transform: uppercase; letter-spacing: .4px; margin-right: 2px; }
button.suggest-chip { cursor: pointer; border: 1px solid transparent; font: inherit;
  font-size: 11.5px; padding: 3px 9px; }
button.suggest-chip:hover { border-color: var(--brand); }

/* An answer that came from outside the building, marked as such. */
.ai-answer { margin-top: 12px; border-left: 3px solid var(--brand);
  background: var(--surface-2); border-radius: 0 var(--r-md) var(--r-md) 0;
  padding: 12px 14px; }
.ai-question { font-weight: var(--fw-bold); color: var(--text-dim);
  font-size: var(--fs-sm); margin-bottom: 6px; }
.ai-text { line-height: 1.65; }
.ai-answer .hint { margin-top: 10px; padding-top: 8px;
  border-top: 1px solid var(--border); }

.insight-basis { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
.insight-basis ul { margin: 6px 0 0; padding-left: 18px; color: var(--text-dim);
  font-size: 12.5px; line-height: 1.7; }

/* ------------------------------- Charts ------------------------------- */
.chart-card .card-body { padding: 14px 16px 12px; }
svg.chart { width: 100%; height: auto; display: block; overflow: visible; }
svg.chart.donut { width: 200px; height: 200px; flex: 0 0 200px; }
.donut-row { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.donut-row .chart-legend { flex: 1; min-width: 180px; }

.chart-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 10px;
  font-size: 12px; color: var(--text-dim); }
.chart-legend .legend-item { display: inline-flex; align-items: center; gap: 6px; }
.chart-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.chart-legend b { color: var(--text); font-variant-numeric: tabular-nums; }

.bar-list { display: flex; flex-direction: column; gap: 9px; }
.bar-row { display: grid; grid-template-columns: minmax(90px, 34%) 1fr auto;
  align-items: center; gap: 10px; font-size: 12.5px; }
.bar-label { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.bar-track { background: var(--surface-2); border-radius: 5px; height: 16px;
  overflow: hidden; border: 1px solid var(--border); }
.bar-fill { display: block; height: 100%; border-radius: 4px; min-width: 2px;
  transition: width .3s ease; }
.bar-value { font-variant-numeric: tabular-nums; font-weight: var(--fw-medium); white-space: nowrap; }

/* ------------------------- Tidier form layout ------------------------- */
.form-grid { align-items: start; }
.field label { display: flex; align-items: center; gap: 4px; min-height: 16px; }
.field input, .field select, .field textarea { height: 34px; }
.field textarea { height: auto; }

/* The month picker in the dashboard's title bar: the same height as the
   buttons beside it, and no wider than the date it holds. */
.dash-month {
  height: 26px; padding: 0 6px; margin-left: 6px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text); font-size: 12px;
}

/* ----------------------- Searchable picker -----------------------------
   A dropdown that has outgrown the browser's own. It looks like every other
   field until you type in it; the list below is the same list, filtered.
   ----------------------------------------------------------------------- */
.combo { position: relative; }
.combo .combo-text { width: 100%; }
.combo .combo-text::placeholder { color: var(--text-faint); opacity: .75; }
/* Fixed, not absolute, and placed by script from the input's own position.
   A card sets `overflow: hidden` to keep its rounded corners, and the content
   area scrolls - between them an absolutely positioned list is sliced off at
   the card edge and shows one row through a letterbox. Fixed positioning
   leaves the card behind entirely. Above the modal's layer, so a picker inside
   a dialog opens over it rather than under it. */
.combo-list {
  position: fixed; z-index: 200;
  max-height: 264px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow); padding: 3px;
}
.combo-item {
  padding: 6px 9px; border-radius: var(--r-sm); cursor: pointer;
  font-size: var(--fs-sm, 13px); line-height: 1.35; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.combo-item.is-active { background: var(--brand-soft); color: var(--brand-dark); }
.combo-item.is-chosen { font-weight: var(--fw-bold, 600); }
.combo-item.is-chosen::after { content: " ✓"; color: var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  .combo-item { transition: background-color .08s ease; }
}
.field .hint { line-height: 1.35; min-height: 14px; }
.filters .field { margin-bottom: 0; }
.filters > button { height: 34px; align-self: flex-end; }
.form-section {
  grid-column: 1 / -1; margin-top: 6px; padding-top: 10px;
  border-top: 1px solid var(--border); font-size: 11px; font-weight: var(--fw-bold);
  text-transform: uppercase; letter-spacing: .7px; color: var(--text-faint);
}

@media (max-width: 1100px) {
  .two-col { grid-template-columns: 1fr; }
}
/* ----------------------------- Sign-in ------------------------------- */
/* The sign-in screen is the one place the mark can be as large as it deserves:
   a lit arch on stone, the way the brand board looks. */
.auth-screen {
  display: flex; align-items: center; justify-content: center; min-height: 100vh;
  width: 100%; padding: 24px; position: relative; overflow: hidden;
  background:
    radial-gradient(1100px 620px at 50% -12%, rgba(0,169,149,.26), transparent 64%),
    radial-gradient(760px 520px at 8% 108%, rgba(0,169,149,.16), transparent 62%),
    linear-gradient(152deg, #17394a 0%, #102B36 52%, #0a1c24 100%);
}
/* A mashrabiya screen, faint, behind everything */
.auth-screen::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='72' height='72' viewBox='0 0 72 72'>\
<g fill='none' stroke='%2300A995' stroke-opacity='0.12' stroke-width='1.1'>\
<path d='M36 2 L70 36 L36 70 L2 36 Z'/><path d='M36 16 L56 36 L36 56 L16 36 Z'/>\
<circle cx='36' cy='36' r='5'/>\
<path d='M0 0 L16 16 M72 0 L56 16 M0 72 L16 56 M72 72 L56 56'/></g></svg>") 0 0/72px 72px;
  /* Was .09 and reading as a texture rather than a watermark. Halved, and
     faded out sooner, so it frames the card instead of competing with it. */
  opacity: .5;
  mask-image: radial-gradient(110% 90% at 50% 0%, #000 8%, transparent 62%);
  -webkit-mask-image: radial-gradient(110% 90% at 50% 0%, #000 8%, transparent 62%);
}
/* The card sits a little above centre: a form the eye falls onto, rather than
   one it has to travel down to. */
.auth-screen { align-items: flex-start; padding-top: 7vh; }
.auth-card {
  position: relative; z-index: 1;
  width: 100%; max-width: 380px; background: #ffffff; border-radius: 14px;
  padding: 26px 28px 22px; text-align: center;
  border: 1px solid rgba(0,169,149,.35);
  box-shadow: 0 26px 70px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.04);
}
.auth-logo {
  /* The artwork is wider than it is tall, so the box is given to it and the
     picture is fitted inside rather than stretched to a square. */
  width: 104px; height: 104px; display: block; margin: 0 auto;
  object-fit: contain;
  filter: drop-shadow(0 8px 18px rgba(0,40,36,.30));
}
.auth-brand { font-size: 31px; font-weight: var(--fw-bold); letter-spacing: 6px; margin: 12px 0 0;
  color: var(--text); padding-left: 6px; }
.auth-tagline { font-size: 9.5px; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--brand); margin: 6px 0 4px; font-weight: var(--fw-medium); }
/* A gold rule between the wordmark and the form, as on the brand board */
.auth-tagline::after {
  content: ""; display: block; width: 52px; height: 2px; margin: 13px auto 15px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
}
.auth-title { font-size: var(--fs-md); margin: 0; font-weight: var(--fw-medium); }
.auth-sub { font-size: var(--fs-sm); color: var(--text-dim); margin: 5px 0 14px; line-height: 1.5; }
.auth-form { display: flex; flex-direction: column; gap: 11px; text-align: left; }
.auth-submit { justify-content: center; padding: 10px; font-size: var(--fs-base); margin-top: 4px; }
.auth-note { font-size: var(--fs-xs); color: var(--text-faint); margin: 14px 0 0; line-height: 1.5; }

/* A password field you can check before you commit to it, and the one link
   people look for when the field refuses them. */
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 42px; width: 100%; }
.pw-peek {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  border: none; background: none; padding: 4px 8px; cursor: pointer;
  color: var(--text-faint); font-size: var(--fs-sm);
}
.pw-peek:hover { color: var(--brand); }
.auth-help { display: flex; justify-content: flex-end; margin-top: -4px; }
.auth-help button {
  border: none; background: none; padding: 0; cursor: pointer;
  color: var(--brand); font-size: var(--fs-sm); text-decoration: underline;
}
/* Burgundy is the right focus colour on a working screen, but on a sign-in
   card a dark red ring around an empty username reads as a rejection before
   anybody has typed anything. Gold says the same thing without the accusation;
   red on this screen now means only that something was actually wrong. */
.auth-card input:focus, .auth-card select:focus {
  border-color: var(--brand); box-shadow: 0 0 0 3px rgba(0, 169, 149, .22);
}
.auth-card input:focus-visible, .auth-card button:focus-visible {
  outline: 2px solid var(--accent); box-shadow: none;
}
.auth-card .field.invalid input { border-color: var(--red); }

.sidebar-foot { display: flex; flex-direction: column; gap: 8px; }
.session-user { display: flex; align-items: center; gap: 9px; }
.session-avatar {
  width: 28px; height: 28px; border-radius: 50%; background: linear-gradient(145deg, var(--brand-pure), var(--brand-dark)); color: #fff;
  display: grid; place-items: center; font-weight: var(--fw-bold); font-size: 12px; flex: 0 0 28px;
}
.session-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.session-text b { color: var(--side-strong); font-size: 12px; font-weight: var(--fw-medium);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.session-text em { color: var(--side-muted); font-size: 11px; font-style: normal; }
.session-actions { display: flex; gap: 6px; }
.session-actions button {
  flex: 1; background: transparent; border-color: var(--side-edge); color: var(--side-text); font-size: 11px;
  justify-content: center; padding: 4px 6px;
}
.session-actions button:hover { background: var(--sidebar-2); border-color: var(--side-muted); color: #fff; }
/* ---------------------------------------------------------------------
   Permissions inside a module

   A long list of small choices, so it folds. A group opens by itself when
   something in it has been withheld - the one state worth seeing without
   being asked for.
   --------------------------------------------------------------------- */
.perm-group { border: 1px solid var(--border); border-radius: 6px; margin-bottom: 8px;
  background: var(--surface); }
.perm-group > summary { cursor: pointer; padding: 9px 12px; list-style: none;
  display: flex; align-items: baseline; gap: 10px; user-select: none; }
.perm-group > summary::-webkit-details-marker { display: none; }
.perm-group > summary::before { content: "\25B8"; color: var(--text-faint);
  font-size: 11px; transition: transform .12s ease; }
.perm-group[open] > summary::before { transform: rotate(90deg); }
.perm-group > summary:hover { background: var(--bg); }
.perm-group[open] > summary { border-bottom: 1px solid var(--border); }
.tick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 2px 14px; padding: 10px 12px 12px; }
.tick { display: flex; align-items: center; gap: 8px; padding: 4px 2px;
  font-size: 12.5px; cursor: pointer; border-radius: 4px; }
.tick:hover { background: var(--bg); }
.tick input { margin: 0; flex: 0 0 auto; }
.tick > span:first-of-type { flex: 1 1 auto; }
/* Unticked is the exception, so it is the one that gets colour. */
.tick:has(input:not(:checked)) > span:first-of-type { color: var(--red);
  text-decoration: line-through; }
@media (max-width: 640px) { .tick-grid { grid-template-columns: 1fr; } }

/* ------------------------- Two-step sign-in --------------------------- */
/* The picture a phone camera has to read. It stays black on white in dark
   mode as well - the contrast is part of what makes it scannable, and a QR
   code inverted to grey on charcoal is one most phones will not take. */
.qr-holder { display: flex; justify-content: center; margin: 4px 0 14px; }
.qr-holder svg { width: 200px; height: 200px; background: #fff;
  padding: 8px; border-radius: 8px; border: 1px solid var(--border); }
.two-step-steps { margin: 0 0 14px; padding-left: 18px; font-size: 13px;
  color: var(--muted); }
.two-step-steps li { margin: 3px 0; }
/* --brand, not --accent: there is no --accent. This pointed at nothing and the
   step numbers fell back to the text colour. On a white dialog, the darker
   brand teal is the one meant for white. */
.two-step-steps li::marker { color: var(--brand); font-weight: 600; }
/* The secret, for somebody whose camera will not focus. Spaced in fours and
   in a fixed pitch, because it is being copied character by character. */
.secret-text { display: inline-block; margin-top: 4px; padding: 5px 9px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 5px;
  font-family: var(--mono, ui-monospace, monospace); font-size: 13px;
  letter-spacing: 1px; user-select: all; }
/* Six digits, read off a phone and typed straight back. Wide and spaced so a
   transposed pair is visible before the button is pressed. */
.code-input { font-size: 22px; letter-spacing: 6px; text-align: center;
  font-family: var(--mono, ui-monospace, monospace); padding: 10px 8px; }
.auth-who { text-align: center; margin: -4px 0 12px; font-weight: 600;
  color: var(--muted); font-size: 13px; }
.code-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px 18px;
  margin: 14px 0; }
.code-grid code { padding: 7px 10px; background: var(--bg); border-radius: 5px;
  border: 1px solid var(--border); font-size: 15px; letter-spacing: 1.5px;
  text-align: center; user-select: all; }
@media (max-width: 480px) { .code-grid { grid-template-columns: 1fr; } }


/* --------------------------- Finding a screen -------------------------- */
/*
   Built from the panel's own parts rather than from a generic form field, so
   it reads as one more piece of the menu:

       the resting fill is the menu's own hover tint, and the border is the
       same hairline that divides the brand block from the list;
       the text is the link colour, the placeholder and the glass are the
       icon colour, so an empty box is exactly as loud as an unlit icon;
       focus lights it in the brand teal - the colour that already means
       "here" on this panel, down the edge of the page you are on.

   It stands on margin, not padding, so the box around it is the field and
   nothing else - which is what lets the shortcut chip centre on it exactly.
*/
.nav-find {
  position: relative;
  /* Room above: it used to sit hard against the NARROW bar and read as part
     of it. */
  margin: 14px 12px 8px;
}
.nav-find input {
  display: block; width: 100%; height: 34px; box-sizing: border-box;
  /* Glass on the leading side, room for the shortcut on the trailing one.
     Logical sides, so Arabic mirrors itself without a rule of its own. */
  padding-inline: 32px 58px;
  font: inherit; font-size: var(--fs-sm); color: var(--side-text);
  background: var(--side-hover)
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%238fa8b1' stroke-width='2.4' stroke-linecap='round'><circle cx='10.5' cy='10.5' r='6.5'/><path d='M20 20l-4.6-4.6'/></svg>")
    no-repeat 11px 50% / 14px 14px;
  border: 1px solid var(--side-line); border-radius: var(--r-md);
  outline: none; -webkit-appearance: none; appearance: none;
  transition: background-color .15s, border-color .15s, box-shadow .15s, color .15s;
}
html[dir="rtl"] .nav-find input { background-position: calc(100% - 11px) 50%; }
.nav-find input::placeholder { color: var(--side-muted); opacity: 1; }
.nav-find input:hover {
  background-color: rgba(255, 255, 255, .075); border-color: rgba(255, 255, 255, .13);
}
.nav-find input:focus {
  color: #fff; background-color: rgba(255, 255, 255, .08);
  border-color: var(--brand-pure);
  box-shadow: 0 0 0 3px rgba(0, 169, 149, .20);
  /* The glass lights up with the border. */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2300A995' stroke-width='2.4' stroke-linecap='round'><circle cx='10.5' cy='10.5' r='6.5'/><path d='M20 20l-4.6-4.6'/></svg>");
}
/* Once something is typed the shortcut chip has gone, so the trailing room
   shrinks to what the clear cross needs. */
.nav-find:focus-within input,
.nav-find input:not(:placeholder-shown) { padding-inline-end: 30px; }

/* The shortcut, as a key cap sitting in the field. Seen while the box is
   idle, gone the moment it is used - by then it has done its job. The words
   come from the page, so a Mac shows the Command key and not Ctrl. */
.nav-find::after {
  content: attr(data-key);
  position: absolute; top: 50%; inset-inline-end: 8px; transform: translateY(-50%);
  padding: 2px 6px; border-radius: var(--r-sm);
  border: 1px solid rgba(255, 255, 255, .12); border-bottom-width: 2px;
  font-size: 10px; line-height: 1.3; letter-spacing: .3px; color: var(--side-muted);
  pointer-events: none; transition: opacity .12s;
}
.nav-find:focus-within::after,
.nav-find:has(input:not(:placeholder-shown))::after { opacity: 0; }

/* The browser's own clear cross is black and vanishes on this panel; this is
   the same cross in the icon colour. */
.nav-find input::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none; cursor: pointer;
  width: 14px; height: 14px; opacity: .75;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23a7bcc4' stroke-width='2.6' stroke-linecap='round'><path d='M6 6l12 12M18 6L6 18'/></svg>")
    center / 11px 11px no-repeat;
}
.nav-find input::-webkit-search-cancel-button:hover { opacity: 1; }

/* Said in the same voice as the links it stands in for. */
.nav-empty {
  padding: 10px 16px 4px; font-size: var(--fs-sm); color: var(--side-muted);
}

/* While searching, what did not match steps out of the way entirely - the
   menu becomes the result list rather than growing a second one beside it. */
.nav .search-hidden { display: none !important; }
/* Headings stay as labels but stop looking like buttons: nothing folds while
   a search is open, so the chevron would be promising something it will not
   do. The chevron is ::after - hiding ::before, as this first did, hid
   nothing at all. */
.nav.searching .nav-group { cursor: default; color: var(--side-label); }
.nav.searching .nav-group::after { visibility: hidden; }
/* Where Enter will take you. Drawn with the same edge and the same teal as
   the page you are on, only fainter - related, and still not the same thing:
   one says "you are here", the other "Enter goes here". */
.nav a.search-pick {
  background: rgba(0, 169, 149, .16); color: #fff;
  border-left-color: rgba(0, 169, 149, .7);
}
.nav a.search-pick::before { color: var(--brand-pure); }

/* Folded to its icons there is no room to type, so the box goes with it.
   Ctrl+K unfolds the panel before putting the cursor here. */
#app.rail .nav-find, #app.rail .nav-empty { display: none; }


/* ============================= The dark theme =============================
   A set of books is read for six hours at a time, and for some of those hours
   a white page is the brightest thing in the room.

   Built on the tokens rather than beside them: every rule above already asks
   for --surface, --text or --border, so the theme is those answers changed
   and very little else. It is chosen on <html data-theme> by a line in the
   page head that runs before anything is painted, so somebody on the dark
   theme never sees a white flash on the way in, and it follows the
   computer's own setting until somebody picks with the button beside the
   language one.

   Screen only. Paper is white, and a page printed from a dark screen would
   otherwise come out as pale ink on nothing.

   Every value was measured before it was written: body text 13.7:1 on a card,
   the faintest text 6.1:1, each status colour 6.9:1 or better on its own
   tinted ground, each chart series 4.8:1 or better against the card. The
   fills - buttons, badges - are deliberately left out: a button stays dark
   teal with white on it, because a light teal button cannot carry white text.
   ========================================================================== */
@media screen {
  :root[data-theme="dark"] {
    color-scheme: dark;              /* native pickers, scrollbars, checkboxes */
    --bg: #0d171c;
    --surface: #15232a;
    --surface-2: #1b2c34;
    --border: #24343c;
    --border-strong: #3a4d56;
    --text: #e6eef0;
    --text-dim: #b3c3c9;
    --text-faint: #8ea3ab;
    --brand: #2ec7b0;
    --brand-dark: #5ad4c1;
    --brand-soft: #0f3833;
    --accent: #5cc6d4;
    --accent-soft: #11303a;
    --accent-line: #1e4a55;
    --green: #5fd39a;
    --green-soft: #10301f;
    --green-line: #1f5236;
    --red: #ff8a85;
    --red-soft: #3b1719;
    --red-line: #6a2a2d;
    --amber: #f2bd57;
    --amber-soft: #36290e;
    --amber-line: #5e4819;
    --slate: #a9c3df;
    --slate-soft: #1b2834;
    --shadow: 0 1px 2px rgba(0, 0, 0, .40), 0 4px 16px rgba(0, 0, 0, .35);
    --topbar-glass: rgba(21, 35, 42, .88);
    --chart-teal: #2CC4AD;
    --chart-ink: #D3E1E6;
    --chart-amber: #EDB44A;
    --chart-blue: #78A2E8;
    --chart-clay: #EC7F57;
    --chart-grey: #7E9098;
    --chart-grid: #24343c;
    --chart-axis: #8ea3ab;
    --chart-dot: #15232a;
  }
  /* The one card that was painted white by hand rather than by token. */
  :root[data-theme="dark"] .auth-card { background: var(--surface); }
  /* The mark on the sign-in card has an ink arrow, drawn for a white card; on
     a dark one the arrow vanishes and the A points nowhere. The app's own
     mark - white arrow on its ink tile, the one the sidebar wears - is the
     version drawn for dark ground. */
  :root[data-theme="dark"] .auth-logo { content: url("/static/assets/accova-mark-app.svg"); }
}

/* The switch, in the top bar beside the language one: a moon while the page
   is light, a sun while it is dark - it shows where a press would take you. */
.theme-toggle { padding: 0; width: 34px; justify-content: center; }
.theme-toggle svg { width: 16px; height: 16px; }
.theme-toggle .sun { display: none; }
:root[data-theme="dark"] .theme-toggle .sun { display: block; }
:root[data-theme="dark"] .theme-toggle .moon { display: none; }


/* ----------------------- Colours on printed documents ------------------- */
/* A scrap of letterhead under the colour pickers, so a colour is chosen by
   looking at a letterhead rather than at a swatch. Paper is white whatever the
   screen is doing, so the sample is white in the dark theme as well. */
.doc-sample {
  margin: 4px 0 14px; padding: 14px 18px; max-width: 420px;
  background: #fff; color: #000; border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-family: Calibri, "Segoe UI", Arial, sans-serif;
}
.doc-sample-name { font-size: 22px; font-weight: 700; line-height: 1.1; color: var(--doc-ink); }
.doc-sample-tag { font-size: 10px; letter-spacing: 2px; text-transform: uppercase;
  margin-top: 3px; min-height: 12px; color: var(--doc-title); }
.doc-sample-title { font-size: 20px; font-weight: 700; text-align: right; margin-top: 6px;
  color: var(--doc-title); }
.doc-sample-contact { font-size: 12px; color: #000; }
.doc-sample-contact i { font-style: normal; margin-inline-end: 4px; color: var(--doc-detail); }
/* A colour field is a swatch, not a text box: the full-width field every other
   input gets turned it into a long coloured bar. */
.field input[type="color"] { width: 64px; height: 36px; padding: 3px; cursor: pointer; }
