/* ==========================================================================
   JEWEL ERP CLOUD — PRODUCTION THEME
   Jewel Technologies (jeweltech.me) · Bahrain
   Lead visual designer · 15 September 2026

   This file is the visual layer for all 346 screens. It is a drop-in
   replacement for `docs/modules/_kit/kit.css`: every class name the wireframe
   kit defines is defined here with the same meaning, so a greyscale wireframe
   becomes a themed screen by swapping ONE stylesheet link. Classes the kit
   does not have (the rail, the command palette, role-home widgets, the device
   shells) are named in the kit's own BEM-ish style and are additive.

   BRAND — fixed, not negotiable:
     navy   #052241   the wordmark, dark grounds, primary fills
     blue   #76BAE5   the mark's lines, the highlight ON navy
     white  #FFFFFF

   The dark theme is not an inversion. Its card surface IS #052241 and its
   accent IS #76BAE5, so dark mode reproduces the logo's own relationship.

   HARD RULES (see theme-README.md §5):
     · No @import, no web fonts, no icon library, no external request. Ever.
       The application runs under XAMPP, sometimes offline at a till.
     · No physical left/right that carries meaning. Logical properties only.
       One dir="rtl" on <html> is the entire RTL implementation.
     · Numbers are tabular, end-aligned and bidi-isolated, always.
     · Colour is never the only signal. Pair it with a word, a glyph or a rule.
     · Components read semantic tokens (--c-*), never ramp steps (--navy-07).

   CONTENTS
     01  BRAND RAMPS          02  SEMANTIC TOKENS (light)
     03  DARK SCHEME          04  DENSITY
     05  RESET & TYPE         06  LAYOUT PRIMITIVES
     07  ICONS                08  APP SHELL (banner, topbar, rail, main)
     09  BREADCRUMBS          10  TABS & SUB-NAVIGATION
     11  DRAWER               12  COMMAND PALETTE
     13  ROLE HOMES           14  BUTTONS
     15  FORMS                16  TABLES & NUMBERS
     17  THE DUAL-UNIT AMOUNT 18  KV / TIMELINE / TILES / LISTS
     19  PILLS & BADGES       20  MODALS, TOASTS, ALERTS
     21  EMPTY / SKELETON / REFUSAL STATES
     22  PAGER & FILTER BAR   23  MODULE COMPONENTS
     24  OTHER DEVICES + EMBEDDED SHELLS   25  PRINT
     26  RTL                  27  MOTION & FORCED COLOURS
   ========================================================================== */

/* ==========================================================================
   01  BRAND RAMPS
   Derived, not guessed. Both ramps were built in OKLCh from the two brand
   colours: a lightness ladder, a chroma curve that peaks in the mid-tones,
   and a hue that drifts from 238deg at the light end to ~253deg at the dark
   end (the hue of #052241 itself). Every step was then gamut-clipped on
   chroma, never on lightness, so the ladder stays perceptually even.

   Nine of the eleven tones already in the client's customer-facing documents
   fall EXACTLY on a step of these ramps (dE-OK = 0.0000):
     band #F5F9FC=navy-01 · rule #D2DEE8=navy-03 · faint #8A9AA9=navy-06
     muted #5B7086=navy-07 · ink2 #2E4459=navy-09 · navy #052241=navy-11
     tint #EAF4FB=blue-02 · light blue #76BAE5=blue-05 · ink #1B5A85=blue-09
   The two that do not are kept as their own named tokens and documented:
     connector #9DB6C9 (dE 0.014 from navy-05) and ink #0B1F33.
   ========================================================================== */
:root {
  color-scheme: light dark;

  /* --- Navy ramp: the structural family. Grounds, rules, ink. ------------ */
  --navy-01: #f5f9fc;   /* band            L .980            */
  --navy-02: #eaf2f8;   /* soft rule       L .952  (solved)  */
  --navy-03: #d2dee8;   /* rule            L .895            */
  --navy-04: #b6c6d5;   /* L .820                            */
  --navy-05: #9eb1c2;   /* L .750                            */
  --navy-06: #8a9aa9;   /* faint           L .679            */
  --navy-07: #5b7086;   /* muted           L .537            */
  --navy-08: #44596e;   /* L .455                            */
  --navy-09: #2e4459;   /* ink2            L .378            */
  --navy-10: #19324c;   /* L .310                            */
  --navy-11: #052241;   /* BRAND NAVY      L .250            */
  --navy-12: #03152a;   /* L .165 — the dark canvas          */

  /* --- Blue ramp: the accent family. Links, focus, highlight on navy. ---- */
  --blue-01: #f5f9fc;
  --blue-02: #eaf4fb;   /* accent tint     L .962            */
  --blue-03: #d0e9fa;
  --blue-04: #a8d4f2;
  --blue-05: #76bae5;   /* BRAND LIGHT BLUE L .760           */
  --blue-06: #54a1d2;
  --blue-07: #2f88bf;
  --blue-08: #1d71a5;
  --blue-09: #1b5a85;   /* accent ink      L .450            */
  --blue-10: #0e446b;
  --blue-11: #043153;
  --blue-12: #00203d;

  /* --- Kit compatibility: the wireframe greyscale, re-pointed at navy.
         A wireframe that reaches for --g-04 gets a navy-tinted rule, not a
         neutral grey, and looks like the product without being touched. --- */
  --g-00: #ffffff;  --g-01: var(--navy-01); --g-02: var(--navy-02);
  --g-03: var(--navy-03); --g-04: var(--navy-04); --g-05: var(--navy-05);
  --g-06: var(--navy-06); --g-07: var(--navy-07); --g-08: var(--navy-08);
  --g-09: var(--navy-09); --g-10: var(--navy-10); --g-11: var(--navy-11);
  --g-12: #0b1f33;

/* ==========================================================================
   02  SEMANTIC TOKENS — LIGHT
   Components read ONLY these. Every text pair below is >= 4.5:1 and every
   boundary pair >= 3:1; the numbers are in theme-README.md §6 and are
   reproducible with `python3 contrast-check.py`.
   ========================================================================== */

  /* --- Surfaces --------------------------------------------------------- */
  --c-bg:           var(--navy-01);
  --c-surface:      #ffffff;
  --c-surface-2:    var(--navy-01);
  --c-surface-3:    var(--navy-02);
  --c-surface-inv:  var(--navy-11);   /* the rail, the till bar, print heads */
  --c-surface-sunk: var(--navy-02);   /* wells, code, payload panes         */

  /* --- Lines. Three, and they are not interchangeable.
         --c-line        decorative hairline (table rules, card edges)
         --c-line-soft   the quietest divider
         --c-line-strong VERIFIED 3:1 — the boundary of a control. Inputs,
                         switches, checkboxes and anything whose edge is the
                         only thing identifying it use this one.            */
  --c-line:         var(--navy-03);
  --c-line-soft:    var(--navy-02);
  --c-line-strong:  #788b9b;

  /* --- Ink. Four levels, all four legal for text.
         --c-ink-faint is explicitly NOT a text colour: disabled controls
         (WCAG-exempt) and decorative glyphs only.                          */
  --c-ink:          #0b1f33;   /* 16.7:1 on white */
  --c-ink-2:        var(--navy-09);   /* 10.1:1 */
  --c-ink-3:        var(--navy-07);   /*  5.1:1 */
  --c-ink-4:        #5f6e7f;          /*  4.6:1 — lightest legal text */
  --c-ink-faint:    var(--navy-06);   /*  2.9:1 — NON-TEXT ONLY */
  --c-ink-inv:      #ffffff;          /* on --c-surface-inv */
  --c-ink-inv-2:    var(--navy-04);   /* 9.2:1 on navy */
  --c-ink-inv-3:    var(--navy-05);

  /* --- Accent: "this is interactive". Blue, never navy. ----------------- */
  --c-accent:       var(--blue-09);
  --c-accent-hi:    var(--blue-10);
  --c-accent-weak:  var(--blue-02);
  --c-accent-line:  #658eac;
  --c-accent-ink:   #ffffff;

  /* --- Primary: "this is the brand, and this is the one action".
         Navy fill + white. It is the wordmark, so it is used sparingly:
         one per screen region, never two side by side.                     */
  --c-primary:      var(--navy-11);
  --c-primary-hi:   #0d3055;
  --c-primary-ink:  #ffffff;

  /* --- Highlight: the light blue. It exists to sit ON navy, exactly as the
         mark's lines sit on the wordmark. Never on white as text.          */
  --c-highlight:    var(--blue-05);

  /* --- Semantics, tuned to sit beside navy rather than shout over it ---- */
  --c-success:      #1b6b4c; --c-success-weak: #e4f1eb; --c-success-line: #6a9180;
  --c-warn:         #a85f17; --c-warn-weak:    #fff5e6; --c-warn-line:    #a2865c;
  --c-danger:       #a3231d; --c-danger-weak:  #fbebe9; --c-danger-line:  #ad7e7a;
  --c-on-status:    #ffffff;   /* text on a solid success/warn/danger fill */
  --c-info:         var(--blue-09); --c-info-weak: var(--blue-02); --c-info-line: #658eac;

  /* --- The ONE metal tone. See theme-README.md §2.4 for why it exists and
         where it may not be used. It is a DATA colour for the gold/gram
         dimension only: the gram twin of a dual-unit figure, the metal
         series in a chart, the [M] account badge. It is never a brand
         colour, never a button, never a link, never a status.             */
  --c-metal:        #8a6a2f; --c-metal-weak: #f9f2e5; --c-metal-line: #9a8865;

  /* --- Diagram / annotation ink (kit chrome, IA diagrams) --------------- */
  --c-connector:    #9db6c9;
  --c-anno:         var(--c-warn);
  --c-anno-weak:    var(--c-warn-weak);
  --c-anno-line:    var(--c-warn-line);

  /* --- Focus. One ring, everywhere, never removed. The inner white/navy
         halo is what makes it survive on a coloured fill.                  */
  --c-focus:        var(--blue-08);
  --focus-ring:     0 0 0 2px var(--c-surface), 0 0 0 4px var(--c-focus);
  --focus-ring-inv: 0 0 0 2px var(--c-surface-inv), 0 0 0 4px var(--c-highlight);

  /* --- Selection -------------------------------------------------------- */
  --c-select-bg:    var(--blue-03);
  --c-select-ink:   var(--c-ink);

  /* --- Elevation. Navy-tinted shadow: a neutral black shadow over a navy
         page reads as dirt.                                                */
  --sh-0: none;
  --sh-1: 0 1px 2px rgba(5,34,65,.07);
  --sh-2: 0 2px 6px rgba(5,34,65,.10), 0 1px 2px rgba(5,34,65,.06);
  --sh-3: 0 8px 24px rgba(5,34,65,.14), 0 2px 6px rgba(5,34,65,.08);
  --sh-4: 0 20px 48px rgba(5,34,65,.20), 0 4px 12px rgba(5,34,65,.10);
  --sh-inset: inset 0 1px 0 rgba(5,34,65,.05);

  /* --- Radii ------------------------------------------------------------ */
  --r-xs: 2px; --r-sm: 4px; --r-md: 6px; --r-lg: 10px; --r-xl: 14px;
  --r-pill: 999px;

  /* --- Spacing (4px base, unchanged from the kit so wireframe rhythm
         survives the swap) --------------------------------------------- */
  --sp-0: 0;  --sp-1: 2px;  --sp-2: 4px;  --sp-3: 8px;  --sp-4: 12px;
  --sp-5: 16px; --sp-6: 24px; --sp-7: 32px; --sp-8: 48px; --sp-9: 64px;

  /* --- Motion. Short, and the whole thing is switchable off. ------------ */
  --dur-1: 90ms; --dur-2: 150ms; --dur-3: 240ms;
  --ease:      cubic-bezier(.2,0,.2,1);
  --ease-out:  cubic-bezier(0,0,.2,1);
  --ease-in:   cubic-bezier(.4,0,1,1);

  /* --- Layout ----------------------------------------------------------- */
  --topbar-h:      56px;
  --banner-h:      36px;
  --rail-w:        248px;
  --rail-w-collapsed: 64px;
  --drawer-w:      360px;
  --drawer-w-wide: 480px;
  --content-max:   1440px;
  --tabbar-h:      56px;

  /* --- Typography ------------------------------------------------------- */
  /* Latin: the system UI stack. No web font is loaded, ever — a till that
     boots offline must render identically to one that does not.           */
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text",
             "Segoe UI", Roboto, "Helvetica Neue", Arial,
             "Noto Sans", "Liberation Sans", sans-serif;
  /* Arabic: Naskh first — Jewel's Arabic is document Arabic, not display.
     The stack is ordered macOS, Windows, Linux, then the safe fallbacks.  */
  --font-ar: "Noto Naskh Arabic", "SF Arabic", "Geeza Pro", "Al Bayan",
             "Segoe UI", "Traditional Arabic", "Simplified Arabic",
             "Noto Sans Arabic", "Droid Arabic Naskh", Tahoma,
             "Times New Roman", serif;
  /* Numbers: a real monospace so that a column of 1,942.420 aligns even
     when the UI font has no tabular figures.                              */
  --font-num: ui-monospace, "SF Mono", "SFMono-Regular", "Cascadia Mono",
              "Segoe UI Mono", Menlo, Consolas, "DejaVu Sans Mono",
              "Liberation Mono", monospace;
  --font-mono: var(--font-num);

  /* Type scale. 13px base is deliberate: this is a dense back-office
     product, and 14px costs a row on a 30-row trial balance.              */
  --fs-micro: 10px; --fs-xs: 11px; --fs-sm: 12px; --fs-base: 13px;
  --fs-md: 15px; --fs-lg: 18px; --fs-xl: 22px; --fs-2xl: 28px;
  --fs-3xl: 36px; --fs-hero: 46px; --fs-mega: 60px;

  --lh-tight: 1.15; --lh-snug: 1.3; --lh-base: 1.5; --lh-loose: 1.7;
  --fw-regular: 400; --fw-medium: 500; --fw-semi: 600; --fw-bold: 700;
  --tracking-caps: .08em;
  --tracking-tight: -.011em;

  /* Tabular figures. Applied to every numeric surface in this file.       */
  --num-feat: tabular-nums lining-nums;
}

/* ==========================================================================
   03  DARK SCHEME
   Token swaps only. Not one component rule appears in this section.
   Guarded both ways: [data-theme="light"] wins over the OS preference, and
   [data-theme="dark"] wins over a light OS preference.
   The dark surface is the brand navy and the dark accent is the brand light
   blue — so the product in dark mode IS the logo.
   ========================================================================== */
:root[data-theme="dark"],
:root[data-theme="dark"] * { color-scheme: dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Ramps are re-pointed, not redefined: navy stays navy in both themes. */
    --c-bg:           var(--navy-12);
    --c-surface:      var(--navy-11);   /* the brand navy IS the card */
    --c-surface-2:    #0b2c50;
    --c-surface-3:    var(--navy-10);
    --c-surface-inv:  var(--blue-02);
    --c-surface-sunk: #021024;
  
    --c-line:         #224061;
    --c-line-soft:    #15304f;
    --c-line-strong:  #677e94;          /* 3.1:1 on every dark ground */
  
    --c-ink:          var(--blue-02);   /* 14.4:1 on navy */
    --c-ink-2:        var(--navy-04);   /*  9.2:1 */
    --c-ink-3:        var(--navy-05);   /*  7.3:1 */
    --c-ink-4:        var(--navy-06);   /*  5.6:1 — navy-06 is legal text here */
    --c-ink-faint:    #6e8194;          /* NON-TEXT ONLY */
    --c-ink-inv:      var(--navy-11);
    --c-ink-inv-2:    var(--navy-09);
    --c-ink-inv-3:    var(--navy-08);
  
    --c-accent:       var(--blue-05);   /* the mark's own blue, on the mark's navy */
    --c-accent-hi:    var(--blue-04);
    --c-accent-weak:  #0d3557;
    --c-accent-line:  #3585bb;
    --c-accent-ink:   var(--navy-11);
  
    --c-primary:      var(--blue-05);
    --c-primary-hi:   var(--blue-04);
    --c-primary-ink:  var(--navy-11);
  
    --c-highlight:    var(--blue-05);
  
    --c-success:      #72c79e; --c-success-weak: #0d3328; --c-success-line: #458166;
    --c-warn:         #e2ab5e; --c-warn-weak:    #38290f; --c-warn-line:    #8a7144;
    --c-danger:       #ef9b93; --c-danger-weak:  #3d1c1a; --c-danger-line:  #a05c55;
    --c-on-status:    var(--navy-12);
    --c-info:         var(--blue-05); --c-info-weak: #0d3557; --c-info-line: #3585bb;
  
    --c-metal:        #d3b071; --c-metal-weak: #33290f; --c-metal-line: #877042;
  
    --c-connector:    var(--navy-06);
    --c-anno:         var(--c-warn);
    --c-anno-weak:    var(--c-warn-weak);
    --c-anno-line:    var(--c-warn-line);
  
    --c-focus:        var(--blue-05);
    --focus-ring:     0 0 0 2px var(--c-surface), 0 0 0 4px var(--c-focus);
    --focus-ring-inv: 0 0 0 2px var(--navy-12), 0 0 0 4px var(--c-highlight);
  
    --c-select-bg:    #10406b;
    --c-select-ink:   var(--c-ink);
  
    --sh-1: 0 1px 2px rgba(0,0,0,.45);
    --sh-2: 0 2px 6px rgba(0,0,0,.50), 0 1px 2px rgba(0,0,0,.35);
    --sh-3: 0 8px 24px rgba(0,0,0,.58), 0 2px 6px rgba(0,0,0,.40);
    --sh-4: 0 20px 48px rgba(0,0,0,.66), 0 4px 12px rgba(0,0,0,.45);
    --sh-inset: inset 0 1px 0 rgba(255,255,255,.04);
  
    /* Kit greyscale, inverted so a wireframe reaching for --g-12 gets light ink */
    --g-00: var(--navy-12); --g-01: var(--navy-11); --g-02: #0b2c50;
    --g-03: var(--navy-10); --g-04: #224061;        --g-05: var(--navy-08);
    --g-06: #677e94;        --g-07: var(--navy-06); --g-08: var(--navy-05);
    --g-09: var(--navy-04); --g-10: #cfdce7;        --g-11: var(--blue-02);
    --g-12: #f2f8fd;
  }
}

/* Explicit choice always wins, in both directions. */
:root[data-theme="dark"] {
  /* Ramps are re-pointed, not redefined: navy stays navy in both themes. */
  --c-bg:           var(--navy-12);
  --c-surface:      var(--navy-11);   /* the brand navy IS the card */
  --c-surface-2:    #0b2c50;
  --c-surface-3:    var(--navy-10);
  --c-surface-inv:  var(--blue-02);
  --c-surface-sunk: #021024;

  --c-line:         #224061;
  --c-line-soft:    #15304f;
  --c-line-strong:  #677e94;          /* 3.1:1 on every dark ground */

  --c-ink:          var(--blue-02);   /* 14.4:1 on navy */
  --c-ink-2:        var(--navy-04);   /*  9.2:1 */
  --c-ink-3:        var(--navy-05);   /*  7.3:1 */
  --c-ink-4:        var(--navy-06);   /*  5.6:1 — navy-06 is legal text here */
  --c-ink-faint:    #6e8194;          /* NON-TEXT ONLY */
  --c-ink-inv:      var(--navy-11);
  --c-ink-inv-2:    var(--navy-09);
  --c-ink-inv-3:    var(--navy-08);

  --c-accent:       var(--blue-05);   /* the mark's own blue, on the mark's navy */
  --c-accent-hi:    var(--blue-04);
  --c-accent-weak:  #0d3557;
  --c-accent-line:  #3585bb;
  --c-accent-ink:   var(--navy-11);

  --c-primary:      var(--blue-05);
  --c-primary-hi:   var(--blue-04);
  --c-primary-ink:  var(--navy-11);

  --c-highlight:    var(--blue-05);

  --c-success:      #72c79e; --c-success-weak: #0d3328; --c-success-line: #458166;
  --c-warn:         #e2ab5e; --c-warn-weak:    #38290f; --c-warn-line:    #8a7144;
  --c-danger:       #ef9b93; --c-danger-weak:  #3d1c1a; --c-danger-line:  #a05c55;
  --c-on-status:    var(--navy-12);
  --c-info:         var(--blue-05); --c-info-weak: #0d3557; --c-info-line: #3585bb;

  --c-metal:        #d3b071; --c-metal-weak: #33290f; --c-metal-line: #877042;

  --c-connector:    var(--navy-06);
  --c-anno:         var(--c-warn);
  --c-anno-weak:    var(--c-warn-weak);
  --c-anno-line:    var(--c-warn-line);

  --c-focus:        var(--blue-05);
  --focus-ring:     0 0 0 2px var(--c-surface), 0 0 0 4px var(--c-focus);
  --focus-ring-inv: 0 0 0 2px var(--navy-12), 0 0 0 4px var(--c-highlight);

  --c-select-bg:    #10406b;
  --c-select-ink:   var(--c-ink);

  --sh-1: 0 1px 2px rgba(0,0,0,.45);
  --sh-2: 0 2px 6px rgba(0,0,0,.50), 0 1px 2px rgba(0,0,0,.35);
  --sh-3: 0 8px 24px rgba(0,0,0,.58), 0 2px 6px rgba(0,0,0,.40);
  --sh-4: 0 20px 48px rgba(0,0,0,.66), 0 4px 12px rgba(0,0,0,.45);
  --sh-inset: inset 0 1px 0 rgba(255,255,255,.04);

  /* Kit greyscale, inverted so a wireframe reaching for --g-12 gets light ink */
  --g-00: var(--navy-12); --g-01: var(--navy-11); --g-02: #0b2c50;
  --g-03: var(--navy-10); --g-04: #224061;        --g-05: var(--navy-08);
  --g-06: #677e94;        --g-07: var(--navy-06); --g-08: var(--navy-05);
  --g-09: var(--navy-04); --g-10: #cfdce7;        --g-11: var(--blue-02);
  --g-12: #f2f8fd;
}

/* ==========================================================================
   04  DENSITY
   Two densities, tokens only. An accountant on a 30-row trial balance and a
   salesperson at a till are not the same user, and 4px of row height is the
   difference between 22 and 30 visible rows on a 1080px laptop.

   Comfortable is the default. Compact is opt-in per user, persisted per
   device, and set on <html data-density="compact">. A third value,
   "touch", is set automatically by the till and handheld shells (§24) and
   must not be offered as a user choice — it is a device fact.

   The selector is the BARE attribute, not :root[data-density]. <html> still
   matches it, so every existing usage is unchanged; but so does any other
   element, which is what lets one page put a touch-density till beside a
   compact back-office table (§24.6) without re-declaring a single value.
   Density is nothing but inherited custom properties, so the nearest
   ancestor carrying [data-density] wins, exactly like a language or a
   direction. Values are mutually exclusive, so there is no cascade fight.
   ========================================================================== */
:root,
[data-density="comfortable"] {
  --d-row-h:     40px;   /* table row, rail item, list row      */
  --d-cell-py:   var(--sp-3);
  --d-cell-px:   var(--sp-4);
  --d-ctl-h:     34px;   /* input, select, button               */
  --d-ctl-px:    var(--sp-4);
  --d-gutter:    var(--sp-6);
  --d-stack:     var(--sp-5);
  --d-card-p:    var(--sp-5);
  --d-fs:        var(--fs-base);
  --d-fs-table:  var(--fs-base);
  --hit:         34px;
  --hit-touch:   44px;
}
[data-density="compact"] {
  --d-row-h:     30px;
  --d-cell-py:   var(--sp-2);
  --d-cell-px:   var(--sp-3);
  --d-ctl-h:     28px;
  --d-ctl-px:    var(--sp-3);
  --d-gutter:    var(--sp-5);
  --d-stack:     var(--sp-4);
  --d-card-p:    var(--sp-4);
  --d-fs:        var(--fs-base);
  --d-fs-table:  var(--fs-sm);
  --hit:         28px;
  --hit-touch:   44px;
}
[data-density="touch"] {
  --d-row-h:     52px;
  --d-cell-py:   var(--sp-4);
  --d-cell-px:   var(--sp-5);
  --d-ctl-h:     48px;
  --d-ctl-px:    var(--sp-5);
  --d-gutter:    var(--sp-6);
  --d-stack:     var(--sp-5);
  --d-card-p:    var(--sp-5);
  --d-fs:        var(--fs-md);
  --d-fs-table:  var(--fs-md);
  --hit:         48px;
  --hit-touch:   48px;
}
/* Kit alias: wireframes ask for --gutter. It has to be re-derived wherever
   the density is re-declared, or a nested [data-density] would inherit the
   root's gutter while everything around it changed. */
:root { --gutter: var(--d-gutter); }
[data-density] { --gutter: var(--d-gutter); }

/* ==========================================================================
   05  RESET & TYPE
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-ink);
  font-family: var(--font-ui);
  font-size: var(--d-fs);
  line-height: var(--lh-base);
  font-variant-numeric: var(--num-feat);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection { background: var(--c-select-bg); color: var(--c-select-ink); }

/* Arabic gets the Naskh stack and a looser line — Naskh needs the room. */
.ar, [lang="ar"], :lang(ar) {
  font-family: var(--font-ar);
  line-height: var(--lh-loose);
  letter-spacing: 0;
}
/* An Arabic string inside an English page, and vice versa. Always isolate. */
bdi, .bidi { unicode-bidi: isolate; }

a { color: var(--c-accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }
a:focus-visible, button:focus-visible, [tabindex]:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
summary:focus-visible, [role="button"]:focus-visible, [role="tab"]:focus-visible,
[role="option"]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--r-sm);
  position: relative;
  z-index: 5;
}
/* On a navy ground the white halo disappears; use the navy halo + highlight. */
.on-navy :focus-visible, .rail :focus-visible, .topbar--till :focus-visible {
  box-shadow: var(--focus-ring-inv);
}

h1,h2,h3,h4,h5,h6 { margin: 0; font-weight: var(--fw-semi); line-height: var(--lh-snug); }
p { margin: 0 0 var(--sp-4); }
p:last-child { margin-block-end: 0; }
hr { border: 0; border-block-start: 1px solid var(--c-line); margin: var(--sp-5) 0; }

.h1 { font-size: var(--fs-xl); letter-spacing: var(--tracking-tight); }
.h2 { font-size: var(--fs-lg); letter-spacing: var(--tracking-tight); }
.h3 { font-size: var(--fs-md); }
.h4 { font-size: var(--fs-base); }
.display { font-size: var(--fs-2xl); font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); line-height: var(--lh-tight); }
.eyebrow {
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  color: var(--c-ink-3);
}
.lede { font-size: var(--fs-md); color: var(--c-ink-2); line-height: var(--lh-base); }

/* Utilities (kit-compatible) */
.muted   { color: var(--c-ink-3); }
.faint   { color: var(--c-ink-4); }
.mono    { font-family: var(--font-num); font-size: .95em; font-variant-numeric: var(--num-feat); }
.caps    { text-transform: uppercase; letter-spacing: var(--tracking-caps); font-size: var(--fs-micro); }
.nowrap  { white-space: nowrap; }
.trunc   { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.grow    { flex: 1 1 auto; min-inline-size: 0; }
.right   { text-align: end; }
.center  { text-align: center; }
.strong  { font-weight: var(--fw-semi); }
.sr-only {
  position: absolute; inline-size: 1px; block-size: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.no-print { }

/* A keyboard key. This product is keyboard-first at the till; .kbd is used
   in buttons, palette rows, tooltips and the shortcut sheet. */
.kbd {
  display: inline-block; min-inline-size: 18px; padding: 1px 5px;
  font-family: var(--font-num); font-size: var(--fs-micro); line-height: 1.5;
  text-align: center; color: var(--c-ink-2);
  background: var(--c-surface); border: 1px solid var(--c-line-strong);
  border-block-end-width: 2px; border-radius: var(--r-sm);
  direction: ltr; unicode-bidi: isolate; white-space: nowrap;
}
.kbd--inv { background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.28); color: var(--c-ink-inv); }

.code {
  font-family: var(--font-num); font-size: var(--fs-xs);
  background: var(--c-surface-sunk); color: var(--c-ink-2);
  border: 1px solid var(--c-line); border-radius: var(--r-sm);
  padding: var(--sp-3) var(--sp-4); overflow: auto;
  direction: ltr; unicode-bidi: isolate; white-space: pre;
}
code:not(.code) {
  font-family: var(--font-num); font-size: .92em;
  background: var(--c-surface-sunk); border-radius: var(--r-xs);
  padding: 1px 4px; direction: ltr; unicode-bidi: isolate;
}

/* ==========================================================================
   06  LAYOUT PRIMITIVES
   ========================================================================== */
.stack        { display: flex; flex-direction: column; gap: var(--d-stack); }
.stack--tight { gap: var(--sp-3); }
.stack--loose { gap: var(--sp-7); }
.row          { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); }
.row--tight   { gap: var(--sp-2); }
.row--between { justify-content: space-between; }
.row--end     { justify-content: flex-end; }
.row--top     { align-items: flex-start; }
.row--base    { align-items: baseline; }
.row--nowrap  { flex-wrap: nowrap; }

.grid-2, .grid-3, .grid-4 { display: grid; gap: var(--d-stack); }
.grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
@media (max-width: 900px) { .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 720px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }

.card {
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  padding: var(--d-card-p);
  box-shadow: var(--sh-1);
}
.card--flush  { padding: 0; }
.card--raised { box-shadow: var(--sh-2); }
.card--quiet  { background: var(--c-surface-2); box-shadow: none; }
.card--accent { border-inline-start: 3px solid var(--c-accent); }
.card--navy   { background: var(--c-surface-inv); color: var(--c-ink-inv); border-color: transparent; }
.card--navy .muted, .card--navy .eyebrow { color: var(--c-ink-inv-3); }

.panel {
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--sh-1);
}
.panel__head {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--d-card-p);
  min-block-size: var(--d-row-h);
  background: var(--c-surface-2);
  border-block-end: 1px solid var(--c-line);
  font-weight: var(--fw-semi);
}
.panel__head .grow { min-inline-size: 0; }
.panel__body  { padding: var(--d-card-p); }
.panel__body--flush { padding: 0; }
.panel__foot {
  padding: var(--sp-3) var(--d-card-p);
  background: var(--c-surface-2);
  border-block-start: 1px solid var(--c-line);
  display: flex; align-items: center; gap: var(--sp-3);
}
.sect { margin-block-end: var(--sp-7); }
.sect__head { margin-block-end: var(--sp-4); display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }

/* A "well": sunken area for code, previews, payloads, print sheets. */
.well {
  background: var(--c-surface-sunk);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  padding: var(--sp-4);
}

/* ==========================================================================
   07  ICONS
   One sprite, inline, no external file. Draw at 24 on a 24 grid; render at
   16 / 20 / 24. Stroke = currentColor at 1.6 (24px) so the optical weight
   matches the 1.3 of the as-built 14px set in app/Views/layout/main.php.
   ========================================================================== */
.ico {
  display: inline-flex; flex: 0 0 auto;
  inline-size: var(--ico-size, 16px); block-size: var(--ico-size, 16px);
  color: inherit; vertical-align: -.15em;
}
.ico svg, .ico > svg { display: block; inline-size: 100%; block-size: 100%; }
.ico--14 { --ico-size: 14px; }
.ico--16 { --ico-size: 16px; }
.ico--20 { --ico-size: 20px; }
.ico--24 { --ico-size: 24px; }
.ico--32 { --ico-size: 32px; }
.ico--48 { --ico-size: 48px; }
.ico--accent  { color: var(--c-accent); }
.ico--muted   { color: var(--c-ink-3); }
.ico--danger  { color: var(--c-danger); }
.ico--success { color: var(--c-success); }
.ico--warn    { color: var(--c-warn); }
.ico--metal   { color: var(--c-metal); }
/* Icons do NOT mirror by default — a gem is a gem, a scale is a scale.
   Only the ones that encode direction carry .ico--dir. */
[dir="rtl"] .ico--dir > svg { transform: scaleX(-1); }

/* A circular icon chip: group headers, empty states, widget heads. */
.ico-chip {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 32px; block-size: 32px; flex: 0 0 auto;
  border-radius: var(--r-md);
  background: var(--c-accent-weak); color: var(--c-accent);
}
.ico-chip--lg      { inline-size: 44px; block-size: 44px; border-radius: var(--r-lg); }
.ico-chip--navy    { background: var(--c-surface-inv); color: var(--c-highlight); }
.ico-chip--quiet   { background: var(--c-surface-3); color: var(--c-ink-3); }
.ico-chip--danger  { background: var(--c-danger-weak);  color: var(--c-danger); }
.ico-chip--warn    { background: var(--c-warn-weak);    color: var(--c-warn); }
.ico-chip--success { background: var(--c-success-weak); color: var(--c-success); }
.ico-chip--metal   { background: var(--c-metal-weak);   color: var(--c-metal); }

/* ==========================================================================
   08  APP SHELL
   The grid named by navigation-ia.md §4.1. Three columns; the drawer column
   collapses to zero unless docked. Everything is logical, so RTL is free.
   ========================================================================== */
.app {
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0,1fr) 0;
  grid-template-rows: auto var(--topbar-h) minmax(0,1fr);
  grid-template-areas:
    "banner banner banner"
    "rail   topbar topbar"
    "rail   main   drawer";
  block-size: 100vh; block-size: 100dvh;
  background: var(--c-bg);
}
.app--collapsed        { grid-template-columns: var(--rail-w-collapsed) minmax(0,1fr) 0; }
.app--with-drawer      { grid-template-columns: var(--rail-w) minmax(0,1fr) var(--drawer-w); }
.app--with-drawer-wide { grid-template-columns: var(--rail-w) minmax(0,1fr) var(--drawer-w-wide); }
.app--no-nav, .app--focus { grid-template-columns: 0 minmax(0,1fr) 0; }
.app--no-banner { grid-template-rows: 0 var(--topbar-h) minmax(0,1fr); }
/* Kit aliases so an existing wireframe shell still lays out. */
.app--compact-nav { grid-template-columns: var(--rail-w-collapsed) minmax(0,1fr) 0; }

/* --- PT-24 account-state banner. Above everything. One at a time, in the
       priority order of §4.3: support > read-only > past due > trial >
       maintenance. The blocking states are not dismissible.               --- */
.acct-banner {
  grid-area: banner;
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: var(--banner-h);
  padding-inline: var(--sp-5);
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  border-block-end: 1px solid transparent;
}
.acct-banner__ico   { flex: 0 0 auto; }
.acct-banner__text  { min-inline-size: 0; }
.acct-banner__actions { margin-inline-start: auto; display: flex; gap: var(--sp-2); align-items: center; }
.acct-banner--support     { background: var(--navy-11);        color: #fff;                border-block-end-color: var(--blue-08); }
.acct-banner--support .acct-banner__ico { color: var(--c-highlight); }
.acct-banner--readonly    { background: var(--c-warn-weak);    color: var(--c-ink);        border-block-end-color: var(--c-warn-line); }
.acct-banner--pastdue     { background: var(--c-danger-weak);  color: var(--c-ink);        border-block-end-color: var(--c-danger-line); }
.acct-banner--trial       { background: var(--c-accent-weak);  color: var(--c-ink);        border-block-end-color: var(--c-accent-line); }
.acct-banner--maintenance { background: var(--c-surface-3);    color: var(--c-ink-2);      border-block-end-color: var(--c-line); }
.acct-banner--blocking .acct-banner__close { display: none; }

/* --- The top bar — 56px, six zones (§4.3) ----------------------------- */
.topbar {
  grid-area: topbar;
  display: flex; align-items: center; gap: var(--sp-3);
  block-size: var(--topbar-h);
  padding-inline: var(--sp-4);
  background: var(--c-surface);
  border-block-end: 1px solid var(--c-line);
  box-shadow: var(--sh-1);
  z-index: 40;
}
.topbar__hamburger { display: none; }
@media (max-width: 1023px) { .topbar__hamburger { display: inline-flex; } }

/* Zone 2b: the L3 screen title. navigation-ia.md §4.4 opens with the rule
   that an L3 MENU screen gets NO breadcrumb — the rail already says where
   you are, and "Money › Receivables › AR Ageing" in the top bar is noise —
   and that "the top bar shows the screen title instead". This is that slot.

   It is mutually exclusive with .crumbs: a screen renders one or the other,
   never both, and never an empty .crumbs faking a title. It is a <span> or
   an <h2>, never an <h1> — the page's only <h1> is .page-title, and a top
   bar that is repeated on every screen must not own the document heading.
   It truncates rather than pushing the rate pill off the bar, because the
   rate is the one thing in the top bar that must never disappear. */
.topbar__title {
  display: flex; align-items: baseline; gap: var(--sp-3);
  min-inline-size: 0; margin: 0;
  font-size: var(--fs-md); font-weight: var(--fw-semi);
  line-height: var(--lh-tight); letter-spacing: var(--tracking-tight);
  color: var(--c-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* A hairline separating the title from the tenant switch, in the same place
   the breadcrumb's first separator would have been. Logical, so it mirrors. */
.topbar__title::before {
  content: ""; flex: 0 0 auto; align-self: center;
  inline-size: 1px; block-size: 18px;
  margin-inline-end: var(--sp-2);
  background: var(--c-line-strong);
}
/* §11.4 courtesy: the other language's name of the same screen, subdued —
   the same pairing .page-title__alt makes in the page head. */
.topbar__title-alt {
  flex: 0 1 auto; min-inline-size: 0;
  font-size: var(--fs-sm); font-weight: var(--fw-regular); color: var(--c-ink-3);
  overflow: hidden; text-overflow: ellipsis;
}
/* A screen that is BOTH an L3 menu screen and plan-locked or read-only says
   so here, next to its name, rather than only in the body. */
.topbar__title .pill { flex: 0 0 auto; align-self: center; }
@media (max-width: 1023px) { .topbar__title { font-size: var(--fs-base); } }
@media (max-width: 767px)  { .topbar__title::before { display: none; }
                             .topbar__title-alt { display: none; } }
/* The two dark chromes. Inherit would give ink on navy. */
.topbar--till .topbar__title, .app--platform .topbar .topbar__title { color: #fff; }
.topbar--till .topbar__title::before,
.app--platform .topbar .topbar__title::before { background: rgba(255,255,255,.28); }
.topbar--till .topbar__title-alt, .app--platform .topbar .topbar__title-alt { color: var(--blue-04); }

/* Zone 1: tenant / outlet, as ONE control. */
.ctx-switch {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  min-block-size: var(--d-ctl-h); max-inline-size: 260px;
  padding: 0 var(--sp-3);
  background: transparent; border: 1px solid transparent; border-radius: var(--r-md);
  color: var(--c-ink); font: inherit; cursor: pointer; text-align: start;
}
.ctx-switch:hover { background: var(--c-surface-2); border-color: var(--c-line); }
.ctx-switch[aria-expanded="true"] { background: var(--c-accent-weak); border-color: var(--c-accent-line); }
.ctx-switch__mark   { flex: 0 0 auto; color: var(--c-primary); }
:root[data-theme="dark"] .ctx-switch__mark,
.topbar--till .ctx-switch__mark { color: var(--c-highlight); }
.ctx-switch__names  { min-inline-size: 0; line-height: var(--lh-tight); }
.ctx-switch__tenant { display: block; font-weight: var(--fw-semi); font-size: var(--fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctx-switch__outlet { display: block; font-size: var(--fs-xs); color: var(--c-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctx-switch[disabled] { opacity: .6; cursor: not-allowed; }
/* Two-pane popover: tenants | outlets. */
.ctx-pop {
  position: absolute; inset-block-start: calc(100% + 4px); inset-inline-start: 0;
  display: grid; grid-template-columns: minmax(180px,1fr) minmax(200px,1fr);
  min-inline-size: 420px; max-block-size: 60vh; overflow: auto;
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-radius: var(--r-lg); box-shadow: var(--sh-3); z-index: 60;
}
.ctx-pop__pane  { padding: var(--sp-2); min-inline-size: 0; }
.ctx-pop__pane + .ctx-pop__pane { border-inline-start: 1px solid var(--c-line); }
.ctx-pop__head  { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); padding: var(--sp-2) var(--sp-3); }
.ctx-pop__item  {
  display: flex; align-items: center; gap: var(--sp-3); inline-size: 100%;
  min-block-size: var(--d-row-h); padding: 0 var(--sp-3);
  border: 0; border-radius: var(--r-sm); background: transparent;
  color: var(--c-ink); font: inherit; text-align: start; cursor: pointer;
}
.ctx-pop__item:hover { background: var(--c-surface-2); }
.ctx-pop__item.is-current { background: var(--c-accent-weak); font-weight: var(--fw-semi); }
.ctx-pop__item.is-current::after { content: ""; margin-inline-start: auto; inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--c-accent); }

/* Zone 3: the palette's resting state. */
.topbar__search {
  flex: 1 1 320px; max-inline-size: 320px;
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-3);
  background: var(--c-surface-2); border: 1px solid var(--c-line);
  border-radius: var(--r-md); color: var(--c-ink-3);
  font: inherit; cursor: text; text-align: start;
  transition: max-inline-size var(--dur-2) var(--ease), border-color var(--dur-1) var(--ease);
}
.topbar__search:hover { border-color: var(--c-line-strong); }
.topbar__search:focus-within, .topbar__search.is-open { max-inline-size: 480px; border-color: var(--c-accent); }
.topbar__search .kbd { margin-inline-start: auto; }
.topbar__spacer { flex: 1 1 auto; }

/* Zone 4: the live rate pill. It is a LINK to CP-01, three states. */
.rate-pill {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-3);
  border: 1px solid var(--c-line); border-radius: var(--r-md);
  background: var(--c-surface-2); color: var(--c-ink);
  font-size: var(--fs-sm); white-space: nowrap; text-decoration: none;
}
.rate-pill:hover { text-decoration: none; border-color: var(--c-line-strong); background: var(--c-surface-3); }
.rate-pill__metal { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); color: var(--c-ink-3); text-transform: uppercase; }
.rate-pill__value { font-family: var(--font-num); font-weight: var(--fw-semi); font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate; }
.rate-pill__sep   { color: var(--c-ink-4); }
.rate-pill__unit  { font-size: var(--fs-xs); color: var(--c-ink-3); }
.rate-pill__age   { font-size: var(--fs-xs); color: var(--c-ink-3); font-variant-numeric: var(--num-feat); }
/* The as-of stamp — the wall-clock time the board was EFFECTIVE FROM, which
   is not the same fact as __age (how long ago that was). §4.3 wants both:
   the age tells a cashier whether to trust it, the as-of tells an auditor
   which board a document was priced against. Render __asof first, __age
   second; a fresh pill may carry only the as-of. */
.rate-pill__asof {
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  font-size: var(--fs-xs); color: var(--c-ink-3);
  direction: ltr; unicode-bidi: isolate;
}
.rate-pill__asof + .rate-pill__age::before,
.rate-pill__asof::before { content: "\00B7"; margin-inline-end: var(--sp-2); color: var(--c-ink-4); }
.rate-pill__caret { color: var(--c-ink-3); }
/* Fresh is the resting state and is deliberately neutral: an amber pill
   means "look at me", so the normal case must not be coloured at all. The
   class is still declared, so a screen can name the state it is drawing. */
.rate-pill--fresh   { background: var(--c-surface-2); border-color: var(--c-line); }
.rate-pill--stale   { background: var(--c-warn-weak);   border-color: var(--c-warn-line); }
.rate-pill--stale   .rate-pill__age { color: var(--c-warn); font-weight: var(--fw-semi); }
.rate-pill--missing { background: var(--c-danger-weak); border-color: var(--c-danger-line); color: var(--c-danger); font-weight: var(--fw-semi); }
/* Colour is never alone (§5): the stale and missing pills carry a glyph as
   well as their word, so the state survives a monochrome screen and a
   red-green eye. The missing pill has no value to show — the markup reads
   "GOLD · No rate today" and the caret still opens CP-01 to fix it. */
.rate-pill--stale::before   { content: "\26A0"; font-size: 11px; line-height: 1; flex: 0 0 auto; }
.rate-pill--missing::before { content: "\2298"; font-size: 11px; line-height: 1; flex: 0 0 auto; }
.rate-pill--missing .rate-pill__metal { color: var(--c-danger); }
.rate-pill--missing .rate-pill__asof, .rate-pill--missing .rate-pill__age { color: var(--c-danger); }
.topbar--till .rate-pill--missing { background: var(--c-danger-weak); border-color: var(--c-danger-line); color: var(--c-danger); }
.topbar--till .rate-pill--missing .rate-pill__metal,
.topbar--till .rate-pill--missing .rate-pill__asof,
.topbar--till .rate-pill--missing .rate-pill__age { color: var(--c-danger); }
.topbar--till .rate-pill__asof { color: var(--blue-04); }
.rate-pop {
  position: absolute; inset-block-start: calc(100% + 4px); inset-inline-end: 0;
  min-inline-size: 300px; padding: var(--sp-4);
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-radius: var(--r-lg); box-shadow: var(--sh-3); z-index: 60;
}

/* Zone 5: the bell. Count is unread-and-routed-to-me, capped at 9+. */
.bell { position: relative; }
.bell__count {
  position: absolute; inset-block-start: -2px; inset-inline-end: -2px;
  min-inline-size: 16px; block-size: 16px; padding-inline: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--c-danger); color: #fff;
  font-size: var(--fs-micro); font-weight: var(--fw-bold); line-height: 1;
  border-radius: var(--r-pill); border: 2px solid var(--c-surface);
  font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate;
}

/* Zone 6: the user menu. */
.usermenu {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-2);
  border: 1px solid transparent; border-radius: var(--r-md);
  background: transparent; color: var(--c-ink); font: inherit; cursor: pointer;
}
.usermenu:hover { background: var(--c-surface-2); border-color: var(--c-line); }
.avatar {
  inline-size: 28px; block-size: 28px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--c-primary); color: var(--c-primary-ink);
  font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: .02em;
  direction: ltr; unicode-bidi: isolate;
}
.avatar--sm { inline-size: 22px; block-size: 22px; font-size: var(--fs-micro); }
.avatar--lg { inline-size: 40px; block-size: 40px; font-size: var(--fs-base); }
.avatar--accent { background: var(--c-accent); color: var(--c-accent-ink); }

/* A generic popover menu used by the user menu, row actions, the "…" crumb. */
.menu {
  min-inline-size: 220px; padding: var(--sp-2);
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-radius: var(--r-lg); box-shadow: var(--sh-3);
}
.menu__item {
  display: flex; align-items: center; gap: var(--sp-3); inline-size: 100%;
  min-block-size: var(--hit); padding: 0 var(--sp-3);
  border: 0; border-radius: var(--r-sm); background: transparent;
  color: var(--c-ink); font: inherit; text-align: start; cursor: pointer;
}
.menu__item:hover { background: var(--c-surface-2); text-decoration: none; }
.menu__item .kbd { margin-inline-start: auto; }
.menu__item--danger { color: var(--c-danger); }
.menu__sep  { block-size: 1px; background: var(--c-line); margin: var(--sp-2) 0; }
.menu__head { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); padding: var(--sp-2) var(--sp-3); }

/* --------------------------------------------------------------------------
   THE RAIL  (§4.1, §4.2)
   248px expanded, 64px collapsed, hidden in till focus mode. The ground is
   the brand navy — this is the single largest area of brand colour in the
   product and it is why the shell reads as Jewel from across a showroom.
   The active marker is the light blue: the mark's colour on the wordmark's
   colour, which is the logo's own relationship at UI scale.

   The kit's `.app-sidebar` / `.nav-*` names are kept as aliases so an
   existing wireframe shell themes without markup changes.
   -------------------------------------------------------------------------- */
.rail, .app-sidebar {
  grid-area: rail;
  display: flex; flex-direction: column;
  inline-size: var(--rail-w);
  background: var(--c-surface-inv);
  color: var(--c-ink-inv);
  border-inline-end: 1px solid rgba(255,255,255,.08);
  overflow: hidden;
  z-index: 50;
}
:root[data-theme="dark"] .rail,
:root[data-theme="dark"] .app-sidebar { background: var(--navy-12); border-inline-end-color: var(--c-line); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .rail,
  :root:not([data-theme="light"]) .app-sidebar { background: var(--navy-12); border-inline-end-color: var(--c-line); }
}

/* --- Brand block. The wordmark lives here; it is the only place the logo
       appears in the application chrome.                                --- */
.rail__brand {
  display: flex; align-items: center; gap: var(--sp-3);
  block-size: var(--topbar-h); flex: 0 0 auto;
  padding-inline: var(--sp-4);
  border-block-end: 1px solid rgba(255,255,255,.08);
}
.rail__mark      { flex: 0 0 auto; color: var(--c-highlight); }
.rail__wordmark  { font-size: var(--fs-md); font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); color: #fff; white-space: nowrap; }
.rail__wordmark small { display: block; font-size: var(--fs-micro); font-weight: var(--fw-regular); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--navy-05); }

/* --- Scroll body ----------------------------------------------------- */
.rail__body { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain; padding: var(--sp-3) var(--sp-3) var(--sp-5); }
.rail__body::-webkit-scrollbar { inline-size: 8px; }
.rail__body::-webkit-scrollbar-thumb { background: rgba(255,255,255,.16); border-radius: var(--r-pill); }
.rail__body { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.16) transparent; }

/* --- Pinned run (§7.1) — above Home, max 8. -------------------------- */
.rail__pinned { padding-block-end: var(--sp-3); margin-block-end: var(--sp-3); border-block-end: 1px solid rgba(255,255,255,.08); }
.rail__pinned-head { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); font-size: var(--fs-micro); font-weight: var(--fw-semi); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--navy-05); }

/* --- A group (L1). The header is always a link to the group's landing
       screen, so the group is never a dead click.                      --- */
.rail__group { margin-block-end: var(--sp-1); }
.rail__group + .rail__group { margin-block-start: var(--sp-2); }

.rail__item, .nav-item {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-3);
  inline-size: 100%; min-block-size: var(--d-row-h);
  padding-inline: var(--sp-3);
  border: 0; border-radius: var(--r-md);
  background: transparent; color: var(--navy-04);
  font: inherit; font-size: var(--fs-base); text-align: start;
  cursor: pointer; text-decoration: none;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.rail__item:hover, .nav-item:hover { background: rgba(255,255,255,.07); color: #fff; text-decoration: none; }
.rail__item:active { background: rgba(255,255,255,.12); }

/* The 3px inline-start accent bar. It mirrors with dir, for free. */
.rail__item.is-active, .nav-item.is-active,
.rail__item[aria-current="page"] {
  background: rgba(118,186,229,.14);
  color: #fff; font-weight: var(--fw-semi);
}
.rail__item.is-active::before, .nav-item.is-active::before,
.rail__item[aria-current="page"]::before {
  content: ""; position: absolute;
    inset-block: 6px;
  inset-inline-start: 0; inline-size: 3px;
  border-radius: var(--r-pill);
  background: var(--c-highlight);
}
/* The group that CONTAINS the current route, while itself not current. */
.rail__item.is-open { color: #fff; }
.rail__item.is-open .rail__chevron > svg { transform: rotate(90deg); }
[dir="rtl"] .rail__item.is-open .rail__chevron > svg { transform: rotate(90deg) scaleX(-1); }

.rail__ico     { flex: 0 0 auto; inline-size: 20px; block-size: 20px; color: inherit; opacity: .92; }
.rail__label   { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail__label-ar{ font-family: var(--font-ar); }
.rail__chevron { margin-inline-start: auto; flex: 0 0 auto; color: var(--navy-05); }
.rail__chevron > svg { transition: transform var(--dur-2) var(--ease); }

/* Badges: an offline queue, an approvals count, an alert. */
.rail__badge, .nav-badge {
  margin-inline-start: auto; flex: 0 0 auto;
  min-inline-size: 18px; block-size: 18px; padding-inline: 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: rgba(255,255,255,.16); color: #fff;
  font-size: var(--fs-micro); font-weight: var(--fw-bold); line-height: 1;
  font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate;
}
.rail__badge--alert, .nav-badge--alert { background: var(--c-danger); color: #fff; }
.rail__badge--warn,  .nav-badge--warn  { background: var(--c-warn);   color: #fff; }
.rail__badge + .rail__chevron { margin-inline-start: var(--sp-2); }

/* Pin affordance on a group header (§4.2 rule 1). */
.rail__pin {
  margin-inline-start: var(--sp-2); flex: 0 0 auto;
  inline-size: 20px; block-size: 20px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--r-sm); background: transparent;
  color: var(--navy-06); cursor: pointer; opacity: 0;
}
.rail__item:hover .rail__pin, .rail__pin:focus-visible, .rail__pin.is-on { opacity: 1; }
.rail__pin.is-on { color: var(--c-highlight); }

/* --- Sections (L2) and screens (L3). Sections stay collapsed to their
       headers until the group is open (§4.2 rationale).                --- */
.rail__sections { padding-block: var(--sp-1); }
.rail__group:not(.is-open) > .rail__sections { display: none; }
.rail__section-head {
  display: flex; align-items: center; gap: var(--sp-2);
  inline-size: 100%; min-block-size: 32px;
  padding-inline: var(--sp-3) var(--sp-3);
  padding-inline-start: calc(var(--sp-3) + 20px + var(--sp-3));
  border: 0; background: transparent; cursor: pointer;
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  color: var(--navy-05); text-align: start;
}
.rail__section-head:hover { color: var(--navy-04); }
.rail__section:not(.is-open) > .rail__screens { display: none; }
.rail__screens { display: flex; flex-direction: column; gap: 1px; }
.rail__screen {
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: 32px; padding-inline: var(--sp-3);
  padding-inline-start: calc(var(--sp-3) + 20px + var(--sp-3));
  border-radius: var(--r-sm);
  color: var(--navy-04); font-size: var(--fs-sm); text-decoration: none;
}
.rail__screen:hover { background: rgba(255,255,255,.07); color: #fff; text-decoration: none; }
.rail__screen.is-active, .rail__screen[aria-current="page"] {
  background: rgba(118,186,229,.16); color: #fff; font-weight: var(--fw-semi);
}
/* A labelled run inside one section (Settings > Policies: trading / governance) */
.rail__run {
  padding-inline-start: calc(var(--sp-3) + 20px + var(--sp-3));
  padding-block: var(--sp-2) var(--sp-1);
  font-size: var(--fs-micro); color: var(--navy-06); font-style: italic;
}

/* --- §10.3 plan-locked. PRESENT, visibly locked, never hidden.
       60% opacity, a lock at the inline-end, the tier as a small pill.  --- */
.rail__item.is-locked, .rail__screen.is-locked, .nav-item.is-locked {
  opacity: .6; cursor: pointer;
}
.rail__item.is-locked:hover, .rail__screen.is-locked:hover { opacity: .85; background: rgba(255,255,255,.05); }
.rail__lock, .nav-lock { margin-inline-start: auto; flex: 0 0 auto; color: var(--navy-05); }
.rail__tier, .nav-tier {
  flex: 0 0 auto; margin-inline-start: var(--sp-2);
  padding: 1px 5px; border-radius: var(--r-xs);
  background: rgba(255,255,255,.14); color: #fff;
  font-size: 9px; font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  direction: ltr; unicode-bidi: isolate;
}
.rail__lock + .rail__tier { margin-inline-start: var(--sp-2); }
.rail__item.is-locked .rail__lock { margin-inline-start: auto; }
/* An empty locked group shows one upsell row, not an empty list. */
.rail__upsell {
  margin: var(--sp-2) var(--sp-3) var(--sp-2);
  padding: var(--sp-3);
  border: 1px dashed rgba(118,186,229,.45); border-radius: var(--r-md);
  background: rgba(118,186,229,.08);
  font-size: var(--fs-xs); color: var(--navy-04);
}
.rail__upsell a { color: var(--c-highlight); font-weight: var(--fw-semi); }

/* §10.4 temporarily unavailable — ENABLED in the menu, never greyed.
   The dot is the only hint; the screen explains itself on arrival. */
.rail__item.is-degraded .rail__label::after,
.rail__screen.is-degraded::after {
  content: ""; inline-size: 5px; block-size: 5px; border-radius: 50%;
  background: var(--c-warn); margin-inline-start: var(--sp-2);
  display: inline-block; vertical-align: middle;
}

/* --- Footer: collapse toggle, density, help --------------------------- */
.rail__footer {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3); border-block-start: 1px solid rgba(255,255,255,.08);
}
.rail__footer .btn { color: var(--navy-04); }

/* --- Collapsed (64px). Icons only, active bar retained, label suppressed,
       tooltip on hover after 400ms and IMMEDIATELY on keyboard focus.  --- */
.app--collapsed .rail, .rail.is-collapsed, .app--compact-nav .app-sidebar {
  inline-size: var(--rail-w-collapsed);
}
.rail.is-collapsed .rail__label,
.rail.is-collapsed .rail__wordmark,
.rail.is-collapsed .rail__chevron,
.rail.is-collapsed .rail__sections,
.rail.is-collapsed .rail__pinned-head,
.rail.is-collapsed .rail__tier,
.rail.is-collapsed .rail__pin { display: none; }
.rail.is-collapsed .rail__item { justify-content: center; padding-inline: 0; }
.rail.is-collapsed .rail__brand { justify-content: center; padding-inline: 0; }
.rail.is-collapsed .rail__badge {
  position: absolute; inset-block-start: 4px; inset-inline-end: 6px;
  margin: 0; min-inline-size: 16px; block-size: 16px;
  border: 2px solid var(--c-surface-inv);
}
.rail.is-collapsed .rail__lock { position: absolute; inset-block-end: 3px; inset-inline-end: 5px; margin: 0; }

.rail__tip {
  position: absolute; inset-inline-start: calc(100% + 8px); inset-block-start: 50%;
  transform: translateY(-50%);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
  background: var(--navy-12); color: #fff; font-size: var(--fs-sm);
  white-space: nowrap; box-shadow: var(--sh-3);
  opacity: 0; pointer-events: none; z-index: 70;
  transition: opacity var(--dur-1) var(--ease) 400ms;
}
.rail.is-collapsed .rail__item:hover .rail__tip { opacity: 1; }
.rail.is-collapsed .rail__item:focus-visible .rail__tip { opacity: 1; transition-delay: 0s; }

/* --- Hidden: print, PS-01 till focus mode, F11 ------------------------ */
.app--focus .rail, .app--no-nav .rail { display: none; }

/* --- Responsive (§4.1) ------------------------------------------------ */
@media (max-width: 1279px) and (min-width: 1024px) {
  .app { grid-template-columns: var(--rail-w-collapsed) minmax(0,1fr) 0; }
  .app .rail { inline-size: var(--rail-w-collapsed); }
  /* expands as an OVERLAY on hover/focus — content never reflows */
  .app .rail:hover, .app .rail:focus-within { inline-size: var(--rail-w); box-shadow: var(--sh-4); }
  .app .rail:hover .rail__label, .app .rail:focus-within .rail__label,
  .app .rail:hover .rail__chevron, .app .rail:focus-within .rail__chevron,
  .app .rail:hover .rail__wordmark, .app .rail:focus-within .rail__wordmark { display: block; }
  .app .rail:hover .rail__item, .app .rail:focus-within .rail__item { justify-content: flex-start; padding-inline: var(--sp-3); }
}
@media (max-width: 1023px) {
  .app { grid-template-columns: 0 minmax(0,1fr) 0; }
  .rail, .app-sidebar {
    position: fixed; inset-block: 0; inset-inline-start: 0;
    inline-size: 288px; transform: translateX(-100%);
    transition: transform var(--dur-3) var(--ease); box-shadow: var(--sh-4);
  }
  [dir="rtl"] .rail, [dir="rtl"] .app-sidebar { transform: translateX(100%); }
  .rail.is-open, .app-sidebar.is-open { transform: none; }
  .app--with-drawer, .app--with-drawer-wide { grid-template-columns: 0 minmax(0,1fr) 0; }
}

/* --- Main column ------------------------------------------------------ */
.app-main, .main {
  grid-area: main; overflow: auto; min-inline-size: 0;
  display: flex; flex-direction: column;
  /* The containing block for everything absolutely positioned inside the page.
     Without it, a visually-hidden label (.sr-only is position:absolute) far down
     a long screen was placed against the viewport instead of this scroller, so
     the document itself grew as tall as the page and the window got a second
     scrollbar beside this one (Load metal, 2026-09). */
  position: relative;
}
.app-content, .main__content {
  flex: 1 1 auto; padding: var(--d-gutter);
  max-inline-size: var(--content-max); inline-size: 100%;
}
.app-content--flush { padding: 0; max-inline-size: none; }
.app-content--wide  { max-inline-size: none; }
/* Inventory reads full width, like the kit pages (oform.css); a form keeps a reading width (2026-10-08) */
.app-main[data-mod="inventory"] { --content-max: none; }
.app-main[data-mod="inventory"] form.card { max-inline-size: 1280px; }
.app-main[data-mod="workshop"] { --content-max: none; }
.app-main[data-mod="workshop"] form.card { max-inline-size: 1280px; }

.page-head {
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-4);
  padding: var(--sp-5) var(--d-gutter) 0;
  max-inline-size: var(--content-max); inline-size: 100%;
}
.page-title {
  font-size: var(--fs-xl); font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-tight); line-height: var(--lh-snug);
  margin-inline-end: auto; min-inline-size: 0;
}
/* §11.4: the other language's name, subdued, on hover/focus of the title. */
.page-title__alt {
  display: block; font-size: var(--fs-sm); font-weight: var(--fw-regular);
  color: var(--c-ink-4); opacity: 0; transition: opacity var(--dur-2) var(--ease);
}
.page-title:hover .page-title__alt, .page-title:focus-within .page-title__alt { opacity: 1; }
.page-title__sub { display: block; font-size: var(--fs-sm); font-weight: var(--fw-regular); color: var(--c-ink-3); }
.page-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }
/* The favourite star every screen header carries (§7.1). */
.page-star { color: var(--c-ink-4); background: transparent; border: 0; cursor: pointer; padding: var(--sp-2); border-radius: var(--r-sm); }
.page-star:hover { color: var(--c-ink-2); background: var(--c-surface-2); }
.page-star.is-on { color: var(--c-metal); }

/* ==========================================================================
   09  BREADCRUMBS  (§4.4)
   Not the menu path — the RECORD path. Absent on an L3 menu screen.
   Truncates from the START (oldest segments), which in RTL means the ones
   furthest to the right. The record identifier is never truncated.
   ========================================================================== */
.crumbs {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: nowrap;
  min-inline-size: 0; font-size: var(--fs-sm); color: var(--c-ink-3);
}
.crumbs__item {
  max-inline-size: 24ch; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--c-ink-3); text-decoration: none;
}
.crumbs__item:hover { color: var(--c-accent); text-decoration: underline; }
/* The origin of a cross-group drill-through keeps its emphasis: the way
   back must be visible without browser-back (§4.4, the accountant's rule). */
.crumbs__origin { color: var(--c-accent); font-weight: var(--fw-semi); }
.crumbs__sep { flex: 0 0 auto; color: var(--c-ink-faint); }
.crumbs__sep::before { content: "\203A"; }              /* > */
[dir="rtl"] .crumbs__sep::before { content: "\2039"; }  /* < */
.crumbs__ellipsis {
  flex: 0 0 auto; border: 0; background: transparent; cursor: pointer;
  color: var(--c-ink-3); padding: 0 var(--sp-2); border-radius: var(--r-xs);
  font: inherit;
}
.crumbs__ellipsis:hover { background: var(--c-surface-3); color: var(--c-ink); }
.crumbs__ellipsis::before { content: "\2026"; }
/* A record identifier: monospace, LTR-isolated, never truncated, never reversed. */
.crumbs__record, .docref {
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  direction: ltr; unicode-bidi: isolate; white-space: nowrap;
  color: var(--c-ink); font-weight: var(--fw-medium);
}
.crumbs__current { color: var(--c-ink); font-weight: var(--fw-semi); }
/* Kit alias */
.breadcrumb { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--c-ink-3); }
.breadcrumb a { color: var(--c-ink-3); }
.breadcrumb__sep::before { content: "\203A"; color: var(--c-ink-faint); }
[dir="rtl"] .breadcrumb__sep::before { content: "\2039"; }
.breadcrumb__current { color: var(--c-ink); font-weight: var(--fw-medium); }
/* On a phone the chain collapses to one back-chip naming the ORIGIN (§9.4). */
.crumbs--chip { display: none; }
@media (max-width: 767px) {
  .crumbs { display: none; }
  .crumbs--chip {
    display: inline-flex; align-items: center; gap: var(--sp-2);
    min-block-size: var(--hit-touch); padding-inline: var(--sp-3);
    border: 1px solid var(--c-line); border-radius: var(--r-pill);
    background: var(--c-surface-2); color: var(--c-accent);
    font-size: var(--fs-sm); font-weight: var(--fw-medium);
  }
}

/* ==========================================================================
   10  TABS & SUB-NAVIGATION  (§4.5)
   Tabs = facets of ONE object. Sub-navigation = stages of one workflow, and
   it carries counts. Never both on one screen.
   ========================================================================== */
.tabs {
  display: flex; align-items: stretch; gap: var(--sp-5);
  border-block-end: 1px solid var(--c-line);
  overflow-x: auto; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: 36px; padding: 0 var(--sp-1);
  border: 0; border-block-end: 2px solid transparent;
  background: transparent; color: var(--c-ink-3);
  font: inherit; font-size: var(--fs-base); font-weight: var(--fw-medium);
  cursor: pointer; white-space: nowrap; text-decoration: none;
  margin-block-end: -1px;
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.tab:hover { color: var(--c-ink); text-decoration: none; }
.tab[aria-selected="true"], .tab.is-active {
  color: var(--c-ink); font-weight: var(--fw-semi);
  border-block-end-color: var(--c-accent);
}
.tab__count {
  min-inline-size: 18px; padding-inline: 5px; border-radius: var(--r-pill);
  background: var(--c-surface-3); color: var(--c-ink-3);
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
  font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate;
}
.tab[aria-selected="true"] .tab__count { background: var(--c-accent-weak); color: var(--c-accent); }
.tabs--boxed { border: 0; gap: var(--sp-2); }
.tabs--boxed .tab { border: 1px solid var(--c-line); border-radius: var(--r-md); padding-inline: var(--sp-4); margin: 0; }
.tabs--boxed .tab[aria-selected="true"] { background: var(--c-accent-weak); border-color: var(--c-accent-line); }

/* Sub-navigation: a segmented control. A count of zero GREYS the segment,
   it never hides it — the workflow's shape must stay visible. */
.subnav {
  display: inline-flex; align-items: stretch; flex-wrap: wrap;
  border: 1px solid var(--c-line); border-radius: var(--r-md);
  background: var(--c-surface-2); overflow: hidden;
}
.subnav__seg {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-4);
  border: 0; border-inline-end: 1px solid var(--c-line);
  background: transparent; color: var(--c-ink-2);
  font: inherit; font-size: var(--fs-sm); cursor: pointer; white-space: nowrap;
  text-decoration: none;
}
.subnav__seg:last-child { border-inline-end: 0; }
.subnav__seg:hover { background: var(--c-surface-3); text-decoration: none; }
.subnav__seg[aria-selected="true"], .subnav__seg.is-active {
  background: var(--c-surface); color: var(--c-ink); font-weight: var(--fw-semi);
  box-shadow: inset 0 -2px 0 var(--c-accent);
}
.subnav__count {
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  font-size: var(--fs-xs); color: var(--c-ink-3);
  direction: ltr; unicode-bidi: isolate;
}
.subnav__seg.is-zero { color: var(--c-ink-4); }
.subnav__seg.is-zero .subnav__count { color: var(--c-ink-faint); }

/* ==========================================================================
   11  THE CONTEXTUAL DRAWER  (§4.6)
   One drawer, inline-end side. 360px, 480px for the pricing trace and the
   journal viewer. Docks at >=1600px, overlays below. Stacks two deep; the
   second shifts the first 32px and dims it.
   ========================================================================== */
.drawer, .app-drawer {
  grid-area: drawer;
  display: flex; flex-direction: column;
  inline-size: var(--drawer-w);
  background: var(--c-surface);
  border-inline-start: 1px solid var(--c-line);
  box-shadow: var(--sh-3);
  z-index: 45; overflow: hidden;
}
.drawer--wide { inline-size: var(--drawer-w-wide); }
.drawer:not(.is-open), .app-drawer:not(.is-open) { display: none; }
.drawer__head {
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: var(--topbar-h); flex: 0 0 auto;
  padding-inline: var(--sp-5);
  border-block-end: 1px solid var(--c-line);
  background: var(--c-surface-2);
}
.drawer__title { font-size: var(--fs-md); font-weight: var(--fw-semi); margin-inline-end: auto; min-inline-size: 0; }
.drawer__close { margin-inline-start: auto; }
.drawer__body  { flex: 1 1 auto; overflow: auto; padding: var(--sp-5); }
.drawer__foot  {
  flex: 0 0 auto; display: flex; gap: var(--sp-3); align-items: center;
  padding: var(--sp-4) var(--sp-5);
  border-block-start: 1px solid var(--c-line); background: var(--c-surface-2);
}
/* Stacking. */
.drawer--under { transform: translateX(-32px); filter: brightness(.94); pointer-events: none; }
[dir="rtl"] .drawer--under { transform: translateX(32px); }
/* Below 1600px the drawer overlays; below 1024px it is a full-screen sheet. */
@media (max-width: 1599px) {
  .drawer, .app-drawer {
    position: fixed; inset-block: 0; inset-inline-end: 0;
    block-size: 100vh; block-size: 100dvh;
  }
}
@media (max-width: 1023px) {
  .drawer, .app-drawer { inline-size: 100%; border-inline-start: 0; }
  .drawer__close { min-block-size: var(--hit-touch); }
}
.scrim {
  position: fixed; inset: 0; z-index: 44;
  background: rgba(5,34,65,.40);
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-5);
  backdrop-filter: saturate(.8) blur(1px);
}
.scrim--top   { align-items: flex-start; padding-block-start: 15vh; }
.scrim--sheet { align-items: flex-end; padding: 0; }
:root[data-theme="dark"] .scrim { background: rgba(0,0,0,.62); }

/* ==========================================================================
   12  THE COMMAND PALETTE  (§5)
   The primary navigation for 44% of the product and the only navigation
   that works on a keyboard-only till. 640px, top at 15vh, 60vh max, nine
   rows visible without scrolling. The frame mirrors in RTL; the input is
   dir="auto" and flips per keystroke; result labels are <bdi>.
   ========================================================================== */
.cmdk {
  inline-size: min(640px, 100% - 32px);
  max-block-size: 60vh;
  display: flex; flex-direction: column;
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-4);
  overflow: hidden;
}
.cmdk__form { display: flex; align-items: center; gap: var(--sp-3); padding-inline: var(--sp-5); border-block-end: 1px solid var(--c-line); flex: 0 0 auto; }
.cmdk__ico-search { color: var(--c-ink-3); flex: 0 0 auto; }
.cmdk__input {
  flex: 1 1 auto; min-inline-size: 0; block-size: 48px;
  border: 0; background: transparent; color: var(--c-ink);
  font: inherit; font-size: 16px;
}
.cmdk__input:focus { outline: none; box-shadow: none; }
.cmdk__input::placeholder { color: var(--c-ink-4); }
/* Scope chip: > actions, # records, @ people, ? help, : settings.
   Backspace on an empty input steps back out of the scope. */
.cmdk__scope {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 2px var(--sp-3); border-radius: var(--r-sm);
  background: var(--c-accent-weak); color: var(--c-accent);
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
}
.cmdk__scope code { background: transparent; padding: 0; }
.cmdk__esc { flex: 0 0 auto; }

.cmdk__results { flex: 1 1 auto; overflow-y: auto; padding: var(--sp-2); overscroll-behavior: contain; }
.cmdk__group + .cmdk__group { margin-block-start: var(--sp-2); }
.cmdk__group-head {
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  color: var(--c-ink-3);
}
.cmdk__row {
  display: flex; align-items: center; gap: var(--sp-3);
  inline-size: 100%; min-block-size: 40px; padding-inline: var(--sp-3);
  border: 0; border-radius: var(--r-md); background: transparent;
  color: var(--c-ink); font: inherit; text-align: start; cursor: pointer;
  text-decoration: none;
}
.cmdk__row:hover { background: var(--c-surface-2); text-decoration: none; }
/* Selection is keyboard-driven, so it must be visible without a pointer. */
.cmdk__row.is-active, .cmdk__row[aria-selected="true"] {
  background: var(--c-accent-weak);
  box-shadow: inset 3px 0 0 var(--c-accent);
}
[dir="rtl"] .cmdk__row.is-active, [dir="rtl"] .cmdk__row[aria-selected="true"] {
  box-shadow: inset -3px 0 0 var(--c-accent);
}
/* §11.1: the result icon is inline-start in LTR and moves to inline-end in
   RTL; the keyboard hint goes the other way. Order does the mirroring. */
.cmdk__ico   { flex: 0 0 auto; color: var(--c-ink-3); }
.cmdk__row.is-active .cmdk__ico { color: var(--c-accent); }
.cmdk__body  { min-inline-size: 0; flex: 1 1 auto; }
.cmdk__label { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk__label mark { background: transparent; color: var(--c-accent); font-weight: var(--fw-bold); }
.cmdk__meta  { display: block; font-size: var(--fs-xs); color: var(--c-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk__id    { font-family: var(--font-num); font-size: var(--fs-xs); color: var(--c-ink-4); direction: ltr; unicode-bidi: isolate; }
.cmdk__path  { font-size: var(--fs-xs); color: var(--c-ink-4); flex: 0 0 auto; white-space: nowrap; }
.cmdk__hint  { flex: 0 0 auto; margin-inline-start: auto; display: none; gap: var(--sp-2); align-items: center; }
.cmdk__row.is-active .cmdk__hint { display: inline-flex; }
/* A shield glyph on any action that will demand step-up (IA-11), so the
   user knows BEFORE they commit (§5.5). */
.cmdk__shield { flex: 0 0 auto; color: var(--c-warn); }
/* §10.3 plan-locked results are shown, scored down, never first. */
.cmdk__row--locked { opacity: .66; }
.cmdk__row--locked .cmdk__tier {
  margin-inline-start: auto; padding: 1px 5px; border-radius: var(--r-xs);
  background: var(--c-ink); color: var(--c-ink-inv);
  font-size: 9px; font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps);
}
/* §10.2 the ONLY place a not-permitted screen is ever named. */
.cmdk__row--denied { opacity: .72; cursor: default; }
.cmdk__row--denied .cmdk__label { text-decoration: line-through; text-decoration-color: var(--c-ink-faint); }
.cmdk__ask { margin-inline-start: auto; }
/* An action that cannot run offline: greyed WITH THE REASON INLINE (§5.8). */
.cmdk__row--unavailable { opacity: .6; cursor: not-allowed; }
.cmdk__why { font-size: var(--fs-xs); color: var(--c-warn); margin-inline-start: auto; white-space: nowrap; }

/* Inline action preview — "Receive transfer TRF-0042 — 6 pieces, 43.083 g" */
.cmdk__preview {
  margin: var(--sp-2) var(--sp-3) var(--sp-3);
  padding: var(--sp-4);
  border: 1px solid var(--c-accent-line); border-radius: var(--r-md);
  background: var(--c-accent-weak);
  font-size: var(--fs-sm);
}
.cmdk__preview .amt { margin-block-start: var(--sp-2); }

/* Empty, no-result, offline. Never a blank box (§5.7). */
.cmdk__empty { padding: var(--sp-6) var(--sp-5); text-align: center; color: var(--c-ink-3); }
.cmdk__empty-title { font-weight: var(--fw-semi); color: var(--c-ink); margin-block-end: var(--sp-2); }
.cmdk__offline {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-5);
  background: var(--c-warn-weak); color: var(--c-warn);
  border-block-end: 1px solid var(--c-warn-line);
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
}
.cmdk__foot {
  flex: 0 0 auto; display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-2) var(--sp-5);
  border-block-start: 1px solid var(--c-line); background: var(--c-surface-2);
  font-size: var(--fs-xs); color: var(--c-ink-3);
}
.cmdk__foot .kbd { }
.cmdk__foot-item { display: inline-flex; align-items: center; gap: var(--sp-2); }
/* On a phone the palette is a full-screen sheet with the keyboard up (§9.4). */
@media (max-width: 767px) {
  .scrim--top { padding: 0; align-items: stretch; }
  .cmdk { inline-size: 100%; max-block-size: none; block-size: 100dvh; border-radius: 0; border: 0; }
  .cmdk__row { min-block-size: var(--hit-touch); }
}

/* ==========================================================================
   13  ROLE-BASED HOME SCREENS  (§6)
   A tile grid composed from the session, not a bespoke page per role.
   A tile whose permission is missing is ABSENT. A tile whose plan flag is
   off is an upsell card at the BOTTOM of the grid, never interleaved.
   Every tile is a link to the screen that fixes it. A tile with no
   destination is a poster, not a tile.
   ========================================================================== */
.home { display: grid; grid-template-columns: repeat(12, minmax(0,1fr)); gap: var(--d-stack); }
.widget {
  grid-column: span 4;
  display: flex; flex-direction: column; gap: var(--sp-3);
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-radius: var(--r-lg); padding: var(--d-card-p);
  box-shadow: var(--sh-1); min-inline-size: 0;
}
.widget--span3  { grid-column: span 3; }
.widget--span4  { grid-column: span 4; }
.widget--span6  { grid-column: span 6; }
.widget--span8  { grid-column: span 8; }
.widget--span12 { grid-column: span 12; }
@media (max-width: 1279px) { .widget, .widget--span3, .widget--span4 { grid-column: span 6; } .widget--span8 { grid-column: span 12; } }
@media (max-width: 767px)  { .widget, .widget--span3, .widget--span4, .widget--span6, .widget--span8 { grid-column: span 12; } }

.widget__head { display: flex; align-items: center; gap: var(--sp-3); }
.widget__title { font-size: var(--fs-sm); font-weight: var(--fw-semi); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); margin-inline-end: auto; }
.widget__count { font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-weight: var(--fw-bold); color: var(--c-ink); direction: ltr; unicode-bidi: isolate; }
.widget__body { flex: 1 1 auto; min-inline-size: 0; }
.widget__foot { margin-block-start: auto; padding-block-start: var(--sp-3); border-block-start: 1px solid var(--c-line-soft); font-size: var(--fs-xs); }
.widget__more { color: var(--c-accent); font-weight: var(--fw-medium); }
.widget__drag { color: var(--c-ink-faint); cursor: grab; }

/* The door: the salesperson's one button. 96px, full width, unmissable. */
.widget--door {
  grid-column: span 12; flex-direction: row; align-items: center; gap: var(--sp-5);
  min-block-size: 96px;
  background: var(--c-surface-inv); border-color: transparent; color: var(--c-ink-inv);
}
.widget--door .widget__title { color: var(--navy-05); }
.widget--door .btn--primary {
  background: var(--c-highlight); border-color: var(--c-highlight); color: var(--navy-11);
  min-block-size: 56px; padding-inline: var(--sp-7); font-size: var(--fs-lg); font-weight: var(--fw-bold);
}
.widget--door .btn--primary:hover { background: var(--blue-04); border-color: var(--blue-04); }

/* The owner's one number. 48px type, phone-first (§6.5). */
.widget--hero { align-items: flex-start; gap: var(--sp-2); }
.widget--hero .widget__title { margin-inline-end: 0; }

/* The accountant's integrity strip: first, full-width, green count and every
   red one NAMED with its variance in BHD and in grams (§6.4). */
.widget--integrity { grid-column: span 12; border-inline-start: 3px solid var(--c-success); }
.widget--integrity.has-red { border-inline-start-color: var(--c-danger); }
.integrity { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }
.integrity__ok {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-pill);
  background: var(--c-success-weak); color: var(--c-success);
  font-size: var(--fs-sm); font-weight: var(--fw-semi);
}
.integrity__red {
  display: flex; align-items: center; gap: var(--sp-3); inline-size: 100%;
  padding: var(--sp-3); border-radius: var(--r-md);
  background: var(--c-danger-weak); border: 1px solid var(--c-danger-line);
}
.integrity__red .amt { margin-inline-start: auto; }

/* "Needs me now" / exception rows. Each is one line and each is a link. */
.exlist { display: flex; flex-direction: column; }
.exrow {
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: var(--d-row-h); padding-inline: var(--sp-2);
  border-block-end: 1px solid var(--c-line-soft);
  color: inherit; text-decoration: none; border-radius: var(--r-sm);
}
.exrow:last-child { border-block-end: 0; }
.exrow:hover { background: var(--c-surface-2); text-decoration: none; }
.exrow__ico    { flex: 0 0 auto; color: var(--c-ink-3); }
.exrow__label  { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exrow__reason { font-size: var(--fs-xs); color: var(--c-ink-3); }
.exrow__figure { margin-inline-start: auto; font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-weight: var(--fw-semi); direction: ltr; unicode-bidi: isolate; }
.exrow--danger .exrow__ico { color: var(--c-danger); }
.exrow--warn   .exrow__ico { color: var(--c-warn); }

/* The upsell card. Bottom of the grid, never interleaved. */
.widget--upsell {
  background: var(--c-accent-weak); border-color: var(--c-accent-line);
  border-style: dashed;
}
.widget--upsell .widget__title { color: var(--c-accent); }
.upsell__tier {
  display: inline-flex; padding: 1px 6px; border-radius: var(--r-xs);
  background: var(--c-ink); color: var(--c-ink-inv);
  font-size: 9px; font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps);
}
.home__reset { grid-column: span 12; text-align: center; padding-block: var(--sp-4); }

/* ==========================================================================
   14  BUTTONS
   Four weights and no more. Primary is NAVY — the wordmark colour — and
   there is at most one per screen region. Accent blue is reserved for
   links, focus and selection; a blue button and a blue link on the same
   screen would make neither mean anything.
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2); flex: 0 0 auto;
  min-block-size: var(--d-ctl-h); padding-inline: var(--d-ctl-px);
  border: 1px solid var(--c-line-strong); border-radius: var(--r-md);
  background: var(--c-surface); color: var(--c-ink);
  font: inherit; font-size: var(--fs-base); font-weight: var(--fw-medium);
  line-height: 1; text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
  box-shadow: var(--sh-1);
}
.btn:hover  { background: var(--c-surface-2); border-color: var(--c-ink-4); text-decoration: none; }
.btn:active { background: var(--c-surface-3); box-shadow: none; transform: translateY(.5px); }
.btn--secondary { }

.btn--primary {
  background: var(--c-primary); border-color: var(--c-primary);
  color: var(--c-primary-ink); font-weight: var(--fw-semi);
}
.btn--primary:hover  { background: var(--c-primary-hi); border-color: var(--c-primary-hi); }
.btn--primary:active { background: var(--c-primary-hi); }

.btn--accent {
  background: var(--c-accent); border-color: var(--c-accent); color: var(--c-accent-ink);
  font-weight: var(--fw-semi);
}
.btn--accent:hover { background: var(--c-accent-hi); border-color: var(--c-accent-hi); }

.btn--ghost { background: transparent; border-color: transparent; box-shadow: none; color: var(--c-ink-2); }
.btn--ghost:hover { background: var(--c-surface-2); border-color: transparent; color: var(--c-ink); }

.btn--quiet { background: transparent; border-color: var(--c-line); box-shadow: none; color: var(--c-ink-2); }
.btn--quiet:hover { background: var(--c-surface-2); }

.btn--danger { background: var(--c-danger); border-color: var(--c-danger); color: #fff; font-weight: var(--fw-semi); }
.btn--danger:hover { filter: brightness(.92); }
.btn--danger-quiet { background: var(--c-surface); border-color: var(--c-danger-line); color: var(--c-danger); }
.btn--danger-quiet:hover { background: var(--c-danger-weak); }

.btn--link { background: transparent; border-color: transparent; box-shadow: none; color: var(--c-accent); padding-inline: 0; min-block-size: auto; }
.btn--link:hover { text-decoration: underline; background: transparent; }

.btn--sm    { min-block-size: calc(var(--d-ctl-h) - 8px); padding-inline: var(--sp-3); font-size: var(--fs-xs); }
.btn--lg    { min-block-size: var(--hit-touch); padding-inline: var(--sp-6); font-size: var(--fs-md); }
.btn--till  { min-block-size: 56px; padding-inline: var(--sp-7); font-size: var(--fs-lg); font-weight: var(--fw-bold); border-radius: var(--r-lg); }
.btn--block { inline-size: 100%; }
.btn--icon  { padding-inline: 0; inline-size: var(--d-ctl-h); }
.btn--icon.btn--lg { inline-size: var(--hit-touch); }

.btn[disabled], .btn.is-disabled, .btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; box-shadow: none; pointer-events: none;
}
/* A disabled action ALWAYS states why, next to it. Programme rule. */
.btn-why { font-size: var(--fs-xs); color: var(--c-ink-3); }

.btn.is-loading { pointer-events: none; position: relative; color: transparent; }
.btn.is-loading::after {
  content: ""; position: absolute; inline-size: 14px; block-size: 14px;
  border: 2px solid currentColor; border-block-start-color: transparent;
  border-radius: 50%; animation: jt-spin 700ms linear infinite;
  color: var(--c-ink-2);
}
.btn--primary.is-loading::after, .btn--accent.is-loading::after, .btn--danger.is-loading::after { color: #fff; }
@keyframes jt-spin { to { transform: rotate(360deg); } }

/* A button that shows its shortcut. The till lives on these. */
.btn .kbd { border-block-end-width: 1px; opacity: .85; }
.btn--primary .kbd, .btn--accent .kbd, .btn--danger .kbd {
  background: rgba(255,255,255,.16); border-color: rgba(255,255,255,.32); color: inherit;
}

.btn-group { display: inline-flex; }
.btn-group .btn { border-radius: 0; margin-inline-start: -1px; box-shadow: none; }
.btn-group .btn:first-child { border-start-start-radius: var(--r-md); border-end-start-radius: var(--r-md); margin-inline-start: 0; }
.btn-group .btn:last-child  { border-start-end-radius: var(--r-md);   border-end-end-radius: var(--r-md); }
.btn-group .btn.is-on {
  background: var(--c-accent-weak); border-color: var(--c-accent-line);
  color: var(--c-accent); font-weight: var(--fw-semi); z-index: 1;
}

/* ==========================================================================
   15  FORMS
   ========================================================================== */
.field { display: block; margin-block-end: var(--sp-4); }
/* `hidden` must win over the display rule above: forms show and hide fields by it. */
.field[hidden] { display: none; }
.field--inline { display: flex; align-items: center; gap: var(--sp-3); }
.label {
  display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
  font-size: var(--fs-sm); font-weight: var(--fw-semi); color: var(--c-ink-2);
  margin-block-end: var(--sp-2);
}
.label-ar  { font-family: var(--font-ar); font-weight: var(--fw-regular); color: var(--c-ink-3); }
.req       { color: var(--c-danger); font-weight: var(--fw-bold); }
.optional  { color: var(--c-ink-4); font-weight: var(--fw-regular); font-size: var(--fs-micro); }

.input, .select, .textarea {
  inline-size: 100%; min-block-size: var(--d-ctl-h);
  padding: 0 var(--d-ctl-px);
  border: 1px solid var(--c-line-strong);   /* VERIFIED 3:1 boundary */
  border-radius: var(--r-md);
  background: var(--c-surface); color: var(--c-ink);
  font: inherit; font-size: var(--d-fs);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.textarea { min-block-size: 76px; padding-block: var(--sp-3); resize: vertical; line-height: var(--lh-base); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--c-ink-4); }
.input:focus, .select:focus, .textarea:focus { border-color: var(--c-accent); }
.input::placeholder, .textarea::placeholder { color: var(--c-ink-4); }
.input[readonly], .input:disabled, .select:disabled, .textarea:disabled {
  background: var(--c-surface-3); color: var(--c-ink-3); cursor: not-allowed;
  border-color: var(--c-line);
}
/* Numeric inputs are monospaced, end-aligned and always LTR. A gram figure
   does not reverse in Arabic. */
.input--num {
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  text-align: end; direction: ltr; unicode-bidi: isolate;
}
.input--lg  { min-block-size: var(--hit-touch); font-size: var(--fs-md); }
.input--till{ min-block-size: 48px; font-size: var(--fs-lg); font-weight: var(--fw-semi); }

/* The native select arrow is drawn with a gradient — no image file, ever. */
.select {
  appearance: none; -webkit-appearance: none;
  padding-inline-end: var(--sp-7);
  background-image:
    linear-gradient(45deg,  transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 16px) calc(50% + 2px),
    calc(100% - 11px) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
[dir="rtl"] .select {
  padding-inline-end: var(--sp-7);
  background-position: 11px calc(50% + 2px), 16px calc(50% + 2px);
}

.input-group { display: flex; align-items: stretch; }
.input-group .input, .input-group .select { border-radius: 0; }
.input-group > :first-child { border-start-start-radius: var(--r-md); border-end-start-radius: var(--r-md); }
.input-group > :last-child  { border-start-end-radius: var(--r-md);   border-end-end-radius: var(--r-md); }
.affix {
  display: inline-flex; align-items: center; padding-inline: var(--sp-3);
  border: 1px solid var(--c-line-strong); background: var(--c-surface-3);
  color: var(--c-ink-3); font-size: var(--fs-sm); white-space: nowrap;
  font-family: var(--font-num);
}
.affix + .input, .input + .affix, .affix + .select { margin-inline-start: -1px; }

.hint { font-size: var(--fs-xs); color: var(--c-ink-3); margin: var(--sp-2) 0 0; }
.err {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  font-size: var(--fs-xs); color: var(--c-danger); font-weight: var(--fw-medium);
  margin: var(--sp-2) 0 0;
}
.err::before {
  content: "!"; flex: 0 0 auto;
  inline-size: 14px; block-size: 14px; border-radius: 50%;
  background: var(--c-danger); color: #fff;
  font-weight: var(--fw-bold); font-size: 10px; line-height: 14px; text-align: center;
}
.field.is-invalid .input, .field.is-invalid .select, .field.is-invalid .textarea {
  border-color: var(--c-danger); background: var(--c-danger-weak);
}
.field.is-warning .input { border-color: var(--c-warn); background: var(--c-warn-weak); }
.field.is-valid   .input { border-color: var(--c-success); }

/* Search and search-with-scan. The scan variant is the POS/handheld door. */
.search { position: relative; display: flex; align-items: center; }
.search .input { padding-inline-start: var(--sp-8); }
.search__ico {
  position: absolute; inset-inline-start: var(--sp-3);
  color: var(--c-ink-3); pointer-events: none;
}
.search--scan .input { padding-inline-end: var(--sp-8); font-family: var(--font-num); }
.search__scan { position: absolute; inset-inline-end: var(--sp-2); }
.scan-ready {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-pill);
  background: var(--c-success-weak); border: 1px solid var(--c-success-line);
  color: var(--c-success); font-size: var(--fs-xs); font-weight: var(--fw-semi);
}
.scan-ready--off { color: var(--c-ink-3); background: var(--c-surface-3); border-color: var(--c-line); }
.scan-bars { display: inline-flex; gap: 1px; align-items: stretch; block-size: 11px; }
.scan-bars i { display: block; inline-size: 1px; background: currentColor; }
.scan-bars i:nth-child(2n) { inline-size: 2px; }
.scan-bars i:nth-child(3n) { opacity: .45; }

.check, .radio {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  min-block-size: var(--hit); cursor: pointer; font-size: var(--d-fs);
}
.check input, .radio input {
  inline-size: 16px; block-size: 16px; flex: 0 0 16px; margin: 3px 0 0;
  accent-color: var(--c-accent);
}
.check__text small, .radio__text small { display: block; color: var(--c-ink-3); font-size: var(--fs-xs); }

.switch { display: inline-flex; align-items: center; gap: var(--sp-3); cursor: pointer; min-block-size: var(--hit); position: relative; }
.switch input { position: absolute; opacity: 0; pointer-events: none; }
.switch__track {
  inline-size: 36px; block-size: 20px; flex: 0 0 auto; position: relative;
  background: var(--c-surface-3); border: 1px solid var(--c-line-strong);
  border-radius: var(--r-pill); transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.switch__track::after {
  content: ""; position: absolute; inset-block-start: 2px; inset-inline-start: 2px;
  inline-size: 14px; block-size: 14px; border-radius: 50%;
  background: var(--c-surface); border: 1px solid var(--c-line-strong);
  transition: inset-inline-start var(--dur-2) var(--ease);
}
.switch input:checked + .switch__track { background: var(--c-accent); border-color: var(--c-accent); }
.switch input:checked + .switch__track::after { inset-inline-start: 18px; border-color: var(--c-accent); }
.switch input:focus-visible + .switch__track { box-shadow: var(--focus-ring); }
.switch input:disabled + .switch__track { opacity: .5; }

.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 0 var(--sp-5); }
.form-grid--3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.form-grid .field--full { grid-column: 1 / -1; }
@media (max-width: 720px) { .form-grid, .form-grid--3 { grid-template-columns: 1fr; } }
.fieldset { border: 1px solid var(--c-line); border-radius: var(--r-md); padding: var(--sp-5); margin: 0 0 var(--sp-5); }
.fieldset > legend { font-size: var(--fs-xs); font-weight: var(--fw-semi); color: var(--c-ink-2); padding-inline: var(--sp-2); text-transform: uppercase; letter-spacing: var(--tracking-caps); }

/* ==========================================================================
   16  TABLES & NUMBERS
   This application is mostly numbers in columns. Every numeric surface in
   this file carries tabular figures, end alignment and bidi isolation. A
   column of 1,942.420 must align in Arabic exactly as it does in English.
   ========================================================================== */
.tbl-wrap {
  overflow-x: auto; background: var(--c-surface);
  border: 1px solid var(--c-line); border-radius: var(--r-lg);
}
.tbl-wrap--flush  { border: 0; border-radius: 0; }
.tbl-wrap--scroll { max-block-size: 420px; overflow: auto; }

.tbl {
  inline-size: 100%; border-collapse: collapse;
  font-size: var(--d-fs-table); font-variant-numeric: var(--num-feat);
}
.tbl caption { text-align: start; padding: var(--sp-3) var(--d-cell-px); font-size: var(--fs-xs); color: var(--c-ink-3); }
.tbl th, .tbl td {
  padding: var(--d-cell-py) var(--d-cell-px);
  border-block-end: 1px solid var(--c-line-soft);
  text-align: start; vertical-align: middle;
}
.tbl thead th {
  background: var(--c-surface-2);
  border-block-end: 1px solid var(--c-line);
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  color: var(--c-ink-3); white-space: nowrap;
  min-block-size: 32px;
}
.tbl tbody tr { min-block-size: var(--d-row-h); }
.tbl tbody th[scope="row"] { font-weight: var(--fw-semi); font-family: var(--font-num); direction: ltr; unicode-bidi: isolate; }
.tbl tbody tr:last-child td, .tbl tbody tr:last-child th { border-block-end: 0; }
.tbl--zebra tbody tr:nth-child(even) { background: var(--c-surface-2); }
.tbl--hover tbody tr:hover { background: var(--c-accent-weak); }
.tbl--compact th, .tbl--compact td { padding-block: var(--sp-1); }
/* Report column blocks — Opening | Inward | Outward | Closing. The block's name
   heads its columns on a row of its own, and a rule runs down between blocks,
   through the heading, the rows and the total alike. */
.rpt-grp th { text-align: center; }
.rpt-grp__h {
  font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--c-ink); background: var(--c-surface-2); border-block-end: 1px solid var(--c-line-strong);
}
.tbl th.g-start, .tbl td.g-start { border-inline-start: 2px solid var(--c-line-strong); }
/* a block report is wide by nature: keep each cell on one line and let it scroll */
.rpt-blocks th, .rpt-blocks td { white-space: nowrap; }
/* …and compact: each column only as wide as its widest figure, so more of the
   four blocks fit on the screen before it has to scroll */
.tbl.rpt-blocks { inline-size: auto; min-inline-size: 100%; }
/* a block report is wider than the 1440px page column: give it the whole screen
   (breadcrumb row included) rather than scroll beside an empty margin */
.app-main:has(table.rpt-blocks) { --content-max: none; }
.rpt-blocks th, .rpt-blocks td { padding-inline: 6px; }
.rpt-blocks .rpt-grp th[rowspan]:not(.num) { text-align: start; }
.rpt-blocks td:has(> .rpt-lbl) { position: relative; }
.rpt-lbl { position: absolute; inset-inline-start: 6px; inset-block-start: 50%; transform: translateY(-50%); white-space: nowrap; }
.rpt-blocks thead th { letter-spacing: 0; }
.rpt-blocks th.g-start, .rpt-blocks td.g-start { padding-inline-start: var(--sp-3); }
/* ---- report column tools (report-table.js) --------------------------------
   Click a heading to group by it; right-click it to sort and filter. */
.rt-head { cursor: pointer; user-select: none; }
.rt-head:hover { background: var(--c-accent-weak); }
.rt-head:focus-visible { outline: 2px solid var(--c-focus); outline-offset: -2px; }
.rt-head.is-rt-sorted::after { content: " \2191"; color: var(--c-accent); }
.rt-head.is-rt-sorted.is-rt-desc::after { content: " \2193"; }
.rt-head.is-rt-filtered, .rt-head.is-rt-grouped { color: var(--c-accent); box-shadow: inset 0 -2px 0 var(--c-accent); }
.rt-head.is-rt-filtered::before { content: "\25BE "; }
tr.is-rt-out, tr.is-rt-shut { display: none; }
tr.rt-grp td { padding: 0; background: var(--c-surface-2); border-block-start: 1px solid var(--c-line-strong); }
.rt-grp__t {
  display: flex; align-items: center; gap: var(--sp-2); inline-size: 100%; padding: var(--sp-2) var(--sp-3);
  border: 0; background: transparent; color: var(--c-ink); font: inherit; text-align: start; cursor: pointer;
}
.rt-grp__t small { color: var(--c-ink-3); }
.rt-chev { inline-size: 0; block-size: 0; border-inline-start: 5px solid transparent; border-inline-end: 5px solid transparent; border-block-start: 6px solid var(--c-ink-3); transition: transform var(--dur-1) var(--ease); }
tr.rt-grp.is-shut .rt-chev { transform: rotate(-90deg); }
[dir="rtl"] tr.rt-grp.is-shut .rt-chev { transform: rotate(90deg); }
tr.rt-sub td { font-weight: var(--fw-semi); background: var(--c-surface-sunk); border-block-end: 1px solid var(--c-line-strong); }
.rt-strip { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4); border-block-end: 1px solid var(--c-line-soft); }
.rt-strip[hidden] { display: none; }   /* empty, it took a 9px band above the table's head */
.rt-pop {
  position: absolute; z-index: 60; min-inline-size: 220px; max-inline-size: 320px;
  padding: var(--sp-3); background: var(--c-surface); color: var(--c-ink);
  border: 1px solid var(--c-line-strong); border-radius: var(--r-md); box-shadow: 0 8px 28px rgb(0 0 0 / .18);
  font-size: var(--fs-sm);
}
.rt-pop p { margin: 0 0 var(--sp-3); }
.rt-pop hr { border: 0; border-block-start: 1px solid var(--c-line-soft); margin: var(--sp-2) 0; }
.rt-pop__btns { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-block-start: var(--sp-3); }
.rt-menu__h { font-weight: var(--fw-bold); color: var(--c-ink-2); margin-block-end: var(--sp-2); }
.rt-mi {
  display: block; inline-size: 100%; padding: var(--sp-2) var(--sp-2); border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--c-ink); font: inherit; text-align: start; cursor: pointer;
}
.rt-mi:hover:not(:disabled), .rt-mi:focus-visible { background: var(--c-accent-weak); outline: none; }
.rt-mi:disabled { color: var(--c-ink-4); cursor: default; }
.rt-menu__q { inline-size: 100%; margin-block-end: var(--sp-2); }
.rt-menu__list { max-block-size: 220px; overflow: auto; padding: var(--sp-1); border: 1px solid var(--c-line); border-radius: var(--r-sm); }
.rt-chk { display: flex; align-items: center; gap: var(--sp-2); padding: 2px var(--sp-1); white-space: nowrap; cursor: pointer; }
.rt-chk--all { border-block-end: 1px solid var(--c-line-soft); margin-block-end: var(--sp-1); }
.rt-help { color: var(--c-ink-3); font-size: var(--fs-xs); }
.rt-bulk__t { inline-size: 100%; min-block-size: 140px; font-family: var(--font-num); }
@media print { .rt-strip, .rt-pop { display: none !important; } }
.rpt-unit { display: block; font-size: var(--fs-micro); font-weight: var(--fw-regular); letter-spacing: 0; text-transform: none; color: var(--c-ink-4); }
/* a row that opens its movements: selectable, and shows that it is */
.tbl tr[data-open] { cursor: pointer; }
.tbl tr[data-open]:focus { outline: none; }
.tbl tr.is-selected > td { background: var(--c-accent-weak) !important; }
.tbl tr.is-selected > td:first-child { box-shadow: inset 3px 0 0 var(--c-accent); }
[dir="rtl"] .tbl tr.is-selected > td:first-child { box-shadow: inset -3px 0 0 var(--c-accent); }
/* a report row: one bar at the row's start, not one on every cell (a later,
   general .tbl rule draws it on each td) */
.tbl tr[data-open].is-selected > td { box-shadow: none; }
.tbl tr[data-open].is-selected > td:first-child { box-shadow: inset 3px 0 0 var(--c-accent); }
[dir="rtl"] .tbl tr[data-open].is-selected > td:first-child { box-shadow: inset -3px 0 0 var(--c-accent); }
.tbl--roomy   th, .tbl--roomy   td { padding-block: var(--sp-4); }
.tbl--roomy   td { min-block-size: var(--hit-touch); }
.tbl--bordered th, .tbl--bordered td { border-inline-end: 1px solid var(--c-line-soft); }
.tbl--sticky thead th { position: sticky; inset-block-start: 0; z-index: 2; }
.tbl--sticky-foot tfoot tr { position: sticky; inset-block-end: 0; z-index: 2; }
.tbl--sticky-foot tfoot td, .tbl--sticky-foot tfoot th { background: var(--c-surface-3); }

.th-sort {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
  text-transform: inherit; letter-spacing: inherit; cursor: pointer;
}
/* Up is up. The sort arrow mirrors nothing. */
.th-sort::after { content: "\2195"; opacity: .4; font-size: var(--fs-xs); }
.is-sorted-asc  .th-sort::after { content: "\2191"; opacity: 1; color: var(--c-accent); }
.is-sorted-desc .th-sort::after { content: "\2193"; opacity: 1; color: var(--c-accent); }
.is-sorted-asc, .is-sorted-desc { background: var(--c-surface-3); }

/* THE numeric cell. Everything numeric in the product ends up here. */
.num, .tbl td.num, .tbl th.num {
  font-family: var(--font-num);
  font-variant-numeric: var(--num-feat);
  text-align: end; direction: ltr; unicode-bidi: isolate;
  white-space: nowrap;
}
.num--bhd { font-weight: var(--fw-medium); }
.num--g   { color: var(--c-ink-2); }
.num--neg { color: var(--c-danger); }
/* A true minus sign, never a hyphen; parentheses are a reporting option. */
.num--neg::before { content: "\2212"; }
.num--paren::before { content: "("; }
.num--paren::after  { content: ")"; }
.num--pos { color: var(--c-success); }
/* A zero in a DATA column is an em-dash; a zero in a TOTAL row is 0.000. */
.nil { color: var(--c-ink-4); }
.nil::after { content: "\2014"; }
.tbl__total .nil::after { content: none; }
/* A figure that is not yet known is not zero and must not read as zero. */
.unknown { color: var(--c-ink-4); font-style: italic; }
.unknown::after { content: "\2014\2014"; }

.tbl__total > td, .tbl__total > th {
  background: var(--c-surface-3);
  border-block-start: 2px solid var(--c-line-strong);
  font-weight: var(--fw-bold);
}
.tbl__subtotal > td, .tbl__subtotal > th { background: var(--c-surface-2); font-weight: var(--fw-semi); }
.tbl__group > th {
  background: var(--c-surface-3); color: var(--c-ink-2);
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
}
/* The report catalogue's group heading carries the question the section answers,
   inline after its name, out of the caps treatment the heading itself wears. */
.tbl__group__ask {
  margin-inline-start: var(--sp-3);
  font-weight: var(--fw-regular); letter-spacing: 0; text-transform: none;
  color: var(--c-ink-3);
}
/* A heading is not a row of data, so it must not light up under the cursor. */
.tbl tbody tr.tbl__group:hover > th { background: var(--c-surface-3); }
/* Row states. Colour is NEVER alone: pair every one with a pill or a word. */
.tbl tr.is-selected > td { background: var(--c-accent-weak); box-shadow: inset 3px 0 0 var(--c-accent); }
[dir="rtl"] .tbl tr.is-selected > td { box-shadow: inset -3px 0 0 var(--c-accent); }
.tbl tr.is-danger > td { background: var(--c-danger-weak); }
.tbl tr.is-warn   > td { background: var(--c-warn-weak); }
.tbl tr.is-void   > td { color: var(--c-ink-4); text-decoration: line-through; text-decoration-color: var(--c-ink-faint); }
.tbl__actions { inline-size: 1%; white-space: nowrap; text-align: end; }
.tbl__actions .btn { opacity: 0; }
.tbl tbody tr:hover .tbl__actions .btn,
.tbl__actions .btn:focus-visible { opacity: 1; }
/* Keyboard users and touch users never hover. */
@media (hover: none) { .tbl__actions .btn { opacity: 1; } }

/* Below 900px a wide table becomes a card list. */
@media (max-width: 900px) {
  .tbl--cards thead { display: none; }
  .tbl--cards tbody tr {
    display: block; padding: var(--sp-3);
    border: 1px solid var(--c-line); border-radius: var(--r-md);
    margin-block-end: var(--sp-3); background: var(--c-surface);
  }
  .tbl--cards tbody td { display: flex; justify-content: space-between; gap: var(--sp-4); border: 0; padding: var(--sp-1) 0; }
  .tbl--cards tbody td::before { content: attr(data-label); color: var(--c-ink-3); font-size: var(--fs-xs); }
}

/* ==========================================================================
   17  THE DUAL-UNIT AMOUNT  —  the product's signature
   BHD to three decimals beside grams to three decimals. This is the one
   irreplaceable idea in Jewel ERP: every figure in a jewellery business has
   two units, and showing only one is the bug the whole system exists to fix.

   It is typeset, not coloured. The BHD figure is the voice; the gram twin is
   a quieter second line separated by a hairline, at 0.82em, in the same
   tabular monospace so the two decimal points stack. The pair is NEVER
   distinguished by colour alone, so it survives a black-and-white print and
   a colour-blind reader, and the hairline survives a 1-bit thermal receipt.

   Markup:
     <span class="amt">
       <span class="amt__label">Net due</span>
       <span class="amt__bhd">1,942.420<span class="amt__unit">BHD</span></span>
       <span class="amt__g">   68.500<span class="amt__unit">g</span></span>
     </span>
   ========================================================================== */
.amt {
  display: inline-flex; flex-direction: column; align-items: flex-end;
  gap: 1px; min-inline-size: 0;
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  direction: ltr; unicode-bidi: isolate; line-height: var(--lh-tight);
}
.amt__label {
  font-family: var(--font-ui); font-size: var(--fs-micro);
  font-weight: var(--fw-semi); text-transform: uppercase;
  letter-spacing: var(--tracking-caps); color: var(--c-ink-3);
  margin-block-end: var(--sp-1);
}
.amt__bhd {
  font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--c-ink);
  white-space: nowrap; letter-spacing: var(--tracking-tight);
}
.amt__unit {
  font-family: var(--font-ui); font-size: .62em; font-weight: var(--fw-medium);
  color: var(--c-ink-3); margin-inline-start: .35em;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
/* The gram twin. Typographically distinguished, not coloured. */
.amt__g {
  font-size: .82em; color: var(--c-ink-2); white-space: nowrap;
  padding-block-start: 2px; border-block-start: 1px solid var(--c-line);
  min-inline-size: 100%; text-align: end;
}
.amt__g .amt__unit { color: var(--c-ink-3); }
/* A purity qualifier that belongs to the gram, not to the money. */
.amt__purity { font-family: var(--font-ui); font-size: .62em; color: var(--c-ink-3); margin-inline-start: .35em; }

/* Inline: the two units side by side, divided by a rule. Used in a dense
   table cell where a second line would double the row height. */
.amt--inline { flex-direction: row; align-items: baseline; gap: var(--sp-3); }
.amt--inline .amt__g {
  border-block-start: 0; border-inline-start: 1px solid var(--c-line);
  padding: 0; padding-inline-start: var(--sp-3);
  min-inline-size: 0; margin: 0;
}
.amt--start { align-items: flex-start; }
.amt--start .amt__g { text-align: start; }

/* Sizes. --cell is the table default; --hero is the one number on a
   dashboard, the owner's metal position, the shift's expected cash. */
.amt--sm   .amt__bhd { font-size: var(--fs-sm); font-weight: var(--fw-medium); }
.amt--cell .amt__bhd { font-size: var(--d-fs-table); font-weight: var(--fw-medium); }
.amt--cell .amt__g   { font-size: .85em; }
.amt--lg   .amt__bhd { font-size: var(--fs-xl); }
.amt--hero {
  gap: var(--sp-2);
  padding: var(--sp-4) 0;
}
.amt--hero .amt__bhd {
  font-size: var(--fs-hero); font-weight: var(--fw-bold);
  letter-spacing: -.02em; line-height: 1;
}
.amt--hero .amt__g {
  font-size: var(--fs-lg); font-weight: var(--fw-medium);
  padding-block-start: var(--sp-3); border-block-start-width: 1px;
  border-block-start-color: var(--c-line-strong);
}
.amt--hero .amt__label { font-size: var(--fs-xs); }
.amt--mega .amt__bhd { font-size: var(--fs-mega); }

/* Sign and state. The BHD figure carries the sign; the gram twin carries it
   independently, because a credit note can be negative in money and
   positive in metal. That is not a bug, and the theme must be able to show
   it without contradiction. */
.amt--neg    .amt__bhd { color: var(--c-danger); }
.amt--neg    .amt__bhd::before { content: "\2212"; }
.amt--pos    .amt__bhd,
.amt--credit .amt__bhd { color: var(--c-success); }
.amt__g--neg { color: var(--c-danger); }
.amt__g--neg::before { content: "\2212"; }
.amt--muted  .amt__bhd, .amt--muted .amt__g { color: var(--c-ink-3); }
/* The gram twin may be tinted with the ONE metal tone when the metal
   dimension is the subject of the screen (metal position, unfixed grams,
   the gram-exposure report). Off by default: it is a data colour, not
   decoration, and it must be switched on deliberately. */
.amt--metal .amt__g { color: var(--c-metal); border-block-start-color: var(--c-metal-line); }

/* The [M] badge that marks a gram-carrying account in the chart of accounts. */
.metal-badge {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 16px; block-size: 16px; flex: 0 0 auto;
  border: 1px solid var(--c-metal-line); border-radius: var(--r-xs);
  background: var(--c-metal-weak); color: var(--c-metal);
  font-family: var(--font-num); font-size: 10px; font-weight: var(--fw-bold);
  line-height: 1; direction: ltr; unicode-bidi: isolate;
}
.metal-badge::after { content: "M"; }

/* A rate quotation: 28.412 / g pure, with its as-of stamp. */
.rate-quote { display: inline-flex; align-items: baseline; gap: var(--sp-2); font-family: var(--font-num); font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate; }
.rate-quote__value { font-weight: var(--fw-semi); }
.rate-quote__as-of { font-family: var(--font-ui); font-size: var(--fs-xs); color: var(--c-ink-3); }
/* Fineness is six decimals and is never rounded in display. */
.fineness { font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-size: .9em; color: var(--c-ink-2); direction: ltr; unicode-bidi: isolate; }
/* Karat / purity chip. */
.karat {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 0 var(--sp-2); border-radius: var(--r-xs);
  background: var(--c-surface-3); color: var(--c-ink-2);
  font-family: var(--font-num); font-size: var(--fs-xs); font-weight: var(--fw-semi);
  direction: ltr; unicode-bidi: isolate;
}
.karat--metal { background: var(--c-metal-weak); color: var(--c-metal); border: 1px solid var(--c-metal-line); }

/* ==========================================================================
   18  KV / TIMELINE / STAT TILES
   ========================================================================== */
.kv { display: grid; grid-template-columns: minmax(120px, 34%) 1fr; gap: 0; margin: 0; font-size: var(--fs-sm); }
.kv--wide  { grid-template-columns: minmax(160px, 45%) 1fr; }
.kv--stack { grid-template-columns: 1fr; }
.kv > dt {
  padding: var(--sp-3) var(--sp-4) var(--sp-3) 0;
  color: var(--c-ink-3); border-block-end: 1px solid var(--c-line-soft);
}
.kv > dd {
  margin: 0; padding: var(--sp-3) 0;
  border-block-end: 1px solid var(--c-line-soft); min-inline-size: 0;
}
[dir="rtl"] .kv > dt { padding: var(--sp-3) 0 var(--sp-3) var(--sp-4); }
.kv > dt:last-of-type, .kv > dd:last-of-type { border-block-end: 0; }
.kv--stack > dt { border: 0; padding-block-end: 0; }
.kv--stack > dd { padding-block-start: var(--sp-1); }
.kv dd .num, .kv dd .amt { }

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline__item {
  position: relative; padding-inline-start: var(--sp-6); padding-block-end: var(--sp-5);
  border-inline-start: 1px solid var(--c-line);
  margin-inline-start: 5px;
}
.timeline__item:last-child { border-inline-start-color: transparent; padding-block-end: 0; }
.timeline__dot {
  position: absolute; inset-inline-start: -6px; inset-block-start: 2px;
  inline-size: 11px; block-size: 11px; border-radius: 50%;
  background: var(--c-surface); border: 2px solid var(--c-line-strong);
}
.timeline__dot--done  { background: var(--c-success); border-color: var(--c-success); }
.timeline__dot--now   { background: var(--c-accent);  border-color: var(--c-accent); box-shadow: 0 0 0 3px var(--c-accent-weak); }
.timeline__dot--issue { background: var(--c-danger);  border-color: var(--c-danger); }
.timeline__head  { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: baseline; }
.timeline__title { font-weight: var(--fw-semi); font-size: var(--fs-sm); }
.timeline__meta  { font-size: var(--fs-xs); color: var(--c-ink-3); margin-inline-start: auto; font-variant-numeric: var(--num-feat); }
.timeline__body  { font-size: var(--fs-sm); color: var(--c-ink-2); }
.diff { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); font-family: var(--font-num); font-size: var(--fs-xs); margin-block-start: var(--sp-2); }
.diff__before { background: var(--c-danger-weak);  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-xs); }
.diff__after  { background: var(--c-success-weak); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-xs); }

/* Stat tiles. Every tile links to the screen that explains it. */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-4); }
.tile {
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--d-card-p);
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-radius: var(--r-lg); box-shadow: var(--sh-1);
  color: inherit; text-decoration: none; min-inline-size: 0;
}
a.tile:hover { border-color: var(--c-accent-line); box-shadow: var(--sh-2); text-decoration: none; }
.tile__label { font-size: var(--fs-xs); color: var(--c-ink-3); font-weight: var(--fw-semi); letter-spacing: var(--tracking-caps); text-transform: uppercase; }
.tile__value {
  font-family: var(--font-num); font-size: var(--fs-2xl); font-weight: var(--fw-bold);
  line-height: var(--lh-tight); letter-spacing: var(--tracking-tight);
  font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate; text-align: start;
}
.tile__sub   { font-size: var(--fs-xs); color: var(--c-ink-3); }
.tile__delta { font-family: var(--font-num); font-size: var(--fs-xs); font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate; }
.tile__delta--up   { color: var(--c-success); }
.tile__delta--up::before   { content: "\25B2\00A0"; }
.tile__delta--down { color: var(--c-danger); }
.tile__delta--down::before { content: "\25BC\00A0"; }
.tile__delta--flat { color: var(--c-ink-3); }
.tile__delta--flat::before { content: "\2192\00A0"; }
.tile--accent  { border-inline-start: 3px solid var(--c-accent); }
.tile--danger  { border-inline-start: 3px solid var(--c-danger); }
.tile--warn    { border-inline-start: 3px solid var(--c-warn); }
.tile--success { border-inline-start: 3px solid var(--c-success); }
.tile--metal   { border-inline-start: 3px solid var(--c-metal); }
.tile--navy    { background: var(--c-surface-inv); color: var(--c-ink-inv); border-color: transparent; }
/* --- THE ONE EXCEPTION TO THE METAL RULE (README §2.4, exception E1) ------
       The rule is that --c-metal is a DATA colour and is barred from chrome.
       It survives everywhere the product has chrome for the metal figure to
       sit in — a rail, a top bar, a table header, a card among cards.

       It does not survive on the owner's phone. There, RB-02's hero IS the
       metal position: one figure, 390px wide, nothing else above the fold.
       A tile with a 3px inline-start rule reads as decoration at that size,
       and the alternative — the navy hero — makes the product's most
       metal-specific number look like every other number in the product.

       So: ONE named carrier, and it is the class you must type to take the
       exception. .tile--metal-hero may fill with --c-metal-weak and edge
       with --c-metal-line. Conditions, all four:
         a) one per screen, and only where the metal figure is the subject;
         b) it is NOT interactive — no link, no button, no focus ring, and
            no metal border on anything that is;
         c) it carries the word as well as the tone ("Gold 916"), so the
            colour is never the signal;
         d) the surrounding chrome — tab bar, top bar, buttons — stays navy
            and blue. The moment a second metal-toned thing appears on the
            same screen, this is a brand accent and the exception is void.
       Everything else in §2.4 stands unchanged. */
.tile--metal-hero {
  background: var(--c-metal-weak);
  border: 1px solid var(--c-metal-line);
  border-inline-start-width: 3px; border-inline-start-color: var(--c-metal);
}
.tile--metal-hero .tile__label { color: var(--c-metal); }
.tile--metal-hero .tile__value, .tile--metal-hero .amt__g { color: var(--c-metal); }
.tile--metal-hero .tile__sub   { color: var(--c-ink-2); }
/* Condition (b), enforced rather than asked for: if the hero is ever made
   interactive the tone is dropped and it falls back to the ordinary tile. */
a.tile--metal-hero, button.tile--metal-hero, .tile--metal-hero[href], .tile--metal-hero[role="button"] {
  background: var(--c-surface); border-color: var(--c-line);
  border-inline-start-color: var(--c-metal);
}
.tile--navy .tile__label, .tile--navy .tile__sub { color: var(--c-ink-inv-3); }
.tile .amt { align-items: flex-start; }

/* A 30-day sparkline, drawn as inline SVG in the page. The theme only sets
   its colours and size so every sparkline in the product matches. */
.spark { display: block; inline-size: 100%; block-size: 34px; overflow: visible; }
.spark path { fill: none; stroke: var(--c-accent); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.spark .spark__area { fill: var(--c-accent-weak); stroke: none; }
/* The stroke must not scale with the box. A spark is drawn in a 100-wide viewBox
   stretched across whatever width it is given, so without this the dash pattern
   stretches with it and a 2-2 dash becomes a row of long bars that reads as a
   second, broken data line rather than as the axis. */
.spark .spark__zero { stroke: var(--c-line-strong); stroke-width: 1; stroke-dasharray: 2 2;
                      vector-effect: non-scaling-stroke; }
.spark--metal path { stroke: var(--c-metal); }
.spark--danger path { stroke: var(--c-danger); }
/* Charts: a time axis runs left-to-right in BOTH directions, because a
   falling gold price must not look like a rising one (§11.2). */
.chart, .spark { direction: ltr; }

/* A simple horizontal meter (allocation, margin split, day-close readiness) */
.meter { display: flex; align-items: center; gap: var(--sp-3); }
.meter__bar { flex: 1 1 auto; block-size: 6px; background: var(--c-surface-3); border-radius: var(--r-pill); overflow: hidden; }
.meter__bar > span { display: block; block-size: 100%; inline-size: var(--pct, 0%); background: var(--c-accent); }
.meter--full > .meter__bar > span { background: var(--c-success); }
.meter--over > .meter__bar > span { background: var(--c-danger); }
.meter--metal > .meter__bar > span { background: var(--c-metal); }
.meter__val { font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-size: var(--fs-xs); color: var(--c-ink-3); direction: ltr; unicode-bidi: isolate; }

/* A SEGMENTED meter: two or three spans sharing one track, each sized by its
   own --pct. Two callers asked for it — the allocation meter (how much of a
   lot is committed, reserved, free) and the owner's metal split (owned /
   held on behalf of a customer / owed to a vendor) — and those are the same
   shape, so they are one component.

   The segments run in the INLINE direction, so in Arabic the first segment
   starts on the right without a single extra rule. Three is the cap: a
   fourth segment on a 6px bar is a stacked bar chart pretending to be a
   meter, and it belongs in .chart.

   Colour is never alone: a .meter--split must be accompanied by .meter__key,
   which repeats each segment's word and figure. The swatch is a decoration
   of a label that is already there, so it is not a colour-only signal. */
.meter--split > .meter__bar { display: flex; block-size: 8px; }
.meter--split > .meter__bar > span,
.meter__seg { display: block; block-size: 100%; inline-size: var(--pct, 0%); flex: 0 0 auto; }
/* A hairline in the SURFACE colour keeps two adjacent tones apart without
   introducing a fourth colour, and disappears when a segment is 0%. */
.meter--split > .meter__bar > span + span { box-shadow: inset 1px 0 0 0 var(--c-surface); }
[dir="rtl"] .meter--split > .meter__bar > span + span { box-shadow: inset -1px 0 0 0 var(--c-surface); }
/* Positional defaults, so a two-span meter needs no modifier at all. */
.meter--split > .meter__bar > span:nth-child(1) { background: var(--c-accent); }
.meter--split > .meter__bar > span:nth-child(2) { background: var(--c-metal); }
.meter--split > .meter__bar > span:nth-child(3) { background: var(--c-surface-3); }
/* The legend swatch is declared BEFORE the segment colours and at the same
   specificity, so a swatch carrying a segment modifier takes that colour. */
.meter__sw {
  inline-size: 8px; block-size: 8px; border-radius: var(--r-xs);
  align-self: center; flex: 0 0 auto; background: var(--c-surface-3);
}
/* Named segments, for when the order is not the meaning. They apply to a bar
   segment and to its swatch in the key, which is the point of the naming. */
.meter__seg--owned  { background: var(--c-accent); }
.meter__seg--held   { background: var(--c-metal); }
.meter__seg--owed   { background: var(--c-warn); }
.meter__seg--free   { background: var(--c-surface-3); }
.meter__seg--over   { background: var(--c-danger); }
.meter__seg--done   { background: var(--c-success); }
/* The legend that makes the colour legal. */
.meter__key { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
              margin: var(--sp-2) 0 0; padding: 0; list-style: none; }
.meter__key > li, .meter__key__item {
  display: inline-flex; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-xs); color: var(--c-ink-3);
}
.meter__key .num, .meter__key .meter__val { color: var(--c-ink-2); }
.meter--split.meter--stack { display: block; }
/* A bar whose segments are named rather than positional.
   `--split` gives its first three spans fixed colours so that a two-segment
   meter needs no modifier, which is right for the meters that have a fixed
   shape and wrong for one built from however many claims a shop happens to
   have: the positional rules out-specify .meter__seg--* (0,2,2 against 0,1,0)
   and a fourth span gets no colour at all. `--claims` is the same flex track
   with the positional defaults left off, so the modifier on each segment is
   what decides its colour, and the count can vary. */
/* --------------------------------------------------------------------------
   DUES STRIP. The figures an action list was derived from, above the list.
   Deliberately not a table: it carries no arithmetic the reader is invited to
   check, only the magnitudes behind the advice. Its total is stated because an
   accountant expects one, and the panel foot carries the rounding note that a
   total of rounded parts requires.
   ========================================================================== */
.rpt-dues {
  display: grid; gap: var(--sp-2) var(--sp-6);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  background: var(--c-surface-2); border-block-end: 1px solid var(--c-line);
}
.rpt-dues__i { display: flex; flex-direction: column; gap: 1px; min-inline-size: 0; }
.rpt-dues__l { font-size: var(--fs-xs); color: var(--c-ink-3); }
.rpt-dues__v {
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--c-ink);
  direction: ltr; unicode-bidi: isolate; white-space: nowrap;
}
/* The total is the one figure here that is a sum, so it is the one that is
   weighted. A rule above it would imply the column adds down, which it does
   not — the items wrap into however many columns fit. */
.rpt-dues__i.is-total .rpt-dues__l { color: var(--c-ink-2); font-weight: var(--fw-semi); }
.rpt-dues__i.is-total .rpt-dues__v { color: var(--c-ink); font-weight: var(--fw-bold); }

.meter--claims > .meter__bar { display: flex; block-size: 8px; }
/* `.meter__bar > span` sets the accent at (0,2,1) so that a plain one-segment
   meter needs no class at all. A named segment is (0,1,0) and loses to it, which
   is why `--split` restates its colours positionally. These restate them by NAME,
   at (0,3,1), which is the same trick with the meaning kept. */
.meter--claims > .meter__bar > span.meter__seg--owned { background: var(--c-accent); }
.meter--claims > .meter__bar > span.meter__seg--held  { background: var(--c-metal); }
.meter--claims > .meter__bar > span.meter__seg--owed  { background: var(--c-warn); }
.meter--claims > .meter__bar > span.meter__seg--free  { background: var(--c-surface-3); }
.meter--claims > .meter__bar > span.meter__seg--over  { background: var(--c-danger); }
.meter--claims > .meter__bar > span.meter__seg--done  { background: var(--c-success); }
/* Where the money runs out.
   When the claims on a sum exceed the sum, the honest bar is the CLAIMS, with a
   mark showing how far the cash reaches — everything past it is not covered.
   Drawing the shortfall as one more segment instead would make the segments sum
   to more than the track and push the last of them off the end. */
.meter--claims > .meter__bar { position: relative; }
/* Selected through the bar, not on its own: `.meter__bar > span` sets both the
   segment width and the accent at (0,2,1), so a bare `.meter__mark` would be
   painted accent-blue and given `inline-size: var(--pct, 0%)` — zero. */
.meter--claims > .meter__bar > .meter__mark {
  position: absolute; inset-block: -3px; inset-inline-start: var(--at, 100%);
  inline-size: 2px; background: var(--c-danger); border-radius: var(--r-xs);
}
.meter--claims > .meter__bar > span + span { box-shadow: inset 1px 0 0 0 var(--c-surface); }
[dir="rtl"] .meter--claims > .meter__bar > span + span { box-shadow: inset -1px 0 0 0 var(--c-surface); }

/* --------------------------------------------------------------------------
   LISTS. Nothing in the theme styled a bare <ul>, so every sheet invented
   its own. This is the one. The reset is on .list, not on ul, because a
   <ul> inside .prose or a print sheet still wants browser defaults.
   Markers sit in a logical indent, so RTL mirrors for free.
   -------------------------------------------------------------------------- */
.list { margin: 0; padding: 0; list-style: none; }
.list > li { min-inline-size: 0; }
.list > li + li { margin-block-start: var(--sp-3); }
.list--tight > li + li { margin-block-start: var(--sp-1); }
.list--loose > li + li { margin-block-start: var(--sp-4); }
.list--sm { font-size: var(--fs-sm); color: var(--c-ink-2); }
.list--muted { color: var(--c-ink-3); }
/* Marked. list-style-position is OUTSIDE so a wrapped second line aligns
   with the first, and the indent is padding-inline-start so it mirrors. */
.list--bullet, .list--num { padding-inline-start: var(--sp-6); }
.list--bullet { list-style: disc outside; }
.list--num    { list-style: decimal outside; }
.list--bullet > li, .list--num > li { list-style: inherit; }
.list--num > li::marker { font-family: var(--font-num); font-variant-numeric: var(--num-feat); }
.list--bullet > li::marker, .list--num > li::marker { color: var(--c-ink-4); }
/* Ticked. The tick is a CHARACTER first and a colour second, so the list
   still reads in forced colours and in a 1-bit thermal print. */
.list--check > li { position: relative; padding-inline-start: var(--sp-6); }
.list--check > li::before {
  content: "\2713"; position: absolute; inset-inline-start: 0; inset-block-start: 0;
  color: var(--c-success); font-weight: var(--fw-bold); line-height: var(--lh-base);
}
.list--check > li.is-no::before  { content: "\2717"; color: var(--c-danger); }
.list--check > li.is-todo::before{ content: "\25CB"; color: var(--c-ink-4); }
/* Rows. A list that behaves like a one-column table: density-aware, ruled,
   and the correct markup for "a list of records" that is not tabular data. */
.list--rows > li {
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: var(--d-row-h); padding-inline: var(--d-cell-px);
  border-block-end: 1px solid var(--c-line);
}
.list--rows > li + li { margin-block-start: 0; }
.list--rows > li:last-child { border-block-end: 0; }
.list--rows > li > .num { margin-inline-start: auto; }
/* Inline. A run of short facts: outlet · till · shift. */
.list--inline { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); }
.list--inline > li + li { margin-block-start: 0; }
.list--inline > li + li::before { content: "\00B7"; color: var(--c-ink-4); margin-inline-end: var(--sp-4); }

/* ==========================================================================
   19  PILLS & BADGES
   Colour is never alone: every pill carries a glyph AND a word.
   ========================================================================== */
.pill {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 1px var(--sp-3); border-radius: var(--r-pill);
  border: 1px solid var(--c-line); background: var(--c-surface-2);
  color: var(--c-ink-2); font-size: var(--fs-xs); font-weight: var(--fw-medium);
  white-space: nowrap; line-height: 1.6;
}
.pill::before { font-size: 10px; line-height: 1; }
/* A screen that has already drawn the state's mark as a real icon gets ONE
   mark, not two. The rule "colour is never alone" is satisfied either way,
   because the pill always carries its word as well. */
.pill:has(> .ico)::before, .pill:has(> svg)::before { content: none; }
.pill--sm { font-size: var(--fs-micro); padding-inline: var(--sp-2); }
.pill--dot::before { content: "\25CF"; }
/* lifecycle */
.pill--draft::before    { content: "\270E"; }
.pill--pending          { background: var(--c-warn-weak); border-color: var(--c-warn-line); color: var(--c-warn); }
.pill--pending::before  { content: "\231B"; }
.pill--open             { background: var(--c-accent-weak); border-color: var(--c-accent-line); color: var(--c-accent); }
.pill--open::before     { content: "\25CB"; }
.pill--active           { background: var(--c-success-weak); border-color: var(--c-success-line); color: var(--c-success); }
.pill--active::before   { content: "\25CF"; }
.pill--closed::before   { content: "\25CF"; }
.pill--inactive         { color: var(--c-ink-3); }
.pill--inactive::before { content: "\25CB"; }
/* positive */
.pill--posted, .pill--paid, .pill--approved, .pill--verified,
.pill--delivered, .pill--synced, .pill--matched, .pill--reconciled {
  background: var(--c-success-weak); border-color: var(--c-success-line); color: var(--c-success);
}
.pill--posted::before, .pill--paid::before, .pill--approved::before,
.pill--verified::before, .pill--delivered::before, .pill--matched::before,
.pill--reconciled::before { content: "\2713"; }
.pill--synced::before { content: "\21BB"; }
/* attention */
.pill--partial, .pill--queued, .pill--transit, .pill--hold,
.pill--expiring, .pill--stale, .pill--unfixed, .pill--unclaimed {
  background: var(--c-warn-weak); border-color: var(--c-warn-line); color: var(--c-warn);
}
.pill--partial::before  { content: "\25D0"; }
.pill--queued::before   { content: "\2191"; }
.pill--transit::before  { content: "\2192"; }
.pill--hold::before     { content: "\23F8"; }
.pill--expiring::before { content: "\231B"; }
.pill--stale::before    { content: "\26A0"; }
.pill--unfixed::before  { content: "\223F"; }
.pill--unclaimed::before{ content: "\231B"; }
/* negative */
.pill--overdue, .pill--failed, .pill--rejected, .pill--blocked, .pill--breach {
  background: var(--c-danger-weak); border-color: var(--c-danger-line); color: var(--c-danger);
}
.pill--overdue::before  { content: "\26A0"; }
.pill--failed::before   { content: "\2717"; }
.pill--rejected::before { content: "\2717"; }
.pill--blocked::before  { content: "\26D4"; }
.pill--breach::before   { content: "\26A0"; }
.pill--reversed         { background: var(--c-surface-3); color: var(--c-ink-2); border-color: var(--c-line-strong); }
.pill--reversed::before { content: "\21BA"; }
.pill--void             { color: var(--c-ink-3); text-decoration: line-through; }
.pill--void::before     { content: "\2298"; text-decoration: none; }
/* informative */
.pill--new    { background: var(--c-accent-weak); border-color: var(--c-accent-line); color: var(--c-accent); font-weight: var(--fw-semi); }
.pill--new::before { content: "\002B"; }
.pill--pro, .pill--ent, .pill--tier {
  background: var(--c-ink); color: var(--c-ink-inv); border-color: var(--c-ink);
  font-size: var(--fs-micro); font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  direction: ltr; unicode-bidi: isolate;
}
.pill--ent::before { content: "\1F512"; font-size: 8px; }
.pill--offline { background: var(--c-warn-weak); border-color: var(--c-warn-line); color: var(--c-warn); }
.pill--offline::before { content: "\26A1"; }
/* .pill--stale already existed with no counterpart, which is why two sheets
   reached for .pill--fresh and .pill--missing and got nothing. They are
   DEFINED rather than renamed away, because both are real domain states with
   no equivalent in the existing vocabulary: "fresh" is the rate-backed
   opposite of "stale" (a price locked against a current board), and a stock
   line that is MISSING at a sweep is not a job that "failed". The two
   families now match: .rate-pill--{fresh,stale,missing} for the top bar
   control, .pill--{fresh,stale,missing} for the same three facts in data. */
.pill--fresh   { background: var(--c-success-weak); border-color: var(--c-success-line); color: var(--c-success); }
.pill--fresh::before   { content: "\2713"; }
.pill--missing { background: var(--c-danger-weak); border-color: var(--c-danger-line); color: var(--c-danger); }
.pill--missing::before { content: "\2298"; }
.pill--metal { background: var(--c-metal-weak); border-color: var(--c-metal-line); color: var(--c-metal); }
.pill--navy  { background: var(--c-surface-inv); border-color: var(--c-surface-inv); color: var(--c-ink-inv); }
.kyc-chip__date { font-family: var(--font-num); font-variant-numeric: var(--num-feat); opacity: .85; direction: ltr; unicode-bidi: isolate; }

/* A count badge that is not a pill: rail, tab, bell, tab bar. */
.badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-inline-size: 18px; block-size: 18px; padding-inline: 5px;
  border-radius: var(--r-pill); background: var(--c-surface-3);
  color: var(--c-ink-2); font-size: var(--fs-micro); font-weight: var(--fw-bold);
  font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate;
}
.badge--danger  { background: var(--c-danger);  color: #fff; }
.badge--warn    { background: var(--c-warn);    color: #fff; }
.badge--success { background: var(--c-success); color: #fff; }
.badge--accent  { background: var(--c-accent);  color: var(--c-accent-ink); }

/* ==========================================================================
   20  MODALS, TOASTS, ALERTS
   ========================================================================== */
.modal {
  inline-size: min(560px, 100%); max-block-size: 86vh;
  display: flex; flex-direction: column;
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-radius: var(--r-xl); box-shadow: var(--sh-4); overflow: hidden;
}
.modal--sm { inline-size: min(400px, 100%); }
.modal--lg { inline-size: min(880px, 100%); }
.modal--xl { inline-size: min(1120px, 100%); }
.modal__head {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-block-end: 1px solid var(--c-line); background: var(--c-surface-2);
  flex: 0 0 auto;
}
.modal__head h3 { font-size: var(--fs-md); margin-inline-end: auto; min-inline-size: 0; }
.modal__body { padding: var(--sp-5); overflow: auto; flex: 1 1 auto; }
.modal__foot {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-block-start: 1px solid var(--c-line); background: var(--c-surface-2);
  flex: 0 0 auto;
}
.modal__foot .grow { text-align: start; }

/* There is no DELETE in this product. Destructive means REVERSE, and a
   reverse always states its consequences before it is confirmed. */
.modal--danger { border-color: var(--c-danger-line); }
.modal--danger .modal__head { background: var(--c-danger-weak); border-block-end-color: var(--c-danger-line); }
.modal--danger .modal__head h3 { color: var(--c-danger); }
.consequence {
  border: 1px solid var(--c-danger-line); background: var(--c-danger-weak);
  border-radius: var(--r-md); padding: var(--sp-4); margin-block-end: var(--sp-4);
  font-size: var(--fs-sm);
}
.consequence ul { margin: var(--sp-2) 0 0; padding-inline-start: var(--sp-6); }
.confirm-type { font-family: var(--font-num); direction: ltr; unicode-bidi: isolate; }

/* Step-up / manager override (IA-11). The accent frame says "authorise". */
.modal--stepup { inline-size: min(440px, 100%); border-color: var(--c-accent-line); }
.modal--stepup .modal__head { background: var(--c-accent-weak); border-block-end-color: var(--c-accent-line); }
.stepup__subject {
  background: var(--c-surface-2); border: 1px solid var(--c-line);
  border-radius: var(--r-md); padding: var(--sp-4); margin-block-end: var(--sp-4);
}
.stepup__action-key { font-family: var(--font-num); font-size: var(--fs-xs); color: var(--c-ink-3); direction: ltr; unicode-bidi: isolate; }
.stepup__modes { display: flex; gap: var(--sp-2); margin-block-end: var(--sp-4); }
.stepup__grant {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--c-success-weak); border: 1px solid var(--c-success-line);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
  color: var(--c-success); font-size: var(--fs-sm); font-weight: var(--fw-medium);
}
.stepup__ttl { font-family: var(--font-num); font-variant-numeric: var(--num-feat); margin-inline-start: auto; direction: ltr; unicode-bidi: isolate; }

/* Bottom sheet — the tablet and handheld form of any modal. */
.modal--sheet {
  inline-size: 100%; max-inline-size: none;
  border-start-start-radius: var(--r-xl); border-start-end-radius: var(--r-xl);
  border-end-start-radius: 0; border-end-end-radius: 0;
  max-block-size: 90vh;
}
.modal--sheet .modal__head::before {
  content: ""; position: absolute; inset-block-start: 6px; inset-inline: 0;
  margin-inline: auto; inline-size: 36px; block-size: 4px;
  border-radius: var(--r-pill); background: var(--c-line-strong);
}
.modal--sheet .modal__head { position: relative; padding-block-start: var(--sp-5); }

/* --- Toasts. An undo belongs here, not in a confirm dialog. ----------- */
.toast-stack {
  position: fixed; inset-block-end: var(--sp-5); inset-inline-end: var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-3);
  z-index: 90; max-inline-size: 420px;
}
.toast {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-inline-start: 3px solid var(--c-line-strong);
  box-shadow: var(--sh-3); font-size: var(--fs-sm);
  animation: jt-toast-in var(--dur-3) var(--ease-out);
}
@keyframes jt-toast-in { from { opacity: 0; transform: translateY(8px); } }
.toast__ico   { flex: 0 0 auto; color: var(--c-ink-3); }
.toast__body  { min-inline-size: 0; flex: 1 1 auto; color: var(--c-ink-2); }
.toast__title { font-weight: var(--fw-semi); color: var(--c-ink); display: block; }
.toast__action{ margin-inline-start: auto; flex: 0 0 auto; }
.toast__close { flex: 0 0 auto; }
.toast--success { border-inline-start-color: var(--c-success); }
.toast--success .toast__ico { color: var(--c-success); }
.toast--danger  { border-inline-start-color: var(--c-danger); }
.toast--danger  .toast__ico { color: var(--c-danger); }
.toast--warn    { border-inline-start-color: var(--c-warn); }
.toast--warn    .toast__ico { color: var(--c-warn); }
.toast--info    { border-inline-start-color: var(--c-accent); }
.toast--info    .toast__ico { color: var(--c-accent); }
@media (max-width: 767px) {
  .toast-stack { inset-inline: var(--sp-4); inset-block-end: calc(var(--tabbar-h) + var(--sp-4)); max-inline-size: none; }
}

/* --- Inline alerts and banners --------------------------------------- */
.alert {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-4); border-radius: var(--r-md);
  border: 1px solid var(--c-line); background: var(--c-surface-2);
  font-size: var(--fs-sm);
}
.alert__ico   { flex: 0 0 auto; margin-block-start: 1px; }
.alert__body  { flex: 1 1 auto; min-inline-size: 0; }
.alert__title { font-weight: var(--fw-semi); display: block; }
.alert__actions { display: flex; gap: var(--sp-2); margin-inline-start: auto; align-items: center; flex: 0 0 auto; }
.alert--info    { background: var(--c-info-weak);    border-color: var(--c-info-line);    color: var(--c-ink); }
.alert--info    .alert__ico { color: var(--c-info); }
.alert--success { background: var(--c-success-weak); border-color: var(--c-success-line); color: var(--c-ink); }
.alert--success .alert__ico { color: var(--c-success); }
.alert--warn    { background: var(--c-warn-weak);    border-color: var(--c-warn-line);    color: var(--c-ink); }
.alert--warn    .alert__ico { color: var(--c-warn); }
.alert--danger  { background: var(--c-danger-weak);  border-color: var(--c-danger-line);  color: var(--c-ink); }
.alert--danger  .alert__ico { color: var(--c-danger); }
.banner { border-radius: 0; border-inline: 0; border-block-start: 0; }
.banner--sticky { position: sticky; inset-block-start: 0; z-index: 30; }

/* ==========================================================================
   21  EMPTY / SKELETON / REFUSAL STATES
   Four states, and they are not interchangeable (§10):
     .empty              nothing exists yet    -> invite
     .empty--first-run   the tenant has NEVER done this -> teach, then start
     .empty--filtered    nothing MATCHES       -> clear the filter
     .state-block--denied  permission          -> name it, name who grants it
     .state-block--gated   plan                -> sell it, never scold
   ========================================================================== */
.empty {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
  padding: var(--sp-8) var(--sp-5); text-align: center;
}
.empty__ico {
  inline-size: 56px; block-size: 56px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-xl);
  background: var(--c-surface-3); color: var(--c-ink-3);
  border: 1px dashed var(--c-line-strong);
}
.empty--filtered .empty__ico { border-style: solid; }
/* First run. The wireframe kit names this flavour in a comment and never
   styles it, and twelve module wireframes use it; without a rule here a
   screen LOSES a state by swapping stylesheets. It is the only empty state
   that is an invitation rather than a report, so it is larger, its icon is
   accent rather than grey, and it may carry numbered steps. It must never
   read as a scold: the tenant has not failed to do this, they have not got
   to it yet. */
.empty--first-run { padding-block: var(--sp-9); gap: var(--sp-4); }
.empty--first-run .empty__ico {
  inline-size: 72px; block-size: 72px;
  background: var(--c-accent-weak); color: var(--c-accent);
  border: 1px solid var(--c-accent-line);
}
.empty--first-run .empty__title { font-size: var(--fs-lg); }
.empty--first-run .empty__body  { max-inline-size: 56ch; font-size: var(--fs-base); color: var(--c-ink-2); }
/* The optional "three things first" run. Numbers are figures, so they are
   tabular and LTR-isolated like every other number in the product. */
.empty__steps {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--sp-3) var(--sp-5); margin-block-start: var(--sp-3);
  padding: 0; list-style: none;
  font-size: var(--fs-sm); color: var(--c-ink-2);
}
.empty__steps > li { display: inline-flex; align-items: center; gap: var(--sp-2); }
.empty__steps > li::before {
  counter-increment: jt-step; content: counter(jt-step);
  inline-size: 20px; block-size: 20px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--c-accent-weak); color: var(--c-accent);
  font-family: var(--font-num); font-size: var(--fs-micro); font-weight: var(--fw-bold);
  direction: ltr; unicode-bidi: isolate;
}
.empty__steps { counter-reset: jt-step; }
.empty__title   { font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--c-ink); }
.empty__body    { max-inline-size: 46ch; font-size: var(--fs-sm); color: var(--c-ink-3); }
.empty__actions { display: flex; gap: var(--sp-3); margin-block-start: var(--sp-2); flex-wrap: wrap; justify-content: center; }

.skel {
  display: block; border-radius: var(--r-xs);
  background: var(--c-surface-3); position: relative; overflow: hidden;
}
.skel::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  animation: jt-shimmer 1.4s infinite;
}
:root[data-theme="dark"] .skel::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,.07), transparent); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .skel::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,.07), transparent); }
}
@keyframes jt-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
.skel--text  { block-size: 9px;  margin-block: 4px; }
.skel--title { block-size: 14px; inline-size: 40%; margin-block: var(--sp-2); }
.skel--line  { block-size: 9px; }
.skel--w25 { inline-size: 25%; } .skel--w40 { inline-size: 40%; }
.skel--w60 { inline-size: 60%; } .skel--w80 { inline-size: 80%; }
.skel--tile  { block-size: 64px; border-radius: var(--r-md); }
.skel--num   { block-size: 9px; inline-size: 68px; margin-inline-start: auto; }
.skel--circle{ border-radius: 50%; inline-size: 28px; block-size: 28px; }
.tbl tr.is-loading td > .skel { inline-size: 80%; }
.is-busy { opacity: .55; pointer-events: none; }

.state-block {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-6); border-radius: var(--r-lg);
  border: 1px solid var(--c-line); background: var(--c-surface);
}
.state-block__title { font-size: var(--fs-md); font-weight: var(--fw-semi); }
.state-block__body  { max-inline-size: 52ch; color: var(--c-ink-2); font-size: var(--fs-sm); }
/* The correlation id is ALWAYS shown on an error — it is how support finds it. */
.state-block__corr {
  font-family: var(--font-num); font-size: var(--fs-xs); color: var(--c-ink-3);
  background: var(--c-surface-sunk); border: 1px solid var(--c-line);
  border-radius: var(--r-sm); padding: var(--sp-2) var(--sp-3);
  direction: ltr; unicode-bidi: isolate; user-select: all;
}
.state-block--error  { border-color: var(--c-danger-line); background: var(--c-danger-weak); }
.state-block--error  .state-block__title { color: var(--c-danger); }
/* IA-16. Never write your own 403. Name the screen, name the permission,
   name the human who can grant it, and offer to ask them. */
.state-block--denied { border-color: var(--c-line-strong); background: var(--c-surface-2); }
.state-block__perm {
  font-family: var(--font-num); font-size: var(--fs-xs);
  background: var(--c-surface-3); border: 1px solid var(--c-line);
  border-radius: var(--r-sm); padding: 1px var(--sp-2);
  direction: ltr; unicode-bidi: isolate; color: var(--c-ink-2);
}
.state-block__who {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-weight: var(--fw-semi);
}
/* PT-23. Sell the upgrade, do not scold. Screenshot, tier, price delta. */
.state-block--gated { border-color: var(--c-accent-line); background: var(--c-accent-weak); }
.state-block--gated .state-block__title { color: var(--c-accent-hi); }
.state-block__shot {
  inline-size: 100%; border: 1px solid var(--c-accent-line); border-radius: var(--r-md);
  overflow: hidden; background: var(--c-surface); margin-block: var(--sp-3);
}
/* §10.4 temporarily unavailable: the menu let you in, the screen explains. */
.state-block--unavailable { border-color: var(--c-warn-line); background: var(--c-warn-weak); }
.state-block--unavailable .state-block__title { color: var(--c-warn); }

/* ==========================================================================
   22  PAGER & FILTER BAR
   ========================================================================== */
.pager { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; padding-block: var(--sp-4); }
.pager__info { font-size: var(--fs-xs); color: var(--c-ink-3); margin-inline-end: auto; font-variant-numeric: var(--num-feat); }
.pager__item {
  display: inline-flex; align-items: center; justify-content: center;
  min-inline-size: var(--hit); min-block-size: var(--hit); padding-inline: var(--sp-2);
  border: 1px solid var(--c-line); border-radius: var(--r-sm);
  background: var(--c-surface); color: var(--c-ink-2);
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  font-size: var(--fs-sm); text-decoration: none; cursor: pointer;
}
.pager__item:hover { background: var(--c-surface-2); text-decoration: none; }
.pager__item.is-current { background: var(--c-accent); border-color: var(--c-accent); color: var(--c-accent-ink); font-weight: var(--fw-semi); }
.pager__item[disabled], .pager__item.is-disabled { opacity: .4; pointer-events: none; }
.pager__gap { color: var(--c-ink-4); padding-inline: var(--sp-2); }
.pager--cursor .pager__item { min-inline-size: auto; padding-inline: var(--sp-4); }

.filterbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--c-surface-2); border: 1px solid var(--c-line);
  border-radius: var(--r-lg); margin-block-end: var(--sp-4);
}
.filterbar .search { flex: 1 1 220px; min-inline-size: 180px; }
.filterbar__group { display: flex; align-items: center; gap: var(--sp-2); }
.filterbar__sep   { inline-size: 1px; align-self: stretch; background: var(--c-line); }
.filterbar__count { font-size: var(--fs-xs); color: var(--c-ink-3); margin-inline-start: auto; font-variant-numeric: var(--num-feat); }
.filter-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-3);
  border: 1px solid var(--c-line); border-radius: var(--r-pill);
  background: var(--c-surface); color: var(--c-ink-2);
  font-size: var(--fs-sm); cursor: pointer; white-space: nowrap;
}
.filter-chip:hover { border-color: var(--c-line-strong); }
.filter-chip.is-on { background: var(--c-accent-weak); border-color: var(--c-accent-line); color: var(--c-accent); font-weight: var(--fw-medium); }
.filter-chip__x { color: var(--c-ink-3); }
.filter-applied { display: flex; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--c-ink-3); padding-block-end: var(--sp-3); }

/* ==========================================================================
   23  MODULE COMPONENTS
   Owned by one module, consumed by many. The theme colours them; it does
   not change their structure.
   ========================================================================== */
/* --- .trace — the pricing trace (CP-TRACE / PS-C3). Shown TO THE CUSTOMER,
       so it must be readable at arm's length and printable.            --- */
.trace { font-size: var(--fs-sm); }
.trace__row {
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--sp-2) var(--sp-4); align-items: baseline;
  padding-block: var(--sp-3); border-block-end: 1px solid var(--c-line-soft);
}
.trace__label  { color: var(--c-ink-3); font-size: var(--fs-xs); }
.trace__calc   { font-family: var(--font-num); font-size: var(--fs-xs); color: var(--c-ink-2); direction: ltr; unicode-bidi: isolate; }
.trace__value  { font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-weight: var(--fw-semi); text-align: end; direction: ltr; unicode-bidi: isolate; }
.trace__source { grid-column: 1 / -1; font-size: var(--fs-micro); color: var(--c-ink-4); }
.trace__source code { background: var(--c-surface-sunk); padding: 0 3px; border-radius: var(--r-xs); }
.trace__row--final {
  border-block-end: 0; border-block-start: 2px solid var(--c-line-strong);
  padding-block-start: var(--sp-4); margin-block-start: var(--sp-2);
}
.trace__row--final .trace__value { font-size: var(--fs-lg); }
.trace__row--negotiated { background: var(--c-warn-weak); }
.trace__stamp { font-size: var(--fs-xs); color: var(--c-ink-3); padding-block-start: var(--sp-3); }
/* A missing trace is a HARD ERROR, not an empty state. */
.trace--missing { border: 1px solid var(--c-danger-line); background: var(--c-danger-weak); padding: var(--sp-4); border-radius: var(--r-md); color: var(--c-danger); }

/* --- .alloc — the allocation workspace (AF-16) ----------------------- */
.alloc { display: grid; grid-template-columns: minmax(220px, 30%) 1fr; gap: var(--sp-5); }
@media (max-width: 900px) { .alloc { grid-template-columns: 1fr; } }
.alloc__source { align-self: start; }
.alloc__strategies { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-block-end: var(--sp-3); }
.alloc__meter { display: flex; align-items: center; gap: var(--sp-3); padding-block: var(--sp-3); }
.alloc__bar { flex: 1 1 auto; block-size: 6px; background: var(--c-surface-3); border-radius: var(--r-pill); overflow: hidden; }
.alloc__bar > span { display: block; block-size: 100%; inline-size: var(--pct, 0%); background: var(--c-accent); }
.alloc__bar--full > span { background: var(--c-success); }
.alloc__bar--over > span { background: var(--c-danger); }
.alloc__input { inline-size: 110px; }
.alloc__row--disputed td { color: var(--c-ink-3); background: var(--c-surface-2); }
.alloc__row--over .alloc__input { border-color: var(--c-danger); background: var(--c-danger-weak); }

/* --- .ageing — the ageing grid (AR / AP / approvals / custody) -------- */
.ageing .num { min-inline-size: 84px; }
.ageing__bucket--warn { color: var(--c-warn); }
.ageing__bucket--late { color: var(--c-danger); font-weight: var(--fw-semi); }
.ageing__bucket--late::after { content: "\00A0\26A0"; font-size: .85em; }
.ageing__limit { font-size: var(--fs-xs); color: var(--c-ink-3); }
.ageing tfoot td { position: sticky; inset-block-end: 0; background: var(--c-surface-3); }

/* --- .report — the report shell (module 10) -------------------------- */
.report { display: flex; flex-direction: column; gap: var(--sp-4); }
.report__params {
  display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: flex-end;
  padding: var(--sp-4); background: var(--c-surface-2);
  border: 1px solid var(--c-line); border-radius: var(--r-lg);
}
.report__params .field { margin: 0; min-inline-size: 140px; }
.report__provenance {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  font-size: var(--fs-xs); color: var(--c-ink-3);
  padding: var(--sp-2) var(--sp-4);
  background: var(--c-surface-sunk); border-radius: var(--r-sm);
}
.report__source { font-family: var(--font-num); direction: ltr; unicode-bidi: isolate; }
.report__body { min-inline-size: 0; }
.report__foot { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }
/* A figure that drills. The dotted rule says "this goes somewhere". */
.drill { border-block-end: 1px dotted var(--c-accent); color: inherit; cursor: pointer; }
.drill:hover { background: var(--c-accent-weak); text-decoration: none; }
.drill-path { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); }
.drill-path__step { color: var(--c-ink-3); }
.drill-path__step.is-current { color: var(--c-ink); font-weight: var(--fw-semi); }

/* --- .payload — the payload inspector (module 12) -------------------- */
.payload { border: 1px solid var(--c-line); border-radius: var(--r-lg); overflow: hidden; background: var(--c-surface); }
.payload__head { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); background: var(--c-surface-2); border-block-end: 1px solid var(--c-line); }
.payload__method { font-family: var(--font-num); font-weight: var(--fw-bold); font-size: var(--fs-xs); padding: 1px var(--sp-2); border-radius: var(--r-xs); background: var(--c-surface-3); direction: ltr; unicode-bidi: isolate; }
.payload__url { font-family: var(--font-num); color: var(--c-ink-2); direction: ltr; unicode-bidi: isolate; overflow: hidden; text-overflow: ellipsis; min-inline-size: 0; }
.payload__status { font-family: var(--font-num); font-weight: var(--fw-semi); }
.payload__status--ok  { color: var(--c-success); }
.payload__status--err { color: var(--c-danger); }
.payload__timing { color: var(--c-ink-3); font-family: var(--font-num); margin-inline-start: auto; }
.payload__panes { display: grid; grid-template-columns: 1fr 1fr; }
@media (max-width: 900px) { .payload__panes { grid-template-columns: 1fr; } }
.payload__pane { min-inline-size: 0; }
.payload__pane + .payload__pane { border-inline-start: 1px solid var(--c-line); }
.payload__pane-head { padding: var(--sp-2) var(--sp-4); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); border-block-end: 1px solid var(--c-line-soft); }
.payload__body { font-family: var(--font-num); font-size: var(--fs-xs); padding: var(--sp-3) var(--sp-4); overflow: auto; max-block-size: 300px; background: var(--c-surface-sunk); direction: ltr; unicode-bidi: isolate; white-space: pre; }
.payload__attempts { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-block-start: 1px solid var(--c-line); }

/* --- .inbox-row — the alert inbox (RB-11) ---------------------------- */
.inbox { border: 1px solid var(--c-line); border-radius: var(--r-lg); overflow: hidden; background: var(--c-surface); }
.inbox-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-block-end: 1px solid var(--c-line-soft);
  color: inherit; text-decoration: none;
}
.inbox-row:last-child { border-block-end: 0; }
.inbox-row:hover { background: var(--c-surface-2); text-decoration: none; }
.inbox-row.is-unread { background: var(--c-accent-weak); }
.inbox-row__sev { align-self: stretch; inline-size: 3px; flex: 0 0 3px; border-radius: var(--r-pill); background: var(--c-line-strong); }
.inbox-row--critical .inbox-row__sev { background: var(--c-danger); }
.inbox-row--warn     .inbox-row__sev { background: var(--c-warn); }
.inbox-row--info     .inbox-row__sev { background: var(--c-accent); }
.inbox-row__module { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); inline-size: 78px; flex: 0 0 78px; }
.inbox-row__subject { min-inline-size: 0; flex: 1 1 auto; }
.inbox-row__title  { font-weight: var(--fw-semi); font-size: var(--fs-sm); }
.inbox-row__detail { font-size: var(--fs-xs); color: var(--c-ink-3); }
.inbox-row__figure { font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-weight: var(--fw-semi); text-align: end; direction: ltr; unicode-bidi: isolate; }
.inbox-row__age    { font-size: var(--fs-xs); color: var(--c-ink-3); font-variant-numeric: var(--num-feat); white-space: nowrap; }
@media (max-width: 720px) { .inbox-row__module { display: none; } }

/* --- capture / scale-read (repair intake, KYC, old gold) -------------- */
.capture { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: var(--sp-3); }
.capture__tile {
  aspect-ratio: 4 / 3;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); border: 1px dashed var(--c-line-strong); border-radius: var(--r-md);
  background: var(--c-surface-2); color: var(--c-ink-3);
  font-size: var(--fs-xs); cursor: pointer; position: relative; overflow: hidden;
}
.capture__tile:hover { border-color: var(--c-accent); color: var(--c-accent); }
.capture__tile--filled { border-style: solid; border-color: var(--c-line); background: var(--c-surface-3); }
.capture__tile--filled::before {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(45deg, transparent 0 6px, var(--c-line) 6px 7px);
  opacity: .45;
}
.capture__tile--required { border-color: var(--c-danger); color: var(--c-danger); }
.capture__meta { position: absolute; inset-block-end: 0; inset-inline: 0; padding: 2px var(--sp-2); background: var(--c-surface); font-size: var(--fs-micro); border-block-start: 1px solid var(--c-line); }
.capture__count { font-size: var(--fs-xs); color: var(--c-ink-3); }
.scale-read {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-md);
  border: 1px solid var(--c-line); background: var(--c-surface-2);
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  direction: ltr; unicode-bidi: isolate;
}
.scale-read--live   { border-color: var(--c-success-line); background: var(--c-success-weak); color: var(--c-success); }
.scale-read--manual { color: var(--c-ink-3); }
.scale-read--out    { border-color: var(--c-danger-line); background: var(--c-danger-weak); color: var(--c-danger); }

/* ==========================================================================
   24  OTHER DEVICES  (§9)
   One IA, four navigation models.
   ========================================================================== */
/* --- 9.1 The till. Chromeless PS-01: rail hidden, top bar reduced to
       outlet, rate, offline state and shift timer. Navy ground so the
       cashier's one screen all shift is unmistakably the product.     --- */
.app--till { --topbar-h: 56px; }
.topbar--till {
  background: var(--navy-11); color: #fff;
  border-block-end: 1px solid var(--blue-10);
}
.topbar--till .ctx-switch, .topbar--till .usermenu { color: #fff; }
.topbar--till .ctx-switch__outlet { color: var(--navy-05); }
.topbar--till .ctx-switch:hover, .topbar--till .usermenu:hover { background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.18); }
.topbar--till .rate-pill { background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.20); color: #fff; }
.topbar--till .rate-pill__metal, .topbar--till .rate-pill__unit, .topbar--till .rate-pill__age { color: var(--blue-04); }
.topbar--till .rate-pill--stale { background: var(--c-warn-weak); border-color: var(--c-warn-line); color: var(--c-warn); }
.topbar--till .rate-pill--stale .rate-pill__metal, .topbar--till .rate-pill--stale .rate-pill__age { color: var(--c-warn); }
.shift-timer {
  display: inline-flex; align-items: baseline; gap: var(--sp-2);
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  font-size: var(--fs-md); font-weight: var(--fw-semi);
  direction: ltr; unicode-bidi: isolate;
}
.shift-timer__label { font-family: var(--font-ui); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--blue-04); }
.shift-timer--long { color: var(--c-warn); }
.conn-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
  background: rgba(255,255,255,.12); color: #fff;
}
/* The chip had no ONLINE modifier, so every screen drew the good state as a
   bare .conn-chip and the three states did not read as one set. They do now,
   and each carries a glyph as well as its word. */
.conn-chip::before { content: "\25CF"; font-size: 9px; line-height: 1; flex: 0 0 auto; }
/* All three take the weak ground / strong ink pattern that .topbar--till
   .rate-pill--stale already uses for a status chip on the navy bar. The
   solid fill with white text that --offline and --syncing used to carry
   measured 2.05:1 in the dark theme, because --c-warn lightens there while
   the #fff did not: a latent AA failure found while adding --online. All
   three pairs are now gated in contrast-check.py. */
.conn-chip--online  { background: var(--c-success-weak); border-color: var(--c-success-line); color: var(--c-success); }
.conn-chip--offline { background: var(--c-warn-weak);    border-color: var(--c-warn-line);    color: var(--c-warn); }
.conn-chip--offline::before { content: "\26A1"; font-size: 11px; }
.conn-chip--syncing { background: var(--c-info-weak);    border-color: var(--c-info-line);    color: var(--c-info); }
.conn-chip--syncing::before { content: "\21BB"; font-size: 11px; }
/* Off the navy till chrome — an office screen, a portal — the neutral chip
   would be invisible, so it takes the ordinary surface. */
.conn-chip { border: 1px solid transparent; }
.topbar:not(.topbar--till) .conn-chip:not([class*="conn-chip--"]),
.app-content .conn-chip:not([class*="conn-chip--"]) {
  background: var(--c-surface-2); border-color: var(--c-line); color: var(--c-ink-2);
}
/* IA-06 session lock: the screen is replaced, with NO navigation at all. */
.lockscreen {
  position: fixed; inset: 0; z-index: 100;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-6); background: var(--navy-11); color: #fff;
}
.lockscreen .pinpad { display: grid; grid-template-columns: repeat(3, 72px); gap: var(--sp-4); }
.lockscreen .pinpad .btn {
  min-block-size: 64px; font-size: var(--fs-xl); font-family: var(--font-num);
  background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.22); color: #fff;
}
.lockscreen .pinpad .btn:hover { background: rgba(255,255,255,.16); }

/* --- 9.2 The handheld. IN-30 is the entire navigation: four tiles at 50%
       of the viewport. No rail, no palette (a palette needs a keyboard). */
.handheld { --topbar-h: 48px; }
.handheld-home {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3);
  padding: var(--sp-3); block-size: calc(100dvh - var(--topbar-h) - 56px);
}
.handheld-tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); border-radius: var(--r-xl);
  background: var(--c-surface); border: 1px solid var(--c-line);
  color: var(--c-ink); font-size: var(--fs-md); font-weight: var(--fw-semi);
  text-decoration: none; box-shadow: var(--sh-1);
}
.handheld-tile:active { background: var(--c-accent-weak); }
.handheld-tile--primary { background: var(--c-surface-inv); color: var(--c-ink-inv); border-color: transparent; }
.handheld-tile--primary .ico { color: var(--c-highlight); }
/* One persistent 56px Back, thumb-reachable, always returning to IN-30. */
.handheld-back {
  position: fixed; inset-block-end: 0; inset-inline: 0; block-size: 56px;
  display: flex; align-items: center; justify-content: center; gap: var(--sp-3);
  background: var(--c-surface); border-block-start: 1px solid var(--c-line);
  color: var(--c-ink); font-weight: var(--fw-semi); text-decoration: none;
}

/* --- 9.3 The tablet at goods-in. Workflow sub-navigation replaces menu
       navigation: a persistent progress strip and 48px targets.       --- */
.stepstrip {
  display: flex; align-items: stretch; gap: 0;
  border: 1px solid var(--c-line); border-radius: var(--r-lg);
  background: var(--c-surface); overflow: hidden;
}
.stepstrip__step {
  flex: 1 1 0; min-inline-size: 0;
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: 56px; padding-inline: var(--sp-4);
  border-inline-end: 1px solid var(--c-line);
  color: var(--c-ink-3); font-size: var(--fs-sm); text-decoration: none;
}
.stepstrip__step:last-child { border-inline-end: 0; }
.stepstrip__n {
  flex: 0 0 auto; inline-size: 24px; block-size: 24px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--c-surface-3); color: var(--c-ink-3);
  font-family: var(--font-num); font-size: var(--fs-xs); font-weight: var(--fw-bold);
}
.stepstrip__step.is-done { color: var(--c-ink-2); }
.stepstrip__step.is-done .stepstrip__n { background: var(--c-success); color: #fff; }
.stepstrip__step.is-current { background: var(--c-accent-weak); color: var(--c-ink); font-weight: var(--fw-semi); }
.stepstrip__step.is-current .stepstrip__n { background: var(--c-accent); color: var(--c-accent-ink); }
/* Steps reverse in RTL for free: step 1 is on the right. Nothing to do. */

/* --- 9.4 The owner's phone. Bottom tab bar, 5 slots, 56px.
       Not a hamburger: a hamburger here hides the four things he came for. */
.tabbar {
  position: fixed; inset-block-end: 0; inset-inline: 0; z-index: 80;
  display: none; align-items: stretch;
  block-size: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  padding-block-end: env(safe-area-inset-bottom, 0px);
  background: var(--c-surface); border-block-start: 1px solid var(--c-line);
  box-shadow: 0 -2px 8px rgba(5,34,65,.08);
}
.tabbar__item {
  flex: 1 1 0; min-inline-size: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; color: var(--c-ink-3); font-size: var(--fs-micro);
  text-decoration: none; position: relative;
}
.tabbar__item.is-active, .tabbar__item[aria-current="page"] { color: var(--c-accent); font-weight: var(--fw-semi); }
.tabbar__item.is-active::before {
  content: ""; position: absolute; inset-block-start: 0; inline-size: 24px;
  block-size: 2px; border-radius: var(--r-pill); background: var(--c-accent);
}
.tabbar__badge {
  position: absolute; inset-block-start: 4px; inset-inline-start: 56%;
  min-inline-size: 16px; block-size: 16px; padding-inline: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--c-danger); color: #fff; border: 2px solid var(--c-surface);
  border-radius: var(--r-pill); font-size: 9px; font-weight: var(--fw-bold);
  direction: ltr; unicode-bidi: isolate;
}
@media (max-width: 767px) {
  .tabbar { display: flex; }
  .app-content, .main__content { padding-block-end: calc(var(--tabbar-h) + var(--sp-5)); }
}

/* --- 9.5 The platform console. Same palette, visibly NOT a tenant:
       the accent is inverted to the light blue on a permanently dark
       chrome, and the wordmark reads PLATFORM. An operator can never
       mistake it for a tenant's own application.                      --- */
.app--platform .rail { background: var(--navy-12); }
.app--platform .rail__wordmark { color: var(--c-highlight); letter-spacing: var(--tracking-caps); text-transform: uppercase; font-size: var(--fs-sm); }
.app--platform .topbar { background: var(--navy-11); color: #fff; border-block-end-color: var(--blue-10); }
.app--platform .topbar .ctx-switch, .app--platform .topbar .usermenu { color: #fff; }
.app--platform .topbar__search { background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.20); color: var(--navy-04); }
.app--platform .rail__item.is-active { background: rgba(118,186,229,.22); }
/* --- The vendor portal (C). Nine screens, a 5-item top nav, no rail,
       Arabic-first as the drawn default.                              --- */
.portal-nav {
  display: flex; align-items: stretch; gap: var(--sp-5);
  padding-inline: var(--d-gutter);
  background: var(--c-surface); border-block-end: 1px solid var(--c-line);
}
.portal-nav__item {
  display: inline-flex; align-items: center; min-block-size: 52px;
  border-block-end: 2px solid transparent; color: var(--c-ink-2);
  font-weight: var(--fw-medium); text-decoration: none;
}
.portal-nav__item.is-active { color: var(--c-ink); border-block-end-color: var(--c-accent); font-weight: var(--fw-semi); }

/* --- 9.6 A SCREEN INSIDE A BOX -----------------------------------------
       Review sheets, this theme's own style guide, a before/after pair, a
       flow of six states down one page: all of them put a whole application
       screen inside a containing box rather than in the viewport. The
       product has five rules that assume it OWNS the viewport, and every
       sheet so far has overridden them privately and differently. Two are
       shipped here instead.

       .app--embedded   re-references those five rules to the FRAME.
       .device-frame    is the frame: a box at a real device's geometry.

       They are independent. A style guide showing one shell in a card wants
       .app--embedded alone. A review sheet showing a 1600x900 till next to a
       390x844 phone wants both. Neither is product chrome: no shipped screen
       carries either class, which is also why grepping for them tells you
       exactly which pages are documentation.
       -------------------------------------------------------------------- */
.app--embedded {
  /* 1. the shell is 100vh/100dvh — it becomes the box it is given. */
  block-size: 100%; min-block-size: 0; max-block-size: 100%;
  /* 2. position:fixed children need a containing block that is not the
        viewport. A containing block is created by a filter, a transform or
        `contain`; `contain: layout paint` is the one with no visual cost. */
  position: relative; contain: layout paint;
  overflow: hidden;
}
/* 3. Six things in the theme pin themselves to the viewport. `contain` above
      already re-homes them, but they are named explicitly so the rule also
      holds in a browser that has dropped containment, and so the list is
      reviewable: if a seventh fixed element is ever added to the theme, this
      block is where it has to be declared. */
.app--embedded .scrim,
.app--embedded .toast-stack,
.app--embedded .lockscreen,
.app--embedded .handheld-back,
.app--embedded .tabbar,
.app--embedded .rail,
.app--embedded .app-sidebar,
.app--embedded .drawer,
.app--embedded .app-drawer { position: absolute; }
/* The rail and the drawer are only fixed inside a media query, and they are
   grid items outside it. Re-state the grid placement so the rule above does
   not tear them out of the grid on a wide page. */
.app--embedded .rail, .app--embedded .app-sidebar { position: relative; inset: auto; }
.app--embedded .drawer, .app--embedded .app-drawer { position: relative; inset: auto; block-size: auto; }
.app--embedded .rail.is-open, .app--embedded .app-sidebar.is-open,
.app--embedded .rail.is-overlay, .app--embedded .drawer.is-overlay,
.app--embedded .app-drawer.is-overlay {
  position: absolute; inset-block: 0; block-size: 100%;
}
.app--embedded .rail.is-overlay, .app--embedded .rail.is-open { inset-inline-start: 0; }
.app--embedded .drawer.is-overlay, .app--embedded .app-drawer.is-overlay { inset-inline-end: 0; }
/* 4. vh and dvh measure the PAGE, never the frame, so the four viewport-
      relative metrics in the theme are re-expressed as percentages of the
      frame. Same geometry, different reference box — the numbers are the
      theme's own, converted, not redesigned. */
.app--embedded .scrim--top { padding-block-start: 12%; }   /* was 15vh  */
.app--embedded .cmdk       { max-block-size: 76%; }        /* was 60vh  */
.app--embedded .ctx-pop    { max-block-size: 60%; }        /* was 60vh  */
.app--embedded .modal      { max-block-size: 86%; }        /* was 86vh  */
.app--embedded .drawer__body { max-block-size: none; }
/* 5. The handheld home is calc(100dvh - chrome). Inside a frame it is simply
      what is left of the grid row. */
.app--embedded .handheld-home { block-size: auto; min-block-size: 0; align-content: stretch; }
/* An embedded shell is a picture of a screen, not a screen: nothing in it
   should animate on its own or trap a scroll that the reader started. */
.app--embedded .skel::after { animation: none; }
.app--embedded .app-content, .app--embedded .main__content { overscroll-behavior: contain; }

/* --- The frame ---------------------------------------------------------
       --dev-w / --dev-h are UNITLESS CSS pixels: the device's real
       geometry, so a reviewer measuring the screenshot measures the device.
       --dev-s is the scale a page may set (1 = true size, .5 = half) when
       the device is wider than the column it has to fit in; leaving it
       unset renders at true size and lets the page scroll.

       The scale is a transform on the inner box, which has the useful side
       effect of being a containing block for position:fixed all by itself —
       so a device frame keeps the tab bar inside even if .app--embedded were
       ever forgotten. It also means the frame's own box is the SCALED size,
       so the surrounding layout does not have to know the device at all.
       -------------------------------------------------------------------- */
.device-frame {
  --dev-w: 1440; --dev-h: 900; --dev-s: 1;
  position: relative; overflow: hidden;
  inline-size: calc(var(--dev-w) * var(--dev-s) * 1px);
  block-size:  calc(var(--dev-h) * var(--dev-s) * 1px);
  max-inline-size: 100%;
  background: var(--c-bg); color: var(--c-ink);
  border: 1px solid var(--c-line-strong); border-radius: var(--r-lg);
  box-shadow: var(--sh-3);
  contain: layout paint;
}
.device-frame__inner {
  position: absolute; inset-block-start: 0; inset-inline-start: 0;
  inline-size: calc(var(--dev-w) * 1px);
  block-size:  calc(var(--dev-h) * 1px);
  transform: scale(var(--dev-s));
  transform-origin: 0 0;
  overflow: hidden;
}
/* transform-origin has no logical keyword, so RTL is the one place the frame
   needs a physical rule. Anchoring to the inline-start corner in both
   directions keeps a scaled RTL screen inside its own frame. */
[dir="rtl"] .device-frame__inner {
  inset-inline-start: auto; inset-inline-end: 0;
  transform-origin: 100% 0;
}
/* A screen taller than its device — a long settings page on a phone — scrolls
   inside the frame instead of being cropped. */
.device-frame__scroll {
  block-size: 100%; overflow: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
/* The strip under a frame naming the device and its geometry. */
.device-frame__label {
  display: block; margin-block-start: var(--sp-2);
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  font-size: var(--fs-micro); color: var(--c-ink-4);
  direction: ltr; unicode-bidi: isolate;
}
/* --- The five devices of §9. The numbers are the ones §9 already names;
       the class only stops six designers inventing six of them. Density is
       a separate, inherited fact and is set with data-density on the frame —
       exactly as a real device sets it — so a frame never hard-codes a
       density token. The reference density for each is in the comment. */
.device-frame--till     { --dev-w: 1600; --dev-h: 900; }   /* data-density="touch"       */
.device-frame--laptop   { --dev-w: 1440; --dev-h: 900; }   /* comfortable, or compact    */
.device-frame--tablet   { --dev-w: 1024; --dev-h: 768; }   /* data-density="touch"       */
.device-frame--handheld { --dev-w: 390;  --dev-h: 844; }   /* data-density="touch"       */
.device-frame--phone    { --dev-w: 390;  --dev-h: 844; }   /* data-density="comfortable" */
.device-frame--handheld, .device-frame--phone { border-radius: var(--r-xl); border-color: var(--c-line-strong); }
.device-frame--till { border-color: var(--navy-10); }
/* --- The phone tab bar. .tabbar is display:none above 767px, and a 390px
       frame on a 1440px page does NOT trigger that media query — the sheet
       is wide even though the device is not. This is the single most-missed
       override, and it is why .device-frame--phone exists as its own variant
       rather than being a width. The handheld shows its Back bar instead. */
.device-frame--phone .tabbar { display: flex; }
.device-frame--phone .app-content,
.device-frame--phone .main__content,
.device-frame--phone .device-frame__scroll { padding-block-end: calc(var(--tabbar-h) + var(--sp-5)); }
.device-frame--handheld .tabbar { display: none; }
.device-frame--handheld .handheld-back { display: flex; }
.device-frame--handheld .app-content,
.device-frame--handheld .main__content,
.device-frame--handheld .device-frame__scroll { padding-block-end: calc(56px + var(--sp-4)); }
/* The till and the tablet are chromeless by §9.1/§9.3; neither ever shows a
   tab bar, whatever the frame's width says. */
.device-frame--till .tabbar, .device-frame--tablet .tabbar { display: none; }
/* Frames sit in a row that wraps. */
.device-row { display: flex; flex-wrap: wrap; gap: var(--sp-5); align-items: flex-start; }
.device-row > * { flex: 0 1 auto; min-inline-size: 0; }
@media print {
  .device-frame { box-shadow: none; break-inside: avoid; }
}

/* ==========================================================================
   25  PRINT
   Paper has no navigation, no theme toggle and no colour budget. Print is
   forced to the light tokens on white, the chrome is removed, tables break
   honestly and every document carries its filter context and its stamp.
   Thermal receipts (80mm) are 1-bit: nothing there may depend on colour.
   ========================================================================== */
.print-preview { background: var(--c-surface-sunk); padding: var(--sp-6); display: flex; flex-direction: column; align-items: center; gap: var(--sp-5); }
.print-sheet {
  inline-size: 210mm; min-block-size: 297mm; padding: 15mm;
  background: #ffffff; color: #111110;
  box-shadow: var(--sh-3); font-size: 11px; line-height: 1.45;
}
.print-sheet--a5      { inline-size: 148mm; min-block-size: 210mm; padding: 10mm; }
.print-sheet--receipt { inline-size: 80mm;  min-block-size: 160mm; padding: 4mm; font-family: var(--font-num); font-size: 10px; }
.print-sheet--land    { inline-size: 297mm; min-block-size: 210mm; }
.print-sheet .tbl, .print-sheet .tbl th, .print-sheet .tbl td { background: transparent; color: inherit; border-color: #c9c9c4; }
.print-head { display: flex; align-items: flex-start; gap: var(--sp-5); border-block-end: 2px solid #111110; padding-block-end: var(--sp-3); }
.print-head__org { font-weight: var(--fw-bold); font-size: 13px; }
.print-title { font-size: 15px; font-weight: var(--fw-bold); letter-spacing: .04em; text-transform: uppercase; }
.print-foot { border-block-start: 1px solid #c9c9c4; padding-block-start: var(--sp-3); margin-block-start: var(--sp-5); font-size: 9px; color: #4e4e4a; }
.print-sign { display: flex; gap: var(--sp-7); margin-block-start: var(--sp-8); }
.print-sign__line { flex: 1 1 0; border-block-start: 1px solid #111110; padding-block-start: var(--sp-2); font-size: 9px; }
.print-bi { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); }
.print-bi__ar { direction: rtl; text-align: right; font-family: var(--font-ar); }
.qr-box {
  inline-size: 84px; block-size: 84px; flex: 0 0 auto;
  border: 1px solid #111110; display: flex; align-items: center; justify-content: center;
  font-size: 8px; text-align: center; color: #4e4e4a;
  background:
    repeating-linear-gradient(0deg,  #111110 0 3px, transparent 3px 6px),
    repeating-linear-gradient(90deg, #111110 0 3px, transparent 3px 6px);
  background-blend-mode: multiply; background-size: 100% 100%;
}
.print-modes { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }

@media print {
  /* Force the light tokens: a navy dark theme costs a cartridge and reads
     as a photocopy artefact. */
  :root, :root[data-theme="dark"] {
    --c-bg: #ffffff; --c-surface: #ffffff; --c-surface-2: #ffffff;
    --c-surface-3: #f2f2f0; --c-surface-sunk: #f2f2f0; --c-surface-inv: #ffffff;
    --c-ink: #000000; --c-ink-2: #1f1f1e; --c-ink-3: #46464a; --c-ink-4: #46464a;
    --c-ink-faint: #767670; --c-ink-inv: #000000; --c-ink-inv-2: #1f1f1e;
    --c-line: #c9c9c4; --c-line-soft: #dededa; --c-line-strong: #767670;
    --c-accent: #000000; --c-accent-weak: #f2f2f0; --c-accent-line: #767670;
    --c-accent-ink: #ffffff;
    --c-primary: #000000; --c-primary-ink: #ffffff;
    --c-success: #000000; --c-success-weak: #f2f2f0; --c-success-line: #767670;
    --c-warn:    #000000; --c-warn-weak:    #f2f2f0; --c-warn-line:    #767670;
    --c-danger:  #000000; --c-danger-weak:  #f2f2f0; --c-danger-line:  #767670;
    --c-info:    #000000; --c-info-weak:    #f2f2f0; --c-info-line:    #767670;
    --c-metal:   #000000; --c-metal-weak:   #f2f2f0; --c-metal-line:   #767670;
    --sh-1: none; --sh-2: none; --sh-3: none; --sh-4: none;
  }
  @page { margin: 14mm; }
  html, body { background: #fff; color: #000; font-size: 10.5pt; }
  /* Chrome does not print. */
  .rail, .app-sidebar, .topbar, .acct-banner, .drawer, .app-drawer, .tabbar,
  .cmdk, .scrim, .toast-stack, .no-print, .rail__tip, .filterbar,
  .pager, .tbl__actions, .handheld-back, .stepstrip, .page-star { display: none !important; }
  .app { display: block; block-size: auto; }
  .app-main, .main { overflow: visible; display: block; }
  .app-content, .main__content { padding: 0; max-inline-size: none; }
  /* Tables break honestly: the header repeats, rows do not split. */
  .tbl { font-size: 9.5pt; }
  .tbl thead { display: table-header-group; }
  .tbl tfoot { display: table-footer-group; }
  .tbl tr, .card, .panel, .widget, .amt { break-inside: avoid; }
  .tbl th, .tbl td { padding: 3pt 5pt; border-block-end: .5pt solid #c9c9c4; }
  .tbl--zebra tbody tr:nth-child(even) { background: transparent; }
  /* The dual-unit amount must survive monochrome: the hairline does the
     work that colour does on screen. */
  .amt__g { border-block-start: .5pt solid #767670; }
  .amt--neg .amt__bhd { color: #000; }
  .amt--neg .amt__bhd::before { content: "\2212"; }
  /* Every printed page names its filters and its stamp. */
  .filter-applied, .report__provenance { display: flex !important; font-size: 8pt; color: #46464a; }
  /* Links print their destination, except internal app links (noise). */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 8pt; color: #46464a; }
  .card, .panel, .widget { box-shadow: none; border: .5pt solid #c9c9c4; }
  .pill { border: .5pt solid #767670; background: transparent !important; color: #000 !important; }
}

/* ==========================================================================
   26  RTL
   One dir="rtl" on <html> is the entire implementation. Everything above
   uses logical properties, so this section holds only the handful of things
   that genuinely cannot be expressed logically (§11.2 exceptions and the
   glyphs whose direction is baked into the character).
   ========================================================================== */
/* WHAT DOES NOT MIRROR — numbers, money, weights, dates, document numbers,
   tags, charts, media controls, long-job progress. Each of these already
   carries direction:ltr and unicode-bidi:isolate above. Listed here so a
   developer reading only this section still learns the rule. */
[dir="rtl"] .num,
[dir="rtl"] .amt,
[dir="rtl"] .docref,
[dir="rtl"] .fineness,
[dir="rtl"] .rate-quote,
[dir="rtl"] .tile__value,
[dir="rtl"] .chart,
[dir="rtl"] .spark { direction: ltr; unicode-bidi: isolate; }
/* A numeric column still ALIGNS to the row's own end. */
[dir="rtl"] .tbl th.num, [dir="rtl"] .tbl td.num { text-align: end; }

/* Glyph-level flips. The arrow characters below encode direction in the
   character itself, so they are swapped rather than transformed. */
[dir="rtl"] .tile__delta--flat::before { content: "\2190\00A0"; }
[dir="rtl"] .pill--transit::before { content: "\2190"; }
[dir="rtl"] .toast__action, [dir="rtl"] .alert__actions { margin-inline-start: auto; }
/* The progress of a long-running job runs LTR in both directions (§11.2). */
.progress--job { direction: ltr; }
/* Bidi isolation for a mixed list: the label renders in its own direction
   without scrambling its neighbours. */
.cmdk__label, .rail__label, .crumbs__item, .tab, .exrow__label { unicode-bidi: isolate; }

/* An Arabic UI needs a touch more line height and a hair less tracking. */
[dir="rtl"] body { line-height: var(--lh-loose); letter-spacing: 0; }
[dir="rtl"] .caps, [dir="rtl"] .eyebrow, [dir="rtl"] .widget__title,
[dir="rtl"] .tbl thead th { letter-spacing: 0; }
/* Arabic headings are never upper-cased (there is no case) nor set in the figure font */
[dir="rtl"] .tbl thead th { text-transform: none; }
[dir="rtl"] .tbl thead th.num { font-family: inherit; }

/* ==========================================================================
   27  MOTION, FORCED COLOURS, CO-OPERATION
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .skel::after { animation: none; }
}

/* Windows High Contrast / forced-colors. The product must not disappear. */
@media (forced-colors: active) {
  .btn, .input, .select, .textarea, .card, .panel, .tbl-wrap,
  .pill, .filter-chip, .rail__item, .cmdk__row { border: 1px solid ButtonBorder; }
  .btn--primary, .btn--accent { forced-color-adjust: none; background: Highlight; color: HighlightText; }
  .rail__item.is-active::before, .tab[aria-selected="true"] { forced-color-adjust: none; }
  .rail__item.is-active, .cmdk__row.is-active, .tbl tr.is-selected > td { background: Highlight; color: HighlightText; }
  .amt__g { border-block-start-color: CanvasText; }
  :focus-visible { outline: 2px solid Highlight; outline-offset: 2px; box-shadow: none; }
  .skel::after { display: none; }
}

/* The theme never assumes it owns the page. A host that sets its own
   background on <body> still gets the right ink. */
.jt-theme { background: var(--c-bg); color: var(--c-ink); font-family: var(--font-ui); }


/* ==========================================================================
   28  WIREFRAME-KIT COMPATIBILITY
   The promise in theme-README.md §4 is that a wireframe becomes a themed
   screen by swapping ONE stylesheet link. These are the kit class names that
   this theme otherwise supersedes, aliased so that promise is literally true
   and no designer has to touch 346 files.

   28a. The kit's shell names, superseded by the rail / topbar model of §08.
   ========================================================================== */
.app-topbar {
  grid-area: topbar;
  display: flex; align-items: center; gap: var(--sp-3);
  block-size: var(--topbar-h); padding-inline: var(--sp-4);
  background: var(--c-surface); border-block-end: 1px solid var(--c-line);
  box-shadow: var(--sh-1); z-index: 40;
}
.app-brand {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-weight: var(--fw-bold); font-size: var(--fs-md);
  letter-spacing: var(--tracking-tight); color: var(--c-ink); white-space: nowrap;
}
.app-brand small { display: block; font-weight: var(--fw-regular); font-size: var(--fs-micro); color: var(--c-ink-3); }
.topbar-spacer  { flex: 1 1 auto; }
.topbar-actions { display: flex; align-items: center; gap: var(--sp-2); }

.nav { display: flex; flex-direction: column; gap: 1px; padding: var(--sp-3); }
.nav-head {
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
  color: var(--navy-05);
}
.nav-sub .nav-item {
  padding-inline-start: calc(var(--sp-3) + 20px + var(--sp-3));
  font-size: var(--fs-sm); min-block-size: 32px;
}

.tenant-switch, .outlet-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-3);
  border: 1px solid transparent; border-radius: var(--r-md);
  background: transparent; color: var(--c-ink-3);
  font-size: var(--fs-sm); cursor: pointer; max-inline-size: 260px;
}
.tenant-switch:hover, .outlet-chip:hover { background: var(--c-surface-2); border-color: var(--c-line); }
.tenant-switch strong, .outlet-chip strong { color: var(--c-ink); font-weight: var(--fw-semi); }

/* The kit's rate ticker is this theme's .rate-pill under its old name. */
.rate-ticker {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-3);
  border: 1px solid var(--c-line); border-radius: var(--r-md);
  background: var(--c-surface-2); color: var(--c-ink);
  font-size: var(--fs-sm); white-space: nowrap; text-decoration: none;
}
.rate-ticker__metal { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--c-ink-3); }
.rate-ticker__value { font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-weight: var(--fw-semi); direction: ltr; unicode-bidi: isolate; }
.rate-ticker__unit  { font-size: var(--fs-xs); color: var(--c-ink-3); }
.rate-age {
  font-size: var(--fs-xs); font-variant-numeric: var(--num-feat);
  padding: 0 var(--sp-2); border-radius: var(--r-pill); color: var(--c-ink-3);
}
.rate-age--stale { background: var(--c-warn-weak);   color: var(--c-warn);   border: 1px solid var(--c-warn-line); }
.rate-age--old   { background: var(--c-danger-weak); color: var(--c-danger); border: 1px solid var(--c-danger-line); }

.user-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: var(--d-ctl-h); padding-inline: var(--sp-2);
  border: 1px solid transparent; border-radius: var(--r-md);
  background: transparent; color: var(--c-ink); cursor: pointer;
}
.user-chip:hover { background: var(--c-surface-2); border-color: var(--c-line); }
.user-chip__avatar {
  inline-size: 28px; block-size: 28px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill); background: var(--c-primary); color: var(--c-primary-ink);
  font-size: var(--fs-xs); font-weight: var(--fw-bold); direction: ltr; unicode-bidi: isolate;
}
.user-chip__role { color: var(--c-ink-3); font-size: var(--fs-xs); }

/* ==========================================================================
   28b. Wireframe review chrome — screen frames, viewports, pins, callouts,
   legends, the state strip and the toolbar.

   None of this ships. It exists so that a reviewer can open a wf-*.html with
   theme.css linked and read the annotations against the real visual design
   rather than against greyscale. Everything here is inside .no-print or is
   removed by the print block of §25, so an annotated wireframe still prints
   as the screen alone.
   ========================================================================== */
.wf-page { max-inline-size: 1700px; margin-inline: auto; padding: var(--sp-6) var(--sp-5) var(--sp-9); }
.wf-toolbar {
  position: sticky; inset-block-start: 0; z-index: 60;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  background: var(--c-surface); border-block-end: 1px solid var(--c-line);
  box-shadow: var(--sh-1);
}
.wf-screen {
  background: var(--c-surface); border: 1px solid var(--c-line);
  border-radius: var(--r-lg); margin-block-end: var(--sp-7);
  overflow: hidden; box-shadow: var(--sh-1);
}
.wf-screen__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  background: var(--c-surface-2); border-block-end: 1px solid var(--c-line);
}
.wf-screen__title    { font-size: var(--fs-lg); font-weight: var(--fw-semi); letter-spacing: var(--tracking-tight); }
.wf-screen__title-ar { font-family: var(--font-ar); font-weight: var(--fw-regular); color: var(--c-ink-3); }
.wf-screen__meta     { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-inline-start: auto; }
.wf-screen__body     { padding: var(--sp-5); }

/* The screen ID badge — PS-01, AF-04. Monospaced, always LTR, never reversed. */
.wf-id {
  font-family: var(--font-num); font-size: var(--fs-xs); font-weight: var(--fw-bold);
  padding: 1px var(--sp-2); border-radius: var(--r-xs);
  background: var(--c-surface-inv); color: var(--c-ink-inv);
  direction: ltr; unicode-bidi: isolate;
}
.wf-id--new { background: var(--c-anno); color: #fff; }

.wf-chip {
  display: inline-flex; align-items: baseline; gap: var(--sp-2);
  padding: 1px var(--sp-3); border-radius: var(--r-pill);
  border: 1px solid var(--c-line); background: var(--c-surface);
  font-size: var(--fs-xs); color: var(--c-ink-2);
}
.wf-chip::before { font-size: var(--fs-micro); color: var(--c-ink-3); }
.wf-chip--persona::before { content: "persona"; }
.wf-chip--perm            { font-family: var(--font-num); }
.wf-chip--perm::before    { content: "perm"; font-family: var(--font-ui); }
.wf-chip--route           { font-family: var(--font-num); }
.wf-chip--route::before   { content: "route"; font-family: var(--font-ui); }
.wf-chip--state::before   { content: "state"; }
.wf-chip--tier::before    { content: "tier"; }
.wf-chip--new { background: var(--c-anno-weak); border-color: var(--c-anno-line); color: var(--c-anno); }

.wf-viewport {
  --vp: 100%;
  inline-size: var(--vp); max-inline-size: 100%; margin-inline: auto;
  border: 1px solid var(--c-line-strong); border-radius: var(--r-md);
  background: var(--c-bg); position: relative; overflow: hidden;
}
.wf-viewport--till     { --vp: 1600px; }
.wf-viewport--laptop   { --vp: 1280px; }
.wf-viewport--tablet   { --vp: 980px; }
.wf-viewport--handheld { --vp: 560px; }
.wf-viewport--phone    { --vp: 390px; border-radius: var(--r-xl); }
.wf-viewport--fluid    { --vp: 100%; }
.wf-viewport::after {
  content: attr(data-vp); position: absolute;
  inset-block-start: 0; inset-inline-end: 0;
  padding: 1px var(--sp-2); font-family: var(--font-num); font-size: var(--fs-micro);
  background: var(--c-surface-3); color: var(--c-ink-3);
  border-start-end-radius: var(--r-md); border-end-start-radius: var(--r-xs);
}

.wf-anchor { position: relative; }
.wf-pin, .wf-note {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 18px; block-size: 18px; flex: 0 0 auto;
  border-radius: var(--r-pill);
  background: var(--c-accent); border: 2px solid var(--c-surface); color: #fff;
  font-family: var(--font-num); font-size: 10px; font-weight: var(--fw-bold);
  line-height: 1; direction: ltr; unicode-bidi: isolate;
}
.wf-note { position: absolute; transform: translate(-50%, -50%); z-index: 10; box-shadow: var(--sh-2); }
[dir="rtl"] .wf-note { transform: translate(50%, -50%); }
.wf-note--issue, .wf-pin--issue { background: var(--c-danger); }

.wf-callout {
  border-inline-start: 3px solid var(--c-accent);
  background: var(--c-surface-2); border-radius: var(--r-sm);
  padding: var(--sp-3) var(--sp-4); font-size: var(--fs-sm); margin-block: var(--sp-3);
}
.wf-callout__title { font-weight: var(--fw-semi); display: block; }
.wf-callout--issue  { border-inline-start-color: var(--c-danger); background: var(--c-danger-weak); }
.wf-callout--decide { border-inline-start-color: var(--c-accent); background: var(--c-accent-weak); }

.wf-legend {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5); font-size: var(--fs-sm);
  border-block-start: 1px solid var(--c-line); background: var(--c-surface-2);
}
.wf-legend__item { display: flex; gap: var(--sp-3); align-items: flex-start; }
.wf-legend__item > .wf-pin { margin-block-start: 2px; }

.wf-states {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-5); font-size: var(--fs-xs);
  border-block-start: 1px solid var(--c-line);
}
.wf-states__label { color: var(--c-ink-3); margin-inline-end: var(--sp-2); }
.wf-states a { color: var(--c-ink-2); border-block-end: 1px dotted var(--c-line-strong); text-decoration: none; }
.wf-states a.is-current { color: var(--c-ink); font-weight: var(--fw-semi); border-block-end-color: var(--c-accent); }

@media print {
  .wf-toolbar, .wf-pin, .wf-note, .wf-callout, .wf-legend, .wf-states { display: none !important; }
  .wf-viewport::after { display: none; }
}

/* --------------------------------------------------------------------------
   END. If you are about to add a rule here, check first whether the kit
   already names the component (docs/modules/_kit/kit.css). If it does, use
   that class name. If it does not, name yours in the same style and say so
   in theme-README.md §4 so the next designer can find it.
   -------------------------------------------------------------------------- */

/* ==========================================================================
   29  LEGACY COMPATIBILITY  —  app.css as it was, re-pointed at the theme
   --------------------------------------------------------------------------
   Everything above this line is docs/modules/_theme/theme.css, verbatim.
   `public/assets/app.css` is that file plus this tail, so that EVERY entry
   point which links app.css — the shell, the sign-in page, the storefront and
   the platform console — is themed without editing a head this wave does not
   own. Regenerate with:

       cat docs/modules/_theme/theme.css public/assets/compat.css > public/assets/app.css

   This tail exists because 346 as-built screens use the pre-theme class names
   (.card .kpi .badge.ok .btn.secondary .grid.cols-2 .frow .flash …). Renaming
   them in the markup is the right end state and is what ships per screen; in
   the meantime a screen that loses its layout because its class no longer
   exists is a regression, not a restyle. So: the legacy names keep their
   geometry and lose their hard-coded colour, which now comes from --c-*.

   Rules kept: logical properties only, no raw hex outside the two ink-on-fill
   cases, no external request. Rules deliberately NOT carried over: .shell,
   .sidebar, .nav, .navsec, .sidefoot, .topbar, .quicksearch, .rate-pill,
   .main, .who, .sep — main.php no longer emits them and .topbar / .rate-pill
   would fight the theme's own.
   ========================================================================== */

:root {
  /* surfaces */
  --bg: var(--c-bg);
  --bg-grad-a: var(--c-bg);
  --bg-grad-b: var(--c-bg);
  --panel:  var(--c-surface);
  --panel2: var(--c-surface-2);
  --panel3: var(--c-surface-3);
  --sidebar-bg: var(--c-surface-inv);
  --line: var(--c-line);
  --line-soft: var(--c-line-soft);
  /* ink */
  --text: var(--c-ink);
  --text-strong: var(--c-ink);
  --muted: var(--c-ink-3);
  --faint: var(--c-ink-4);
  /* brand — the one metal tone, never in chrome (theme-README §2.4) */
  --gold: var(--c-metal);
  --gold-bright: var(--c-metal);
  --gold-dim: var(--c-metal-line);
  --gold-ink: var(--c-surface);
  --gold-soft: var(--c-metal-weak);
  /* status */
  --green: var(--c-success); --red: var(--c-danger);
  --blue:  var(--c-accent);  --amber: var(--c-warn);
  --green-soft: var(--c-success-weak); --red-soft: var(--c-danger-weak);
  --blue-soft:  var(--c-accent-weak);  --amber-soft: var(--c-warn-weak);
  --muted-soft: var(--c-surface-3);
  /* effects */
  --hover: var(--c-surface-2);
  --zebra: var(--c-surface-2);
  --shadow-1: var(--sh-1);
  --shadow-2: var(--sh-2);
  --ring: var(--c-focus);
  --scroll-thumb: var(--c-line-strong);
  --scroll-thumb-hover: var(--c-ink-4);
  --btn-danger-ink: #fff;
  /* rhythm */
  --radius: var(--r-lg);
  --radius-sm: var(--r-md);
}

/* ---- layout blocks the kit does not name ---- */
.grid { display: grid; gap: var(--d-stack); }
.grid.cols-4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }

/* .card is the theme's. Only the as-built heading convention is added back. */
.card > h3:first-child { margin-block-start: 0; }
.card h3 {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-xs); color: var(--c-ink-3); font-weight: var(--fw-semi);
  text-transform: uppercase; letter-spacing: var(--tracking-caps);
}
.card h3 .h3-note { text-transform: none; letter-spacing: 0; font-weight: var(--fw-regular); color: var(--c-ink-4); }

/* ---- the as-built KPI. The theme's own is .amt / .tile. ---- */
.kpi {
  font-family: var(--font-num);
  font-size: var(--fs-2xl); font-weight: var(--fw-bold);
  font-variant-numeric: var(--num-feat);
  letter-spacing: var(--tracking-tight); line-height: var(--lh-tight);
  color: var(--c-ink);
  direction: ltr; unicode-bidi: isolate;
}
.kpi small { font-family: var(--font-ui); font-size: var(--fs-sm); color: var(--c-ink-3); font-weight: var(--fw-regular); letter-spacing: 0; }
.kpi.gold  { color: var(--c-metal); }
.kpi.green { color: var(--c-success); }
.kpi.sub   { font-size: var(--fs-xl); }
.kpi-delta { font-size: var(--fs-xs); font-weight: var(--fw-semi); font-variant-numeric: var(--num-feat); }
.kpi-delta.up   { color: var(--c-success); }
.kpi-delta.down { color: var(--c-danger); }

/* ---- tables: .tbl is the theme's; these are the as-built modifiers ---- */
table.tbl { inline-size: 100%; }
.tbl.zebra tbody tr:nth-child(even) { background: var(--c-surface-2); }
.tbl tbody tr:hover > td { background: var(--c-accent-weak); }
.tbl .indent { padding-inline-start: var(--sp-8); }
.tbl tfoot td, .tbl tfoot th {
  font-weight: var(--fw-bold); color: var(--c-ink);
  background: var(--c-surface-3); border-block-start: 1px solid var(--c-line-strong);
}

/* ---- badges: the as-built name for the theme's .pill ---- */
.badge {
  display: inline-block; padding: 1px var(--sp-3); border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: var(--fw-semi); line-height: 1.6;
  border: 1px solid transparent;
}
.badge.ok   { background: var(--c-success-weak); color: var(--c-success); border-color: var(--c-success-line); }
.badge.warn { background: var(--c-warn-weak);    color: var(--c-warn);    border-color: var(--c-warn-line); }
.badge.bad  { background: var(--c-danger-weak);  color: var(--c-danger);  border-color: var(--c-danger-line); }
.badge.info { background: var(--c-accent-weak);  color: var(--c-accent);  border-color: var(--c-accent-line); }
.badge.dim  { background: var(--c-surface-3);    color: var(--c-ink-3);   border-color: var(--c-line); }

/* ---- buttons: .btn is the theme's. The as-built markup has no --modifier,
       so the bare .btn is the form's submit and reads as the primary; the
       row-level .btn.sm stays quiet so a table is not ten primaries.

       `:not([class*="btn--"])` is the line that keeps that shim honest. Without
       it the shim out-specifies every BEM modifier in section 14 — four :not()
       against one class — so `btn--ghost`, `btn--secondary` and `btn--sm` all
       came out the same navy as `btn--primary`, on every screen built on the
       modern kit. Nothing on those screens read as quieter than anything else,
       which is the whole of what a button hierarchy is for. Legacy markup is
       untouched: a bare `.btn` with no modifier still reads as the primary, so
       the as-built screens this shim was written for look exactly as before. ---- */
.btn:not(.secondary):not(.danger):not(.sm):not([class*="btn--"]) {
  background: var(--c-primary); border-color: var(--c-primary);
  color: var(--c-primary-ink); font-weight: var(--fw-semi);
}
.btn:not(.secondary):not(.danger):not(.sm):not([class*="btn--"]):hover {
  background: var(--c-primary-hi); border-color: var(--c-primary-hi);
}
.btn.danger { background: var(--c-danger); border-color: var(--c-danger); color: #fff; font-weight: var(--fw-semi); }
.btn.danger:hover { filter: brightness(.92); background: var(--c-danger); }
.btn.sm { min-block-size: calc(var(--d-ctl-h) - 8px); padding-inline: var(--sp-3); font-size: var(--fs-xs); }
.btn:disabled { opacity: .5; cursor: not-allowed; box-shadow: none; }

/* ---- forms: the as-built screens style bare elements, not .input ---- */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(.input):not(.cmdk__input):not(.of-in),
select:not(.select):not(.of-in), textarea:not(.textarea):not(.of-in) {
  inline-size: 100%;
  min-block-size: var(--d-ctl-h);
  padding-block: var(--sp-2); padding-inline: var(--sp-4);
  border: 1px solid var(--c-line-strong); border-radius: var(--r-md);
  background: var(--c-surface); color: var(--c-ink);
  font: inherit; font-size: var(--fs-base);
}
input:not(.input):not(.cmdk__input):not(.of-in):hover, select:not(.select):not(.of-in):hover, textarea:not(.textarea):not(.of-in):hover { border-color: var(--c-ink-4); }
input:not(.input):not(.cmdk__input):not(.of-in):focus, select:not(.select):not(.of-in):focus, textarea:not(.textarea):not(.of-in):focus { border-color: var(--c-accent); }
input::placeholder, textarea::placeholder { color: var(--c-ink-4); }
label { display: block; font-size: var(--fs-xs); color: var(--c-ink-2); margin: var(--sp-4) 0 var(--sp-2); font-weight: var(--fw-medium); }
.frow { display: flex; gap: var(--sp-4); }
.frow > * { flex: 1; min-inline-size: 0; }

/* ---- flashes: the as-built name for the theme's .alert ---- */
.flash {
  border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5);
  margin-block-end: var(--sp-5); font-size: var(--fs-base);
  border: 1px solid var(--c-line); background: var(--c-surface-2); color: var(--c-ink);
}
.flash.ok    { background: var(--c-success-weak); border-color: var(--c-success-line); color: var(--c-ink); }
.flash.error { background: var(--c-danger-weak);  border-color: var(--c-danger-line);  color: var(--c-ink); }
.flash.info  { background: var(--c-accent-weak);  border-color: var(--c-accent-line);  color: var(--c-ink); }
.flash.warn  { background: var(--c-warn-weak);    border-color: var(--c-warn-line);    color: var(--c-ink); }

/* ---- empty states and skeletons ---- */
.empty .empty-ico { font-size: var(--fs-2xl); opacity: .5; display: block; margin-block-end: var(--sp-3); }
.empty b { color: var(--c-ink); display: block; margin-block-end: var(--sp-1); }
.skeleton {
  display: inline-block; min-block-size: 12px; border-radius: var(--r-md); inline-size: 100%;
  background: linear-gradient(90deg, var(--c-surface-2) 25%, var(--c-surface-3) 50%, var(--c-surface-2) 75%);
  background-size: 200% 100%; animation: jt-shimmer 1.2s infinite linear; color: transparent !important;
}
@keyframes jt-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* ---- charts (inline SVG, drawn by the views) ---- */
.chart-wrap { margin: var(--sp-2) 0 var(--sp-4); }
.chart-wrap svg { display: block; inline-size: 100%; block-size: auto; }
.chart-bar { fill: var(--c-accent); opacity: .85; }
.chart-bar:hover { opacity: 1; }
.chart-bar.dimday { fill: var(--c-ink-4); opacity: .35; }
.chart-line { fill: none; stroke: var(--c-accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart-area { fill: var(--c-accent-weak); stroke: none; }
.chart-dot  { fill: var(--c-accent); }
.chart-axis { font-size: 9px; fill: var(--c-ink-4); }
.chart-grid { stroke: var(--c-line-soft); stroke-width: 1; }

/* ---- POS (PS-01) — sidebar · cart · sticky summary ----
   The client's words: "cart is important and must not be on the side bar, and make
   a clear summary on the footer". So: a narrow context rail, the cart taking the
   rest, and one summary strip pinned to the bottom of the scroller. Old gold and
   payment are buttons in that strip; their panels are modals. */
.app-content:has(.pos-screen) { max-inline-size: none; }
.pos-screen {
  display: flex; flex-direction: column; gap: var(--sp-4);
  min-block-size: calc(100dvh - var(--topbar-h) - var(--d-gutter) * 2);
}
.pos-till {
  display: grid; grid-template-columns: var(--pos-side-w, 300px) minmax(0, 1fr);
  gap: var(--d-stack); align-items: start; flex: 1 1 auto; min-block-size: 0;
}
.pos-side { display: flex; flex-direction: column; gap: var(--sp-4); min-inline-size: 0; }
.pos-side .field { margin-block-end: 0; }
.pos-side .pill, .pos-side .stepup__grant { align-self: flex-start; }
/* The theme gives .stepup__grant a display, which beats the [hidden] default. */
.stepup__grant[hidden] { display: none; }
.pos-main { display: flex; flex-direction: column; gap: var(--sp-4); min-inline-size: 0; }
.pos-scan { position: relative; }
.pos-cart { min-block-size: 260px; }
.pos-cart .empty { padding-block: var(--sp-8); }
.pos-cart .tbl caption { font-variant-numeric: var(--num-feat); }
.pos-num-col { inline-size: 4ch; }
.pos-trace { font-size: var(--fs-xs); color: var(--c-ink-3); margin-block-start: 4px; line-height: var(--lh-base); }
.pos-ovr { margin-block-start: var(--sp-2); max-inline-size: 480px; }
.pos-ovr .input { font-size: var(--fs-xs); min-block-size: calc(var(--d-ctl-h) - 8px); }
.pos-credit-row > td, .pos-credit-row > th { background: var(--c-success-weak); }

/* THE SUMMARY. Subtotal · discount · VAT · grand · old gold, then NET PAYABLE as
   the one large figure, with the gram twin beside the money wherever the ledger
   carries both. It stays on screen while the cart scrolls. */
.pos-foot {
  position: sticky; inset-block-end: 0; z-index: 30;
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-4) var(--sp-6);
  padding: var(--sp-4) var(--sp-5);
  background: var(--c-surface-3); border: 1px solid var(--c-line-strong);
  border-radius: var(--r-lg); box-shadow: var(--sh-3);
}
.pos-foot__sum {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-4) var(--sp-6);
  flex: 1 1 320px; min-inline-size: 0;
}
.pos-foot__sum .amt--hero { padding-block: 0; }
.pos-foot__sum > .pill { align-self: center; }
.pos-foot__act { display: flex; align-items: center; gap: var(--sp-3); flex: 0 0 auto; }
.pos-foot__lock { flex: 1 0 100%; font-size: var(--fs-xs); font-variant-numeric: var(--num-feat); }

/* PS-C2 leads on three figures: payable, tendered, balance. */
.pay-head {
  display: flex; flex-wrap: wrap; gap: var(--sp-6);
  padding-block-end: var(--sp-4); border-block-end: 1px solid var(--c-line);
}

.search-results { max-block-size: 340px; overflow-y: auto; border-radius: var(--r-md); }
.search-results:not(:empty) { border: 1px solid var(--c-line); margin-block-start: var(--sp-2); background: var(--c-surface); }
.result-item {
  padding: var(--sp-3) var(--sp-4); border-block-end: 1px solid var(--c-line-soft); cursor: pointer;
  display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3);
  min-block-size: var(--hit-touch);
}
.result-item:last-child { border-block-end: 0; }
.result-item:hover, .result-item.kbsel { background: var(--c-accent-weak); }
.result-item .meta { font-size: var(--fs-xs); }

@media (max-width: 1100px) {
  /* One column — and the cart goes FIRST. It is the screen; the context rail is
     not something a salesperson should scroll past to reach the sale. */
  .pos-till { grid-template-columns: 1fr; }
  .pos-screen { min-block-size: 0; }
  .pos-main { order: 0; }
  .pos-side { order: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); align-items: start; }
}
@media (max-width: 700px) {
  .pos-foot { gap: var(--sp-3); }
  .pos-foot__act { inline-size: 100%; }
  .pos-foot__act .btn { flex: 1 1 auto; }
}

/* ---- keyboard hint bar ---- */
.kbd-hints { display: flex; gap: var(--sp-5); flex-wrap: wrap; margin-block-start: var(--sp-4); color: var(--c-ink-4); font-size: var(--fs-xs); }
.kbd-hints kbd {
  font-family: var(--font-ui); font-size: var(--fs-micro);
  background: var(--c-surface-2); border: 1px solid var(--c-line-strong);
  border-block-end-width: 2px; border-radius: var(--r-sm);
  padding: 1px var(--sp-3); color: var(--c-ink-2); margin-inline-end: var(--sp-1);
}

/* ---- utilities ---- */
.gold  { color: var(--c-metal); }
.green { color: var(--c-success); }
.red   { color: var(--c-danger); }
.mt { margin-block-start: var(--sp-5); }
.mb { margin-block-end: var(--sp-5); }
.flex { display: flex; gap: var(--sp-4); align-items: center; flex-wrap: wrap; }
.spread { justify-content: space-between; }

@media print {
  .no-print { display: none !important; }
}

/* ==========================================================================
   30  SHELL PLUMBING
   Five rules the theme cannot carry because they depend on how this shell
   hangs its popovers and remembers its rail. Everything else about the rail,
   the top bar, the breadcrumb and the palette is the theme's own.
   ========================================================================== */

/* The collapsed rail is a per-device choice restored before first paint, so the
   grid column has to narrow from <html> — the class the head script sets. */
html.jt-rail-collapsed .app { grid-template-columns: var(--rail-w-collapsed) minmax(0,1fr) 0; }

/* Popover anchors. .ctx-pop already positions itself; .menu is generic and is
   positioned here, at the inline-end so it mirrors with `dir` and nothing else. */
.jt-pop-host { position: relative; display: inline-flex; }
.menu.jt-pop { position: absolute; inset-block-start: calc(100% + 4px); inset-inline-end: 0; z-index: 60; }
.jt-pop[hidden], .scrim[hidden] { display: none; }

/* A rail item hosts its own collapsed-state tooltip. */
.rail__item { position: relative; }

/* The palette's plan tier, when the row is a group rather than a screen. */
.cmdk__tier { margin-inline-start: auto; }

/* ==========================================================================
   28  PARTNERS — CC-01 list · CC-03 edit · import wizard
   Tokens and logical properties only; light, dark and RTL come for free.
   ========================================================================== */
.pt [hidden] { display: none !important; }
/* The legacy compat layer (§ as-built) paints every bare .btn as primary with a
   0,4,0 selector. These screens use the BEM modifiers, so restore their meaning. */
.pt .btn:not(.btn--primary):not(.btn--danger):not(.btn--accent) { background: var(--c-surface); border-color: var(--c-line-strong); color: var(--c-ink); font-weight: var(--fw-medium); }
.pt .btn:not(.btn--primary):not(.btn--danger):not(.btn--accent):hover { background: var(--c-surface-2); border-color: var(--c-ink-4); }
.pt .btn.btn--ghost:not(.btn--primary):not(.btn--danger) { background: transparent; border-color: transparent; box-shadow: none; color: var(--c-ink-2); }
.pt .btn.btn--ghost:not(.btn--primary):not(.btn--danger):hover { background: var(--c-surface-3); color: var(--c-ink); }
.pt .btn.btn--quiet:not(.btn--primary):not(.btn--danger) { background: transparent; border-color: var(--c-line); box-shadow: none; color: var(--c-ink-2); }
.pt .btn.btn--quiet:not(.btn--primary):not(.btn--danger):hover { background: var(--c-surface-2); }
.pt .btn.btn--link:not(.btn--primary):not(.btn--danger) { background: transparent; border-color: transparent; box-shadow: none; color: var(--c-accent); padding-inline: 0; min-block-size: auto; }
.pt .btn.btn--link:not(.btn--primary):not(.btn--danger):hover { text-decoration: underline; background: transparent; }
.pt .btn.btn--danger-quiet:not(.btn--primary):not(.btn--danger) { background: var(--c-surface); border-color: var(--c-danger-line); color: var(--c-danger); }
.pt .btn.btn--danger-quiet:not(.btn--primary):not(.btn--danger):hover { background: var(--c-danger-weak); }
.pt .btn.is-on:not(.btn--primary):not(.btn--danger) { border-color: var(--c-accent-line); background: var(--c-accent-weak); color: var(--c-accent); }
.pt .btn.btn--primary { font-weight: var(--fw-semi); }
html.pt-locked, html.pt-locked body { overflow: hidden; }
.pt-head { padding: 0 0 var(--sp-5); max-inline-size: none; align-items: center; }
.pt-head .page-title { display: flex; flex-direction: column; }
.pt-kpis { margin-block-end: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--sp-3); }
.pt-kpis .tile__sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pt-kpi .tile__label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; }
.pt-kpi { position: relative; }
.pt-kpi .tile__label { display: inline-flex; align-items: center; gap: var(--sp-2); }
.pt-kpi .tile__value { font-size: var(--fs-xl); }
.tile.is-on { border-color: var(--c-accent-line); box-shadow: inset 0 0 0 1px var(--c-accent-line), var(--sh-1); background: var(--c-accent-weak); }
.pt-tabs { margin-block-end: var(--sp-4); }

/* filter bar */
.pt-filterbar { position: relative; }
.pt-filterbar .search .input { inline-size: 100%; padding-inline-end: var(--sp-7); }
.pt-search-kbd { position: absolute; inset-inline-end: var(--sp-3); pointer-events: none; }
.pt-filterbar .select { inline-size: auto; min-inline-size: 150px; }
.pt-colpick { position: relative; }
.pt-pop { position: absolute; inset-block-start: calc(100% + 6px); inset-inline-end: 0; z-index: 60; max-block-size: 70vh; overflow: auto; }
.pt-pop .check.menu__item { align-items: center; min-block-size: 34px; }
.pt-pop .check.menu__item input { margin: 0; }
.pt-rowpop { position: fixed; inset: auto; z-index: 70; }
.pt-chips { align-items: center; }

/* slide-over sheet (filters, quick view) */
.pt-scrim { z-index: 80; }
.pt-sheet {
  position: fixed; inset-block: 0; inset-inline-end: 0; z-index: 81;
  inline-size: min(420px, 100vw); display: flex; flex-direction: column;
  background: var(--c-surface); border-inline-start: 1px solid var(--c-line); box-shadow: var(--sh-4, var(--sh-3));
  animation: pt-sheet-in var(--dur-3, .2s) var(--ease-out, ease-out);
}
.pt-sheet--wide { inline-size: min(520px, 100vw); }
@keyframes pt-sheet-in { from { opacity: .4; transform: translateX(24px); } }
:root[dir="rtl"] .pt-sheet { animation-name: pt-sheet-in-rtl; }
@keyframes pt-sheet-in-rtl { from { opacity: .4; transform: translateX(-24px); } }
.pt-sheet .drawer__head { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); border-block-end: 1px solid var(--c-line); }
.pt-sheet .drawer__title { display: inline-flex; align-items: center; gap: var(--sp-2); }
.pt-sheet .drawer__body { flex: 1 1 auto; overflow: auto; padding: var(--sp-5); }
.pt-sheet .drawer__foot { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); border-block-start: 1px solid var(--c-line); background: var(--c-surface-2); }
.pt-fset { border: 0; padding: 0; margin: 0 0 var(--sp-5); min-inline-size: 0; }
.pt-fset > legend { font-size: var(--fs-xs); font-weight: var(--fw-semi); color: var(--c-ink-2); text-transform: uppercase; letter-spacing: var(--tracking-caps); margin-block-end: var(--sp-3); padding: 0; }
.pt-seg { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); }
.pt-segbtn { position: relative; display: inline-flex; align-items: center; gap: var(--sp-2); min-block-size: var(--d-ctl-h); padding-inline: var(--sp-4); border: 1px solid var(--c-line-strong); border-radius: var(--r-md); background: var(--c-surface); cursor: pointer; font-size: var(--fs-sm); }
.pt-segbtn input { position: absolute; opacity: 0; pointer-events: none; }
.pt-segbtn:has(input:checked) { background: var(--c-accent-weak); border-color: var(--c-accent); color: var(--c-accent); font-weight: var(--fw-semi); }
.pt-segbtn:has(input:focus-visible) { box-shadow: var(--focus-ring); }
.pt-seg .pt-segbtn { margin: 0; }
.pt-checklist { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--sp-4); max-block-size: 220px; overflow: auto; padding: var(--sp-2); border: 1px solid var(--c-line); border-radius: var(--r-md); margin-block-start: var(--sp-2); }
.pt-checklist .check { min-block-size: 30px; align-items: center; }
.pt-checklist .check input { margin: 0; }
.pt-natfind { inline-size: 100%; }
.pt-range { display: flex; align-items: center; gap: var(--sp-2); margin-block-start: var(--sp-2); }
.pt-range > * { flex: 1 1 0; min-inline-size: 0; }
.pt-range > span { flex: 0 0 auto; color: var(--c-ink-4); }
.pt-range .input { inline-size: 100%; }
.pt-sheet .select, .pt-sheet .input { inline-size: 100%; }
.pt-sheet .form-grid { margin-block-end: var(--sp-2); }
.pt-sheet .pt-range { margin-block-start: var(--sp-3); }

/* bulk bar */
.pt-bulkbar {
  position: sticky; inset-block-start: 0; z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4); margin-block-end: var(--sp-3);
  background: var(--c-accent-weak); border: 1px solid var(--c-accent-line); border-radius: var(--r-lg);
}
.pt-bulkbar__count { font-weight: var(--fw-semi); font-variant-numeric: var(--num-feat); margin-inline-end: auto; }

/* table */
.pt-tblwrap { transition: opacity var(--dur-2, .15s); }
.pt-tblwrap.is-busy { opacity: .5; pointer-events: none; }
.pt-tbl .pt-check { inline-size: 1%; text-align: center; padding-inline: var(--sp-3); }
.pt-tbl .pt-check input { inline-size: 16px; block-size: 16px; accent-color: var(--c-accent); vertical-align: middle; }
.pt-tbl tbody tr { cursor: pointer; }
.pt-tbl tbody tr.is-selected { background: var(--c-accent-weak); }
.pt-tbl tr.is-selected > td, [dir="rtl"] .pt-tbl tr.is-selected > td { box-shadow: none; }
.pt-tbl tr.is-selected > td:first-child { box-shadow: inset 3px 0 0 var(--c-accent); }
[dir="rtl"] .pt-tbl tr.is-selected > td:first-child { box-shadow: inset -3px 0 0 var(--c-accent); }
.pt-tbl tbody tr.is-cursor { box-shadow: inset 3px 0 0 var(--c-accent); }
:root[dir="rtl"] .pt-tbl tbody tr.is-cursor { box-shadow: inset -3px 0 0 var(--c-accent); }
.pt-tbl tbody tr.is-inactive .pt-name__primary { color: var(--c-ink-3); }
.pt-code { font-weight: var(--fw-semi); white-space: nowrap; }
.pt-name { min-inline-size: 200px; }
.pt-namecell { display: flex; align-items: center; gap: var(--sp-3); }
.pt-name__txt { display: flex; flex-direction: column; align-items: flex-start; gap: 0; min-inline-size: 0; }
.pt-name__primary { font-weight: var(--fw-medium); color: var(--c-ink); }
.pt-name__alt { font-size: var(--fs-xs); line-height: 1.3; }
.pt-avatar { flex: 0 0 auto; inline-size: 28px; block-size: 28px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--c-surface-3); color: var(--c-ink-3); }
.pt-roles { white-space: nowrap; }
.pt-roles .pill + .pill { margin-inline-start: var(--sp-1); }
.pt-email { max-inline-size: 220px; }
.pt-tbl .pt-actions { inline-size: 1%; text-align: end; white-space: nowrap; }
.pt-tbl td { white-space: nowrap; }
.pt-tbl td.pt-name { white-space: normal; }
.pt-pager { justify-content: flex-end; }
.pt-per { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); margin-inline-end: var(--sp-4); }
.pt-per .select { inline-size: auto; min-block-size: calc(var(--d-ctl-h) - 6px); }
.pt-emptycard { padding: 0; }
.pt-toasts { z-index: 95; }
@media (max-width: 1180px) { .pt-tbl [data-col="email"], .pt-tbl [data-col="nationality"], .pt-tbl [data-col="city"], .pt-tbl [data-col="credit"], .pt-tbl [data-col="created"] { display: none; } }
@media (max-width: 900px) {
  .pt-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pt-tbl .pt-check, .pt-tbl [data-col="roles"], .pt-tbl [data-col="spend"] { display: none; }
  .pt-tbl tbody td.pt-actions { justify-content: flex-end; }
  .pt-tbl tbody td.pt-actions::before { content: none; }
  .pt-tbl td.pt-name::before { content: none; }
  .pt-bulkbar { display: none !important; }
  .pt-filterbar .select { min-inline-size: 0; flex: 1 1 140px; }
}
@media (max-width: 600px) { .pt-kpis { display: none; } }

/* modal wrap */
.pt-modalwrap { z-index: 85; }
.pt-modalwrap .modal { max-block-size: 90vh; }
.pt-modalwrap .modal__head h3 { display: inline-flex; align-items: center; gap: var(--sp-2); }
.pt-presets { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-block-end: var(--sp-3); }
.pt-colgroups { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-4); }
.pt-colgroup__head { font-size: var(--fs-micro); font-weight: var(--fw-semi); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); margin-block-end: var(--sp-2); }
.pt-colgroup .check { min-block-size: 28px; align-items: center; font-size: var(--fs-sm); }
.pt-colgroup .check input { margin: 0; }
.pt-key { font-family: var(--font-num); font-size: var(--fs-micro); color: var(--c-ink-4); background: var(--c-surface-sunk); padding: 0 4px; border-radius: var(--r-xs); direction: ltr; unicode-bidi: isolate; }
.pt-expfmt { font-size: var(--fs-xs); }
@media (max-width: 760px) { .pt-colgroups { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* quick view */
.pt-pv__head { display: flex; gap: var(--sp-4); align-items: flex-start; margin-block-end: var(--sp-5); }
.pt-pv__name { font-size: var(--fs-lg); font-weight: var(--fw-semi); line-height: var(--lh-snug); }
.pt-pv__pills { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-block-start: var(--sp-2); }
.pt-pv__tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-block-end: var(--sp-5); gap: var(--sp-3); }
.pt-pv__v { font-size: var(--fs-lg); }
.pt-pv__h { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); margin: var(--sp-5) 0 var(--sp-2); }
.pt-pv__notes { white-space: pre-line; font-size: var(--fs-sm); background: var(--c-surface-2); border-radius: var(--r-md); padding: var(--sp-3); margin: 0; }
.pt-pv__foot { display: flex; gap: var(--sp-3); margin-block-start: var(--sp-6); }
#ptPreviewBody .skel--line { margin-block-end: var(--sp-4); }

/* ---- edit ------------------------------------------------------------ */
.pt-alert { margin-block-end: var(--sp-5); }
.pt-errlist { margin: var(--sp-2) 0 0; padding-inline-start: var(--sp-5); }
.pt-formlayout { display: grid; gap: var(--sp-5); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 1200px) {
  .pt-formlayout { grid-template-columns: minmax(0, 880px) 300px; }
  .pt-formaside { position: sticky; inset-block-start: var(--sp-4); }
}
.pt-formmain { display: flex; flex-direction: column; gap: var(--sp-5); min-inline-size: 0; }
.pt-formaside { display: flex; flex-direction: column; gap: var(--sp-4); }
.pt-section__title { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-md); font-weight: var(--fw-semi); margin: 0 0 var(--sp-5); }
.pt-section__n { inline-size: 24px; block-size: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--c-accent-weak); color: var(--c-accent); font-size: var(--fs-xs); font-family: var(--font-num); font-weight: var(--fw-bold); }
.pt-section.is-locked .pt-section__n { background: var(--c-surface-3); color: var(--c-ink-3); }
.pt-lockhint { margin-block: calc(-1 * var(--sp-3)) var(--sp-4); }
.pt-section .input, .pt-section .select, .pt-section .textarea, .pt-kycfield .select { inline-size: 100%; }
.pt-rolecards, .pt-creditmodes { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-3); }
.pt-rolecard { position: relative; display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-4); border: 1px solid var(--c-line-strong); border-radius: var(--r-lg); background: var(--c-surface); cursor: pointer; }
.pt-rolecard:hover { border-color: var(--c-accent-line); }
.pt-rolecard input { margin: 3px 0 0; inline-size: 16px; block-size: 16px; accent-color: var(--c-accent); flex: 0 0 auto; }
.pt-rolecard b { display: block; font-weight: var(--fw-semi); }
.pt-rolecard small { display: block; color: var(--c-ink-3); font-size: var(--fs-xs); margin-block-start: 2px; }
.pt-rolecard:has(input:checked) { border-color: var(--c-accent); background: var(--c-accent-weak); box-shadow: inset 0 0 0 1px var(--c-accent); }
.pt-rolecard:has(input:disabled) { cursor: not-allowed; opacity: .7; }
.pt-rolecard__ico { flex: 0 0 auto; inline-size: 36px; block-size: 36px; border-radius: var(--r-md); display: inline-flex; align-items: center; justify-content: center; background: var(--c-surface-3); color: var(--c-ink-2); }
.pt-rolecard:has(input:checked) .pt-rolecard__ico { background: var(--c-accent); color: var(--c-accent-ink); }
.pt-rolecard--radio { padding: var(--sp-3) var(--sp-4); }
.pt-creditamt { max-inline-size: 280px; margin-block-start: var(--sp-3); }
.input-group__addon { display: inline-flex; align-items: center; padding-inline: var(--sp-3); border: 1px solid var(--c-line-strong); background: var(--c-surface-2); color: var(--c-ink-3); font-size: var(--fs-sm); white-space: nowrap; }
.input-group .input-group__addon { border-inline-start: 0; }
.pt-counter { margin-inline-start: auto; font-size: var(--fs-micro); font-weight: var(--fw-regular); color: var(--c-ink-4); font-variant-numeric: var(--num-feat); }
.pt-counter.is-near { color: var(--c-warn); }
.pt-dupehint { color: var(--c-warn); }
.pt-asidecard { display: flex; flex-direction: column; gap: var(--sp-3); }
.pt-aside__row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-sm); }
.pt-kycfield { margin: 0; }
.pt-asidekv { font-size: var(--fs-sm); }
.pt-shortcuts { font-size: var(--fs-xs); gap: var(--sp-2); }
.pt-shortcuts__h { display: inline-flex; align-items: center; gap: var(--sp-2); }
.pt-savebar {
  position: sticky; inset-block-end: 0; z-index: 30;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  margin: var(--sp-5) calc(-1 * var(--d-gutter)) calc(-1 * var(--d-gutter));
  padding: var(--sp-3) var(--d-gutter);
  background: color-mix(in srgb, var(--c-surface) 94%, transparent);
  backdrop-filter: blur(6px);
  border-block-start: 1px solid var(--c-line); box-shadow: 0 -4px 16px rgba(5,34,65,.06);
}
.pt-savebar__state { font-size: var(--fs-sm); color: var(--c-ink-3); }
.pt-savebar.is-dirty .pt-savebar__state { color: var(--c-warn); font-weight: var(--fw-medium); }
.pt-savebar.is-dirty .pt-savebar__state::before { content: "\25CF\00A0"; }
.pt-ack { min-block-size: auto; align-items: center; font-weight: var(--fw-medium); color: var(--c-warn); }
.pt-ack input { margin: 0; }

/* ---- import ----------------------------------------------------------- */
.pt-steps { list-style: none; padding: 0; margin: 0 0 var(--sp-5); }
.pt-imp-grid { display: grid; gap: var(--sp-5); grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); align-items: start; }
@media (max-width: 1000px) { .pt-imp-grid { grid-template-columns: minmax(0, 1fr); } }
.pt-dropzone {
  position: relative; display: grid; place-items: center; gap: var(--sp-2);
  min-block-size: 220px; padding: var(--sp-6); text-align: center; cursor: pointer;
  border: 2px dashed var(--c-line-strong); border-radius: var(--r-lg); background: var(--c-surface-2);
  transition: border-color var(--dur-1, .1s), background var(--dur-1, .1s);
}
.pt-dropzone:hover, .pt-dropzone.is-over { border-color: var(--c-accent); background: var(--c-accent-weak); }
.pt-dropzone.has-file { border-style: solid; border-color: var(--c-success-line); background: var(--c-success-weak); }
.pt-dropzone input[type=file] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.pt-dropzone__ico { inline-size: 56px; block-size: 56px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--c-accent-weak); color: var(--c-accent); }
.pt-dropzone__title { font-weight: var(--fw-semi); font-size: var(--fs-md); }
.pt-formactions { display: flex; align-items: center; gap: var(--sp-3); margin-block-start: var(--sp-5); }
.pt-howto { margin: 0 0 var(--sp-4); padding-inline-start: var(--sp-5); display: grid; gap: var(--sp-2); font-size: var(--fs-sm); }
.pt-keys { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.pt-keys .pt-key { font-size: var(--fs-xs); padding: 2px 6px; }
.pt-filemeta { margin-inline-start: auto; font-size: var(--fs-xs); font-weight: var(--fw-regular); display: inline-flex; align-items: center; gap: var(--sp-2); }
.pt-maptbl .select { inline-size: 100%; min-inline-size: 220px; }
.pt-maphead { font-family: inherit !important; }
.pt-samples { max-inline-size: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs); }
.pt-imp-opts { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: var(--sp-6); margin-block-start: var(--sp-6); }
.pt-imp-opts .pt-rolecard { margin-block-end: var(--sp-2); }
@media (max-width: 900px) { .pt-imp-opts { grid-template-columns: minmax(0, 1fr); } }
.pt-revtbl td { vertical-align: top; }
.pt-row--err { background: var(--c-danger-weak); }
.pt-row--warn { background: var(--c-warn-weak); }
.pt-issues { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; font-size: var(--fs-xs); }
.pt-issue { display: flex; gap: var(--sp-2); align-items: baseline; }
.pt-issue--err { color: var(--c-danger); }
.pt-issue--warn { color: var(--c-warn); }
.pt-import .pt-savebar { margin-block-start: var(--sp-4); }
.pt-done .empty__ico { background: var(--c-success-weak); color: var(--c-success); border-color: var(--c-success-line); }
@media (forced-colors: active) { .pt-bulkbar, .pt-savebar, .pt-sheet, .pt-rolecard { border: 1px solid CanvasText; } }
@media print { .pt-bulkbar, .pt-savebar, .pt-sheet, .pt-kpis, .pt-colpick { display: none !important; } }

/* ---- 28b PARTNERS — extended profile ------------------------------------ */
.pt-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 900px) { .pt-edit .form-grid, .pt-edit .form-grid--3, .pt-grid-4 { grid-template-columns: minmax(0, 1fr) 1fr; } }
@media (max-width: 560px) { .pt-edit .form-grid, .pt-edit .form-grid--3, .pt-grid-4 { grid-template-columns: minmax(0, 1fr); } }
.pt-grid-names { grid-template-columns: 120px minmax(0, 1fr) minmax(0, 1fr); }
.pt-grid-names:has(> [data-when="individual"][hidden]) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
@media (max-width: 900px) { .pt-grid-names { grid-template-columns: minmax(0, 1fr); } }
.pt-subhead { display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-5) 0 var(--sp-3); padding-block-start: var(--sp-4); border-block-start: 1px dashed var(--c-line); font-size: var(--fs-xs); font-weight: var(--fw-semi); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); }
.pt-section > .pt-subhead:first-of-type { margin-block-start: 0; padding-block-start: 0; border: 0; }
.pt-checkrow { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-6); margin-block-end: var(--sp-4); }
.pt-inlinecheck { align-items: flex-start; min-block-size: auto; }
.pt-consents .label { display: inline-flex; align-items: center; gap: var(--sp-2); }
.pt-section.is-partlocked .field:has(:disabled) .label { color: var(--c-ink-3); }
.pt-ok { color: var(--c-success); font-family: var(--font-num); }
.pt-kbdhint { font-size: var(--fs-xs); }
@media (max-width: 700px) { .pt-kbdhint { display: none; } }

/* contacts repeater */
.pt-contacts { display: grid; gap: var(--sp-2); margin-block-end: var(--sp-3); }
.pt-contact { display: grid; grid-template-columns: 1.3fr 1fr 1fr 1.3fr auto auto; gap: var(--sp-2); align-items: center; padding: var(--sp-2); border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-surface-2); }
.pt-contact .input { inline-size: 100%; }
.pt-contact__primary { min-block-size: auto; align-items: center; white-space: nowrap; font-size: var(--fs-xs); }
.pt-contact__primary input { margin: 0; }
@media (max-width: 900px) { .pt-contact { grid-template-columns: 1fr 1fr; } }

/* tags */
.pt-tags { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); min-block-size: var(--d-ctl-h); padding: var(--sp-1) var(--sp-2); border: 1px solid var(--c-line-strong); border-radius: var(--r-md); background: var(--c-surface); cursor: text; }
.pt-tags:focus-within { border-color: var(--c-accent); box-shadow: var(--focus-ring); }
.pt-tags__chips { display: contents; }
.pt-tags__input { flex: 1 1 140px; min-inline-size: 120px; border: 0 !important; outline: 0; background: transparent !important; box-shadow: none !important; font: inherit; padding: var(--sp-1); color: var(--c-ink); }
.pt-tagchip { display: inline-flex; align-items: center; gap: 2px; padding: 1px var(--sp-2); border-radius: var(--r-pill); background: var(--c-accent-weak); border: 1px solid var(--c-accent-line); color: var(--c-accent); font-size: var(--fs-xs); font-weight: var(--fw-medium); text-decoration: none; white-space: nowrap; }
.pt-tagchip + .pt-tagchip { margin-inline-start: 2px; }
a.pt-tagchip:hover { text-decoration: none; background: var(--c-surface-3); }
.pt-tagchip__x { border: 0; background: transparent; color: inherit; cursor: pointer; padding: 0 2px; font-size: 14px; line-height: 1; }
.pt-tagchip--sm { font-size: var(--fs-micro); padding: 0 6px; }
.pt-tagcell { white-space: normal !important; max-inline-size: 220px; }

/* tier badge */
.pt-tier { display: inline-flex; align-items: center; padding: 0 var(--sp-2); border-radius: var(--r-sm); font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; border: 1px solid var(--c-line); color: var(--c-ink-3); background: var(--c-surface-2); line-height: 1.8; white-space: nowrap; }
.pt-tier--regular { border-color: transparent; background: transparent; font-weight: var(--fw-medium); text-transform: none; letter-spacing: 0; color: var(--c-ink-4); }
.pt-tier--silver { color: var(--c-ink-2); background: linear-gradient(135deg, var(--c-surface-2), var(--c-surface-3)); border-color: var(--c-line-strong); }
.pt-tier--gold { color: var(--c-metal); background: var(--c-metal-weak); border-color: var(--c-metal-line); }
.pt-tier--vip { color: var(--c-ink-inv); background: var(--c-surface-inv); border-color: var(--c-surface-inv); }
.pt-tier--mini { margin-inline-start: var(--sp-2); vertical-align: 1px; }
.pt-name__primary .pill { margin-inline-start: var(--sp-2); vertical-align: 1px; }

/* section navigator + completeness */
.pt-secnav { gap: var(--sp-3); }
.pt-secnav__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.pt-secnav__list a { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); color: var(--c-ink-2); font-size: var(--fs-sm); text-decoration: none; border-inline-start: 2px solid transparent; }
.pt-secnav__list a:hover { background: var(--c-surface-2); text-decoration: none; }
.pt-secnav__list a.is-active { background: var(--c-accent-weak); color: var(--c-accent); border-inline-start-color: var(--c-accent); font-weight: var(--fw-semi); }
.pt-secnav__list a span:first-of-type { flex: 1 1 auto; }
.pt-secnav__err { inline-size: 16px; block-size: 16px; border-radius: 50%; background: var(--c-danger); color: #fff; font-size: 10px; font-weight: var(--fw-bold); display: inline-flex; align-items: center; justify-content: center; }
.pt-meter { block-size: 6px; border-radius: var(--r-pill); background: var(--c-surface-3); overflow: hidden; margin-block-start: var(--sp-2); }
.pt-meter span { display: block; block-size: 100%; background: var(--c-warn); border-radius: inherit; transition: inline-size var(--dur-2) var(--ease); }
.pt-meter.is-good span { background: var(--c-success); }
@media (max-width: 1199px) { .pt-secnav { display: none; } }
.pt-section { scroll-margin-block-start: var(--sp-5); }

/* typeahead */
.pt-typeahead { position: relative; }
.pt-typeahead__list { inset-inline-start: 0; inset-inline-end: auto; min-inline-size: 100%; }
.pt-typeahead__list .menu__item { gap: var(--sp-3); }
.pt-fgroup__h { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); font-weight: var(--fw-semi); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-2); margin: 0 0 var(--sp-3); }
.pt-fgroup__h ~ .form-grid { margin-block-end: var(--sp-5); }
.pt-pv__contacts { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); font-size: var(--fs-sm); }
.pt-pv__contacts li { padding: var(--sp-2) var(--sp-3); background: var(--c-surface-2); border-radius: var(--r-md); }
/* ==========================================================================
   23b  MODULE 03 — SETTINGS › MASTERS  and  CATALOGUE › ITEM MASTER
   ms-* is shared by the six master screens; im-* is the item master list and
   its full-page editor. Tokens only; logical properties only; both themes.
   ========================================================================== */
.ms .page-head { padding-inline: 0; }
.ms-muted { color: var(--c-ink-3); }
.ms-small { font-size: var(--fs-xs); }
.ms-push { margin-inline-start: auto; }
.ms-alt { display: block; text-align: start; font-size: var(--fs-xs); color: var(--c-ink-3); line-height: 1.3; font-weight: var(--fw-regular); }
.ms-lock { display: inline-flex; color: var(--c-ink-3); vertical-align: -1px; margin-inline-start: var(--sp-2); }


/* list + edit panel */
.ms-split { display: grid; gap: var(--sp-5); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 1100px) {
  .ms-split { grid-template-columns: minmax(0, 1fr) 360px; }
  .ms-split--full { grid-template-columns: minmax(0, 1fr); }
  .ms-split--nav { grid-template-columns: 260px minmax(0, 1fr); }
  .ms-side { position: sticky; inset-block-start: var(--sp-4); }
}
@media (min-width: 1500px) { .ms-split { grid-template-columns: minmax(0, 1fr) 400px; } .ms-split--full { grid-template-columns: minmax(0, 1fr); } .ms-split--nav { grid-template-columns: 260px minmax(0, 1fr); } }
.ms-side, .ms-stack { display: flex; flex-direction: column; gap: var(--sp-5); min-inline-size: 0; }
.ms-listcard { overflow: hidden; }
.ms-cardhead { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-4) var(--sp-5); border-block-end: 1px solid var(--c-line-soft); }
.ms-cardhead > div { min-inline-size: 0; margin-inline-end: auto; }
.ms-cardhead__title { font-size: var(--fs-md); font-weight: var(--fw-semi); margin: 0; }
.ms-cardhead__sub { margin: var(--sp-1) 0 0; font-size: var(--fs-xs); color: var(--c-ink-3); display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.ms-cardfoot { display: flex; align-items: center; gap: var(--sp-2); margin: 0; padding: var(--sp-3) var(--sp-5); font-size: var(--fs-xs); color: var(--c-ink-3); border-block-start: 1px solid var(--c-line-soft); }
.ms-panel__body { padding: var(--sp-5); }
.ms-panel__body > .field:last-child, .ms-panel__body .form-grid:last-child .field { margin-block-end: 0; }
.ms-panel__foot { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-3); padding: var(--sp-3) var(--sp-5); border-block-start: 1px solid var(--c-line-soft); background: var(--c-surface-2); border-end-start-radius: var(--r-lg); border-end-end-radius: var(--r-lg); }
.ms-alert { margin: 0 0 var(--sp-4); }
.ms-panel .input, .ms-panel .select, .ms-panel .textarea { inline-size: 100%; }
.ms-tbl td { vertical-align: middle; }
.ms-tbl tbody tr[data-href] { cursor: pointer; }
.ms-tbl tbody tr.is-selected { background: var(--c-accent-weak); }
.ms-tbl tr.is-selected > td, [dir="rtl"] .ms-tbl tr.is-selected > td { box-shadow: none; }
.ms-tbl tbody tr.is-selected > td:first-child { box-shadow: inset 3px 0 0 var(--c-accent); }
[dir="rtl"] .ms-tbl tbody tr.is-selected > td:first-child { box-shadow: inset -3px 0 0 var(--c-accent); }
.ms-tbl tbody tr.is-inactive { color: var(--c-ink-3); }
.ms-switch { align-items: flex-start; }
.ms-switch__text { display: flex; flex-direction: column; font-size: var(--fs-sm); }
.ms-switch__text small { color: var(--c-ink-3); font-size: var(--fs-xs); }
.ms-inline3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
.ms-details { border: 1px solid var(--c-line); border-radius: var(--r-md); margin-block-start: var(--sp-3); }
.ms-details > summary { cursor: pointer; padding: var(--sp-3) var(--sp-4); font-weight: var(--fw-medium); }
.ms-checkgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0 var(--sp-4); padding: 0 var(--sp-4) var(--sp-3); }
.ms-checkgrid .check { min-block-size: 30px; align-items: center; }
.ms-checkgrid .check input { margin: 0; }

/* metals */
.ms-metalcards { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); margin-block-end: var(--sp-5); }
.ms-metalcard { display: flex; flex-direction: column; gap: var(--sp-4); color: inherit; transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease); }
.ms-metalcard:hover { text-decoration: none; border-color: var(--c-accent-line); }
.ms-metalcard.is-on { border-color: var(--c-accent); box-shadow: inset 0 0 0 1px var(--c-accent), var(--sh-2); }
.ms-metalcard.is-off { opacity: .7; }
.ms-metalcard__head { display: flex; align-items: flex-start; gap: var(--sp-3); }
.ms-metalcard__name { display: flex; flex-direction: column; margin-inline-end: auto; min-inline-size: 0; }
.ms-metalcard__name b { font-size: var(--fs-md); }
.ms-metalcard__rates { display: flex; gap: var(--sp-6); }
.ms-metalcard__rates > span { display: flex; flex-direction: column; }
.ms-metalcard__rates small { font-size: var(--fs-micro); color: var(--c-ink-3); text-transform: uppercase; letter-spacing: var(--tracking-caps); }
.ms-metalcard__rates b { font-family: var(--font-num); font-size: var(--fs-lg); direction: ltr; unicode-bidi: isolate; }
.ms-metalcard__foot { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-xs); color: var(--c-ink-3); padding-block-start: var(--sp-3); border-block-start: 1px dashed var(--c-line); }
.ms-swatch { flex: 0 0 auto; inline-size: 34px; block-size: 34px; border-radius: var(--r-md); background: linear-gradient(135deg, #e7ecef, #7d8a94); box-shadow: inset 0 -3px 6px rgba(0,0,0,.18), inset 0 2px 3px rgba(255,255,255,.55); }
.ms-swatch--gold { background: linear-gradient(135deg, #f3d98b, #b8862f); }
.ms-swatch--silver { background: linear-gradient(135deg, #f4f6f8, #9aa4ad); }
.ms-swatch--platinum { background: linear-gradient(135deg, #e7ecef, #7d8a94); }
.ms-swatch--palladium { background: linear-gradient(135deg, #eceae4, #8f8a7c); }
.ms-swatch--rosegold, .ms-swatch--copper { background: linear-gradient(135deg, #f4d0c4, #b9745e); }
.ms-fineness { border: 0; padding: 0; margin: 0 0 var(--sp-4); min-inline-size: 0; }
.ms-fineness .pt-seg { margin-block-end: var(--sp-3); }
.ms-fineness.is-invalid .input { border-color: var(--c-danger); background: var(--c-danger-weak); }
.ms-readout { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-block-start: var(--sp-3); border: 1px solid var(--c-line); border-radius: var(--r-md); overflow: hidden; }
.ms-readout > span { display: flex; flex-direction: column; padding: var(--sp-3); border-inline-end: 1px solid var(--c-line-soft); }
.ms-readout > span:last-child { border-inline-end: 0; }
.ms-readout small { font-size: var(--fs-micro); color: var(--c-ink-3); }
.ms-readout b { font-family: var(--font-num); direction: ltr; unicode-bidi: isolate; }
.ms-readout .is-metal { background: var(--c-metal-weak); }

/* collections */
.ms-cover--navy { background: linear-gradient(135deg, #052241, #1b5a85); }
.ms-cover--gold { background: linear-gradient(135deg, #7a5a20, #c89b45); }
.ms-cover--rose { background: linear-gradient(135deg, #7a1f3d, #c2566f); }
.ms-cover--green { background: linear-gradient(135deg, #14563d, #4a9a78); }
.ms-cover--violet { background: linear-gradient(135deg, #53307e, #9474c4); }
.ms-cover--slate { background: linear-gradient(135deg, #2e4459, #6d8296); }
.ms-cover--red { background: linear-gradient(135deg, #8f1f1a, #d0564f); }
.ms-swatches { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.ms-swatchpick { position: relative; inline-size: 34px; block-size: 34px; border-radius: var(--r-md); cursor: pointer; }
.ms-swatchpick input { position: absolute; opacity: 0; }
.ms-swatchpick:has(input:checked) { box-shadow: 0 0 0 2px var(--c-surface), 0 0 0 4px var(--c-accent); }
.ms-swatchpick:has(input:focus-visible) { outline: 2px solid var(--c-accent); outline-offset: 3px; }

/* value lists & grades */
.ms-listnav { display: flex; flex-direction: column; padding: var(--sp-2); }
.ms-listnav__item { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); color: inherit; }
.ms-listnav__item > span:first-child { display: flex; flex-direction: column; gap: var(--sp-1); min-inline-size: 0; }
.ms-listnav__item:hover { background: var(--c-surface-2); text-decoration: none; }
.ms-listnav__item.is-on { background: var(--c-accent-weak); box-shadow: inset 3px 0 0 var(--c-accent); }
[dir="rtl"] .ms-listnav__item.is-on { box-shadow: inset -3px 0 0 var(--c-accent); }
.ms-listnav__item.is-inactive b { color: var(--c-ink-3); }

/* stones */
.ms-bandbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding: var(--sp-3) var(--sp-5); border-block-end: 1px solid var(--c-line-soft); background: var(--c-surface-2); }
.ms-bandbar .label { margin: 0 var(--sp-2) 0 0; }
.ms-legend { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--c-ink-3); }
.ms-legend i { inline-size: 80px; block-size: 8px; border-radius: var(--r-pill); background: linear-gradient(90deg, var(--c-accent-weak), var(--c-accent)); }
.ms-matrixwrap { margin-block-start: var(--sp-3); }
.ms-matrix { border-collapse: separate; border-spacing: 0; inline-size: 100%; font-family: var(--font-num); }
.ms-matrix th { padding: var(--sp-3); font-size: var(--fs-xs); color: var(--c-ink-3); background: var(--c-surface-2); border-block-end: 1px solid var(--c-line); text-align: center; white-space: nowrap; }
.ms-matrix tbody th { border-inline-end: 1px solid var(--c-line); text-align: start; }
.ms-matrix__corner { text-align: start !important; }
.ms-matrix td { padding: 0; border-block-end: 1px solid var(--c-line-soft); border-inline-end: 1px solid var(--c-line-soft);
  background: color-mix(in srgb, var(--c-accent) calc(var(--heat, 0) * 78%), var(--c-surface)); }
.ms-matrix td input { inline-size: 100%; min-inline-size: 64px; block-size: 34px; border: 0; background: transparent; text-align: end; padding: 0 var(--sp-3); font: inherit; font-size: var(--fs-sm); color: var(--c-ink); direction: ltr; }
.ms-matrix td.is-hot input { color: #fff; }
.ms-matrix td input:focus { outline: 2px solid var(--c-accent); outline-offset: -2px; background: var(--c-surface); color: var(--c-ink); }
.ms-matrix td.is-dirty input { box-shadow: inset 0 -2px 0 var(--c-warn); }
.ms-resolver { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) auto; gap: var(--sp-4); align-items: end; }
.ms-resolver .field { margin: 0; }
.ms-resolved { margin: 0 var(--sp-5) var(--sp-5); }

/* ---------------------------------------------------------- item master */






@media (max-width: 720px) {
  .ms-readout, .ms-resolver, .ms-inline3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      }


/* ==========================================================================
   31  MODULE SHELL — app launcher, module bar, module dashboards, Settings app,
       roles & permissions (Odoo-style navigation, 16 Sep 2026)
   The rail is replaced by ONE bar across the top. The grid button returns to
   the launcher; inside a module the bar carries only that module's menus.
   Tokens only, logical properties only, so RTL is free.
   ========================================================================== */
:root {
  --c-modbar: var(--navy-11);
  --c-modbar-ink: #ffffff;
  --c-modbar-ink-2: var(--navy-04);
  --c-modbar-hover: rgba(255,255,255,.10);
  --c-modbar-active: var(--blue-05);
  /* One hue per module, mid-chroma so white glyphs pass 4.5:1 and the set sits
     beside the navy instead of shouting over it. */
  --mod-sales: #1b5a85;      --mod-customers: #2e7a64;  --mod-inventory: #7a6326;
  --mod-rates: #9a7418;      --mod-purchasing: #6f4d8a; --mod-workshop: #9a5231;
  --mod-accounting: #3f5596; --mod-reports: #3a6a9e;    --mod-online: #2c7f8c;
  --mod-settings: #4d6072;   --mod-overview: #5b7086;   --mod-brand: #052241;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --c-modbar: var(--navy-12); --c-modbar-hover: rgba(118,186,229,.14); }
}
:root[data-theme="dark"] { --c-modbar: var(--navy-12); --c-modbar-hover: rgba(118,186,229,.14); }

/* --- the grid: no rail column any more ------------------------------------ */
.app.app--modbar, html.jt-rail-collapsed .app.app--modbar {
  grid-template-columns: minmax(0,1fr);
  grid-template-rows: auto var(--topbar-h) minmax(0,1fr);
  grid-template-areas: "banner" "topbar" "main";
}

/* --- the module mark (launcher tile, bar, headings) ----------------------- */
.app-mark {
  --mark: var(--mod-overview);
  position: relative; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 64px; block-size: 64px; border-radius: 18px;
  background: var(--mark); color: #fff;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,.14), var(--sh-1);
}
.app-mark .ico { inline-size: 30px; block-size: 30px; stroke-width: 1.6; }
.app-mark--sm { inline-size: 28px; block-size: 28px; border-radius: 8px; box-shadow: none; }
.app-mark--sm .ico { inline-size: 16px; block-size: 16px; }
.app-mark--xs { inline-size: 22px; block-size: 22px; border-radius: 6px; box-shadow: none; }
.app-mark--xs .ico { inline-size: 13px; block-size: 13px; }
.app-mark--sales { --mark: var(--mod-sales); }         .app-mark--customers { --mark: var(--mod-customers); }
.app-mark--inventory { --mark: var(--mod-inventory); } .app-mark--rates { --mark: var(--mod-rates); }
.app-mark--purchasing { --mark: var(--mod-purchasing); } .app-mark--workshop { --mark: var(--mod-workshop); }
.app-mark--accounting { --mark: var(--mod-accounting); } .app-mark--reports { --mark: var(--mod-reports); }
.app-mark--online { --mark: var(--mod-online); }       .app-mark--settings { --mark: var(--mod-settings); }
.app-mark--overview { --mark: var(--mod-overview); }   .app-mark--brand { --mark: var(--c-modbar-active); color: var(--navy-11); }


.app-mark__lock {
  position: absolute; inset-block-start: -6px; inset-inline-end: -6px;
  inline-size: 22px; block-size: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--c-surface); color: var(--c-ink-2); border: 1px solid var(--c-line);
}
.app-mark__lock .ico { inline-size: 12px; block-size: 12px; }

/* --- the bar ---------------------------------------------------------------- */
.modbar {
  grid-area: topbar; position: relative; z-index: 40;
  display: flex; align-items: center; gap: var(--sp-2);
  block-size: var(--topbar-h); padding-inline: var(--sp-3);
  background: var(--c-modbar); color: var(--c-modbar-ink);
  border-block-end: 1px solid rgba(118,186,229,.18);
}
.modbar a { color: inherit; text-decoration: none; }
.modbar .ico { stroke: currentColor; }
.modbar__apps, .modbar__burger, .modbar__icon, .modbar__user, .modbar__search, .modbar__ctx {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-block-size: 38px; min-inline-size: 38px; padding-inline: var(--sp-3);
  background: transparent; border: 0; border-radius: var(--r-md);
  color: var(--c-modbar-ink); font: inherit; cursor: pointer;
}
.modbar__apps:hover, .modbar__burger:hover, .modbar__icon:hover, .modbar__user:hover,
.modbar__search:hover, .modbar__ctx:hover, .modbar__ctx[aria-expanded="true"], .modbar__user[aria-expanded="true"] { background: var(--c-modbar-hover); }
.modbar :focus-visible { outline: none; box-shadow: var(--focus-ring-inv); }
.modbar__apps { padding-inline: var(--sp-3); }
.modbar__app {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding-inline: var(--sp-2) var(--sp-4); min-block-size: 38px; border-radius: var(--r-md);
  font-size: var(--fs-md); font-weight: var(--fw-semi); white-space: nowrap;
}
.modbar__app:hover { background: var(--c-modbar-hover); }
.modbar__burger { display: none; }
.modbar__menus { display: flex; align-items: center; gap: var(--sp-1); min-inline-size: 0; flex: 0 1 auto; }
.modbar__menu { position: relative; }
.modbar__link {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: 38px; padding-inline: var(--sp-3);
  background: transparent; border: 0; border-radius: var(--r-md);
  color: var(--c-modbar-ink-2); font: inherit; font-size: var(--fs-base); font-weight: var(--fw-medium);
  white-space: nowrap; cursor: pointer; position: relative;
}
.modbar__link:hover, .modbar__link[aria-expanded="true"] { background: var(--c-modbar-hover); color: var(--c-modbar-ink); }
.modbar__link.is-active { color: var(--c-modbar-ink); }
.modbar__link.is-active::after {
  content: ""; position: absolute; inset-inline: var(--sp-3); inset-block-end: -9px;
  block-size: 3px; border-radius: 3px 3px 0 0; background: var(--c-modbar-active);
}
.modbar__link.is-locked { opacity: .7; }
.modbar__drop {
  position: absolute; inset-block-start: calc(100% + 8px); inset-inline-start: 0; z-index: 60;
  min-inline-size: 240px; padding: var(--sp-2);
  background: var(--c-surface); color: var(--c-ink);
  border: 1px solid var(--c-line); border-radius: var(--r-lg); box-shadow: var(--sh-3);
}
.modbar__drop--end { inset-inline-start: auto; inset-inline-end: 0; }
.modbar__drop[hidden] { display: none; }
/* never taller than the window: a long list scrolls inside the menu (2026-10-08) */
.modbar__drop { max-block-size: calc(100dvh - var(--topbar-h) - 16px); overflow-y: auto; overscroll-behavior: contain; }
/* a long menu in two columns, each labelled run kept whole (main.php) */
.modbar__drop--cols { inline-size: max-content; min-inline-size: 460px; }
/* the columns sit inside, so a short window scrolls the menu down, never sideways */
.modbar__cols { columns: 2; column-gap: var(--sp-3); }
.modbar__cols .modbar__run { break-inside: avoid; padding-block-end: var(--sp-2); }
.modbar__cols > .modbar__item { break-inside: avoid; }
/* opened too near the window's edge (nav.js): it grows towards the inside */
.modbar__drop--flip { inset-inline-start: auto; inset-inline-end: 0; }
.modbar .modbar__item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  min-block-size: var(--hit); padding-inline: var(--sp-3); border-radius: var(--r-sm);
  color: var(--c-ink); font-size: var(--fs-base);
}
.modbar .modbar__item:hover, .modbar .modbar__item:focus-visible { background: var(--c-surface-2); box-shadow: none; }
.modbar .modbar__item.is-active { background: var(--c-accent-weak); color: var(--c-accent); font-weight: var(--fw-semi); }
.modbar .modbar__item.is-locked { color: var(--c-ink-3); }
.modbar__sid { font-family: var(--font-num); font-size: var(--fs-micro); color: var(--c-ink-4); }
.modbar__tier { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-xs); color: var(--c-ink-3); }
.modbar__sep { block-size: 1px; background: var(--c-line); margin: var(--sp-2) 0; }
/* A labelled run inside a module menu — statements, then the audit trail, then
   the partner ledgers. It is a caption, not a row: nothing here is clickable. */
.modbar__grp {
  margin: var(--sp-3) 0 var(--sp-1); padding-inline: var(--sp-3);
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--c-ink-3);
}
.modbar__grp:first-child { margin-block-start: 0; }
.modbar__search .kbd { background: transparent; color: var(--c-modbar-ink-2); border-color: rgba(255,255,255,.3); }
.modbar__rate {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: 32px; padding-inline: var(--sp-3); border-radius: var(--r-pill);
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.16);
  font-size: var(--fs-sm); white-space: nowrap;
}
.modbar__rate:hover { background: var(--c-modbar-hover); }
.modbar__rate .rate-pill__metal, .modbar__rate .rate-pill__unit, .modbar__rate .rate-pill__sep { color: var(--c-modbar-ink-2); }
.modbar__rate .rate-pill__value { color: var(--c-modbar-ink); }
.modbar__rate .rate-pill__asof { color: var(--c-modbar-ink-2); }
.modbar__rate.rate-pill--stale { border-color: #e0a94f; }
.modbar__rate.rate-pill--stale .rate-pill__age { color: #f3c67a; font-weight: var(--fw-semi); }
.modbar__rate.rate-pill--missing { border-color: #f08a80; color: #ffd1cc; }
.modbar__rate.rate-pill--stale::before, .modbar__rate.rate-pill--missing::before { font-size: 11px; }
.modbar__rate.rate-pill--stale::before { content: "\26A0"; }
.modbar__rate.rate-pill--missing::before { content: "\2298"; }
.modbar__ctx { max-inline-size: 220px; font-size: var(--fs-sm); }
.modbar__ctx-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.modbar__pop { min-inline-size: 260px; color: var(--c-ink); }
.modbar__pop .menu__item { color: var(--c-ink); }
.modbar__pop .menu__item.is-current { background: var(--c-accent-weak); font-weight: var(--fw-semi); }
.modbar__pop-note { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-xs); color: var(--c-ink-3); max-inline-size: 280px; }
.modbar .jt-pop .menu__item { color: var(--c-ink); }
.modbar .avatar { background: var(--c-modbar-active); color: var(--navy-11); }
.modbar .bell { color: var(--c-modbar-ink); }

@media (max-width: 1180px) { .modbar__rate .rate-pill__sep, .modbar__rate .rate-pill__value + .rate-pill__sep + .rate-pill__value { display: none; } }
@media (max-width: 1023px) {
  .modbar__rate { display: none; }
  .modbar__burger { display: inline-flex; }
  .modbar__menus {
    display: none; position: absolute; inset-block-start: 100%; inset-inline: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: var(--sp-3); background: var(--c-modbar); box-shadow: var(--sh-4);
    max-block-size: calc(100dvh - var(--topbar-h)); overflow: auto;
  }
  .modbar__menus.is-open { display: flex; }
  .modbar__menus .modbar__link { justify-content: space-between; inline-size: 100%; }
  .modbar__menus .modbar__link.is-active::after { display: none; }
  .modbar__menus .modbar__link.is-active { background: var(--c-modbar-hover); }
  .modbar__drop { position: static; box-shadow: none; margin: var(--sp-1) 0 var(--sp-3); max-block-size: none; overflow: visible; min-inline-size: 0; inline-size: auto; }
  .modbar__cols { columns: auto; }
  .modbar__ctx-name { display: none; }
}
/* A module whose menus do not fit the bar folds them behind the burger (nav.js
   measures; the media query above is the no-JS floor). */
.modbar.modbar--folded .modbar__burger { display: inline-flex; }
.modbar.modbar--folded .modbar__menus {
    display: none; position: absolute; inset-block-start: 100%; inset-inline: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: var(--sp-3); background: var(--c-modbar); box-shadow: var(--sh-4);
    max-block-size: calc(100dvh - var(--topbar-h)); overflow: auto;
  }
.modbar.modbar--folded .modbar__menus.is-open { display: flex; }
.modbar.modbar--folded .modbar__menus .modbar__link { justify-content: space-between; inline-size: 100%; }
.modbar.modbar--folded .modbar__menus .modbar__link.is-active::after { display: none; }
.modbar.modbar--folded .modbar__menus .modbar__link.is-active { background: var(--c-modbar-hover); }
.modbar.modbar--folded .modbar__drop { position: static; box-shadow: none; margin: var(--sp-1) 0 var(--sp-3); max-block-size: none; overflow: visible; min-inline-size: 0; inline-size: auto; }
.modbar.modbar--folded .modbar__cols { columns: auto; }
@media (max-width: 600px) { .modbar__name { display: none; } .modbar__search .kbd { display: none; } }

/* --- no breadcrumb row under the bar (2026-10-07): the page's first line is its
   own title or control panel — grid.css §1 (.pagebar, .cp-path). ------------- */

/* --- the launcher ------------------------------------------------------------ */
.launch { max-inline-size: 1040px; margin: 0 auto; padding: var(--sp-7) 0 var(--sp-8); }
.launch__head { text-align: center; display: grid; justify-items: center; gap: var(--sp-3); margin-block-end: var(--sp-7); }
.launch__hello { margin: 0; font-size: var(--fs-2xl); font-weight: var(--fw-semi); letter-spacing: var(--tracking-tight); text-wrap: balance; }
.launch__sub { margin: 0; color: var(--c-ink-3); }
.launch__search {
  display: flex; align-items: center; gap: var(--sp-3); inline-size: min(520px, 100%); margin-block-start: var(--sp-4);
  min-block-size: 44px; padding-inline: var(--sp-5); border-radius: var(--r-pill);
  background: var(--c-surface); border: 1px solid var(--c-line-strong); color: var(--c-ink-3); box-shadow: var(--sh-1);
}
.launch__search:focus-within { border-color: var(--c-accent); box-shadow: var(--focus-ring); }
.launch__search input { flex: 1 1 auto; border: 0; outline: 0; background: transparent; font: inherit; color: var(--c-ink); min-inline-size: 0; }
.launch__grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: var(--sp-6) var(--sp-4);
}
.launch__cell[hidden] { display: none; }
.app-tile {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-3); border-radius: var(--r-xl); text-align: center;
  color: var(--c-ink); text-decoration: none; transition: background var(--dur-2) var(--ease);
}
.app-tile:hover, .app-tile:focus-visible { background: var(--c-surface); box-shadow: var(--sh-2); text-decoration: none; outline: none; }
.app-tile:focus-visible { box-shadow: var(--focus-ring); }
.app-tile .app-mark { transition: transform var(--dur-2) var(--ease); }
.app-tile:hover .app-mark { transform: translateY(-2px); }
.app-tile__name { font-weight: var(--fw-semi); font-size: var(--fs-md); }
.app-tile__desc { font-size: var(--fs-xs); color: var(--c-ink-3); line-height: var(--lh-snug); max-inline-size: 22ch; }
.app-tile.is-locked .app-mark { filter: saturate(.35); opacity: .75; }
.launch__none, .launch__empty { text-align: center; color: var(--c-ink-3); margin-block-start: var(--sp-6); }
@media (max-width: 520px) {
  .launch { padding-block-start: var(--sp-5); }
  .launch__grid { grid-template-columns: repeat(3, minmax(0,1fr)); gap: var(--sp-4) var(--sp-2); }
  .app-tile .app-mark { inline-size: 54px; block-size: 54px; border-radius: 15px; }
  .app-tile__desc { display: none; }
}

/* --- a module dashboard -------------------------------------------------- */
.modpage { display: grid; gap: var(--sp-6); padding-block-start: var(--sp-3); }
.modpage__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-5); }
.modpage__head .app-mark { inline-size: 52px; block-size: 52px; border-radius: 14px; }
.modpage__head .app-mark .ico { inline-size: 26px; block-size: 26px; }
.modpage__titles { flex: 1 1 280px; min-inline-size: 0; }
.modpage__title { margin: 0; font-size: var(--fs-xl); font-weight: var(--fw-semi); }
.modpage__desc { margin: var(--sp-1) 0 0; color: var(--c-ink-3); max-inline-size: 70ch; }
.modpage__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.modpage__kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-4); }
.modkpi {
  display: grid; gap: var(--sp-1); padding: var(--sp-5);
  background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg);
  color: var(--c-ink); text-decoration: none; position: relative; overflow: hidden;
}
.modkpi:hover { border-color: var(--c-accent-line); box-shadow: var(--sh-2); text-decoration: none; }
.modkpi__label { font-size: var(--fs-xs); font-weight: var(--fw-semi); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--c-ink-3); }
.modkpi__value { font-size: var(--fs-2xl); font-weight: var(--fw-semi); font-family: var(--font-num); font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate; text-align: start; }
/* The figure box stays LTR so digits never reverse, but in Arabic it sits under
   its right-aligned label rather than at the far left of the card. */
[dir="rtl"] .tile__value, [dir="rtl"] .modkpi__value { text-align: right; }
.modkpi__sep { color: var(--c-ink-4); font-weight: var(--fw-regular); }
.modkpi__unit { font-size: var(--fs-xs); color: var(--c-ink-3); }
.modkpi--warn { border-inline-start: 4px solid var(--c-warn); }
.modkpi--danger { border-inline-start: 4px solid var(--c-danger); }
.modkpi--warn .modkpi__label::after { content: " \26A0"; color: var(--c-warn); }
.modkpi--danger .modkpi__label::after { content: " \25CF"; color: var(--c-danger); }
.modpage__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--sp-4); align-items: start; }
.modcard { background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-3) var(--sp-3); }
.modcard__title { display: flex; align-items: center; gap: var(--sp-2); margin: 0 var(--sp-2) var(--sp-2); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--c-ink-3); }
.modcard__list { list-style: none; margin: 0; padding: 0; }
/* A heading inside a module card's list, for a section long enough to need one.
   Same job and same weight as `.modbar__grp` in the dropdown, so a reader meets
   one vocabulary in both places. */
.modcard__grp {
  margin-block-start: var(--sp-3); padding-inline: var(--sp-1);
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--c-ink-3);
}
.modcard__grp:first-child { margin-block-start: 0; }
.modcard__link { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3); min-block-size: var(--hit); padding-inline: var(--sp-2); border-radius: var(--r-sm); color: var(--c-ink); }
.modcard__link:hover { background: var(--c-surface-2); text-decoration: none; }
.modcard__link.is-locked { color: var(--c-ink-3); }
.modcard__meta { display: inline-flex; align-items: center; gap: var(--sp-1); font-family: var(--font-num); font-size: var(--fs-micro); color: var(--c-ink-4); white-space: nowrap; }
.modcard--config { background: var(--c-surface-2); border-style: dashed; }

/* --- Settings app ----------------------------------------------------------- */
.setapp { display: grid; grid-template-columns: 220px minmax(0,1fr); gap: var(--sp-6); align-items: start; }
.setapp--single { grid-template-columns: minmax(0,1fr); }
.setapp__side { position: sticky; inset-block-start: var(--sp-4); display: grid; gap: var(--sp-1); padding-block-start: var(--sp-2); }
.setapp__nav { display: flex; align-items: center; gap: var(--sp-3); min-block-size: 36px; padding-inline: var(--sp-3); border-radius: var(--r-md); color: var(--c-ink-2); font-weight: var(--fw-medium); }
.setapp__nav:hover { background: var(--c-surface); text-decoration: none; }
.setapp__nav.is-active { background: var(--c-accent-weak); color: var(--c-accent); font-weight: var(--fw-semi); }
.setapp__main { min-inline-size: 0; display: grid; gap: var(--sp-5); }
.setapp__bar {
  position: sticky; inset-block-start: 0; z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) 0; background: var(--c-bg); border-block-end: 1px solid var(--c-line);
}
.setapp__title { margin: 0; margin-inline-end: var(--sp-3); font-size: var(--fs-lg); font-weight: var(--fw-semi); }
.setapp__dirty { font-size: var(--fs-sm); color: var(--c-warn); font-weight: var(--fw-semi); }
.setapp__search { margin-inline-start: auto; display: flex; align-items: center; gap: var(--sp-2); min-block-size: var(--d-ctl-h); padding-inline: var(--sp-3); border: 1px solid var(--c-line-strong); border-radius: var(--r-pill); background: var(--c-surface); color: var(--c-ink-3); inline-size: min(280px, 100%); }
.setapp__search input { border: 0; outline: 0; background: transparent; font: inherit; color: var(--c-ink); inline-size: 100%; }
.setapp__none { color: var(--c-ink-3); }
.setsec { background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg); padding: var(--sp-5) var(--sp-6) var(--sp-6); scroll-margin-block-start: 72px; }
.setsec[hidden] { display: none; }
.setsec__title { display: flex; align-items: center; gap: var(--sp-3); margin: 0 0 var(--sp-2); font-size: var(--fs-md); font-weight: var(--fw-semi); }
.setsec__open { margin-inline-start: auto; font-size: var(--fs-sm); font-weight: var(--fw-regular); }
.setsec__group { display: flex; align-items: baseline; gap: var(--sp-3); margin: var(--sp-5) 0 var(--sp-2); padding-block-end: var(--sp-2); border-block-end: 1px solid var(--c-line); font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--c-ink-3); }
.setsec__grouplink { margin-inline-start: auto; font-size: var(--fs-xs); font-weight: var(--fw-medium); letter-spacing: 0; text-transform: none; }
.setsec__rows { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 0 var(--sp-6); }
@media (max-width: 860px) { .setsec__rows { grid-template-columns: 1fr; } .setapp { grid-template-columns: 1fr; } .setapp__side { position: static; display: flex; overflow-x: auto; } .setapp__nav { white-space: nowrap; } }
.setrow { display: grid; grid-template-columns: minmax(0,1fr) auto; grid-template-areas: "label input" "hint input"; align-items: center; gap: 0 var(--sp-4); padding: var(--sp-3) 0; border-block-end: 1px solid var(--c-line-soft); }
.setrow[hidden] { display: none; }
.setrow__label { grid-area: label; font-weight: var(--fw-semi); color: var(--c-ink); }
.setrow__hint { grid-area: hint; margin: 0; font-size: var(--fs-xs); color: var(--c-ink-3); }
.setrow__input { grid-area: input; inline-size: 200px; }
.setrow__input.input--num { inline-size: 120px; }
/* a yes/no preference: the switch sits where the input would, with its own word */
.setrow__check { grid-area: input; display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--c-ink-2); }
.setrow__check input { inline-size: 16px; block-size: 16px; accent-color: var(--c-accent); }
.setrow--link { color: var(--c-ink); border-radius: var(--r-sm); padding-inline: var(--sp-2); }
.setrow--link:hover { background: var(--c-surface-2); text-decoration: none; }
.setrow__go { grid-area: input; color: var(--c-ink-4); }
[dir="rtl"] .setrow__go { transform: scaleX(-1); }
.setsec__access { margin-block-start: var(--sp-2); }
.access-mini th, .access-mini td { vertical-align: middle; }
.access-mini__perm { font-size: var(--fs-xs); white-space: normal; min-inline-size: 90px; max-inline-size: 140px; line-height: var(--lh-snug); }
.access-mini__cell { text-align: center; }
.acc-yes { color: var(--c-success); font-weight: var(--fw-bold); }
.acc-no { color: var(--c-ink-4); }
.acc-chip { display: inline-flex; align-items: center; gap: var(--sp-1); margin: 1px; padding: 1px var(--sp-3); border-radius: var(--r-pill); font-size: var(--fs-xs); white-space: nowrap; border: 1px solid; }
.acc-chip--grant { color: var(--c-success); background: var(--c-success-weak); border-color: var(--c-success-line); }
.acc-chip--deny { color: var(--c-danger); background: var(--c-danger-weak); border-color: var(--c-danger-line); }

/* --- Roles list --------------------------------------------------------------- */
.rolepage { display: grid; gap: var(--sp-5); }
.rolepage__head { padding: 0; }
.rolehow { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: var(--sp-4); }
@media (max-width: 860px) { .rolehow { grid-template-columns: 1fr; } }
.rolehow__step { display: grid; gap: var(--sp-1); padding: var(--sp-4) var(--sp-5); background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg); font-size: var(--fs-sm); color: var(--c-ink-2); }
.rolehow__step b { color: var(--c-ink); font-size: var(--fs-base); }
.rolelist__name { font-weight: var(--fw-semi); margin-inline-end: var(--sp-2); }
.rolelist__desc { font-size: var(--fs-xs); color: var(--c-ink-3); }
.rolelist__meter { display: inline-block; vertical-align: middle; inline-size: 70px; block-size: 6px; margin-inline-end: var(--sp-2); border-radius: 3px; background: var(--c-surface-3); overflow: hidden; }
.rolelist__meter span { display: block; block-size: 100%; background: var(--c-accent); }
.rolepage__platform summary { cursor: pointer; color: var(--c-ink-3); font-size: var(--fs-sm); }

/* --- Role editor ----------------------------------------------------------- */
.roleedit { display: grid; gap: var(--sp-4); }
.roleedit__head { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-4); position: sticky; inset-block-start: 0; z-index: 6; padding-block: var(--sp-3); background: var(--c-bg); }
.roleedit__titles { flex: 1 1 320px; min-inline-size: 0; }
.roleedit__titles .page-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin: 0; }
.roleedit__titles .page-title__sub { inline-size: 100%; }
.roleedit__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.roleedit__dirty { font-size: var(--fs-sm); color: var(--c-warn); font-weight: var(--fw-semi); }
.roleedit__note { display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-4) var(--sp-5); border-radius: var(--r-lg); background: var(--c-surface-2); border: 1px solid var(--c-line); color: var(--c-ink-2); font-size: var(--fs-sm); margin-block-end: var(--sp-4); }
.roleedit__note--info { background: var(--c-accent-weak); border-color: var(--c-accent-line); }
.roleedit__note ul { margin: var(--sp-2) 0 0; }
.roleedit__tabs { margin-block-start: var(--sp-2); }
.roleedit__panel[hidden] { display: none; }
.roleedit__filter { display: flex; align-items: center; gap: var(--sp-2); inline-size: min(360px, 100%); min-block-size: var(--d-ctl-h); padding-inline: var(--sp-3); margin-block-end: var(--sp-4); border: 1px solid var(--c-line-strong); border-radius: var(--r-pill); background: var(--c-surface); color: var(--c-ink-3); }
.roleedit__filter input { border: 0; outline: 0; background: transparent; font: inherit; color: var(--c-ink); inline-size: 100%; }
.permgrid { columns: 2 380px; column-gap: var(--sp-4); }
.permmod { break-inside: avoid; margin: 0 0 var(--sp-4); padding: var(--sp-2) var(--sp-5) var(--sp-4); background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg); transition: box-shadow var(--dur-3) var(--ease); }
.permmod[hidden] { display: none; }
.permmod.is-flash { box-shadow: 0 0 0 3px var(--c-accent-line); }
.permmod__head { display: flex; align-items: center; gap: var(--sp-3); inline-size: 100%; padding: var(--sp-3) 0; float: inline-start; }
.permmod__head + * { clear: both; }
.permmod__name { font-weight: var(--fw-semi); font-size: var(--fs-md); }
.permmod__all { margin-inline-start: auto; display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--c-ink-3); cursor: pointer; }
.permrow { padding-block: var(--sp-2); border-block-start: 1px solid var(--c-line-soft); }
.permrow[hidden] { display: none; }
.permrow .pill { margin-inline-start: var(--sp-2); vertical-align: middle; }
.roleedit__legacy code { font-size: var(--fs-xs); }
.locgrid th, .locgrid td { vertical-align: middle; }
.locgrid__perm { min-inline-size: 200px; font-weight: var(--fw-medium); text-align: start; }
.locgrid__base { white-space: nowrap; font-size: var(--fs-sm); }
.acc-base[data-on="1"] { color: var(--c-success); font-weight: var(--fw-semi); }
.acc-base[data-on="0"] { color: var(--c-ink-3); }
.locgrid__outlet { min-inline-size: 170px; }
.locgrid__code { display: block; font-size: var(--fs-micro); font-weight: var(--fw-regular); color: var(--c-ink-3); font-family: var(--font-num); }
.locgrid__select { inline-size: 100%; min-inline-size: 150px; }
.locgrid__cell--grant .locgrid__select { border-color: var(--c-success-line); background-color: var(--c-success-weak); color: var(--c-success); font-weight: var(--fw-semi); }
.locgrid__cell--deny .locgrid__select { border-color: var(--c-danger-line); background-color: var(--c-danger-weak); color: var(--c-danger); font-weight: var(--fw-semi); }
.roleedit__danger { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-start; padding-block-start: var(--sp-4); border-block-start: 1px solid var(--c-line); }
.roleedit__confirm details { position: relative; }
.roleedit__confirm summary { list-style: none; }
.roleedit__confirm summary::-webkit-details-marker { display: none; }
.roleedit__confirm-body { position: absolute; inset-block-end: calc(100% + 6px); inset-inline-start: 0; z-index: 20; inline-size: 300px; padding: var(--sp-4); background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg); box-shadow: var(--sh-3); display: grid; gap: var(--sp-3); }
.roleedit__confirm-body p { margin: 0; font-size: var(--fs-sm); }
@media print { .modbar, .pagebar--eyebrow { display: none !important; } }

/* Section 29's legacy rule paints every bare .btn as the primary; the module
   shell's buttons carry the theme's modifiers, so give those modifiers back. */
:is(.modpage, .setapp, .rolepage, .roleedit) .btn.btn--secondary:not(.secondary):not(.danger) {
  background: var(--c-surface); border-color: var(--c-line-strong); color: var(--c-ink); font-weight: var(--fw-medium);
}
:is(.modpage, .setapp, .rolepage, .roleedit) .btn.btn--secondary:not(.secondary):not(.danger):hover { background: var(--c-surface-2); }
:is(.modpage, .setapp, .rolepage, .roleedit) .btn.btn--ghost:not(.secondary):not(.danger) {
  background: transparent; border-color: transparent; color: var(--c-ink-2); font-weight: var(--fw-medium);
}
:is(.modpage, .setapp, .rolepage, .roleedit) .btn.btn--ghost:not(.secondary):not(.danger):hover { background: var(--c-surface-2); color: var(--c-ink); }
:is(.modpage, .setapp, .rolepage, .roleedit) .btn.btn--danger:not(.secondary):not(.danger) { background: var(--c-danger); border-color: var(--c-danger); color: #fff; }
:is(.modpage, .setapp, .rolepage, .roleedit) .btn.btn--danger-quiet:not(.secondary):not(.danger) { background: var(--c-surface); border-color: var(--c-danger-line); color: var(--c-danger); }
:is(.launch__search, .setapp__search, .roleedit__filter) input[type="search"]:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(.input):not(.cmdk__input) {
  border: 0; box-shadow: none; background: transparent; padding: 0; min-block-size: 0; block-size: auto; outline: 0;
}
.setsec__access { overflow-x: auto; }
.access-mini { table-layout: auto; inline-size: 100%; }
.access-mini thead th.access-mini__perm { white-space: normal; vertical-align: bottom; }
.access-mini td.access-mini__role, .locgrid td.locgrid__perm { font-weight: var(--fw-semi); white-space: nowrap; }
.modbar .btn.bell:not(.secondary):not(.danger):not(.sm) { background: transparent; border-color: transparent; color: var(--c-modbar-ink); box-shadow: none; }
.modbar .btn.bell:not(.secondary):not(.danger):not(.sm):hover { background: var(--c-modbar-hover); }
@media (max-width: 1480px) {
  .modbar__search .kbd, .modbar__rate .rate-pill__age { display: none; }
  .modbar__ctx { max-inline-size: 170px; }
  .modbar__app { padding-inline-end: var(--sp-2); }
}
/* ==========================================================================
   23c  Rules that started in the Workshop and are now used across modules.
        The Workshop's own rp-* rules live in repairs.css (loaded on Workshop
        pages only) since 2026-10-08.
   ========================================================================== */
td.is-invalid .input { border-color: var(--c-danger); background: var(--c-danger-weak); }
tr.is-inactive > td { opacity: .6; }
@media print { .page-actions { display: none !important; } }
.tab__count--warn { background: var(--c-warn-weak); color: var(--c-warn); }
.setrow--stack { grid-template-columns: minmax(0, 1fr); grid-template-areas: none; gap: var(--sp-2); }
.setrow--stack > .setrow__label, .setrow--stack > .setrow__hint, .setrow--stack > * { grid-area: auto; }
.form-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1000px) { .form-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .form-grid--4 { grid-template-columns: minmax(0, 1fr); } }
/* 23e · the customer's tracking page (.trk-*) moved to repairs.css (2026-10-08): track.php links it */


/* ==========================================================================
   32  INVENTORY (module 04) — the six components the module needs and the
       system did not already have. Everything else on these fourteen screens
       is existing vocabulary: .page-head/.page-title, .card, .tbl/.tbl-wrap,
       .tile (3px keyline, never a fill), .amt/.amt--metal, .num--g/.num--neg,
       .pill/.pill--dot/.pill--metal, .tabs/.tab, .alert--warn, .kv, .field,
       .btn, .drawer, .empty, .state-block--denied.

       Design rules this section obeys, from the approved redesign:
         · colour is never the only signal — every state carries a word
         · no fill where a keyline will do; a tint is for the one row that
           must be acted on now, not for a whole column of them
         · grams of different metals never share a figure
         · logical properties only, so one dir="rtl" is the whole RTL story
   ========================================================================== */

/* --- iv-scan: the module's primary input device ---------------------------
   Every operational screen opens focused here. 44px, or 56px where the screen
   is used standing up with a gun in one hand (count, receive). */
.iv-scan { display: flex; flex-direction: column; gap: var(--sp-2); }
.iv-scan__in { position: relative; display: flex; align-items: center; }
.iv-scan__in > .ico {
  position: absolute; inset-inline-start: var(--sp-3);
  color: var(--c-ink-4); pointer-events: none;
}
.iv-scan__in .input {
  block-size: 44px; font-family: var(--font-num); font-size: var(--fs-lg);
  letter-spacing: .02em;
  padding-inline-start: 38px; padding-inline-end: 96px;
}
.iv-scan__in .input:focus { border-color: var(--c-accent); }
.iv-scan__aff {
  flex: none; white-space: nowrap;
  display: flex; align-items: center; gap: var(--sp-2); pointer-events: none;
}
.iv-scan__count {
  font-family: var(--font-num); font-size: var(--fs-xs); font-weight: var(--fw-semi);
  font-variant-numeric: var(--num-feat);
  background: var(--c-surface-3); color: var(--c-ink-2);
  border-radius: var(--r-sm); padding: 2px var(--sp-2);
}
.iv-scan__last {
  display: flex; align-items: center; gap: var(--sp-3);
  min-block-size: 20px; font-size: var(--fs-xs); color: var(--c-ink-3);
}
.iv-scan__last b { font-family: var(--font-num); color: var(--c-ink-2); }
.iv-scan--touch .input { block-size: var(--hit-touch); font-size: var(--fs-xl); }
/* A scan that landed. 600ms, no bounce — it reports a state change and stops. */
.is-scanned { box-shadow: inset 0 -2px 0 var(--c-success); }

/* --- iv-piece: the piece identity block -----------------------------------
   Three weights, always all three, always labelled. "12.400 g" on its own is
   not a fact about a piece — it is one of four numbers it could be. */
.iv-piece { display: flex; align-items: center; gap: var(--sp-3); min-inline-size: 0; }
.iv-piece__body { display: flex; flex-direction: column; gap: var(--sp-1); min-inline-size: 0; flex: 1; }
.iv-piece__l1 { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.iv-piece__tag {
  font-family: var(--font-num); font-size: var(--fs-sm); font-weight: var(--fw-semi);
  direction: ltr; unicode-bidi: isolate; white-space: nowrap;
}
.iv-piece__l2 { font-size: var(--fs-xs); color: var(--c-ink-3); }
.iv-piece__l3 { display: flex; gap: var(--sp-4); flex-wrap: wrap; }
.iv-wt { display: inline-flex; flex-direction: column; line-height: var(--lh-tight); }
.iv-wt__k {
  font-size: var(--fs-micro); font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--c-ink-4);
}
.iv-wt__v {
  font-family: var(--font-num); font-size: var(--fs-sm); font-weight: var(--fw-semi);
  font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate;
}
.iv-wt--fine .iv-wt__v { color: var(--c-metal); }

/* --- iv-metal: metal + purity + fine grams --------------------------------
   The unit of every aggregate in this module. Several of them STACK; they
   never add up, and there is deliberately no container that totals them. */
.iv-metal {
  display: inline-flex; align-items: baseline; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: var(--fw-semi); color: var(--c-ink-2);
  white-space: nowrap;
}
.iv-metal__bead {
  inline-size: 8px; block-size: 8px; border-radius: 50%; flex: none; align-self: center;
  background: linear-gradient(140deg, #f0d79a 0%, #d9b76a 45%, #a67c2e 100%);
  box-shadow: inset 0 -1px 1px rgb(0 0 0 / .28), inset 0 1px 1px rgb(255 255 255 / .55);
}
.iv-metal--ag .iv-metal__bead { background: linear-gradient(140deg, #f4f7f9, #e8edf1 45%, #9aa7b2); }
.iv-metal--pt .iv-metal__bead { background: linear-gradient(140deg, #f7fafb, #eef2f4 45%, #b7c3c9); }
.iv-metal__fine {
  font-family: var(--font-num); font-size: var(--fs-micro); color: var(--c-ink-4);
  direction: ltr; unicode-bidi: isolate;
}
.iv-metal__g {
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  color: var(--c-ink); direction: ltr; unicode-bidi: isolate;
}
.iv-metal-stack { display: flex; flex-direction: column; gap: var(--sp-1); align-items: flex-start; }
.iv-metal-stack__note { font-size: var(--fs-micro); color: var(--c-ink-4); }

/* --- iv-var: the variance cell -------------------------------------------
   Word first, then the sign, then the colour. In a thermal print the word is
   carrying the whole meaning on its own, and it still reads correctly. */
.iv-var {
  display: inline-flex; align-items: baseline; gap: var(--sp-2);
  white-space: nowrap; unicode-bidi: isolate;
}
.iv-var__w {
  font-size: var(--fs-micro); font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
.iv-var__n {
  font-family: var(--font-num); font-size: var(--fs-sm); font-weight: var(--fw-semi);
  font-variant-numeric: var(--num-feat); direction: ltr; unicode-bidi: isolate;
}
.iv-var--short { color: var(--c-danger); }
.iv-var--short .iv-var__w::before { content: "\25BE\00A0"; }
.iv-var--over  { color: var(--c-warn); }
.iv-var--over  .iv-var__w::before { content: "\25B4\00A0"; }
.iv-var--match { color: var(--c-ink-3); }
.iv-var--match .iv-var__w::before { content: "=\00A0"; }

/* --- iv-steps: where a document is in its life ---------------------------- */
.iv-steps { display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.iv-step {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); font-weight: var(--fw-semi); color: var(--c-ink-4);
  padding: 4px var(--sp-3);
  border: 1px solid var(--c-line); border-radius: var(--r-md);
}
.iv-step__dot { inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--c-line-strong); flex: none; }
.iv-step--done { color: var(--c-success); }
.iv-step--done .iv-step__dot { background: var(--c-success); }
.iv-step--now  { color: var(--c-ink-inv); background: var(--c-surface-inv); border-color: transparent; }
.iv-step--now  .iv-step__dot { background: var(--c-ink-inv); }
.iv-step--bad  { color: var(--c-danger); border-color: var(--c-danger); }
.iv-step--bad  .iv-step__dot { background: var(--c-danger); }
/* In a table cell the rail loses its labels: only the step you are ON says its
   name, the rest are dots. A status column is not the place for a sentence. */
.tbl .iv-step { padding: 0; border: 0; background: none; font-size: 0; gap: 0; }
.tbl .iv-step--now, .tbl .iv-step--bad { font-size: var(--fs-xs); gap: var(--sp-2); padding-inline-end: var(--sp-1); }
/* The inverse ground is gone in a cell, so the inverse ink has to go with it. */
.tbl .iv-step--now { color: var(--c-ink); }
.tbl .iv-step--now .iv-step__dot { background: var(--c-accent); }
.tbl .iv-step--bad { color: var(--c-danger); }
.tbl .iv-step--bad .iv-step__dot { background: var(--c-danger); }

/* --- iv-age: the ageing band ---------------------------------------------
   A five-step ramp is the one legitimate use of a multi-step colour scale.
   Only the two oldest bands fill; the rest are outlined so the table does not
   turn into a heat map of things that are perfectly fine. */
.iv-age {
  display: inline-block; min-inline-size: 32px; text-align: center;
  font-family: var(--font-num); font-size: var(--fs-micro); font-weight: var(--fw-semi);
  font-variant-numeric: var(--num-feat); line-height: 1.5;
  padding-inline: var(--sp-1); vertical-align: middle;
  border-radius: var(--r-sm); box-shadow: inset 0 0 0 1px currentColor;
  direction: ltr; unicode-bidi: isolate;
}
.iv-age--0 { color: var(--c-success); }
.iv-age--1 { color: color-mix(in srgb, var(--c-success) 55%, var(--c-warn)); }
.iv-age--2 { color: var(--c-warn); }
.iv-age--3 { color: var(--c-warn); background: var(--c-warn-weak); }
.iv-age--4 { color: var(--c-danger); background: var(--c-danger-weak); }


/* ==========================================================================
   32b  FIXES FOUND ON THE LIVE SCREENS (19 Sep 2026)
   Three of these are classes the Inventory views ask for that nothing defined,
   so the markup was correct and the page simply had no styling for it. The
   fourth is the inline field, which only module 04 uses.
   ========================================================================== */

/* The second line inside a table cell — a bin's full name, a design's SKU, why
   a row is the way it is. Twelve uses, no definition, so every one of them was
   rendering at body size in body ink and shouting over the row it explains. */
.tbl__sub {
  display: block;
  font-size: var(--fs-xs); font-weight: var(--fw-regular);
  line-height: var(--lh-snug); color: var(--c-ink-3);
}
.tbl__sub .mono { font-size: var(--fs-micro); }

/* The one icon size the ramp was missing. */
.ico--12 { inline-size: 12px; block-size: 12px; }

/* The module name in the top bar. Inherited from the shell, never defined. */
.modbar__name { font-weight: var(--fw-semi); white-space: nowrap; }

/* A label beside its control rather than above it. Used only by module 04.
   Three things were wrong at once: the label kept the stacked field's bottom
   margin so it sat off-centre, it wrapped onto two lines whenever it was more
   than one word, and the select sized itself to its longest OPTION — which is
   how one "Every bin" box ended up 377px wide next to a 115px "Every metal"
   and made the whole filter bar look broken. */
.field--inline { gap: var(--sp-2); flex-wrap: nowrap; }
.field--inline > .label {
  margin-block-end: 0; white-space: nowrap; flex: none;
  font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--c-ink-3);
}
.field--inline > .select,
.field--inline > .input {
  inline-size: 168px; min-inline-size: 0; flex: 0 1 168px;
  text-overflow: ellipsis;
}
.field--inline > .input[type="search"],
.field--inline > .input[type="text"] { flex: 0 1 220px; inline-size: 220px; }
/* A disclosure of further filters is not a field; it must not take a field's
   full-width column box. */
details.field { display: block; inline-size: auto; }
details.field > summary { display: inline-flex; width: auto; cursor: pointer; }

/* ==========================================================================
   33. Inventory (module 04) — layout audit fixes
   Five things the QA pass found, each of which is a rule rather than a patch:
   a table inside a 445px drawer must fit the drawer, a screen used standing up
   needs 44px targets, subdued text on a tinted row still has to reach 4.5:1,
   the Arabic ageing pill needs an Arabic font, and a bin that is below zero is
   not an ordinary row.
   ========================================================================== */

/* --- a table inside a drawer or a narrow side panel ----------------------
   The old behaviour scrolled the last column out of sight, and the last
   column is "what happened" — the one the reader opened the drawer for. A
   fixed layout makes every column share the width it actually has, and the
   long cells wrap instead. */
.drawer--fit .tbl-wrap,
.drawer--fit .tbl-wrap--scroll { overflow-x: clip; }
.drawer--fit .tbl { inline-size: 100%; table-layout: fixed; }
.drawer--fit .tbl th, .drawer--fit .tbl td {
  white-space: normal; overflow-wrap: anywhere; word-break: break-word;
}
/* A tag, a document number and a stamp are single tokens. Broken across two
   lines they stop being readable at all in Arabic, where the bidi algorithm
   then lays the halves out in the wrong order. */
.drawer--fit .tbl bdi.mono { white-space: nowrap; overflow-wrap: normal; word-break: normal; }
/* The metal chip is one unbreakable line everywhere else; in a fixed-width
   cell it has to be allowed to fold rather than run into the number beside it. */
.drawer--fit .iv-metal { flex-wrap: wrap; white-space: normal; max-inline-size: 100%; }

/* --- iv-route: from one outlet to another --------------------------------
   Two Latin codes and a chevron that mirrors in Arabic. As loose inline text
   the three resolve into ONE left-to-right run and the mirrored chevron then
   points the wrong way down it. As a flex row each code is its own item, the
   row itself follows the page direction, and the chevron means what it draws. */
.iv-route { display: inline-flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.iv-route > bdi { unicode-bidi: isolate; }

/* --- iv-touch: the screens a person uses on their feet -------------------
   Counting a safe and unpacking a parcel are done standing up, one-handed,
   often on a tablet. 34px is a miss; 16px is a joke. Everything that can be
   pressed on those two screens is at least 44px high. */
.iv-touch .btn,
.iv-touch .input,
.iv-touch .select,
.iv-touch .textarea { min-block-size: 44px; }
.iv-touch .btn--sm { min-block-size: 44px; padding-inline: var(--sp-4); }
.iv-touch .btn--icon { min-inline-size: 44px; }
.iv-touch .radio { display: flex; align-items: center; gap: var(--sp-2); min-block-size: 44px; }
/* A 16px radio is a miss on a tablet and a 44px native one is an ellipse, so
   the control is drawn as a circle inside a 24x44 hit area instead. The circle
   is the same size the rest of the product draws; only the target grew. */
.iv-touch .radio > input[type="radio"] {
  appearance: none; -webkit-appearance: none;
  inline-size: 24px; block-size: 44px; flex: none; margin: 0;
  border: 0; background-color: transparent; cursor: pointer;
  background-repeat: no-repeat;
  background-image: radial-gradient(circle at 50% 50%,
      var(--c-surface) 0 7px, var(--c-line-strong) 7px 8.5px, transparent 8.5px);
}
.iv-touch .radio > input[type="radio"]:checked {
  background-image: radial-gradient(circle at 50% 50%,
      var(--c-accent) 0 4px, var(--c-surface) 4px 7px, var(--c-accent) 7px 8.5px, transparent 8.5px);
}
.iv-touch .radio > input[type="radio"]:focus-visible {
  outline: 2px solid var(--c-accent); outline-offset: -11px; border-radius: var(--r-sm);
}
.iv-touch .textarea { min-block-size: 88px; }

/* --- subdued text on a tinted row ---------------------------------------
   --c-ink-3 is 5.1:1 on white but only 4.42:1 on the danger and warning
   washes, and the sentence it carries there is the one that says what to do
   about the row. It steps up a rank rather than the row losing its tint. */
.tbl tr.is-danger .muted,
.tbl tr.is-warn .muted,
.tbl tr.is-below-zero .muted,
.alert--danger .muted,
.alert--warn .muted { color: var(--c-ink-2); }

/* --- the ageing pill in Arabic ------------------------------------------
   --font-num is a monospace stack with no Arabic coverage, so the day suffix
   fell back to whatever the system had and its descender ran into the pill.
   Arabic gets the Arabic face and a little more room. */
[dir="rtl"] .iv-age {
  font-family: var(--font-ar); min-inline-size: 40px;
  line-height: 1.9; padding-block: 2px;
}

/* --- a balance below zero ------------------------------------------------
   Negative stock on hand is never a fact about the shelf; it is a fact about
   the ledger. The row says so in words as well as in colour. */
.tbl tr.is-below-zero > td { background: var(--c-danger-weak); }
/* 23f · the photo lightbox (.rp-lb*, a[data-lightbox]) moved to repairs.css (2026-10-08) */


/* ==========================================================================
   REPORT CATALOGUE (RB-01 v7)
   --------------------------------------------------------------------------
   Find → Quick access → Browse. Each category carries one colour (--cat) used
   only for its icon tile and a thin top rule, so colour helps the eye find a
   panel without turning the page into a paint chart. Tints come from
   color-mix against the surface, so dark mode follows on its own.
   ========================================================================== */
.rlib { --rl-gap: var(--sp-7); display: grid; gap: var(--rl-gap); max-inline-size: 1200px; margin: var(--sp-5) auto var(--sp-9); }
.rlib mark { background: color-mix(in srgb, var(--c-warn) 22%, transparent); color: inherit; border-radius: 2px; padding: 0 1px; }

.rlib__label {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-size: var(--fs-xs); font-weight: var(--fw-semi); letter-spacing: var(--tracking-caps);
  text-transform: uppercase; color: var(--c-ink-3);
}
section > .rlib__label { margin-block-end: var(--sp-4); }

/* --- 1 · find ----------------------------------------------------------- */
.rlib__find { display: grid; gap: var(--sp-4); }
.rlib__search { position: relative; display: flex; align-items: center; gap: var(--sp-5); }
.rlib__search > .ico { position: absolute; inset-inline-start: 18px; color: var(--c-ink-3); pointer-events: none; }
.rlib__q {
  inline-size: 100%; min-block-size: 52px; font-size: var(--fs-md);
  padding-inline-start: 46px; border-radius: var(--r-xl);
  background: var(--c-surface); box-shadow: 0 1px 3px rgba(9, 30, 66, .07);
}
.rlib__q:focus { box-shadow: 0 0 0 4px color-mix(in srgb, var(--c-accent) 18%, transparent); }
.rlib__count { flex: none; white-space: nowrap; font-size: var(--fs-sm); color: var(--c-ink-3); min-inline-size: 6.5rem; }
.rlib__opts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); justify-content: space-between; }
.rlib__kbd { font-size: var(--fs-xs); color: var(--c-ink-3); }

.rseg { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.rseg__label { font-size: var(--fs-sm); color: var(--c-ink-3); margin-inline-end: var(--sp-2); }
.rseg__btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px;
  border: 1px solid var(--c-line); border-radius: 999px; background: var(--c-surface);
  color: var(--c-ink-2); font-size: var(--fs-sm); cursor: pointer; transition: all .12s;
}
.rseg__btn:hover { border-color: var(--c-accent); color: var(--c-accent); }
.rseg__btn.is-on { background: var(--c-ink); border-color: var(--c-ink); color: var(--c-surface); }
.rseg__n { font-family: var(--font-num); font-size: var(--fs-xs); opacity: .7; }

/* --- 2 · quick access --------------------------------------------------- */
.rshelf {
  padding: var(--sp-5) var(--sp-6) var(--sp-6); border-radius: var(--r-xl);
  background: linear-gradient(180deg, var(--c-accent-weak), color-mix(in srgb, var(--c-accent-weak) 35%, var(--c-surface)));
  border: 1px solid color-mix(in srgb, var(--c-accent) 14%, var(--c-line));
}
.rshelf[hidden] { display: none; }
.rshelf__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4) var(--sp-5); margin-block-end: var(--sp-5); }
.rshelf__head .rlib__label { color: var(--c-accent); }
.rtabs { display: inline-flex; gap: 2px; padding: 3px; border-radius: 999px; background: color-mix(in srgb, var(--c-surface) 70%, transparent); }
.rtabs__btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border: 0; border-radius: 999px;
  background: none; color: var(--c-ink-2); font-size: var(--fs-sm); cursor: pointer;
}
.rtabs__btn:hover { color: var(--c-accent); }
.rtabs__btn.is-on { background: var(--c-surface); color: var(--c-ink); font-weight: var(--fw-semi); box-shadow: 0 1px 3px rgba(9, 30, 66, .12); }
.rtabs__n { font-family: var(--font-num); font-size: var(--fs-xs); color: var(--c-ink-3); }
.rshelf__clear { margin-inline-start: auto; border: 0; background: none; color: var(--c-ink-3); font-size: var(--fs-sm); cursor: pointer; text-decoration: underline; }
.rshelf__clear[hidden] { display: none; }
.rshelf__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--sp-4); }
.rshelf__grid:empty { display: none; }
.rshelf__hint { margin: 0; font-size: var(--fs-sm); color: var(--c-ink-2); }
.rshelf__hint[hidden] { display: none; }

.rq {
  display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-lg); background: var(--c-surface); color: var(--c-ink); text-decoration: none;
  box-shadow: 0 1px 2px rgba(9, 30, 66, .06); border: 1px solid transparent;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.rq:hover { text-decoration: none; border-color: var(--cat); box-shadow: 0 6px 16px rgba(9, 30, 66, .10); transform: translateY(-1px); }
.rq:focus-visible { outline: 2px solid var(--c-focus, #1d71a5); outline-offset: 2px; }
.rq__ico, .rcat__ico {
  flex: none; display: grid; place-items: center; border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--cat) 13%, var(--c-surface)); color: var(--cat);
}
.rq__ico { inline-size: 38px; block-size: 38px; }
.rq__body { display: grid; gap: 2px; min-inline-size: 0; flex: 1; }
.rq__name { font-size: var(--fs-base); font-weight: var(--fw-semi); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rq__cat { font-size: var(--fs-xs); color: var(--c-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rq__go { color: var(--c-ink-3); }
.rq:hover .rq__go { color: var(--cat); }

/* --- 3 · browse --------------------------------------------------------- */
.rlib__cats { columns: 2 460px; column-gap: var(--sp-6); }
.rcat {
  break-inside: avoid; margin-block-end: var(--sp-6);
  border: 1px solid var(--c-line); border-block-start: 3px solid var(--cat);
  border-radius: var(--r-xl); background: var(--c-surface); overflow: hidden;
}
.rcat[hidden] { display: none; }
.rcat__head { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-5) var(--sp-5) var(--sp-4); }
.rcat__ico { inline-size: 40px; block-size: 40px; }
.rcat__txt { display: grid; gap: 2px; min-inline-size: 0; flex: 1; }
.rcat__name { margin: 0; font-size: var(--fs-md); font-weight: var(--fw-bold); color: var(--c-ink); }
.rcat__ask { font-size: var(--fs-sm); color: var(--c-ink-3); }
.rcat__n {
  flex: none; font-family: var(--font-num); font-size: var(--fs-xs); color: var(--c-ink-3);
  background: var(--c-surface-2); border-radius: 999px; padding: 3px 9px;
}

.rcat__list { list-style: none; margin: 0; padding: 0 var(--sp-3) var(--sp-3); }
.rrow { position: relative; display: flex; align-items: center; border-radius: var(--r-lg); }
.rrow + .rrow::before {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: var(--sp-4);
  border-block-start: 1px solid var(--c-line-soft);
}
.rrow:hover, .rrow:focus-within { background: var(--c-surface-2); }
.rrow:hover::before, .rrow:hover + .rrow::before,
.rrow:focus-within::before, .rrow:focus-within + .rrow::before { border-color: transparent; }
.rrow[hidden] { display: none; }
.rrow__link {
  display: flex; align-items: center; gap: var(--sp-5); flex: 1; min-inline-size: 0;
  padding: var(--sp-4) var(--sp-4); color: var(--c-ink); text-decoration: none; border-radius: var(--r-lg);
}
.rrow__link:hover { text-decoration: none; }
.rrow__link:focus-visible { outline: 2px solid var(--c-focus, #1d71a5); outline-offset: -2px; }
.rrow__body { display: grid; gap: 3px; min-inline-size: 0; flex: 1; }
.rrow__name { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-base); font-weight: var(--fw-semi); }
.rrow__link:hover .rrow__name, .rrow__link:focus-visible .rrow__name { color: var(--c-accent); }
.rrow__star { display: inline-flex; color: var(--c-warn); }
.rrow__ask { font-size: var(--fs-sm); color: var(--c-ink-3); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rrow__meta { flex: none; display: grid; justify-items: end; gap: 3px; text-align: end; }
.rrow__cad { font-size: var(--fs-xs); color: var(--c-ink-2); }
.rrow__code { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--c-ink-3); }

.rpin {
  flex: none; display: grid; place-items: center; inline-size: 32px; block-size: 32px; margin-inline-end: var(--sp-2);
  border: 0; border-radius: var(--r-md); background: none; color: var(--c-ink-3); cursor: pointer;
  opacity: 0; transition: opacity .12s, color .12s, background .12s;
}
.rrow:hover .rpin, .rpin:focus-visible, .rrow.is-pinned .rpin { opacity: 1; }
.rpin:hover { background: var(--c-surface); color: var(--c-accent); }
.rpin:focus-visible { outline: 2px solid var(--c-focus, #1d71a5); }
.rrow.is-pinned .rpin { color: var(--c-accent); background: var(--c-accent-weak); }

/* --- nothing found ------------------------------------------------------ */
.rnone { text-align: center; padding: var(--sp-8) var(--sp-5); border: 1px dashed var(--c-line); border-radius: var(--r-xl); background: var(--c-surface); }
.rnone[hidden] { display: none; }
.rnone__ico { display: inline-grid; place-items: center; inline-size: 52px; block-size: 52px; border-radius: 50%; background: var(--c-surface-2); color: var(--c-ink-3); }
.rnone__title { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--c-ink); }
.rnone__txt { margin: 0; font-size: var(--fs-sm); color: var(--c-ink-3); }
.rnone__try { margin: var(--sp-5) 0 0; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--sp-3); font-size: var(--fs-sm); color: var(--c-ink-3); }
.rnone__chip { padding: 4px 12px; border: 1px solid var(--c-line); border-radius: 999px; background: var(--c-surface-2); color: var(--c-accent); cursor: pointer; font-size: var(--fs-sm); }
.rnone__chip:hover { border-color: var(--c-accent); }

/* hover-only affordances are always visible where there is no hover */
@media (hover: none) { .rpin { opacity: 1; } .rlib__kbd { display: none; } }

@media (max-width: 720px) {
  .rlib { --rl-gap: var(--sp-6); margin-block-start: var(--sp-3); }
  .rlib__count, .rlib__kbd { display: none; }
  .rshelf { padding: var(--sp-4); }
  .rseg { flex-wrap: nowrap; overflow-x: auto; max-inline-size: 100%; padding-block-end: 2px; }
  .rseg__btn { white-space: nowrap; }
  .rrow__cad { display: none; }
}
@media print {
  .rlib__find, .rshelf, .rpin { display: none !important; }
  .rlib__cats { columns: 1; }
  .rcat { break-inside: avoid; }
}


/* --- financial statements inside the report shell -------------------------
   A balance sheet is read down its left edge: headings, then lines stepped in
   under them, then a subtotal ruled off, then the answer. Indentation is the
   only thing carrying that structure, so it is a real step and not a nudge. */
.rpt-stmt__head > td {
  background: var(--c-surface-2);
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  font-size: var(--fs-xs); color: var(--c-ink-2);
}
.tbl tbody tr.rpt-stmt__head:hover > td { background: var(--c-surface-2); }
.rpt-stmt__lvl1 { padding-inline-start: calc(var(--d-cell-px) + 1.25rem) !important; }
.rpt-stmt__lvl2 { padding-inline-start: calc(var(--d-cell-px) + 2.5rem) !important; }
.rpt-stmt__lvl3 { padding-inline-start: calc(var(--d-cell-px) + 3.75rem) !important; }
/* A variance reads as a direction before it reads as a number. */
.rpt-var--up   { color: var(--c-success); }
.rpt-var--down { color: var(--c-danger); }

/* --- .report__answer — the generated sentence (RB-02 v2) -------------------
       The report's headline is one sentence with the figures in it, in the
       reader's language. It takes the accent rail by default and the warn or
       danger rail when a threshold is crossed — and when it does, the sentence
       itself must also SAY so, because colour is never the only signal (§2.4).
       Capped near 62ch: a headline the eye has to track across a wide screen
       is not a headline.                                                   --- */
.report__answer {
  padding: var(--sp-5) var(--sp-6);
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-inline-start: 4px solid var(--c-accent);
  border-radius: var(--r-md);
}
.report__answer p { margin: 0; max-inline-size: 62ch; font-size: var(--fs-lg); line-height: var(--lh-snug); color: var(--c-ink); }
.report__answer .num { font-weight: var(--fw-semi); }
.report__answer--warn   { border-inline-start-color: var(--c-warn); }
.report__answer--danger { border-inline-start-color: var(--c-danger); background: var(--c-danger-weak); }

/* --- .report--simple — the two levels ------------------------------------
       Simple and Full are one body at two densities, not two templates. The
       modifier hides the detail; it must never change the query, the route,
       the permission or the export, or the two levels drift into two reports
       with two definitions of the same number.                            --- */
.report--simple .report__detail { display: none; }
/* Simple keeps the table — truncated in PHP to the first rows — because a report
   with no table reads as a summary of something the reader cannot see. What it
   drops is the calculation drawer and the trailing tiles. */
.report__answer + .tiles { margin-block-start: var(--sp-4); }
/* A unit symbol is not a label: `g` is not `G`, and the theme's unit style
   uppercases because it is written for currency codes. */
.report .tile__value .amt__unit { font-size: .5em; text-transform: none; letter-spacing: 0; }

/* ==========================================================================
   PS-13  REGISTERS
   A register is a drawer with a name. These screens show what is in it, what
   went through it and what was counted out of it. Tokens only, so light, dark
   and RTL follow the theme; every figure is set in the numeral face so the
   columns line up when you scan down them.
   ========================================================================== */
.reg { display: flex; flex-direction: column; gap: var(--sp-5); }
.reg .panel__head h2 { margin: 0; font-size: var(--fs-sm); font-weight: var(--fw-semi); }
.reg .panel__head .hint { margin: 0; }

.reg-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-4); }
.reg-h { margin: var(--sp-2) 0 0; font-size: var(--fs-sm); font-weight: var(--fw-semi);
         text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--c-ink-3); }

/* the two-column working area: the ledger on the left, the asides on the right */
.reg-cols { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr); gap: var(--sp-5); align-items: start; }
.reg-cols > .col { display: flex; flex-direction: column; gap: var(--sp-5); min-inline-size: 0; }

/* ── the board ─────────────────────────────────────────────────────────── */
.reg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--sp-4); }
.reg-card { background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg);
            box-shadow: var(--sh-1); display: flex; flex-direction: column; overflow: hidden; }
.reg-card.is-mine { border-color: var(--c-accent-line); box-shadow: 0 0 0 1px var(--c-accent-line), var(--sh-1); }
.reg-card.is-idle { background: var(--c-surface-2); box-shadow: none; }
.reg-card__h { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-4);
               border-block-end: 1px solid var(--c-line); }
.reg-card__h b { display: block; }
.reg-card__h small { display: block; font-size: var(--fs-xs); color: var(--c-ink-3); }
.reg-card__ic { display: inline-flex; align-items: center; justify-content: center;
                inline-size: 34px; block-size: 34px; border-radius: var(--r-md);
                background: var(--c-surface-sunk); color: var(--c-ink-3); flex: 0 0 auto; }
.reg-card__ic--open { background: var(--c-accent-weak); color: var(--c-accent); }
.reg-card__b { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); flex: 1 1 auto; }
.reg-card__f { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4);
               background: var(--c-surface-2); border-block-start: 1px solid var(--c-line); }
.reg-card__f .btn { flex: 1 1 auto; justify-content: center; }
.reg-head-ic { inline-size: 40px; block-size: 40px; }

/* ── a labelled figure ─────────────────────────────────────────────────── */
.reg-kv { display: flex; align-items: baseline; gap: var(--sp-3); font-size: var(--fs-sm); }
.reg-kv + .reg-kv { margin-block-start: var(--sp-2); }
.reg-kv > span:first-child { color: var(--c-ink-3); flex: 1 1 auto; min-inline-size: 0; }
.reg-kv > b { font-family: var(--font-num); font-variant-numeric: var(--num-feat); text-align: end; }
.reg-kv > b .mono, .reg-kv > span .mono { font-size: var(--fs-xs); color: var(--c-ink-3); margin-inline-start: var(--sp-2); }
.reg-kv--tot { border-block-start: 1px solid var(--c-line); padding-block-start: var(--sp-3); margin-block-start: var(--sp-3); }
.reg-kv--tot > b { font-size: var(--fs-lg); }
.reg-kv--blind > b { letter-spacing: .2em; color: var(--c-ink-4); }
.reg-kv--note { align-items: flex-start; }
.reg-kv--note > b { font-family: var(--font-ui); font-weight: var(--fw-regular); text-align: start; max-inline-size: 22ch; }

/* signed figures. The global .num--neg prefixes its own minus sign, which
   would double up on a value that already carries one, so variance columns
   colour themselves and leave the text alone. */
.reg-neg { color: var(--c-danger); }
.reg-pos { color: var(--c-success); }

/* ── choosing a register ───────────────────────────────────────────────── */
.reg-open__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); gap: var(--sp-5); align-items: start; }
.reg-open__grid > .col { display: flex; flex-direction: column; gap: var(--sp-5); min-inline-size: 0; }
.reg-pick { display: flex; flex-direction: column; gap: var(--sp-2); }
.reg-pick__row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3);
                 border: 1px solid var(--c-line); border-radius: var(--r-md); cursor: pointer; }
.reg-pick__row:hover { background: var(--c-accent-weak); border-color: var(--c-accent-line); }
.reg-pick__row:has(input:checked) { border-color: var(--c-accent); background: var(--c-accent-weak); }
.reg-pick__row.is-busy { opacity: .55; cursor: not-allowed; }
.reg-pick__row.is-busy:hover { background: none; border-color: var(--c-line); }
.reg-pick__row small { display: block; font-size: var(--fs-xs); color: var(--c-ink-3); }

/* ── the count sheet ───────────────────────────────────────────────────── */
.reg-den { display: flex; flex-direction: column; gap: 2px; max-inline-size: 30rem; }
.reg-den.is-off { opacity: .45; }
.reg-den__h, .reg-den__row, .reg-den__sum {
  display: grid; grid-template-columns: 5.5rem minmax(4rem, 1fr) 7rem; gap: var(--sp-3); align-items: center;
}
.reg-den__h { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tracking-caps);
              color: var(--c-ink-3); padding-block-end: var(--sp-2); }
.reg-den__h > :last-child, .reg-den__row > :last-child, .reg-den__sum > :last-child { text-align: end; }
.reg-den__v { font-family: var(--font-num); font-variant-numeric: var(--num-feat); color: var(--c-ink-2); }
.reg-den__i { text-align: end; font-family: var(--font-num); }
.reg-den__t { color: var(--c-ink-3); font-size: var(--fs-sm); }
.reg-den__sum { border-block-start: 1px solid var(--c-line); margin-block-start: var(--sp-3); padding-block-start: var(--sp-3); font-weight: var(--fw-semi); }
.reg-den__sum b { font-size: var(--fs-lg); }
.reg-den__cur { display: none; }
.reg-den--ro .reg-den__row { grid-template-columns: 5.5rem 4rem 1fr; }

/* ── the close, walked in three ────────────────────────────────────────── */
.reg-steps { display: flex; gap: var(--sp-2); list-style: none; margin: 0; padding: 0; flex-wrap: wrap; }
.reg-steps__i { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4);
                border: 1px solid var(--c-line); border-radius: var(--r-pill); font-size: var(--fs-sm);
                color: var(--c-ink-3); background: var(--c-surface); cursor: pointer; }
.reg-steps__i > span { display: inline-flex; align-items: center; justify-content: center;
                       inline-size: 20px; block-size: 20px; border-radius: 50%;
                       background: var(--c-surface-sunk); font-size: var(--fs-micro); font-weight: var(--fw-semi); }
.reg-steps__i.is-on { border-color: var(--c-accent); color: var(--c-accent); background: var(--c-accent-weak); }
.reg-steps__i.is-on > span { background: var(--c-accent); color: var(--c-accent-ink); }
.reg-steps__i.is-done { color: var(--c-success); border-color: var(--c-success-line); }
.reg-steps__i.is-done > span { background: var(--c-success-weak); color: var(--c-success); }
.reg-steps__i.is-locked { opacity: .5; cursor: default; }
.reg-pane { display: flex; flex-direction: column; gap: var(--sp-5); }
.reg-pane[hidden] { display: none; }   /* a display: rule outranks the UA's [hidden] */
.reg-nav { display: flex; align-items: center; gap: var(--sp-3); }
.reg-dec__i { inline-size: 9rem; text-align: end; margin-inline-start: auto; }
.reg-rev tfoot th, .reg-rev td { vertical-align: middle; }
.reg-bignum { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); padding-block: var(--sp-5); }
.reg-bignum__v { font-family: var(--font-num); font-variant-numeric: var(--num-feat);
                 font-size: var(--fs-3xl); font-weight: var(--fw-semi); line-height: 1; }
.reg-bignum__l { font-size: var(--fs-xs); color: var(--c-ink-3); text-transform: uppercase; letter-spacing: var(--tracking-caps); }
.reg-appr { border-color: var(--c-warn-line); }
.reg-appr .panel__head { background: var(--c-warn-weak); }

/* ── set-up ────────────────────────────────────────────────────────────── */
.reg-methods { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
/* a rule with its own one-line explanation under it */
.reg .check { align-items: flex-start; }
.reg .check + .check { margin-block-start: var(--sp-3); }
.reg .check > span > b, .reg .check > span > small { display: block; }
.reg .check > span > small { color: var(--c-ink-3); font-size: var(--fs-xs); font-weight: var(--fw-regular); }
.reg-setup .tbl tr.is-on { background: var(--c-accent-weak); }

/* ── the set-up tabs ───────────────────────────────────────────────────── */
.reg-tabs { display: flex; gap: var(--sp-2); flex-wrap: wrap; border-block-end: 1px solid var(--c-line); padding-block-end: var(--sp-3); }
.reg-tabs__i { display: inline-flex; align-items: center; padding: var(--sp-2) var(--sp-4);
               border-radius: var(--r-pill); font-size: var(--fs-sm); font-weight: var(--fw-semi);
               color: var(--c-ink-3); text-decoration: none; }
.reg-tabs__i:hover { background: var(--c-surface-2); color: var(--c-ink); text-decoration: none; }
.reg-tabs__i.is-on { background: var(--c-accent-weak); color: var(--c-accent); }

/* the methods a register takes, listed on its row */
.reg-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.reg-chip { display: inline-flex; padding: 1px var(--sp-2); border: 1px solid var(--c-line);
            border-radius: var(--r-sm); font-size: var(--fs-micro); color: var(--c-ink-3); white-space: nowrap; }

/* a card that wants looking at, and why */
.reg-card.is-attention { border-color: var(--c-warn-line); box-shadow: 0 0 0 1px var(--c-warn-line), var(--sh-1); }
.reg-card__ic--warn { background: var(--c-warn-weak); color: var(--c-warn); }
.reg-flag { display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-2) 0 0;
            font-size: var(--fs-xs); color: var(--c-warn); }

/* the variance spread bar in the history */
.reg-spread { display: block; inline-size: 110px; block-size: 6px; border-radius: var(--r-pill);
              background: var(--c-surface-sunk); overflow: hidden; }
.reg-spread i { display: block; block-size: 100%; background: var(--c-ink-4); border-radius: inherit; }
.reg-spread i.is-neg { background: var(--c-danger); }
.reg-spread i.is-pos { background: var(--c-success); }
.reg-spread__h { inline-size: 120px; }

/* a standing note, not a state: the old-gold reminder on the denominations tab */
.reg-note { border-inline-start: 3px solid var(--c-metal); }
.reg-note .panel__body { display: flex; gap: var(--sp-3); align-items: flex-start;
                         font-size: var(--fs-sm); color: var(--c-ink-2); }
.reg-note .ico { color: var(--c-metal); flex: 0 0 auto; }

.reg-tiles--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.reg-h .muted { font-weight: var(--fw-regular); text-transform: none; letter-spacing: 0; margin-inline-start: var(--sp-2); }

/* small shared pieces these screens are the first to need */
.pill--acc  { background: var(--c-accent-weak); border-color: var(--c-accent-line); color: var(--c-accent); }
.pill--warn { background: var(--c-warn-weak); border-color: var(--c-warn-line); color: var(--c-warn); }
.pill--acc::before, .pill--warn::before { content: none; }
.inline-form { display: flex; align-items: center; gap: var(--sp-2); }
.select--sm { block-size: 28px; padding-block: 0; font-size: var(--fs-xs); }
.input--sm  { min-block-size: 28px; padding-block: 0; font-size: var(--fs-sm); }
.tbl .input--sm { inline-size: 6.5rem; text-align: end; }
.field__err { display: block; margin-block-start: var(--sp-1); font-size: var(--fs-xs); color: var(--c-danger); }

@media (max-width: 1100px) {
  .reg-cols, .reg-open__grid { grid-template-columns: 1fr; }
  .reg-tiles, .reg-tiles--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .reg-tiles, .reg-tiles--3, .reg-methods { grid-template-columns: 1fr; }
  .reg-spread, .reg-spread__h { display: none; }
  .reg-den__h, .reg-den__row, .reg-den__sum { grid-template-columns: 4.5rem minmax(3rem, 1fr) 6rem; }
  .reg-card__f { flex-direction: column; }
}
@media print {
  .reg .page-actions, .reg-nav, .reg-steps, .scrim { display: none !important; }
  .reg-cols { grid-template-columns: 1fr; }
}

/* ==========================================================================
   34  INVENTORY · THE PIECES FILTER ROW AND THE PIECE PAGE
   Two changes to module 04, and both of them are the same change: stop making
   the reader work around a container that is the wrong shape for its content.
   ========================================================================== */

/* --- the weight strip ------------------------------------------------------
   Gross = net + stone + other, written as the arithmetic it is, with the fine
   weight set apart at the end because it is the only one of the five that is
   not a term in that sum. The operators are aria-hidden: a screen reader gets
   the same relation from the two expressions spelled out on the Overview tab,
   and "equals" read between two figures on a dashboard is noise. */
.iv-pv-strip {
  display: flex; align-items: stretch; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-lg);
}
.iv-pv-strip__op {
  display: flex; align-items: center; padding-inline: var(--sp-1);
  font-family: var(--font-num); font-size: var(--fs-lg); color: var(--c-ink-4);
}
.iv-pv-strip__gap { flex: 1 1 var(--sp-4); }
.iv-pv-tile {
  display: flex; flex-direction: column; gap: 2px; min-inline-size: 84px;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md); background: var(--c-surface-2);
}
.iv-pv-tile__k {
  font-size: var(--fs-micro); font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--c-ink-3);
}
.iv-pv-tile__v {
  font-family: var(--font-num); font-variant-numeric: var(--num-feat);
  font-size: var(--fs-lg); font-weight: var(--fw-semi); line-height: var(--lh-tight);
  color: var(--c-ink); white-space: nowrap;
}
.iv-pv-tile__v small { font-size: var(--fs-xs); font-weight: var(--fw-regular); color: var(--c-ink-4); margin-inline-start: 3px; }
.iv-pv-tile--fine { background: var(--c-metal-weak); border: 1px solid var(--c-metal-line); }
.iv-pv-tile--fine .iv-pv-tile__k,
.iv-pv-tile--fine .iv-pv-tile__v { color: var(--c-metal); }

/* the customer-hold card (inventory/_hold.php, when it is not inside a dialog) */
.iv-pv-card { display: flex; flex-direction: column; gap: var(--sp-3); }
.iv-pv-card__h {
  display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
  margin: 0; font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--c-ink);
}
.iv-pv-card .kv { margin: 0; }

/* The two arithmetic lines. They are the answer to "where did the grams go",
   so they are set in the numeric face and boxed away from the prose. */
.iv-pv-sum {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin: 0;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
  background: var(--c-surface-sunk);
  font-size: var(--fs-sm); color: var(--c-ink-2);
}
.iv-pv-sum .mono { font-family: var(--font-num); font-variant-numeric: var(--num-feat); }
.iv-pv-sum.is-off { background: var(--c-danger-weak); color: var(--c-ink); }

@media (max-width: 720px) {
  .iv-pv-strip { gap: var(--sp-2); }
  .iv-pv-strip__op, .iv-pv-strip__gap { display: none; }
  .iv-pv-tile { flex: 1 1 calc(50% - var(--sp-2)); }
}
@media print {
  .iv-pv-strip, .iv-pv-card { break-inside: avoid; }
}

/* the piece table (the piece record's Cost & price tab): cost and target selling side by side, each under its own
   group heading and tint, so a reader never mistakes one for the other */
.iv-pv2-comp td, .iv-pv2-comp th { vertical-align: top; }
.iv-pv2-comp__grp th {
  padding-block: var(--sp-2) 0; border-block-end: 0;
  font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
.iv-pv2-comp__grp th.is-cost { color: var(--c-ink-2); text-align: center; border-block-end: 2px solid var(--c-line-strong); }
.iv-pv2-comp__grp th.is-sell { color: var(--c-success); text-align: center; border-block-end: 2px solid var(--c-success-line); }
.iv-pv2-comp__grp small { font-weight: var(--fw-regular); letter-spacing: 0; text-transform: none; }
.iv-pv2-comp .is-cost { background: var(--c-surface-sunk); }
.iv-pv2-comp .is-sell { background: var(--c-success-weak); }
.iv-pv2-comp__metal td:not(.is-cost):not(.is-sell) { background: var(--c-metal-weak); }
.iv-pv2-comp__metal b { color: var(--c-metal); }
.iv-pv2-comp__basis { display: block; font-size: var(--fs-micro); white-space: normal; }
.iv-pv2-comp__basis.is-neg { color: var(--c-danger); }
/* unfixed metal: the amount is provisional until the metal is fixed */
.iv-pv2-comp .is-prov > .num { font-style: italic; color: var(--c-ink-3); }
.iv-pv2-comp .is-prov b { color: var(--c-ink-3); }
.iv-pv2-prov { color: var(--c-warn); }
.iv-pv2-comp__grp a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.iv-pv2-comp tfoot th, .iv-pv2-comp tfoot td {
  border-block-start: 2px solid var(--c-line-strong); font-weight: var(--fw-semi); vertical-align: middle;
}
.iv-pv2-comp__srp b { font-size: var(--fs-lg); }
.iv-pv2-comp__srp small { color: var(--c-success); font-weight: var(--fw-bold); }

/* ==========================================================================
   35  CATALOGUE · THE PICTURES OF A DESIGN
   A gallery inside a form section, which is an odd place for one: it has to
   look like part of the form and behave like a media library.
   ========================================================================== */

/* Which gallery is on screen — the product's, or one variant's. Reads as a row
   of tabs because that is what it is: one set of images at a time, never two. */
/* A variant with no pictures of its own is not broken — it is showing the
   product's. It reads as available rather than as missing. */

/* The gallery. `auto-fill` rather than `auto-fit`: with two photographs in a
   wide section, auto-fit stretches them to half the page each and a ring fills
   a 600px tile. auto-fill leaves the empty columns empty and the tiles the
   size they were designed to be. */
.im-gal {
  display: grid; gap: var(--sp-3); margin: var(--sp-4) 0 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.im-gal__item {
  position: relative; display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-2);
  border: 1px solid var(--c-line); border-radius: var(--r-lg);
  background: var(--c-surface);
}
.im-gal__item.is-primary { border-color: var(--c-metal-line); background: var(--c-metal-weak); }
.im-gal__shot {
  display: block; aspect-ratio: 1; border-radius: var(--r-md); overflow: clip;
  /* A chequerboard, so a PNG cut out on transparency is visibly cut out rather
     than looking like it has a white background it does not have. */
  background-color: var(--c-surface-sunk);
  background-image: linear-gradient(45deg, var(--c-surface-2) 25%, transparent 25% 75%, var(--c-surface-2) 75%),
                    linear-gradient(45deg, var(--c-surface-2) 25%, transparent 25% 75%, var(--c-surface-2) 75%);
  background-size: 16px 16px; background-position: 0 0, 8px 8px;
}
.im-gal__shot img { inline-size: 100%; block-size: 100%; object-fit: contain; display: block; }
.im-gal__badge {
  position: absolute; inset-block-start: var(--sp-3); inset-inline-start: var(--sp-3);
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px var(--sp-2); border-radius: var(--r-pill);
  background: var(--c-metal); color: #fff;
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
}
.im-gal__bar { display: flex; align-items: center; gap: 2px; }
.im-gal__x:hover { color: var(--c-danger); }
.im-gal__meta { margin: 0; text-align: center; }

/* Nothing here yet. Says which scope is empty and what putting something in it
   would do, rather than drawing an empty frame. */

/* The drop zone. A label for the file input, so a click anywhere on it opens
   the picker with no script at all. */
.im-galadd { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-block-start: var(--sp-4); }
.im-galadd__drop {
  display: flex; align-items: center; gap: var(--sp-3); flex: 1 1 260px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px dashed var(--c-line-strong); border-radius: var(--r-lg);
  background: var(--c-surface-2); cursor: pointer;
  font-size: var(--fs-sm); line-height: var(--lh-snug);
}
.im-galadd__drop:hover, .im-galadd__drop.is-over { border-color: var(--c-accent); background: var(--c-accent-weak); }
.im-galadd__ico { color: var(--c-ink-3); flex: none; }
.im-galadd__file.is-hidden {
  /* Not display:none — that takes it out of the tab order and off the
     accessibility tree, and the label above is the only other way in. */
  position: absolute; inline-size: 1px; block-size: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.im-galadd__go.is-busy { opacity: .6; pointer-events: none; }
.im-galadd.is-full { justify-content: center; }

@media (max-width: 720px) {
  .im-gal { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .im-galadd__drop { flex-basis: 100%; }
}

/* A row's picture, in the slot the type icon had. Same box, so a list of
   photographed and unphotographed designs has one column edge, not two. */


/* --- iv-mk: what a making charge is made of ------------------------------
   Three columns rather than a sentence, because the reader is checking one of
   the three — what it is for, what the rate was, what it came to — and a
   sentence makes them read all of it to find one. */
.iv-mk { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.iv-mk > li {
  display: grid; grid-template-columns: 1fr auto auto; gap: var(--sp-2);
  align-items: baseline; font-size: var(--fs-sm);
}
.iv-mk__b { font-size: var(--fs-xs); color: var(--c-ink-3); white-space: nowrap; }
.iv-mk__a { font-family: var(--font-num); font-variant-numeric: var(--num-feat); }

/* The making-charge rows on the design screen. The label column earns the room:
   "Stone setting" and "Rhodium plating" are what makes the list readable. */

/* ==========================================================================
   LIVE MARKET RATES (tenant step 25) — the module bar's rate pill
   The Gold Rates board's lr-* rules live in rates.css since 2026-10-08 (Gold Rates
   pages only). What stays here is what the pill (main.php, live-rate.js) needs on
   every page: hidden parts, the pulse, the flash on a new price, the market figure.
   ========================================================================== */
.modbar__rate [hidden] { display: none !important; }
@keyframes lr-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c-success) 55%, transparent); } 100% { box-shadow: 0 0 0 7px transparent; } }
@keyframes lr-up   { 0% { background: var(--c-success-weak); color: var(--c-success); } 100% { background: transparent; } }
@keyframes lr-down { 0% { background: var(--c-danger-weak); color: var(--c-danger); } 100% { background: transparent; } }
.lr-flash--up   { animation: lr-up 1.4s ease-out; }
.lr-flash--down { animation: lr-down 1.4s ease-out; }

/* the pill's live market figure */
.rate-pill__live { display: inline-flex; align-items: center; gap: 4px; padding-inline-end: var(--sp-2); margin-inline-end: 2px;
  border-inline-end: 1px solid currentColor; border-inline-end-color: color-mix(in srgb, currentColor 30%, transparent);
  font-family: var(--font-num); font-variant-numeric: var(--num-feat); font-size: var(--fs-xs); font-weight: var(--fw-semi);
  color: inherit; direction: ltr; unicode-bidi: isolate; }
.rate-pill__dot { inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--c-success); animation: lr-pulse 1.8s ease-out infinite; }
.rate-pill__live--lag .rate-pill__dot { background: var(--c-warn); animation: none; }
.rate-pill__live--up .rate-pill__mkt::before   { content: "\25B2\00A0"; font-size: 8px; vertical-align: 1px; color: color-mix(in srgb, var(--c-success) 55%, #fff); }
.rate-pill__live--down .rate-pill__mkt::before { content: "\25BC\00A0"; font-size: 8px; vertical-align: 1px; color: color-mix(in srgb, var(--c-danger) 55%, #fff); }
.rate-pill__mkt { border-radius: 3px; padding-inline: 2px; }
@media (prefers-reduced-motion: reduce) { .rate-pill__dot, .lr-flash--up, .lr-flash--down { animation: none !important; } }

/* ==========================================================================
   Module 04 · tags & labels, customer holds, value at today's rate
   (INV-021, INV-030). Logical properties throughout, so RTL needs nothing.
   ========================================================================== */

/* --- value at today's rate: the strip above the stock tree ---------------- */
.iv-val { display: flex; flex-direction: column; gap: var(--sp-3); margin-block-end: var(--d-stack); }
.iv-val__head { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.iv-val__grid { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.iv-val__total, .iv-val__metal {
  display: flex; flex-direction: column; gap: var(--sp-1);
  padding: var(--sp-3) var(--sp-4); border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-surface);
}
.iv-val__total { background: var(--c-accent-weak); border-color: var(--c-accent-line); }
.iv-val__metal.is-stale { border-color: var(--c-warn-line); background: var(--c-warn-weak); }
.iv-val__k { font-size: var(--fs-sm); color: var(--c-ink-faint); }
.iv-val__v { font-size: var(--fs-xl); font-weight: var(--fw-semi); color: var(--c-ink); font-variant-numeric: tabular-nums; }
.iv-val__sub { font-size: var(--fs-sm); color: var(--c-ink-faint); display: flex; gap: var(--sp-1); flex-wrap: wrap; align-items: center; }
.iv-val__sub .is-up { color: var(--c-success); } .iv-val__sub .is-down { color: var(--c-danger); }
.iv-val-tile .tile__sub { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.iv-val-chip { display: inline-flex; gap: var(--sp-1); align-items: baseline; white-space: nowrap; }

/* --- print screen: on the oform kit since 2026-10-08 (inventory.css .ivl-tp*); the
       printer status line of the layouts screen still reads these two ------------ */
.hint.is-ok { color: var(--c-success); } .hint.is-err { color: var(--c-danger); }

/* --- tags & labels configuration ------------------------------------------ */
.iv-tt { display: grid; gap: var(--d-stack); grid-template-columns: minmax(260px, 340px) minmax(0, 1fr); align-items: start; margin-block-start: var(--d-stack); }
@media (max-width: 900px) { .iv-tt { grid-template-columns: 1fr; } }
.iv-tt__items { list-style: none; margin: 0; padding: 0; }
.iv-tt__items li + li { border-block-start: 1px solid var(--c-line-soft); }
.iv-tt__items a { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-3) var(--sp-4); color: var(--c-ink); text-decoration: none; border-inline-start: 3px solid transparent; }
.iv-tt__items a:hover { background: var(--c-surface-sunk); }
.iv-tt__items li.is-on a { background: var(--c-accent-weak); border-inline-start-color: var(--c-accent); }
.iv-tt__items li.is-off b { color: var(--c-ink-faint); }
.iv-tt__edit form { display: flex; flex-direction: column; gap: var(--sp-3); }
.iv-tt__tokens { display: flex; flex-wrap: wrap; gap: 4px; margin-block-end: var(--sp-2); }
.iv-tt__tok {
  font: var(--fs-xs)/1.4 var(--font-num, ui-monospace, monospace); padding: 2px 6px; cursor: pointer;
  border: 1px solid var(--c-accent-line); border-radius: var(--r-sm); background: var(--c-surface); color: var(--c-ink);
}
.iv-tt__tok:hover { background: var(--c-accent); color: var(--c-ink-inv); }
.iv-tt__body { font-family: var(--font-num, ui-monospace, monospace); font-size: var(--fs-sm); line-height: 1.55; min-block-size: 18em; tab-size: 2; }
.iv-tt__more { margin-block-start: var(--sp-3); padding-block-start: var(--sp-3); border-block-start: 1px solid var(--c-line-soft); }
.iv-tt__preview { margin-block-start: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }
.iv-tt__zpl { margin: 0; padding: var(--sp-3); max-block-size: 22em; overflow: auto; background: var(--c-surface-sunk); border: 1px solid var(--c-line); border-radius: var(--r-sm); font-size: var(--fs-xs); white-space: pre-wrap; word-break: break-all; }
.iv-tt__label { background: #fff; color: #000; border: 1px dashed var(--c-line-strong); border-radius: 2mm; overflow: hidden; zoom: 1.6; font: 7pt/1.2 Arial, sans-serif; }
.iv-tt__modes { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.iv-tt__mode { display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-3); border: 1px solid var(--c-line); border-radius: var(--r-md); cursor: pointer; }
.iv-tt__mode.is-on, .iv-tt__mode:has(input:checked) { border-color: var(--c-accent); background: var(--c-accent-weak); }
.iv-tt__mode span { display: flex; flex-direction: column; gap: 2px; }
.iv-tt__printer { max-inline-size: 720px; margin-block-start: var(--d-stack); }
.iv-tt__printer form { display: flex; flex-direction: column; gap: var(--sp-3); }

/* The seeded HTML labels, for the preview above (the print page carries its own copy). */
.lbl { width: 100%; height: 100%; padding: 1.2mm 1.6mm; display: flex; flex-direction: column; justify-content: space-between; box-sizing: border-box; }
.lbl--split { flex-direction: row; gap: 1.5mm; padding: 1mm 1.5mm; }
.lbl__half { flex: 1 1 50%; display: flex; flex-direction: column; justify-content: space-between; min-width: 0; }
.lbl__co { font-weight: 700; font-size: 6.5pt; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lbl__nm { font-size: 6.5pt; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lbl__bc { height: 5.5mm; } .lbl__bc .lbl-bc { width: 100%; height: 100%; display: block; }
.lbl__tag { font: 700 7pt/1 Consolas, "Courier New", monospace; text-align: center; }
.lbl__row { font-size: 7pt; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lbl__sm { font-size: 5.5pt; }

/* --- customer holds: the customer search under the hold form (holds.js) ---- */
.iv-hold__find { position: relative; }
.iv-hold__results {
  position: absolute; z-index: 20; inset-inline: 0; inset-block-start: 100%; margin: 4px 0 0; padding: 4px; list-style: none;
  background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-md); box-shadow: 0 10px 28px rgba(0,0,0,.14);
  max-block-size: 16em; overflow: auto;
}
.iv-hold__results li { padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); cursor: pointer; }
.iv-hold__results li:hover, .iv-hold__results li:focus { background: var(--c-accent-weak); outline: none; }

/* --- layout editor: the label preview beside the name and the size -------- */
.iv-tt__top { display: grid; gap: var(--sp-4); grid-template-columns: minmax(220px, 1fr) minmax(280px, 1.35fr); align-items: start; }
@media (max-width: 1100px) { .iv-tt__top { grid-template-columns: 1fr; } }
.iv-tt__meta { display: flex; flex-direction: column; gap: var(--sp-3); }
.iv-tt__pv { margin: 0; display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-surface-sunk); }
.iv-tt__pvcap { display: flex; gap: var(--sp-2); align-items: baseline; flex-wrap: wrap; font-size: var(--fs-sm); }
.iv-tt__stage { display: flex; justify-content: center; align-items: center; min-block-size: 110px; padding: var(--sp-2); border-radius: var(--r-sm);
  background: repeating-conic-gradient(var(--c-surface) 0 25%, var(--c-surface-sunk) 0 50%) 0 0 / 14px 14px; overflow: auto; }
.iv-tt__svg { inline-size: 100%; max-inline-size: 520px; block-size: auto; box-shadow: 0 1px 6px rgba(0,0,0,.18); border-radius: 3px; background: #fff; }
.iv-tt__svg .z-t { font-family: "Arial Narrow", "Roboto Condensed", "Helvetica Neue", Arial, sans-serif; font-weight: 700; fill: #000; }
.iv-tt__svg .z-t.is-over { fill: #c0392b; text-decoration: underline wavy #c0392b; }
.iv-tt__frame { border: 0; background: #fff; box-shadow: 0 1px 6px rgba(0,0,0,.18); border-radius: 3px; }
.iv-tt__pvsize { margin: 0; }
.iv-tt__pvacts { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.iv-tt__exact { display: flex; justify-content: center; }
.iv-tt__exact img { max-inline-size: 100%; border: 1px solid var(--c-line); background: #fff; }
.iv-tt__filled > summary { cursor: pointer; font-size: var(--fs-sm); color: var(--c-ink-faint); }
.iv-tt__filled .iv-tt__zpl { margin-block-start: var(--sp-2); max-block-size: 14em; }

/* ── Item page · General (2026-09-23) ─────────────────────────────────────────
   "For" sits in a grid cell beside Purity and Design no., so it is one joined
   control exactly as tall as an input, filling its cell — same label, same
   field margin, same height as its neighbours. */

/* Image + sketch pickers: two equal tiles on one row, under the descriptions. */
.im-up {
  display: flex; align-items: center; gap: var(--sp-3); flex: 1 1 auto; min-inline-size: 0;
  padding: var(--sp-2) var(--sp-3); border: 1px dashed var(--c-line-strong); border-radius: var(--r-md);
  background: var(--c-surface-2); cursor: pointer; font-size: var(--fs-sm); line-height: var(--lh-snug);
}
.im-up:hover, .im-up.is-picked { border-color: var(--c-accent); background: var(--c-accent-weak); }
.im-up__thumb {
  flex: none; inline-size: 44px; block-size: 44px; display: grid; place-items: center; overflow: hidden;
  border-radius: var(--r-sm); background: var(--c-surface); color: var(--c-ink-3); border: 1px solid var(--c-line);
}
.im-up__thumb img { inline-size: 100%; block-size: 100%; object-fit: cover; }
.im-up__txt { display: flex; flex-direction: column; min-inline-size: 0; }
.im-up__txt small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.im-up__file { position: absolute; inline-size: 1px; block-size: 1px; clip-path: inset(50%); overflow: hidden; white-space: nowrap; }
.im-up:has(+ .im-up__file:focus-visible) { box-shadow: var(--focus-ring); }
/* A <label> picks up a top margin from the base `label` rule; the For, Images
   and Sketch headings are <span class="label"> (a radio group or a picker, not
   one input), so give them the same margin and every cell in the row lines up. */

/* ── Item page · Details tabs (2026-09-24) ────────────────────────────────────
   Labour · Stones · Images · Variants · Vendor Ref. · Notification in one card,
   so the page is as long as one of them instead of all of them. */


.im-snap { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.im-snap__thumb { inline-size: 34px; block-size: 34px; border-radius: var(--r-sm); overflow: hidden; border: 1px solid var(--c-line); flex: none; }
.im-snap__thumb img { inline-size: 100%; block-size: 100%; object-fit: cover; }
.im-snap__rm { display: inline-flex; align-items: center; gap: 4px; color: var(--c-ink-3); }

/* Item page · General in four columns (2026-09-24): Stocked as fills its cell
   like For did; the status cell stacks eCommerce and Active. */

/* ── Type-to-search drop-downs (combo.js, 2026-09-24) ─────────────────────────
   An input in front of a hidden <select>: type to filter, ▾ or ↓ to see the
   whole list. The list is fixed to the viewport so a table's scroll box never
   clips it. */
.combo { position: relative; display: block; min-inline-size: 0; }
.combo__native { display: none !important; }
.combo__input { inline-size: 100%; padding-inline-end: 30px; text-overflow: ellipsis; }
.combo__btn {
  position: absolute; inset-block: 1px; inset-inline-end: 1px; inline-size: 28px;
  border: 0; background: transparent; cursor: pointer; color: var(--c-ink-3); border-start-end-radius: var(--r-md); border-end-end-radius: var(--r-md);
}
.combo__btn::before {
  content: ""; position: absolute; inset-block-start: calc(50% - 5px); inset-inline-start: calc(50% - 3px);
  inline-size: 6px; block-size: 6px; border: solid currentColor; border-width: 0 1.5px 1.5px 0; transform: rotate(45deg);
  transition: transform var(--dur-1) var(--ease);
}
.combo.is-open .combo__btn::before { transform: translateY(3px) rotate(-135deg); }
.combo__btn:hover { color: var(--c-ink-1); }
.combo.is-disabled .combo__btn { cursor: not-allowed; opacity: .5; }
.combo__list {
  position: fixed; z-index: 1000; margin: 0; padding: var(--sp-1); list-style: none;
  max-block-size: 320px; max-inline-size: min(420px, 92vw); overflow: auto;
  background: var(--c-surface); border: 1px solid var(--c-line); border-radius: var(--r-md);
  box-shadow: var(--shadow-2, 0 6px 20px rgba(0,0,0,.14)); font-size: var(--fs-sm);
}
.combo__opt { padding: 7px 10px; border-radius: var(--r-sm); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.combo__opt.is-active { background: var(--c-accent-weak); color: var(--c-accent); }
.combo__opt.is-selected { font-weight: var(--fw-semi); }
.combo__opt.is-disabled { color: var(--c-ink-4); cursor: not-allowed; }
.combo__group { padding: 8px 10px 4px; font-size: var(--fs-xs); font-weight: var(--fw-semi); color: var(--c-ink-3); text-transform: uppercase; letter-spacing: .04em; }
.combo__none { padding: 7px 10px; color: var(--c-ink-4); }
/* An option that carries a picture: the picture in the list, and the chosen
   one's inside the box, ahead of the text. */
.combo__opt.has-icon { display: flex; align-items: center; gap: var(--sp-3); }
.combo__ico { flex: 0 0 auto; inline-size: 18px; block-size: 18px; color: var(--c-ink-3); }
.combo__opt.is-active .combo__ico { color: inherit; }
.combo__lead {
  position: absolute; inset-block-start: 50%; inset-inline-start: 9px; inline-size: 16px; block-size: 16px;
  transform: translateY(-50%); color: var(--c-ink-3); pointer-events: none;
}
.combo.has-icon .combo__input { padding-inline-start: 32px; }
.field.is-invalid .combo__input { border-color: var(--c-danger, #c0392b); }

/* -- partners vendor form (G-VEN) -- */
/* the vendor form (partners/edit, G-VEN) opens from Purchasing OR Accounting, and purchases.css loads only under Purchasing: the SWIFT field reads upper case wherever it opens */
.pt-swift { text-transform: uppercase; }

/* -- module page attention card (G-DASH) -- */
/* the generic module page's "Needs doing" card (apps/module.php): its spacing, no inline style= (2026-10-09) */
.modattn { margin-block-end: var(--sp-4, 16px); }
.modattn .muted { margin: 0; }
