/* =====================================================================
   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;
  /* Gold is gone from the identity. The token stays because forty rules use it,
     and now points at the ink, which is what the brand board puts in its place. */
  --gold: #0E7C8C;
  --gold-soft: #e7f2f4;
  --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;
  --sidebar: #102B36;
  --sidebar-2: #17394a;
  --radius: 8px;
  --shadow: 0 1px 2px rgba(16, 43, 54, .06), 0 4px 16px rgba(16, 43, 54, .08);

  /* ---------------------------------------------------------------------
     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: #b9cbd2;
  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 rgba(255,255,255,.08);
  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: #94adb6; margin-top: 7px;
  padding-top: 7px; border-top: 1px solid rgba(255,255,255,.08);
  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: #8fa8b1; 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; }
.rail-toggle:hover { background: rgba(0,169,149,.16); color: #eaf4f6; }
#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: #eaf4f6; 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: #a7bcc4; opacity: 1; font-weight: var(--fw-bold);
  cursor: pointer; user-select: none;
}
.nav-group:hover { color: #eaf4f6; }
.nav-group:focus-visible { outline: 2px solid var(--gold); 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: #8fa8b1; }
/* 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: #cbdbe0; 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: #85a0a9;
  width: 14px; text-align: center; }
.nav a:hover { background: rgba(255,255,255,.055); color: #fff; }
/* Where you are, said properly: the brand colour behind it and a gold 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); 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 rgba(255,255,255,.07);
  font-size: 11px; color: #a39296; }

/* -------------------------------- 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: rgba(255,255,255,.86);
  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(--gold), 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); }

/* 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 dark sidebar the maroon ring disappears; gold is the readable one. */
.nav a:focus-visible, .nav-group:focus-visible,
.sidebar-foot button:focus-visible {
  outline: 2px solid var(--gold); outline-offset: -2px; box-shadow: none;
}
table.grid tbody tr.clickable:focus-visible { outline-offset: -2px; }
.btn-primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.btn-primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); }
.btn-danger { background: var(--surface); border-color: var(--red); color: var(--red); }
.btn-danger:hover { background: var(--red-soft); }
.btn-success { background: var(--green); border-color: var(--green); 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); 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; }
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; }
.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(--gold); 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: #f0dcae; }
.alert-info { background: var(--gold-soft); color: #7a5e17; border-color: #e6d3a4; }
.alert-error { background: var(--red-soft); color: var(--red); border-color: #f2c3c5; }
.alert-ok { background: var(--green-soft); color: var(--green); border-color: #b9e2cd; }
/* 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 {
  @page { margin: 14mm 12mm; }
  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,
  .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: #1b1418;
    letter-spacing: -.2px; }
  .print-title { font-size: 12px; color: #6b5f63; margin-top: 2px; }
  .print-stamp { font-size: 10px; color: #8a7c80; white-space: nowrap;
    align-self: flex-end; }
  .card { box-shadow: none; border: none; break-inside: avoid; 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; }
  .chip, table.grid thead th, table.grid tfoot td, .alert, .metric {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  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(--gold); }
@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(94,15,30,.28));
}
.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(--gold), 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(--gold); 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), #A32B41); 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: #efe6e8; font-size: 12px; font-weight: var(--fw-medium);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.session-text em { color: #a39296; font-size: 11px; font-style: normal; }
.session-actions { display: flex; gap: 6px; }
.session-actions button {
  flex: 1; background: transparent; border-color: #4a3339; color: #c3b6b9; font-size: 11px;
  justify-content: center; padding: 4px 6px;
}
.session-actions button:hover { background: var(--sidebar-2); 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; } }