/* ============================================================
   REBOTA — Design system
   ------------------------------------------------------------
   One token layer for the website, the dashboard and every module.

   COLOUR IS FIXED. The palette below is the Rebota Works palette,
   copied verbatim from inc/works-header.php. It is the mandatory
   standard and is NOT redesigned here — not one hue is changed,
   added to the brand ramp, or substituted. Everything else
   (typography, spacing, density, elevation, motion, components)
   is rebuilt to the standard set by SAP Fiori, Oracle Redwood and
   Odoo, because the audit found none of it had a system at all.

   WHAT THE AUDIT FOUND
     * 125 distinct hex values in app.css alone, against 67 token
       definitions — so tokens existed but two thirds of the colour
       in the product bypassed them. The dashboard's blue (#0F1E3D,
       #F0F7FF) is not the Works blue (#1877F2): the marketing site
       and the product did not share an accent.
     * 28 distinct font sizes, on a half-pixel scale: 8.5px, 9px,
       9.5px, 10px, 10.5px, 11px, 11.5px, 12px, 12.5px, 13px, 13.5px…
       That is not a type scale, it is 28 individual decisions. 8.5px
       body text is below any legibility floor.
     * 31 distinct padding/margin values (1,2,3,5,7,9,11,13,21,26,42…).
       No spacing rhythm, so nothing aligns to a grid.
     * 1 focus-visible rule in 188KB of CSS. Keyboard users are an
       explicit requirement in enterprise procurement, not an extra.
     * No density control at all. Density is the single biggest UX
       differentiator in ERP: SAP ships Cozy/Compact, Oracle ships
       comfortable/compact, and an accountant reconciling 400 lines
       needs a different row height from a site engineer on a phone.

   HOW TO USE
     Load AFTER the existing stylesheets. This file only defines
     tokens and opt-in classes; it overrides nothing by itself, so it
     is safe to add before any page is migrated.
   ============================================================ */

/* ------------------------------------------------------------
   1. COLOUR — Rebota Works palette, verbatim. Do not edit.
   ------------------------------------------------------------ */
:root {
  /* Brand — exactly as defined in inc/works-header.php */
  --rb-accent:        #1877F2;
  --rb-accent-hover:  #1565D8;
  --rb-accent-muted:  #6EA8FF;
  --rb-accent-border: #CFDFFA;
  --rb-accent-soft:   #EBF3FE;
  --rb-accent-soft-2: #F5F9FF;
  --rb-accent-soft-3: #F8FBFF;
  --rb-link:          #1877F2;

  /* Ink */
  --rb-heading:       #0F172A;
  --rb-text:          #1E293B;
  --rb-text-body:     #334155;
  /* Slate 500 (#64748B) measured 4.3:1 against the soft card ground on six
     pages — under the 4.5:1 AA floor, and it is the colour almost every
     empty-state sentence uses, so the text a new user reads first was the
     least legible on the page. Darkened just enough to clear AA on the
     lightest surface we put it on (5.3:1 on #F1F5F9, 5.8:1 on white) while
     staying visibly lighter than body #334155. */
  --rb-text-muted:    #5A6779;
  --rb-text-subtle:   #94A3B8;   /* already in use as .wu-search-ph */

  /* Surface */
  --rb-page:          #FFFFFF;
  --rb-card:          #FFFFFF;
  --rb-card-border:   #E5E9F0;
  --rb-nav-border:    #EDF0F7;

  /* Neutral ramp, derived from the palette's own slate family so it
     stays in the same colour space rather than introducing a
     second grey. These are the values the product already uses. */
  --rb-slate-50:  #F8FAFC;
  --rb-slate-100: #F1F5F9;
  --rb-slate-200: #E2E8F0;
  --rb-slate-300: #CBD5E1;
  --rb-slate-400: #94A3B8;
  --rb-slate-500: #64748B;   /* palette ramp — verbatim, see the header */
  --rb-slate-600: #475569;
  --rb-slate-700: #334155;
  --rb-slate-800: #1E293B;
  --rb-slate-900: #0F172A;

  /* Semantic status. Separate from the accent on purpose: SAP,
     Oracle and Odoo all keep status colour independent of brand
     colour, because "this row is in error" must never be confused
     with "this row is selected". Values are the ones already in the
     codebase, not new inventions. */
  --rb-success:      #16A34A;
  --rb-success-soft: #E7F6EC;
  --rb-warning:      #B45309;
  --rb-warning-soft: #FEF3C7;
  --rb-danger:       #DC2626;
  --rb-danger-soft:  #FEE2E2;
  --rb-info:         #1877F2;
  --rb-info-soft:    #EBF3FE;

  /* Financial figures. Red/green alone fails for the ~8% of men with
     a red-green deficiency, so negative figures also carry
     parentheses in the .rb-num-negative class below. */
  --rb-positive: #16A34A;
  --rb-negative: #DC2626;
}

/* ------------------------------------------------------------
   1b. DARK THEME — the token values
   ------------------------------------------------------------
   These did not exist. The whole of section 1 above was defined once,
   in light, and nothing anywhere redefined a single --rb-* token for a
   dark viewer. app.css does carry a dark block, but it redefines the
   LEGACY variables (--gray100, --offwhite, --navy and the rest), so
   anything written against the design system - 1279 token references
   across the stylesheets at the time of writing - rendered its light
   surface and its light ink on top of a dark application. A component
   built the way this file asks you to build one was the only kind of
   component guaranteed to be wrong in dark mode.

   The tokens are redefined here, once, so components do not each need
   a hand-written dark rule. Where app.css already has a per-component
   dark override, that override still wins on specificity and ordering;
   this changes what a component gets when it has NOT been given one,
   which previously was white.

   THREE STATES, NOT TWO. An explicit choice stamps data-theme; the
   default "system" setting stamps nothing at all, and for those viewers
   only prefers-color-scheme separates light from dark. So the media
   query is guarded with :not([data-theme="light"]) - an explicit light
   choice must beat a dark operating system - and the attribute rule is
   repeated after it so an explicit dark choice beats a light one.

   HOW THE VALUES WERE PICKED
   Not by inverting. The ink ramp is re-anchored on the same slate
   family so the two themes stay in one colour space, surfaces lift
   rather than drop (a raised card in the dark is LIGHTER than the page,
   the opposite of the light theme), and the accent moves to the
   --rb-accent-muted blue, because #1877F2 on a near-black ground is
   under 4.5:1 and vibrates. Status hues are lightened for the same
   reason and their soft backgrounds become low-alpha washes of
   themselves rather than pale tints, which on a dark ground read as
   blocks of glare.                                                  */
:root[data-theme="dark"] {
  /* Brand. The mid blue is unreadable on near-black; the muted one is
     the same hue with the luminance a dark ground needs. */
  --rb-accent:        #4D9FFF;
  --rb-accent-hover:  #6EB0FF;
  --rb-accent-muted:  #2C7BE0;
  --rb-accent-border: #1E3A5F;
  --rb-accent-soft:   rgba(77, 159, 255, .14);
  --rb-accent-soft-2: rgba(77, 159, 255, .09);
  --rb-accent-soft-3: rgba(77, 159, 255, .05);
  --rb-link:          #6EA8FF;

  /* Ink. Not pure white: #FFFFFF on #0A1628 is a contrast of about
     17:1 and reads as glare over a full screen of text. */
  --rb-heading:       #F8FAFC;
  --rb-text:          #E7ECF3;
  --rb-text-body:     #CBD5E1;
  --rb-text-muted:    #94A3B8;
  --rb-text-subtle:   #6B7A90;

  /* Surface. The card is LIGHTER than the page here - elevation in the
     dark is light, not shadow, because a shadow on a dark ground is
     invisible. */
  --rb-page:          #0A1628;
  --rb-card:          #111F35;
  --rb-card-border:   #24344E;
  --rb-nav-border:    #1C2B42;

  /* The neutral ramp flips end for end so that "50 is the faintest
     background, 900 is the strongest ink" still holds. A component
     reaching for --rb-slate-100 as a subtle fill gets a subtle fill in
     both themes instead of a white block in one of them. */
  --rb-slate-50:  #16253C;
  --rb-slate-100: #1B2C45;
  --rb-slate-200: #24344E;
  --rb-slate-300: #33465F;
  --rb-slate-400: #6B7A90;
  --rb-slate-500: #94A3B8;
  --rb-slate-600: #B6C2D1;
  --rb-slate-700: #CBD5E1;
  --rb-slate-800: #E2E8F0;
  --rb-slate-900: #F8FAFC;

  /* Status. Lightened to clear 4.5:1 on the page colour; the soft
     variants become washes so a status row tints rather than glares. */
  --rb-success:      #3DD68C;
  --rb-success-soft: rgba(61, 214, 140, .14);
  --rb-warning:      #F0B429;
  --rb-warning-soft: rgba(240, 180, 41, .16);
  --rb-danger:       #FF6B6B;
  --rb-danger-soft:  rgba(255, 107, 107, .16);
  --rb-info:         #4D9FFF;
  --rb-info-soft:    rgba(77, 159, 255, .14);

  --rb-positive: #3DD68C;
  --rb-negative: #FF6B6B;

  /* Shadows are nearly invisible on a dark ground; the border above is
     what separates a card from the page, so the shadows only deepen. */
  --rb-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --rb-shadow-md: 0 4px 14px rgba(0, 0, 0, .5);
  --rb-shadow-lg: 0 14px 34px rgba(0, 0, 0, .6);
  --rb-shadow-focus: 0 0 0 3px rgba(77, 159, 255, .35);

  color-scheme: dark;
}

/* The viewer who never chose: no attribute is stamped, so the operating
   system decides. Guarded so an explicit light choice still wins. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --rb-accent:        #4D9FFF;
    --rb-accent-hover:  #6EB0FF;
    --rb-accent-muted:  #2C7BE0;
    --rb-accent-border: #1E3A5F;
    --rb-accent-soft:   rgba(77, 159, 255, .14);
    --rb-accent-soft-2: rgba(77, 159, 255, .09);
    --rb-accent-soft-3: rgba(77, 159, 255, .05);
    --rb-link:          #6EA8FF;

    --rb-heading:       #F8FAFC;
    --rb-text:          #E7ECF3;
    --rb-text-body:     #CBD5E1;
    --rb-text-muted:    #94A3B8;
    --rb-text-subtle:   #6B7A90;

    --rb-page:          #0A1628;
    --rb-card:          #111F35;
    --rb-card-border:   #24344E;
    --rb-nav-border:    #1C2B42;

    --rb-slate-50:  #16253C;
    --rb-slate-100: #1B2C45;
    --rb-slate-200: #24344E;
    --rb-slate-300: #33465F;
    --rb-slate-400: #6B7A90;
    --rb-slate-500: #94A3B8;
    --rb-slate-600: #B6C2D1;
    --rb-slate-700: #CBD5E1;
    --rb-slate-800: #E2E8F0;
    --rb-slate-900: #F8FAFC;

    --rb-success:      #3DD68C;
    --rb-success-soft: rgba(61, 214, 140, .14);
    --rb-warning:      #F0B429;
    --rb-warning-soft: rgba(240, 180, 41, .16);
    --rb-danger:       #FF6B6B;
    --rb-danger-soft:  rgba(255, 107, 107, .16);
    --rb-info:         #4D9FFF;
    --rb-info-soft:    rgba(77, 159, 255, .14);

    --rb-positive: #3DD68C;
    --rb-negative: #FF6B6B;

    --rb-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --rb-shadow-md: 0 4px 14px rgba(0, 0, 0, .5);
    --rb-shadow-lg: 0 14px 34px rgba(0, 0, 0, .6);
    --rb-shadow-focus: 0 0 0 3px rgba(77, 159, 255, .35);

    color-scheme: dark;
  }
}

/* Paper is white whatever the screen is set to. Without this, printing
   from a dark session produces a page of dark ink boxes, or - on the
   printers that drop backgrounds - white text on nothing. The document
   iframes do not inherit this, but Ctrl+P on the application does. */
@media print {
  :root, :root[data-theme="dark"] {
    --rb-page: #FFFFFF; --rb-card: #FFFFFF;
    --rb-card-border: #E5E9F0; --rb-nav-border: #EDF0F7;
    --rb-heading: #0F172A; --rb-text: #1E293B; --rb-text-body: #334155;
    --rb-text-muted: #5A6779; --rb-text-subtle: #94A3B8;
    --rb-slate-50: #F8FAFC; --rb-slate-100: #F1F5F9; --rb-slate-200: #E2E8F0;
    --rb-slate-300: #CBD5E1; --rb-slate-400: #94A3B8; --rb-slate-500: #5A6779;
    --rb-slate-600: #475569; --rb-slate-700: #334155; --rb-slate-800: #1E293B;
    --rb-slate-900: #0F172A;
    color-scheme: light;
  }
}

/* ------------------------------------------------------------
   2. TYPOGRAPHY
   ------------------------------------------------------------
   A 9-step scale on a 1.125 ratio, snapped to whole pixels.
   Replaces 28 ad-hoc sizes. 12px is the floor for any text a user
   must read; 11px is permitted only for uppercase metadata labels,
   which is the same line SAP Fiori draws.

   Inter is retained — it is already the product's face, it has the
   tabular figures a financial UI needs, and changing it would churn
   every layout for no gain.                                        */
:root {
  --rb-font: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  /* Tabular figures matter more than the face: in a ledger, columns
     of numbers must align on the decimal. */
  --rb-font-num: 'Inter', ui-monospace, 'SF Mono', 'Consolas', monospace;
}

/* ── Devanagari (Marathi, and Hindi when it lands) ─────────────────
   Inter carries NO Devanagari glyphs. Left alone, every Marathi
   character falls back per-glyph to whatever the OS picks, so a line
   mixes two faces at two optical sizes and the leading fights itself.

   These are SYSTEM faces on purpose. Noto Sans Devanagari from Google
   Fonts would render beautifully and would also send every visitor's
   IP to Google before consent — the compliance gate already carries
   that exact finding as an open item, and adding a second instance of
   a problem being fixed is not a trade worth making. Nirmala UI ships
   with Windows, Kohinoor with macOS/iOS, Noto with Android and most
   Linux desktops, so the coverage is real without a new recipient.

   1.06em because Devanagari's x-height runs smaller than Inter's at
   the same nominal size; without it Marathi reads noticeably lighter
   than the English it sits beside. The line-height increase is for
   the matras above and below the baseline, which Latin leading does
   not allow room for.                                              */
:root[data-script="devanagari"] {
  --rb-font: 'Nirmala UI', 'Kohinoor Devanagari', 'Noto Sans Devanagari',
             'Mangal', system-ui, sans-serif;
  /* Numerals stay Latin and tabular — Marathi business documents use
     Latin digits, and a GST return must match the portal. */
  --rb-font-num: 'Inter', ui-monospace, 'SF Mono', 'Consolas', monospace;
}
:root[data-script="devanagari"] body {
  font-size: 1.06em;
  line-height: 1.7;
}

:root {
  /* ── Type size ──────────────────────────────────────────────────
     One multiplier drives the whole scale. A person who finds 12px
     table text hard to read at the end of a shift moves one control,
     and every step moves together — which is the point of having a
     scale at all. Setting nine sizes independently is how a type
     system stops being one.

     Values are computed rather than listed per preference so that
     adding a step later cannot leave one preference behind. The scale
     is clamped in the switcher, not here, because CSS cannot refuse a
     bad cookie — inc/theme-head.php validates it against a whitelist
     before it ever reaches the attribute. */
  --rb-type-scale: 1;

  --rb-text-2xs: calc(11px * var(--rb-type-scale));   /* uppercase labels only */
  --rb-text-xs:  calc(12px * var(--rb-type-scale));   /* dense table cells, captions */
  --rb-text-sm:  calc(13px * var(--rb-type-scale));   /* secondary UI text */
  --rb-text-md:  calc(14px * var(--rb-type-scale));   /* BODY DEFAULT */
  --rb-text-lg:  calc(16px * var(--rb-type-scale));   /* emphasised body, form inputs */
  --rb-text-xl:  calc(18px * var(--rb-type-scale));   /* card titles */
  --rb-text-2xl: calc(22px * var(--rb-type-scale));   /* section headings */
  --rb-text-3xl: calc(28px * var(--rb-type-scale));   /* page titles */
  --rb-text-4xl: calc(36px * var(--rb-type-scale));   /* marketing hero only */

  --rb-leading-tight:  1.25;   /* headings */
  --rb-leading-snug:   1.4;    /* dense UI */
  --rb-leading-normal: 1.55;   /* body */
  --rb-leading-relaxed:1.7;    /* long-form prose */

  --rb-weight-regular:  400;
  --rb-weight-medium:   500;
  --rb-weight-semibold: 600;
  --rb-weight-bold:     700;

  --rb-tracking-tight: -0.011em;  /* large headings only */
  --rb-tracking-wide:   0.06em;   /* uppercase labels */
}

/* ------------------------------------------------------------
   3. SPACING — 4px base grid
   ------------------------------------------------------------
   Replaces 31 arbitrary values. Every gap, pad and margin resolves
   to a multiple of 4, which is what makes columns line up across
   components nobody designed together.                             */
:root {
  --rb-space-0:  0;
  --rb-space-1:  4px;
  --rb-space-2:  8px;
  --rb-space-3:  12px;
  --rb-space-4:  16px;
  --rb-space-5:  20px;
  --rb-space-6:  24px;
  --rb-space-8:  32px;
  --rb-space-10: 40px;
  --rb-space-12: 48px;
  --rb-space-16: 64px;
  --rb-space-20: 80px;
}

/* ------------------------------------------------------------
   4. RADII, ELEVATION, MOTION
   ------------------------------------------------------------
   Elevation is deliberately restrained. ERP screens are dense; a
   heavy shadow on every card turns a data grid into visual noise.
   Two levels of lift plus a border is what Fiori and Redwood use.  */
:root {
  --rb-radius-sm: 4px;
  --rb-radius-md: 6px;
  --rb-radius-lg: 10px;
  --rb-radius-pill: 999px;

  --rb-shadow-none: none;
  --rb-shadow-sm: 0 1px 2px rgba(15, 23, 42, .06);
  --rb-shadow-md: 0 2px 8px -2px rgba(15, 23, 42, .10), 0 1px 2px rgba(15, 23, 42, .04);
  --rb-shadow-lg: 0 12px 32px -12px rgba(15, 23, 42, .20);
  --rb-shadow-focus: 0 0 0 3px rgba(24, 119, 242, .28);   /* accent at 28% */

  --rb-duration-fast: 120ms;
  --rb-duration-base: 180ms;
  --rb-ease: cubic-bezier(.2, 0, .2, 1);

  --rb-z-dropdown: 1000;
  --rb-z-sticky:   1020;
  --rb-z-drawer:   1040;
  --rb-z-modal:    1060;
  --rb-z-toast:    1080;
}

/* ------------------------------------------------------------
   5. DENSITY
   ------------------------------------------------------------
   The single most important ERP-specific control, and the one
   Rebota had none of. Set data-density on <html> or any container.

     compact      — reconciliation, ledgers, bulk edit. ~28px rows.
     default      — most screens. ~36px rows.
     comfortable  — touch, site use, low-frequency forms. ~44px rows,
                    which is also the minimum touch target.

   Row height and control height are driven from one variable each,
   so a screen switches density without any component knowing.      */
:root,
[data-density="default"] {
  --rb-row-h:      36px;
  --rb-control-h:  36px;
  --rb-cell-pad-y: var(--rb-space-2);
  --rb-cell-pad-x: var(--rb-space-3);
  --rb-ui-size:    var(--rb-text-md);
}
[data-density="compact"] {
  --rb-row-h:      28px;
  --rb-control-h:  30px;
  --rb-cell-pad-y: var(--rb-space-1);
  --rb-cell-pad-x: var(--rb-space-2);
  --rb-ui-size:    var(--rb-text-sm);
}
[data-density="comfortable"] {
  --rb-row-h:      44px;
  --rb-control-h:  44px;
  --rb-cell-pad-y: var(--rb-space-3);
  --rb-cell-pad-x: var(--rb-space-4);
  --rb-ui-size:    var(--rb-text-md);
}

/* Coarse pointers get comfortable density regardless of preference:
   a 28px row is not tappable, and a stored preference set on a
   desktop should not follow the user onto a phone. */
@media (pointer: coarse) {
  :root, [data-density] {
    --rb-row-h:     44px;
    --rb-control-h: 44px;
    --rb-cell-pad-y: var(--rb-space-3);
  }
}

/* ------------------------------------------------------------
   6. BASE
   ------------------------------------------------------------ */
.rb {
  font-family: var(--rb-font);
  font-size: var(--rb-text-md);
  line-height: var(--rb-leading-normal);
  color: var(--rb-text);
  background: var(--rb-page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Headings: balanced wrapping, tightened tracking only where the
   size is large enough for it to help. */
.rb h1, .rb-h1 { font-size: var(--rb-text-3xl); line-height: var(--rb-leading-tight); letter-spacing: var(--rb-tracking-tight); font-weight: var(--rb-weight-semibold); color: var(--rb-heading); text-wrap: balance; }
.rb h2, .rb-h2 { font-size: var(--rb-text-2xl); line-height: var(--rb-leading-tight); letter-spacing: var(--rb-tracking-tight); font-weight: var(--rb-weight-semibold); color: var(--rb-heading); text-wrap: balance; }
.rb h3, .rb-h3 { font-size: var(--rb-text-xl);  line-height: var(--rb-leading-snug);  font-weight: var(--rb-weight-semibold); color: var(--rb-heading); }
.rb h4, .rb-h4 { font-size: var(--rb-text-lg);  line-height: var(--rb-leading-snug);  font-weight: var(--rb-weight-semibold); color: var(--rb-heading); }

.rb-label {
  font-size: var(--rb-text-2xs);
  font-weight: var(--rb-weight-semibold);
  letter-spacing: var(--rb-tracking-wide);
  text-transform: uppercase;
  color: var(--rb-text-muted);
}
.rb-muted  { color: var(--rb-text-muted); }
.rb-subtle { color: var(--rb-text-subtle); }

/* Prose measure. Long-form text past ~75 characters costs the reader
   their place on every line return. */
.rb-prose { max-width: 72ch; line-height: var(--rb-leading-relaxed); }

/* ------------------------------------------------------------
   7. NUMERIC — the part a financial UI lives or dies on
   ------------------------------------------------------------ */
.rb-num {
  font-family: var(--rb-font-num);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  text-align: right;
  white-space: nowrap;
}
.rb-num-positive { color: var(--rb-positive); }
/* Parentheses as well as colour: accounting convention, and the only
   part of this that survives a monochrome print or a red-green
   colour deficiency. */
.rb-num-negative { color: var(--rb-negative); }
.rb-num-negative::before { content: "("; }
.rb-num-negative::after  { content: ")"; }
.rb-num-total {
  font-weight: var(--rb-weight-semibold);
  border-top: 1px solid var(--rb-slate-300);
}
/* A closing balance is ruled twice — the convention every accountant
   already reads without being told. */
.rb-num-grand-total {
  font-weight: var(--rb-weight-bold);
  border-top: 1px solid var(--rb-slate-400);
  border-bottom: 3px double var(--rb-slate-400);
}

/* ------------------------------------------------------------
   8. DATA TABLE
   ------------------------------------------------------------ */
.rb-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--rb-ui-size);
  background: var(--rb-card);
}
.rb-table th {
  position: sticky; top: 0; z-index: 2;
  background: var(--rb-slate-50);
  color: var(--rb-text-muted);
  font-size: var(--rb-text-2xs);
  font-weight: var(--rb-weight-semibold);
  letter-spacing: var(--rb-tracking-wide);
  text-transform: uppercase;
  text-align: left;
  padding: var(--rb-cell-pad-y) var(--rb-cell-pad-x);
  border-bottom: 1px solid var(--rb-card-border);
  white-space: nowrap;
}
.rb-table td {
  height: var(--rb-row-h);
  padding: var(--rb-cell-pad-y) var(--rb-cell-pad-x);
  border-bottom: 1px solid var(--rb-nav-border);
  color: var(--rb-text-body);
  vertical-align: middle;
}
.rb-table tbody tr:hover td { background: var(--rb-accent-soft-3); }
.rb-table tbody tr[aria-selected="true"] td { background: var(--rb-accent-soft); }
/* Zebra striping is deliberately NOT the default. On a dense grid it
   competes with the selected and hover states, and with any status
   colour in the row. Opt in only where rows are tall and sparse. */
.rb-table--zebra tbody tr:nth-child(even) td { background: var(--rb-slate-50); }

/* Freeze the first column on wide grids so the row's identity stays
   visible while scrolling the figures. */
.rb-table--sticky-first th:first-child,
.rb-table--sticky-first td:first-child {
  position: sticky; left: 0; z-index: 1;
  background: var(--rb-card);
  box-shadow: 1px 0 0 var(--rb-card-border);
}
.rb-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ------------------------------------------------------------
   9. CONTROLS
   ------------------------------------------------------------ */
.rb-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--rb-space-2);
  height: var(--rb-control-h);
  padding: 0 var(--rb-space-4);
  font-family: var(--rb-font);
  font-size: var(--rb-ui-size);
  font-weight: var(--rb-weight-medium);
  border-radius: var(--rb-radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--rb-duration-fast) var(--rb-ease),
              border-color var(--rb-duration-fast) var(--rb-ease);
}
.rb-btn--primary   { background: var(--rb-accent); color: #FFFFFF; }
.rb-btn--primary:hover { background: var(--rb-accent-hover); }
.rb-btn--secondary { background: var(--rb-card); color: var(--rb-text); border-color: var(--rb-card-border); }
.rb-btn--secondary:hover { border-color: var(--rb-accent-muted); color: var(--rb-accent); }
.rb-btn--ghost     { background: transparent; color: var(--rb-text-muted); }
.rb-btn--ghost:hover { background: var(--rb-accent-soft-2); color: var(--rb-accent); }
.rb-btn--danger    { background: var(--rb-danger); color: #FFFFFF; }
.rb-btn:disabled   { opacity: .5; cursor: not-allowed; }

.rb-input, .rb-select, .rb-textarea {
  width: 100%;
  min-height: var(--rb-control-h);
  padding: 0 var(--rb-space-3);
  font-family: var(--rb-font);
  font-size: var(--rb-ui-size);
  color: var(--rb-text);
  background: var(--rb-card);
  border: 1px solid var(--rb-card-border);
  border-radius: var(--rb-radius-md);
  transition: border-color var(--rb-duration-fast) var(--rb-ease);
}
.rb-textarea { padding: var(--rb-space-2) var(--rb-space-3); min-height: calc(var(--rb-control-h) * 2); line-height: var(--rb-leading-normal); }
.rb-input:hover, .rb-select:hover { border-color: var(--rb-accent-muted); }
.rb-input[aria-invalid="true"] { border-color: var(--rb-danger); }
/* Numeric inputs align right and use tabular figures, so a column of
   amounts in a form lines up the same way it does in the grid. */
.rb-input--num { text-align: right; font-variant-numeric: tabular-nums; }

/* Required is marked in text, not by colour alone. */
.rb-required::after { content: " *"; color: var(--rb-danger); font-weight: var(--rb-weight-bold); }

.rb-field { display: flex; flex-direction: column; gap: var(--rb-space-1); }
.rb-field-hint  { font-size: var(--rb-text-xs); color: var(--rb-text-muted); }
.rb-field-error { font-size: var(--rb-text-xs); color: var(--rb-danger); font-weight: var(--rb-weight-medium); }

/* ------------------------------------------------------------
   10. FOCUS AND ACCESSIBILITY
   ------------------------------------------------------------
   188KB of existing CSS contained ONE focus-visible rule. Keyboard
   operability is a procurement requirement in every enterprise
   tender; this is the floor, not a nicety.                         */
.rb :focus-visible,
.rb-btn:focus-visible,
.rb-input:focus-visible,
.rb-select:focus-visible,
.rb-textarea:focus-visible,
.rb-table td:focus-visible {
  outline: 2px solid var(--rb-accent);
  outline-offset: 1px;
  box-shadow: var(--rb-shadow-focus);
  border-radius: var(--rb-radius-sm);
}
.rb-skip-link {
  position: absolute; left: -9999px;
  padding: var(--rb-space-2) var(--rb-space-4);
  background: var(--rb-accent); color: #FFFFFF;
  border-radius: var(--rb-radius-md); z-index: var(--rb-z-toast);
}
.rb-skip-link:focus { left: var(--rb-space-4); top: var(--rb-space-4); }
.rb-sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .rb *, .rb *::before, .rb *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Windows High Contrast / forced-colors: never rely on our colours. */
@media (forced-colors: active) {
  .rb-btn, .rb-input, .rb-select, .rb-textarea { border: 1px solid ButtonBorder; }
  .rb-status { border: 1px solid currentColor; }
}

/* ------------------------------------------------------------
   11. STATUS
   ------------------------------------------------------------
   Every status carries a text label, never colour alone. */
.rb-status {
  display: inline-flex; align-items: center; gap: var(--rb-space-1);
  padding: 2px var(--rb-space-2);
  font-size: var(--rb-text-2xs);
  font-weight: var(--rb-weight-semibold);
  letter-spacing: var(--rb-tracking-wide);
  text-transform: uppercase;
  border-radius: var(--rb-radius-pill);
  white-space: nowrap;
}
.rb-status--neutral { background: var(--rb-slate-100);      color: var(--rb-slate-600); }
.rb-status--info    { background: var(--rb-info-soft);      color: var(--rb-accent-hover); }
.rb-status--success { background: var(--rb-success-soft);   color: var(--rb-success); }
.rb-status--warning { background: var(--rb-warning-soft);   color: var(--rb-warning); }
.rb-status--danger  { background: var(--rb-danger-soft);    color: var(--rb-danger); }

/* A severity stripe reads at a glance down a long list, where a pill
   at the row's end does not. */
.rb-row--danger  { box-shadow: inset 3px 0 0 var(--rb-danger); }
.rb-row--warning { box-shadow: inset 3px 0 0 var(--rb-warning); }
.rb-row--success { box-shadow: inset 3px 0 0 var(--rb-success); }

/* ------------------------------------------------------------
   12. SURFACES AND LAYOUT
   ------------------------------------------------------------ */
.rb-card {
  background: var(--rb-card);
  border: 1px solid var(--rb-card-border);
  border-radius: var(--rb-radius-lg);
  box-shadow: var(--rb-shadow-sm);
}
.rb-card-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--rb-space-3);
  padding: var(--rb-space-4) var(--rb-space-5);
  border-bottom: 1px solid var(--rb-nav-border);
}
.rb-card-body { padding: var(--rb-space-5); }

.rb-stack   { display: flex; flex-direction: column; gap: var(--rb-space-4); }
.rb-row     { display: flex; align-items: center; gap: var(--rb-space-3); }
.rb-grid    { display: grid; gap: var(--rb-space-4); }
.rb-grid--2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.rb-grid--3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.rb-grid--4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

/* Forms are two columns above the fold-out point and one below.
   A three-column form on a laptop forces horizontal eye travel that
   costs more than the vertical space it saves. */
.rb-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--rb-space-4) var(--rb-space-5); }
.rb-form-grid--full { grid-column: 1 / -1; }

/* Toolbar above a grid: actions left, search/filters right. */
.rb-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--rb-space-2);
  padding: var(--rb-space-3) var(--rb-space-4);
  border-bottom: 1px solid var(--rb-nav-border);
}
.rb-toolbar-spacer { margin-left: auto; }

/* Sticky action bar. On a long ERP form, Save at the bottom of 60
   fields is a scroll each time; keeping it in view is standard in
   Fiori and Redwood. */
.rb-actionbar {
  position: sticky; bottom: 0; z-index: var(--rb-z-sticky);
  display: flex; justify-content: flex-end; gap: var(--rb-space-2);
  padding: var(--rb-space-3) var(--rb-space-5);
  background: var(--rb-card);
  border-top: 1px solid var(--rb-card-border);
}

/* ------------------------------------------------------------
   13. EMPTY, LOADING, ERROR
   ------------------------------------------------------------
   Named states, because "no data" and "failed to load" look the same
   to a user unless the product says which it is.                    */
.rb-empty {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--rb-space-2);
  padding: var(--rb-space-12) var(--rb-space-5);
  text-align: center; color: var(--rb-text-muted);
}
.rb-empty-title { font-size: var(--rb-text-lg); font-weight: var(--rb-weight-semibold); color: var(--rb-text); }
.rb-skeleton {
  background: linear-gradient(90deg, var(--rb-slate-100) 25%, var(--rb-slate-200) 37%, var(--rb-slate-100) 63%);
  background-size: 400% 100%;
  animation: rb-shimmer 1.4s ease infinite;
  border-radius: var(--rb-radius-sm);
}
@keyframes rb-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ------------------------------------------------------------
   14. PRINT — statutory documents
   ------------------------------------------------------------
   Invoices, vouchers and registers are printed and filed. Colour
   must not carry meaning on paper, and nothing may be clipped.     */
@media print {
  .rb-no-print, .rb-toolbar, .rb-actionbar { display: none !important; }
  .rb, .rb-card { background: #FFFFFF; box-shadow: none; border-color: #000000; }
  .rb-table { font-size: 10pt; }
  .rb-table th { background: #FFFFFF; color: #000000; border-bottom: 1pt solid #000000; }
  .rb-table td { border-bottom: .5pt solid #666666; }
  .rb-table-scroll { overflow: visible !important; }
  .rb-status { border: 1pt solid #000000; color: #000000; background: transparent; }
  .rb-num-negative { color: #000000; }   /* parentheses carry the sign */
  thead { display: table-header-group; }  /* repeat headers across pages */
  tr, .rb-card { break-inside: avoid; }
}


/* ════════════════════════════════════════════════════════════════════
   TYPE SIZE AND TYPEFACE — the viewer's choice
   ────────────────────────────────────────────────────────────────────
   Set on <html> by inc/theme-head.php before first paint, from a cookie,
   so nothing reflows in front of the reader.

   Four sizes, not a slider. A slider invites 1.03 and produces a scale
   whose steps no longer land on whole pixels, and half-pixel text is
   what makes a screen look slightly out of focus without the reader
   being able to say why.
   ════════════════════════════════════════════════════════════════════ */
/* Applied as zoom on the page, not only through the type tokens: most
   screens set sizes in px, so a token multiplier alone changed a handful of
   labels and nothing else (reported 2026-09-13 as "not working across the
   website"). Zoom scales text, controls and spacing together, so a layout
   keeps its proportions at every step. Two steps below default, one above. */
:root[data-typesize="xsmall"] { --rb-type-scale: 1; --rb-zoom: 0.85; }
:root[data-typesize="small"]  { --rb-type-scale: 1; --rb-zoom: 0.92; }
:root[data-typesize="default"]{ --rb-type-scale: 1; --rb-zoom: 1; }
:root[data-typesize="large"]  { --rb-type-scale: 1; --rb-zoom: 1.12; }
@media screen {
  :root[data-typesize="xsmall"] body, :root[data-typesize="small"] body, :root[data-typesize="large"] body { zoom: var(--rb-zoom); }
}

/* ── Typeface ──────────────────────────────────────────────────────
   Every stack ends in a real fallback, and every one keeps
   --rb-font-num on a face whose digits are the same width: a column of
   amounts that does not line up is harder to read than any typeface
   choice can fix.

   No webfont is fetched. The product runs on shop floors with poor
   connectivity, and a face that arrives half a second late reflows the
   whole page; these are all faces the machine already has. */
:root[data-typeface="system"] {
  --rb-font: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
:root[data-typeface="inter"] {
  --rb-font: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
}
/* A serif reads more comfortably in long documents, and some finance
   teams simply prefer it on a statement. */
:root[data-typeface="serif"] {
  --rb-font: 'Source Serif 4', Georgia, 'Times New Roman', serif;
}
/* Everything monospaced: for people who reconcile ledgers all day and
   want every character in the same column position. */
:root[data-typeface="mono"] {
  --rb-font: ui-monospace, 'SF Mono', Consolas, 'DejaVu Sans Mono', monospace;
}
/* Higher legibility: faces drawn so that 1/l/I and 0/O cannot be
   confused, which is what matters when the text is a serial number or a
   GSTIN and a misread is a real error rather than a typo. */
:root[data-typeface="legible"] {
  --rb-font: 'Atkinson Hyperlegible', 'Verdana', 'Tahoma', system-ui, sans-serif;
  --rb-font-num: 'Atkinson Hyperlegible', ui-monospace, Consolas, monospace;
}

/* A Devanagari interface keeps a face that can actually draw it,
   whatever Latin preference is stored. Honouring "serif" here would
   render Marathi in a fallback with no Devanagari coverage, which is
   not a preference anybody expressed. */
:root[lang="mr"], :root[lang="hi"] {
  --rb-font: 'Nirmala UI', 'Kohinoor Devanagari', 'Noto Sans Devanagari',
             system-ui, sans-serif !important;
}

/* ── Where the preference must NOT reach ───────────────────────────
   A document is not the screen. An invoice, a challan, a wage register
   and a serial label are laid out to fit a sheet of paper or a roll of
   stock, and scaling their type by a screen preference overflows the
   page or the label.

   As things stand today that cannot happen anyway: every document and
   label is written into a fresh iframe with srcdoc (rbPrintDoc() in
   app.js, RebotaLabel.print() in serial-label.js), and an iframe does
   not inherit the parent's custom properties or the data-typesize
   attribute on the parent's <html>. That isolation is what protects
   the paper output, not the rules below.

   They are kept as a guard for the day someone renders a document
   in-page instead - a preview panel is the obvious candidate - so that
   change does not silently start posting customers invoices with the
   last column missing. Do not read them as load-bearing today. The
   print block is the exception: it covers Ctrl+P on the application
   itself, which is a real route - rbPrintDoc()'s error path tells
   people to use it when the print dialog will not open. */
@media print {
  :root { --rb-type-scale: 1 !important; }
}
.rbdoc, .rbdoc *,
.lbl, .lbl *,
#rbPrintFrame, #rbLabelFrame {
  --rb-type-scale: 1;
}

/* ============================================================
   PULL-TO-REFRESH: OFF EVERYWHERE ON MOBILE
   ------------------------------------------------------------
   A downward drag at the top of a page or a popup reloaded the page,
   so scrolling up inside Wage Register (or any form) threw away the
   work. Off on every page and every popup, with no exceptions.
   The CSS covers Chrome/Edge/Firefox/Safari 16+; a touch guard in
   inc/theme-head.php covers browsers that ignore it.
   ============================================================ */
html, body {
  overscroll-behavior-y: none !important;
}
.modal-overlay, .modal-body, .mini-overlay, .mini-box, .notif-panel-body,
.sidebar-nav, .field-overlay, .share-sheet, [role="dialog"] {
  overscroll-behavior: contain;
}
