/* ==========================================================================
   ENTERPRISE ERP — SHARED DESIGN SYSTEM
   theme.css
   Single source of truth for color, typography, spacing and elevation
   tokens used across every module (Portal Shell, Inventory, Menu
   Management, and any future module).

   Modules do not redefine these values — their own stylesheets alias
   their local variable names to these tokens, so visual changes only
   ever need to happen in this one file.
   ========================================================================== */

:root {
  /* ---------- Brand / Primary (Enterprise Navy) ---------- */
  --color-primary: #1e2d46;         /* primary action button color */
  --color-primary-hover: #334155;   /* lighter shade for button hover */
  --color-primary-dark: #1B2A40;    /* deep charcoal-navy (headers/sidebar)*/
  --color-primary-darker: #0f172a;
  --color-primary-light: #475569;
  --color-primary-xlight: #f1f5f9;

  --color-accent: #4C6C93;          /* secondary accent (muted steel blue) */
  --color-accent-teal: #5B7C78;     /* tertiary accent (muted slate teal)  */

  /* ---------- Semantic (kept legible but not neon) ---------- */
  --color-success: #3F7E52;
  --color-success-light: #E7F1E9;
  --color-danger: #B3453F;
  --color-danger-light: #F6E8E7;
  --color-warning: #A9762C;
  --color-warning-light: #F4ECDD;
  --color-info: #3E5E85;
  --color-info-light: #E9EEF3;

  /* ---------- Neutrals (soft gray / charcoal scale) ---------- */
  --gray-50:  #FAFAFA;
  --gray-100: #F2F3F4;
  --gray-200: #E5E7E9;
  --gray-300: #D3D6D9;
  --gray-400: #A7ADB3;
  --gray-500: #767E86;
  --gray-600: #565E66;
  --gray-700: #3E454C;
  --gray-800: #292F35;
  --gray-900: #1C2126;
  --white: #FFFFFF;

  /* ---------- Surfaces ---------- */
  --surface-page: #F4F5F6;
  --surface-card: var(--white);
  --surface-sidebar: var(--color-primary-dark);
  --surface-sidebar-hover: #24384F;
  --surface-header: var(--color-primary-dark);
  /* The portal shell paints its sidebar with a vertical gradient rather than a
     flat colour, so --surface-sidebar alone could not describe it and the
     gradient stayed hard-coded navy in dark mode - the one genuinely blue
     surface left. Exact current stops, so light is unchanged. */
  --sidebar-gradient: linear-gradient(180deg, #233552 0%, #1E2D46 50%, #162235 100%);

  /* Sidebar text. The sidebar is a DARK surface in both themes, so its text
     cannot come from the neutral ramp - the ramp inverts, and the nav labels
     measured #3A3A3A on a #141414 sidebar (1.58:1, invisible). These are the
     exact values portal.css already used, so light is unchanged. */
  --sidebar-text: #CBD5E1;
  --sidebar-text-muted: #94A3B8;
  --sidebar-text-dim: #64748B;
  --sidebar-border: #1E293B;

  /* Solid status buttons. --color-danger etc. have to serve two jobs: coloured
     TEXT on a page surface (wants to be light in dark mode) and the BACKGROUND
     of a solid button carrying white text (wants to stay deep). Those pull in
     opposite directions - measured: white on the dark --color-danger came out
     2.88:1. Splitting them lets each be right. Light values are the existing
     --color-* values, so nothing changes here. */
  --color-danger-strong: #B3453F;
  --color-success-strong: #3F7E52;
  --color-warning-strong: #A9762C;

  /* The brand colour has the same two-jobs problem, and it is the most visible
     one: --color-primary is used 28 times as TEXT (active tab, links, chips,
     breadcrumb hover) and 14 times as a FILL behind white text. In dark those
     pull apart - a navy that carries white text at 5.4:1 only reaches 2.41:1
     as a label on a charcoal card. --color-primary stays the text/accent role
     and lightens in dark; -solid is the fill role and stays deep. Light values
     are identical, so nothing moves in light mode. */
  --color-primary-solid: #1e2d46;
  --color-primary-solid-hover: #334155;

  /* ---------- Login page ----------
     The sign-in page paints its whole canvas with one brand colour and lays
     white branding over it. It followed --color-primary, which is the TEXT role
     and is deliberately lightened in dark mode - so the login canvas came out
     pale blue while its own card was already charcoal. Naming the surface lets
     it go dark with the rest of the ERP. Light values resolve to exactly what
     renders today, and --login-canvas still tracks the brand in light mode. */
  --login-canvas: var(--color-primary-solid);
  --login-logo-disc: var(--surface-card);
  --login-orbit-bg: rgba(255, 255, 255, 0.04);
  --login-orbit-border: rgba(255, 255, 255, 0.1);
  --login-orbit-fg: rgba(255, 255, 255, 0.5);
  --border-color: var(--gray-200);

  /* ---------- Text ---------- */
  --text-primary: var(--gray-900);
  --text-secondary: var(--gray-500);
  --text-on-dark: #FFFFFF;
  --text-on-dark-muted: rgba(255,255,255,.58);

  /* ---------- Typography ---------- */
  --font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-size-base: 14px;

  /* ---------- Radius (small, restrained — not oversized/pill-shaped) --- */
  --radius-sm: 4px;
  --radius: 6px;
  --radius-lg: 8px;

  /* ---------- Elevation (flat enterprise cards — thin border first,
     shadow only as a faint separation cue, never a "floating" effect) --- */
  --shadow-sm: 0 1px 2px rgba(28, 33, 38, .05);
  --shadow: 0 1px 3px rgba(28, 33, 38, .08);
  --shadow-md: 0 2px 8px rgba(28, 33, 38, .10);
  --shadow-lg: 0 4px 16px rgba(28, 33, 38, .14);

  /* ---------- Motion & Micro-animations ---------- */
  --transition: .15s ease;
  --transition-fast: .1s ease;
  --transition-slow: .2s ease;

  /* ---------- Layout ---------- */
  --header-h: 56px;
  --sidebar-w: 256px;
  --sidebar-w-collapsed: 68px;

  /* ---------- Status tints ----------
     Badges, pills, alerts and soft-background chips across the modules were
     each written with their own literal pair (a pale background and a strong
     text colour). Those pairs are named here so a module stylesheet can stop
     hard-coding them: the LIGHT values below are the exact colours those
     modules already used, so adopting a token changes nothing on screen - it
     only makes the pair swappable for the dark set further down. */
  --tint-success-bg: #F0FDF4;
  --tint-success-fg: #15803D;
  --tint-success-br: #BBF7D0;
  --tint-danger-bg: #FFF1F2;
  --tint-danger-fg: #B91C1C;
  --tint-danger-br: #FECDD3;
  --tint-warning-bg: #FFFBEB;
  --tint-warning-fg: #B45309;
  --tint-warning-br: #FDE68A;
  --tint-info-bg: #EFF6FF;
  --tint-info-fg: #1D4ED8;
  --tint-info-br: #BFDBFE;
  --tint-neutral-bg: #F1F5F9;
  --tint-neutral-fg: #334155;
  --tint-neutral-br: #E2E8F0;

  /* ---------- Extra surfaces ----------
     --surface-card was the only surface token, which is why "a slightly
     different background from the card" was always written as a literal.
     Naming the three that actually recur keeps them themeable. */
  --surface-input: var(--white);      /* text inputs, selects, textareas   */
  --surface-raised: var(--gray-50);   /* table headers, inset panels, wells */
  --surface-overlay: var(--white);    /* modals, dropdown popups, menus     */
  /* A surface that is DELIBERATELY dark in both themes, carrying --text-on-dark:
     System Administration's table headers, the portal toast. Without its own
     token these were written as var(--gray-800), which inverts with the neutral
     ramp - measured: the user-list header came out #DCDCDC with near-white text
     on it, 1.16:1. */
  --surface-inverse: var(--gray-800);
  --overlay-scrim: rgba(28, 33, 38, .45);

  /* ---------- Second neutral ramp (slate) ----------
     A Tailwind slate ramp was pasted into the module stylesheets long before
     this file existed and is still used ~120 times for muted text, hairline
     borders and inset backgrounds. Deleting it would mean re-picking 120
     colours; naming it costs nothing and makes it themeable. THESE VALUES ARE
     THE EXACT LITERALS ALREADY IN USE - swapping a literal for its token here
     is a no-op in light mode, which is the whole point. */
  --slate-50:  #F8FAFC;
  --slate-100: #F1F5F9;
  --slate-200: #E2E8F0;
  --slate-300: #CBD5E1;
  --slate-400: #94A3B8;
  --slate-500: #64748B;
  --slate-600: #475569;
  --slate-700: #334155;
  --slate-800: #1E293B;
  --slate-900: #0F172A;

  /* ---------- Status ramps ----------
     Same story: badges, pills and alert boxes across Order, Purchase and
     Customer Management each hard-code a Tailwind status shade. Exact current
     values, so adopting the token changes nothing until the dark block
     re-points it. */
  --green-50:  #F0FDF4;
  --green-100: #DCFCE7;
  --green-200: #BBF7D0;
  --green-300: #86EFAC;
  --green-500: #22C55E;
  --green-600: #16A34A;
  --green-700: #15803D;
  --red-50:  #FFF1F2;
  --red-100: #FEE2E2;
  --red-200: #FECDD3;
  --red-500: #EF4444;
  --red-600: #DC2626;
  --red-700: #B91C1C;
  --amber-50:  #FFFBEB;
  --amber-100: #FEF3C7;
  --amber-200: #FDE68A;
  --amber-600: #B45309;
  --amber-700: #92400E;
  /* Named --azure-*, not --blue-*: Order Management's combined.css/styles.css
     already declare --blue-50..--blue-700 in their own :root, aliasing them to
     the brand navy. A global --blue-* would be silently overridden on every
     Order Management page - and worse, a migrated literal would come out navy
     instead of the blue it replaced. Different name, no collision. */
  --azure-50:  #EFF6FF;
  --azure-100: #DBEAFE;
  --azure-200: #BFDBFE;
  --azure-500: #3B82F6;
  --azure-600: #2563EB;
  --azure-700: #1D4ED8;
  --violet-50:  #FAF5FF;
  --violet-200: #DDD6FE;
  --violet-600: #7C3AED;
  --violet-700: #6D28D9;
  --teal-700: #0F766E;
  --indigo-500: #6366F1;

  /* ---------- Literals that only ever appear in inline style="" ----------
     ~937 inline colour declarations live in the module HTML/JS, and an inline
     style beats every stylesheet, so they cannot be themed from CSS at all -
     they have to become tokens in the markup itself. These are the values that
     recur there and had no token yet. Exact current values, same as above. */
  --cool-50:  #F9FAFB;
  --cool-100: #F3F4F6;
  --cool-500: #6B7280;
  --cool-700: #374151;
  --cool-900: #111827;
  --emerald-50:  #ECFDF5;
  --emerald-500: #10B981;
  --emerald-600: #059669;
  --amber-500: #F59E0B;
  --amber-550: #D97706;
  --violet-500: #8B5CF6;
  --sky-500: #0EA5E9;
  --link-blue: #0052CC;
  --surface-wash: #F9F9F9;
  --cool-200: #E5E7EB;
  --cool-300: #D1D5DB;
  --cool-400: #9CA3AF;
  --cool-800: #1F2937;
  --green-800: #166534;
  --green-900: #14532D;
  --red-800: #991B1B;
  --azure-800: #1E40AF;
  --emerald-800: #065F46;
  --violet-800: #5B21B6;
  --indigo-600: #4F46E5;
  --indigo-700: #4338CA;
  --indigo-800: #3730A3;
  --sky-800: #0369A1;
}

/* ==========================================================================
   DARK THEME
   --------------------------------------------------------------------------
   One token set, one place. Nothing below this block is a component rule:
   dark mode is expressed ONLY by re-pointing the same custom properties the
   light theme uses, so any component already built on tokens adapts with no
   dark-specific CSS of its own, and light mode is untouched by design.

   shared/theme-boot.js stamps data-theme="dark" on <html> before the first
   paint. Matching on the attribute (rather than a media query alone) is what
   lets Settings override the OS in both directions.

   Palette direction: near-black page, charcoal panels, one step lighter for
   inputs, low-contrast borders - the ChatGPT-style dark UI asked for. The
   brand navy is NOT reused as a surface here: at these luminances a navy
   sidebar against a near-black page reads as a rendering fault rather than a
   brand cue, so the brand stays on the accents and the primary button.
   ========================================================================== */
html[data-theme="dark"] {
  /* Neutrals invert: --gray-50 stays "the subtlest background" and --gray-900
     stays "the strongest text", so every existing usage keeps its MEANING and
     only its value changes. This is why no module rule has to be rewritten. */
  --gray-50:  #1E1E1E;
  --gray-100: #242424;
  --gray-200: #2E2E2E;
  --gray-300: #3A3A3A;
  /* Not the strict inverse position (#565656). --gray-400 is used for muted
     TEXT - page subtitles, hints, placeholders - far more than for borders,
     and the mirrored value measured 2.44:1 against the page, under the 3:1
     floor. Raised until it clears it; the border uses are unaffected because
     --border-color is its own token. */
  --gray-400: #757575;
  --gray-500: #8E8E8E;
  --gray-600: #A8A8A8;
  --gray-700: #C4C4C4;
  --gray-800: #DCDCDC;
  --gray-900: #ECECEC;

  /* --white deliberately stays white. It is used 41 times as a foreground
     (label text on the primary button, icons on the dark sidebar) and only
     61 times as a background; flipping it would turn all of the former
     invisible. Background usages are migrated to --surface-card instead. */

  --surface-page: #171717;
  --surface-card: #212121;
  --surface-input: #2A2A2A;
  --surface-raised: #262626;
  --surface-overlay: #2A2A2A;
  --surface-sidebar: #0D0D0D;
  --surface-sidebar-hover: #1F1F1F;
  --surface-header: #0D0D0D;
  /* Still a gradient so the sidebar keeps its subtle top-to-bottom depth, but
     in charcoal. The white/rgba(255,255,255,.n) text and hover overlays the
     shell already uses read correctly on it unchanged. */
  --sidebar-gradient: linear-gradient(180deg, #1C1C1C 0%, #141414 50%, #0D0D0D 100%);

  /* Light greys, NOT the inverted ramp: the surface underneath is still dark. */
  --sidebar-text: #D4D4D4;
  --sidebar-text-muted: #A3A3A3;
  --sidebar-text-dim: #8A8A8A;
  --sidebar-border: #2A2A2A;

  /* Deep enough to carry white text at >=4.5:1, unlike the lightened
     --color-danger / --color-success used for coloured text. */
  --color-danger-strong: #C2564A;
  --color-success-strong: #3E8C63;
  --color-warning-strong: #8A6520;

  --color-primary-solid: #3E5E85;
  --color-primary-solid-hover: #4C6C93;

  /* Charcoal, not the brand navy: on a near-black ERP a navy sign-in page reads
     as a different product. #141414 is the mid stop of the dark sidebar
     gradient, so the login canvas and the app chrome are the same surface
     family, and the #212121 card still lifts off it clearly.

     The branding sits ON this canvas, so the orbit icons lift a little - white
     at 0.5 alpha carries on navy but goes muddy against near-black. The logo
     disc stays near-white in both themes because the logo artwork is dark. */
  --login-canvas: #141414;
  --login-logo-disc: #F2F2F2;
  --login-orbit-bg: rgba(255, 255, 255, 0.06);
  --login-orbit-border: rgba(255, 255, 255, 0.14);
  --login-orbit-fg: rgba(255, 255, 255, 0.72);
  --border-color: #333333;
  /* Stays dark. It is one step below the card so the header still separates
     from the rows it sits above. */
  --surface-inverse: #161616;
  --overlay-scrim: rgba(0, 0, 0, .62);

  --text-primary: #ECECEC;
  --text-secondary: #A0A0A0;
  /* Unchanged in meaning: these are for text sitting on a dark brand surface,
     which is still dark here. */
  --text-on-dark: #FFFFFF;
  --text-on-dark-muted: rgba(255, 255, 255, .58);

  /* Brand: lifted, not re-hued. The navy primary is nearly invisible on a
     near-black page, so the button surface moves up the same hue ramp while
     the accent keeps the family recognisable. */
  --color-primary: #8FB4E8;
  --color-primary-hover: #A6C6EE;
  --color-primary-dark: #1B2A40;
  --color-primary-darker: #0F172A;
  --color-primary-light: #6B87AD;
  --color-primary-xlight: #23303F;

  --color-accent: #7A9CC6;
  --color-accent-teal: #7FA5A0;

  /* Semantic colours brighten so they clear the contrast floor on charcoal;
     their -light partners become dark tints rather than pale washes. */
  --color-success: #5FBF8B;
  --color-success-light: #14301F;
  --color-danger: #E8776B;
  --color-danger-light: #351C1A;
  --color-warning: #D9A441;
  --color-warning-light: #33270F;
  --color-info: #7FA8DE;
  --color-info-light: #1A2534;

  --tint-success-bg: #14301F;
  --tint-success-fg: #6FCF97;
  --tint-success-br: #1F4A32;
  --tint-danger-bg: #351C1A;
  --tint-danger-fg: #F08C80;
  --tint-danger-br: #522A26;
  --tint-warning-bg: #33270F;
  --tint-warning-fg: #E0B25C;
  --tint-warning-br: #4D3A18;
  --tint-info-bg: #1A2534;
  --tint-info-fg: #8FB4E8;
  --tint-info-br: #27384F;
  --tint-neutral-bg: #262626;
  --tint-neutral-fg: #C4C4C4;
  --tint-neutral-br: #333333;

  /* The slate ramp inverts like the gray ramp: --slate-50 remains "the
     subtlest background" and --slate-900 "the strongest text", so the ~120
     existing usages keep their meaning without being rewritten. */
  --slate-50:  #1E1E1E;
  --slate-100: #242424;
  --slate-200: #2E2E2E;
  --slate-300: #3A3A3A;
  --slate-400: #6E6E6E;
  --slate-500: #909090;
  --slate-600: #ADADAD;
  --slate-700: #C8C8C8;
  --slate-800: #DEDEDE;
  --slate-900: #ECECEC;

  /* Status ramps: the pale 50-200 end becomes a dark tint (these are used as
     backgrounds), the strong 500-700 end brightens (used as text and icons).
     The ramp direction flips so "50" is still the background shade and "700"
     is still the readable foreground. */
  --green-50:  #14301F;
  --green-100: #173925;
  --green-200: #1F4A32;
  --green-300: #2C6344;
  --green-500: #4FB07C;
  --green-600: #5FBF8B;
  --green-700: #6FCF97;
  --red-50:  #351C1A;
  --red-100: #3E211E;
  --red-200: #522A26;
  --red-500: #DE6A5E;
  --red-600: #E8776B;
  --red-700: #F08C80;
  --amber-50:  #33270F;
  --amber-100: #3D2F13;
  --amber-200: #4D3A18;
  --amber-600: #D9A441;
  --amber-700: #E0B25C;
  --azure-50:  #1A2534;
  --azure-100: #1F2E40;
  --azure-200: #27384F;
  --azure-500: #6B9AD8;
  --azure-600: #7FA8DE;
  --azure-700: #93B8E6;
  --violet-50:  #241E33;
  --violet-200: #362C4D;
  --violet-600: #A18BE0;
  --violet-700: #AE9BE6;
  --teal-700: #5FB3A9;
  --indigo-500: #8B8DE8;

  --cool-50:  #1E1E1E;
  --cool-100: #242424;
  --cool-500: #909090;
  --cool-700: #C8C8C8;
  --cool-900: #ECECEC;
  --emerald-50:  #14301F;
  --emerald-500: #4FB07C;
  --emerald-600: #5FBF8B;
  --amber-500: #D9A441;
  --amber-550: #D9A441;
  --violet-500: #A18BE0;
  --sky-500: #6FB4DE;
  --link-blue: #7FA8DE;
  --surface-wash: #1E1E1E;
  --cool-200: #2E2E2E;
  --cool-300: #3A3A3A;
  --cool-400: #757575;
  --cool-800: #DEDEDE;
  /* The deep 800/900 end of each status ramp is foreground text on a tint, so
     in dark it has to become the LIGHTEST step of that hue, not the darkest. */
  --green-800: #7FD6A5;
  --green-900: #93DEB4;
  --red-800: #F5A096;
  --azure-800: #A3C4EC;
  --emerald-800: #6FCFA0;
  --violet-800: #BBA9EC;
  --indigo-600: #9B9DEC;
  --indigo-700: #A9ABF0;
  --indigo-800: #B7B9F3;
  --sky-800: #8CC3E6;

  /* Shadows carry no separation on a dark ground - depth reads from the
     surface step instead - so they drop to a rim that only deepens edges. */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);
  --shadow: 0 1px 3px rgba(0, 0, 0, .45);
  --shadow-md: 0 2px 8px rgba(0, 0, 0, .5);
  --shadow-lg: 0 4px 16px rgba(0, 0, 0, .6);
}

/* Native widgets the page does not draw itself: scrollbars, the canvas behind
   the document, date pickers, and the dropdown list of a native <select>. */
html[data-theme="dark"] { color-scheme: dark; }

/* ==========================================================================
   DARK THEME — STRUCTURAL SAFETY NET
   --------------------------------------------------------------------------
   Everything above is tokens. This block is the one exception, and it exists
   because the modules pre-date the token system: ~500 colour literals still
   sit in their stylesheets, spread thinly over 184 distinct values (mostly
   one-off status pills and accent washes). Tokenising every one would mean
   inventing 184 tokens, and mapping them to the nearest existing token would
   shift light mode - which must not change.

   So instead of chasing values, this catches STRUCTURE. These are the shared
   class names the whole portal is built from, so one rule per structural role
   covers every module at once. It is a floor, not a paint job: a component
   that already uses tokens is unaffected (it resolves to the same colours
   anyway), and a component that still uses literals at least lands on a dark
   surface with readable text instead of a white card on a black page.

   Scoped entirely under html[data-theme="dark"], so light mode never sees a
   single one of these declarations.

   As modules are migrated to tokens, rules here become redundant and can be
   deleted - that is the intended direction of travel, not permanent scaffolding.
   ========================================================================== */

html[data-theme="dark"] body { background: var(--surface-page); color: var(--text-primary); }

/* ---- Surfaces: anything that reads as a panel ---- */
html[data-theme="dark"] .card,
html[data-theme="dark"] .panel,
html[data-theme="dark"] .dw-panel,
html[data-theme="dark"] .filter-card,
html[data-theme="dark"] .stat-card,
html[data-theme="dark"] .widget,
html[data-theme="dark"] .box,
html[data-theme="dark"] .section-card,
html[data-theme="dark"] .content-card {
  background: var(--surface-card);
  border-color: var(--border-color);
  color: var(--text-primary);
}

/* ---- Form controls ----
   The single most damaging leftover: a white input on a charcoal card. Also
   covers the placeholder, which inherits from a colour the module never set. */
html[data-theme="dark"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
html[data-theme="dark"] select,
html[data-theme="dark"] textarea,
html[data-theme="dark"] .form-input,
html[data-theme="dark"] .form-control,
html[data-theme="dark"] .form-select,
html[data-theme="dark"] .filter-input,
html[data-theme="dark"] .search-input {
  background-color: var(--surface-input);
  color: var(--text-primary);
  border-color: var(--border-color);
}
html[data-theme="dark"] ::placeholder { color: var(--gray-500); opacity: 1; }
html[data-theme="dark"] input:disabled,
html[data-theme="dark"] select:disabled,
html[data-theme="dark"] textarea:disabled { background-color: var(--gray-100); color: var(--gray-500); }

/* ---- Tables ----
   Header, body rows, hover and zebra striping all have to move together or the
   grid reads as torn. */
html[data-theme="dark"] table { background: var(--surface-card); color: var(--text-primary); }
html[data-theme="dark"] th {
  background: var(--surface-raised);
  color: var(--text-primary);
  border-color: var(--border-color);
}
html[data-theme="dark"] td { border-color: var(--border-color); color: var(--text-primary); }
html[data-theme="dark"] tbody tr:nth-child(even) { background: var(--surface-raised); }
html[data-theme="dark"] tbody tr:hover { background: var(--gray-100); }

/* ---- Overlays: modals, dropdowns, popovers, menus ---- */
html[data-theme="dark"] .modal,
html[data-theme="dark"] .modal-content,
html[data-theme="dark"] .modal-body,
html[data-theme="dark"] .modal-header,
html[data-theme="dark"] .modal-footer,
html[data-theme="dark"] .dialog,
html[data-theme="dark"] .dropdown,
html[data-theme="dark"] .dropdown-menu,
html[data-theme="dark"] .popover,
html[data-theme="dark"] .tooltip-panel,
html[data-theme="dark"] .erp-select-list,
html[data-theme="dark"] .erp-dropdown-list,
html[data-theme="dark"] .search-select-list,
html[data-theme="dark"] .search-results,
html[data-theme="dark"] .cpo-product-results,
html[data-theme="dark"] .autocomplete-list {
  background: var(--surface-overlay);
  color: var(--text-primary);
  border-color: var(--border-color);
}
html[data-theme="dark"] .modal-backdrop,
html[data-theme="dark"] .modal-overlay,
html[data-theme="dark"] .backdrop,
html[data-theme="dark"] .scrim { background: var(--overlay-scrim); }
html[data-theme="dark"] .erp-select-option:hover,
html[data-theme="dark"] .dropdown-item:hover,
html[data-theme="dark"] .ss-item:hover { background: var(--gray-100); }

/* ---- Filter panel (shared/erp-filters.css) ----
   Built on tokens already; named here only so the panel and its chips are
   explicitly covered rather than incidentally. */
html[data-theme="dark"] .erp-filter-panel { background: var(--surface-raised); border-color: var(--border-color); }
html[data-theme="dark"] .erp-chip { background: var(--gray-100); color: var(--text-primary); border-color: var(--border-color); }

/* ---- Separators ----
   A hairline in a module stylesheet is nearly always a literal grey, and a
   light hairline on charcoal is the most visible "unfinished" tell. */
html[data-theme="dark"] hr,
html[data-theme="dark"] .divider,
html[data-theme="dark"] .separator { border-color: var(--border-color); background: var(--border-color); }

/* ---- Icons ----
   Font Awesome glyphs are text, so they follow `color`. The ones that break are
   those a module pinned to a dark literal; inheriting is right in every case
   where the icon sits on a surface rather than inside a coloured button. */
html[data-theme="dark"] .card i.fa-solid:not([class*="text-"]):not([style*="color"]),
html[data-theme="dark"] .card i.fa-regular:not([class*="text-"]):not([style*="color"]) { color: inherit; }

/* ---- Tab buttons ----
   A tab rendered as <button> with no background of its own falls through to the
   UA's `buttonface`. In light that is a pale grey nobody notices; under
   color-scheme:dark it is rgb(107,107,107) - a mid-grey blob behind every
   inactive tab. The shared .tab and Customer Management's .tab-btn both omit a
   background (Order Management's sets `background:none`, which is why only some
   modules showed it). Dark-scoped so light keeps its current appearance. */
html[data-theme="dark"] button.tab,
html[data-theme="dark"] button.tab-btn,
html[data-theme="dark"] button.pp-tab,
html[data-theme="dark"] button.ud-tab,
html[data-theme="dark"] button.um-modal-tab,
html[data-theme="dark"] button.podx-tab {
  background-color: transparent;
}

/* Same class of problem for any other unstyled button: a UA-default surface is
   never what the design intended. Buttons that DO set their own background are
   unaffected, because this only fills in where nothing else applies. */
html[data-theme="dark"] button:not([class]) { background-color: var(--surface-card); color: var(--text-primary); }

/* ---- Empty / loading / error states ---- */
html[data-theme="dark"] .empty-state,
html[data-theme="dark"] .loading-state,
html[data-theme="dark"] .error-state,
html[data-theme="dark"] .no-data { background: transparent; color: var(--text-secondary); }

/* ---- Images that are really line art ----
   Logos and illustrations shipped as dark-on-transparent PNG/SVG disappear on
   a dark ground. Only marked ones are inverted; a photo must never be. */
html[data-theme="dark"] img[data-theme-invert] { filter: invert(1) hue-rotate(180deg); }

/* ---------- Utility Classes ---------- */
.hidden { display: none !important; }

/* ---------- Global reset shared by every module ---------- */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  font-family: var(--font-family);
  font-size: var(--font-size-base);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Thin, professional scrollbars used everywhere */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--gray-300); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--gray-400); }

/* Clearly discoverable table horizontal and vertical scrollbars */
.table-container,
.tbl-wrap,
.table-wrap,
.table-responsive {
  overflow-x: auto;
  overflow-y: auto;
  max-width: 100%;
  max-height: clamp(340px, 58vh, 560px);
  position: relative;
  scrollbar-width: thin;
  scrollbar-color: var(--gray-400) var(--gray-100);
}
.table-container::-webkit-scrollbar,
.tbl-wrap::-webkit-scrollbar,
.table-wrap::-webkit-scrollbar,
.table-responsive::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
.table-container::-webkit-scrollbar-track,
.tbl-wrap::-webkit-scrollbar-track,
.table-wrap::-webkit-scrollbar-track,
.table-responsive::-webkit-scrollbar-track {
  background: var(--gray-100);
  border-radius: 4px;
}
.table-container::-webkit-scrollbar-thumb,
.tbl-wrap::-webkit-scrollbar-thumb,
.table-wrap::-webkit-scrollbar-thumb,
.table-responsive::-webkit-scrollbar-thumb {
  background: var(--gray-400);
  border-radius: 4px;
  border: 2px solid var(--gray-100);
}
.table-container::-webkit-scrollbar-thumb:hover,
.tbl-wrap::-webkit-scrollbar-thumb:hover,
.table-wrap::-webkit-scrollbar-thumb:hover,
.table-responsive::-webkit-scrollbar-thumb:hover {
  background: var(--gray-500);
}
.table-container::-webkit-scrollbar-corner,
.tbl-wrap::-webkit-scrollbar-corner,
.table-wrap::-webkit-scrollbar-corner,
.table-responsive::-webkit-scrollbar-corner {
  background: var(--gray-100);
}

html[data-theme="dark"] .table-container,
html[data-theme="dark"] .tbl-wrap,
html[data-theme="dark"] .table-wrap,
html[data-theme="dark"] .table-responsive,
body.dark-mode .table-container,
body.dark-mode .tbl-wrap,
body.dark-mode .table-wrap,
body.dark-mode .table-responsive {
  scrollbar-color: var(--gray-500) var(--gray-800);
}
html[data-theme="dark"] .table-container::-webkit-scrollbar-track,
html[data-theme="dark"] .tbl-wrap::-webkit-scrollbar-track,
html[data-theme="dark"] .table-wrap::-webkit-scrollbar-track,
html[data-theme="dark"] .table-responsive::-webkit-scrollbar-track,
body.dark-mode .table-container::-webkit-scrollbar-track,
body.dark-mode .tbl-wrap::-webkit-scrollbar-track,
body.dark-mode .table-wrap::-webkit-scrollbar-track,
body.dark-mode .table-responsive::-webkit-scrollbar-track {
  background: var(--gray-800);
}
html[data-theme="dark"] .table-container::-webkit-scrollbar-thumb,
html[data-theme="dark"] .tbl-wrap::-webkit-scrollbar-thumb,
html[data-theme="dark"] .table-wrap::-webkit-scrollbar-thumb,
html[data-theme="dark"] .table-responsive::-webkit-scrollbar-thumb,
body.dark-mode .table-container::-webkit-scrollbar-thumb,
body.dark-mode .tbl-wrap::-webkit-scrollbar-thumb,
body.dark-mode .table-wrap::-webkit-scrollbar-thumb,
body.dark-mode .table-responsive::-webkit-scrollbar-thumb {
  background: var(--gray-500);
  border: 2px solid var(--gray-800);
}
html[data-theme="dark"] .table-container::-webkit-scrollbar-thumb:hover,
html[data-theme="dark"] .tbl-wrap::-webkit-scrollbar-thumb:hover,
html[data-theme="dark"] .table-wrap::-webkit-scrollbar-thumb:hover,
html[data-theme="dark"] .table-responsive::-webkit-scrollbar-thumb:hover,
body.dark-mode .table-container::-webkit-scrollbar-thumb:hover,
body.dark-mode .tbl-wrap::-webkit-scrollbar-thumb:hover,
body.dark-mode .table-wrap::-webkit-scrollbar-thumb:hover,
body.dark-mode .table-responsive::-webkit-scrollbar-thumb:hover {
  background: var(--gray-400);
}
html[data-theme="dark"] .table-container::-webkit-scrollbar-corner,
html[data-theme="dark"] .tbl-wrap::-webkit-scrollbar-corner,
html[data-theme="dark"] .table-wrap::-webkit-scrollbar-corner,
html[data-theme="dark"] .table-responsive::-webkit-scrollbar-corner,
body.dark-mode .table-container::-webkit-scrollbar-corner,
body.dark-mode .tbl-wrap::-webkit-scrollbar-corner,
body.dark-mode .table-wrap::-webkit-scrollbar-corner,
body.dark-mode .table-responsive::-webkit-scrollbar-corner {
  background: var(--gray-800);
}

.table-container table thead th,
.tbl-wrap table thead th,
.table-wrap table thead th,
.table-responsive table thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--gray-50);
  box-shadow: 0 1px 0 var(--border-color, #e2e8f0);
}

html[data-theme="dark"] .table-container table thead th,
html[data-theme="dark"] .tbl-wrap table thead th,
html[data-theme="dark"] .table-wrap table thead th,
html[data-theme="dark"] .table-responsive table thead th,
body.dark-mode .table-container table thead th,
body.dark-mode .tbl-wrap table thead th,
body.dark-mode .table-wrap table thead th,
body.dark-mode .table-responsive table thead th {
  background: var(--surface-raised, #243042);
  color: var(--text-primary);
  border-color: var(--border-color);
  box-shadow: 0 1px 0 var(--border-color, #334155);
}

/* ---------- Embedded mode inside Portal shell iframe ---------- */
html.embedded .sidebar,
body.embedded .sidebar,
html.embedded .top-header,
body.embedded .top-header,
html.embedded .topbar,
body.embedded .topbar,
html.embedded .top-bar,
body.embedded .top-bar,
html.embedded .module-header,
body.embedded .module-header,
html.embedded .navbar,
body.embedded .navbar,
html.embedded .main-header {
  display: none !important;
}

html.embedded .main-content,
body.embedded .main-content,
html.embedded .main,
body.embedded .main,
html.embedded .content-area,
body.embedded .content-area {
  margin-left: 0 !important;
  width: 100% !important;
  max-width: 100% !important;
  box-sizing: border-box !important;
}

/* ==========================================================================
   STANDARD TABLE ROW ACTIONS  (.erp-actions / .erp-act)
   --------------------------------------------------------------------------
   THE single action-icon system for every data table in the ERP (Inventory,
   Purchase, Order, Customer and Menu/System Administration). Before this
   existed each module shipped its own: FontAwesome <i> inside bare <span>s
   (Inventory, Purchase), Bootstrap Icons inside .action-btn (Order), inline
   SVG inside .icon-btn (Customer), and text+icon .btn.btn-xs pills (Menu) --
   five different icons, sizes, hover effects and tooltips for the same three
   actions.

   Lives here because shared/theme.css is the one stylesheet every page that
   renders a table already loads, so modules get the standard with no new
   <link>, no extra request and no script load-order dependency.

   The glyph is painted with mask-image from a data-URI, so the icon set is
   defined exactly once (below) and the markup carries no icon markup at all:

     <div class="erp-actions">
       <button type="button" class="erp-act erp-act--edit"
               title="Edit" aria-label="Edit" onclick="...">
       </button>
     </div>

   Use <a class="erp-act ..."> when the action is a real navigation (keeps
   middle-click / open-in-new-tab), <button type="button"> for JS actions.
   Icons are Feather-style outline strokes -- the same house style already
   used by shared/icons.js -- so no new icon library is introduced.
   ========================================================================== */

.erp-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}

.erp-act {
  /* Same box for every action, in every module */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  padding: 0;
  margin: 0;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  background: var(--surface-card);
  color: var(--gray-600);
  cursor: pointer;
  text-decoration: none;
  line-height: 1;
  font: inherit;
  -webkit-appearance: none;
          appearance: none;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}

.erp-act::before {
  content: "";
  display: block;
  width: 16px;
  height: 16px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-size: 16px 16px;
          mask-size: 16px 16px;
  -webkit-mask-image: var(--erp-act-glyph);
          mask-image: var(--erp-act-glyph);
}

/* Resting state is deliberately neutral for every action so an Actions column
   reads as one calm group; the semantic colour appears on hover/focus, where
   it signals intent (this is what keeps Delete unmistakable without making
   every table row shout). */
.erp-act:hover { background: var(--gray-100); border-color: var(--gray-300); color: var(--gray-800); }
.erp-act:focus-visible { outline: 2px solid var(--color-info); outline-offset: 1px; }

.erp-act--view:hover    { background: var(--color-info-light);    border-color: var(--color-info);    color: var(--color-info); }
.erp-act--edit:hover    { background: var(--color-warning-light); border-color: var(--color-warning); color: var(--color-warning); }
.erp-act--delete:hover  { background: var(--color-danger-light);  border-color: var(--color-danger);  color: var(--color-danger); }
.erp-act--approve:hover { background: var(--color-success-light); border-color: var(--color-success); color: var(--color-success); }
.erp-act--reject:hover  { background: var(--color-danger-light);  border-color: var(--color-danger);  color: var(--color-danger); }
.erp-act--print:hover,
.erp-act--download:hover{ background: var(--color-info-light);    border-color: var(--color-accent);  color: var(--color-accent); }

/* Disabled: kept in the DOM (so the column never reflows between rows) but
   inert. Matches the .disabled / :disabled convention already used by
   Order Management's approve/reject buttons. */
.erp-act:disabled,
.erp-act.is-disabled {
  opacity: .38;
  pointer-events: none;
  cursor: default;
}

/* ---------- The icon set: defined once, used everywhere ---------- */
.erp-act--view     { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8Z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); }
.erp-act--edit     { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg%3E"); }
.erp-act--delete   { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2'/%3E%3Cpath d='M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6'/%3E%3Cpath d='M10 11v6'/%3E%3Cpath d='M14 11v6'/%3E%3C/svg%3E"); }
.erp-act--approve  { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); }
.erp-act--reject   { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E"); }
.erp-act--print    { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 6 2 18 2 18 9'/%3E%3Cpath d='M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2'/%3E%3Crect x='6' y='14' width='12' height='8'/%3E%3C/svg%3E"); }
.erp-act--download { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/%3E%3Cpolyline points='7 10 12 15 17 10'/%3E%3Cline x1='12' y1='15' x2='12' y2='3'/%3E%3C/svg%3E"); }
.erp-act--more     { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000' stroke='none'%3E%3Ccircle cx='12' cy='5' r='1.7'/%3E%3Ccircle cx='12' cy='12' r='1.7'/%3E%3Ccircle cx='12' cy='19' r='1.7'/%3E%3C/svg%3E"); }
.erp-act--receipt  { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 2v20l2.5-1.5L9 22l2.5-1.5L14 22l2.5-1.5L19 22V2l-2.5 1.5L14 2l-2.5 1.5L9 2 6.5 3.5Z'/%3E%3Cpath d='M8 8h8'/%3E%3Cpath d='M8 12h8'/%3E%3Cpath d='M8 16h5'/%3E%3C/svg%3E"); }
.erp-act--duplicate{ --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='9' width='13' height='13' rx='2'/%3E%3Cpath d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1'/%3E%3C/svg%3E"); }
.erp-act--archive  { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='3' width='20' height='5' rx='1'/%3E%3Cpath d='M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8'/%3E%3Cline x1='10' y1='12' x2='14' y2='12'/%3E%3C/svg%3E"); }

.erp-act--items    { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='8' y1='6' x2='21' y2='6'/%3E%3Cline x1='8' y1='12' x2='21' y2='12'/%3E%3Cline x1='8' y1='18' x2='21' y2='18'/%3E%3Cline x1='3' y1='6' x2='3.01' y2='6'/%3E%3Cline x1='3' y1='12' x2='3.01' y2='12'/%3E%3Cline x1='3' y1='18' x2='3.01' y2='18'/%3E%3C/svg%3E"); }
.erp-act--permissions { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2'/%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'/%3E%3C/svg%3E"); }
.erp-act--refund   { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M14.5 9.5A2.5 2.5 0 0 0 12 8h-1.2a1.8 1.8 0 0 0 0 3.6h2.4a1.8 1.8 0 0 1 0 3.6H12a2.5 2.5 0 0 1-2.5-1.5'/%3E%3Cline x1='12' y1='6.2' x2='12' y2='8'/%3E%3Cline x1='12' y1='15.2' x2='12' y2='17'/%3E%3C/svg%3E"); }
.erp-act--pickup   { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 17h4V5H2v12h3'/%3E%3Cpath d='M20 17h2v-3.34a4 4 0 0 0-1.17-2.83L19 9h-5v8h1'/%3E%3Ccircle cx='7.5' cy='17.5' r='2.5'/%3E%3Ccircle cx='17.5' cy='17.5' r='2.5'/%3E%3C/svg%3E"); }
.erp-act--pause    { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='10' y1='15' x2='10' y2='9'/%3E%3Cline x1='14' y1='15' x2='14' y2='9'/%3E%3C/svg%3E"); }
.erp-act--play     { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolygon points='10 8 16 12 10 16 10 8'/%3E%3C/svg%3E"); }
.erp-act--package  { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z'/%3E%3Cpolyline points='3.29 7 12 12 20.71 7'/%3E%3Cline x1='12' y1='22' x2='12' y2='12'/%3E%3C/svg%3E"); }
.erp-act--history  { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3v5h5'/%3E%3Cpath d='M3.05 13A9 9 0 1 0 6 5.3L3 8'/%3E%3Cpolyline points='12 7 12 12 15.5 14'/%3E%3C/svg%3E"); }
.erp-act--refresh  { --erp-act-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='23 4 23 10 17 10'/%3E%3Cpolyline points='1 20 1 14 7 14'/%3E%3Cpath d='M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15'/%3E%3C/svg%3E"); }

/* Archive is a soft-delete, not a delete -- it gets the warning tint so it is
   never mistaken for the destructive red Delete action. */
.erp-act--archive:hover   { background: var(--color-warning-light); border-color: var(--color-warning); color: var(--color-warning); }
.erp-act--duplicate:hover { background: var(--color-info-light);    border-color: var(--color-info);    color: var(--color-info); }
.erp-act--refund:hover,
.erp-act--pickup:hover,
.erp-act--receipt:hover    { background: var(--color-info-light); border-color: var(--color-accent-teal); color: var(--color-accent-teal); }

/* ==========================================================================
   DROPDOWN LIST SIZING — shared standard
   --------------------------------------------------------------------------
   One rule for every dropdown the page itself renders, so a Supplier list with
   50 rows behaves exactly like a Warehouse list with 3: about five rows visible
   at a time, the rest reachable by scrolling. The full dataset is never
   trimmed — this is purely how much of it is on screen at once.

   Sized in ROWS rather than pixels. Each list declares its own row height and
   inherits the shared row count, so every list lands on the same number of
   visible rows even though their rows are different heights (a plain name row
   is ~34px; the Create PO product row carries a second meta line and is taller).
   Custom properties are substituted where they are USED, so redefining
   --erp-dropdown-row-height on the list recomputes --erp-dropdown-max-height
   for that list.

   SCOPE — read before extending this:
   This governs dropdowns rendered by the page (absolutely-positioned <div>
   lists). It CANNOT govern a native <select>'s option popup. That popup is not
   in the DOM or the page's layout: measured in Chromium, an <option> reports a
   0px box while the select is closed, and max-height/overflow-y on the <select>
   leaves the control at exactly the same height (19px with or without it) while
   doing nothing at all to the popup. The only CSS that changes the row count is
   the size="N" attribute, which turns the control into a permanently-expanded
   inline listbox (19px -> 82px) and would break every form layout in the ERP.
   Browsers already scroll long native popups themselves. Native <select>s are
   therefore left alone deliberately — see the dropdown section of the task
   report. Do not add a max-height rule for <select> here believing it works.
   ========================================================================== */

:root {
  /* Rows visible before the list starts scrolling. */
  --erp-dropdown-visible-rows: 5;
  /* Default row height; each list overrides this to match its own row. */
  --erp-dropdown-row-height: 34px;
  /* Fallback for any list not covered by the block below. The real value is
     declared on the list itself -- see the note there. */
  --erp-dropdown-max-height: calc(var(--erp-dropdown-visible-rows) * var(--erp-dropdown-row-height));
}

.erp-dropdown-list,
.search-select-list,
.cpo-product-results,
.search-results,
.erp-select-list {
  /* Declared HERE, on the list, and not at :root. A custom property is
     substituted where it is declared, so a calc() living at :root freezes the
     default row height into the inherited value and a per-list override of
     --erp-dropdown-row-height would never reach it (measured: the Create PO
     picker came out at 3.78 rows instead of 5). Declaring it on the element
     means each list resolves the calc against its own row height. */
  --erp-dropdown-max-height: calc(var(--erp-dropdown-visible-rows) * var(--erp-dropdown-row-height));
  max-height: var(--erp-dropdown-max-height);
  overflow-y: auto;
  /* Keeps the wheel inside the list instead of scrolling the page behind it
     once the last row is reached. */
  overscroll-behavior: contain;
  /* Slim scrollbar so the "there is more below" cue is visible without
     changing any colour or font in the theme. */
  scrollbar-width: thin;
}

/* Inventory — Category / Sub Category / Brand pickers on the Product form.
   .ss-item is 9px+9px padding on a ~16px line = 34px. */
.search-select-list { --erp-dropdown-row-height: 34px; }

/* Purchase — Create PO product picker. Each row is a name plus a meta line
   (8px+8px padding, 13px name, 11.5px meta) and the list also carries a
   "Search results" label and 6px of vertical padding, so the row height is
   raised slightly to keep five product rows visible rather than four. */
.cpo-product-results { --erp-dropdown-row-height: 45px; }

/* Menu Management — global search results. .sr-item is 10px+10px padding on a
   ~16px line plus its 1px bottom divider. */
.search-results { --erp-dropdown-row-height: 37px; }

/* ErpSelect (shared/erp-select.js) — the page-rendered replacement popup used
   where a native <select> popup cannot be capped. .erp-select-option is
   8px+8px padding on a ~18px line. */
.erp-select-list { --erp-dropdown-row-height: 34px; }

/* ==========================================================================
   RESPONSIVE PRIMITIVES
   --------------------------------------------------------------------------
   Cross-module responsive behaviour lives HERE rather than in components.css
   for one reason: Order Management's ~80 pages load theme.css but NOT
   components.css. Anything written there reaches four modules out of five,
   which is how the filter panel ended up unstyled on Order Management earlier.
   Component-level refinements still belong in components.css; what is here is
   only the part that must reach every page.

   Desktop is untouched - every rule below sits inside a max-width query.

   Breakpoints are the four the layout actually changes at, not a ladder for
   its own sake:
     1024  small laptop / tablet landscape - side-by-side still works
      768  tablet portrait - two columns at most, denser furniture
      640  phone - single column, tables become scroll surfaces
      430  small phone - the last squeeze
   ========================================================================== */

/* Specificity note: every rule below carries a `body ` prefix (or an equally
   weighted alternative). theme.css is the FIRST stylesheet each page loads, so
   an equally specific rule in a module stylesheet wins on source order - and
   Order Management's combined.css, which has no media queries of its own, is
   exactly the file that would win. `body ` outranks it without !important.
   This is the same trick components.css already uses for the filter row. */

/* ---- Tablet portrait ---------------------------------------------------- */
@media (max-width: 768px) {
  /* Furniture gives up its generous padding first; content keeps its size. */
  body .card, body .panel, body .dw-panel,
  body .content .card, body .content .panel { padding: 14px; }
  body .card-head, body .card-header, body .pw-card-header { padding: 12px 14px; }
  body .page-header { margin-bottom: 16px; }

  /* Icon chips are sized in px, so they do not follow a type scale and stay
     desktop-sized on a phone unless told otherwise. */
  body .s-icon, body .stat-icon, body .stat-icon-box, body .activity-icon,
  body .es-icon, body .icon-box, body .dashboard-card-icon {
    width: 34px; height: 34px; font-size: 14px;
  }
  body .avatar, body .profile-avatar, body .uds-avatar { width: 30px; height: 30px; font-size: 11.5px; }

  /* Two columns at most, whatever the module asked for. */
  body .form-grid-3, body .form-grid.cols-3, body .form-grid-4, body .form-grid.cols-4,
  body .kpi-grid, body .stat-grid, body .summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Action rows stop being a single unwrappable line. Order Management pins
     .toolbar-buttons-group with flex-shrink:0 !important inside a nowrap
     .filter-card, so the group measured 447px inside a 304px parent and ran
     off the side of the page. */
  body .filter-card, body .filter-row, body .toolbar { flex-wrap: wrap !important; }
  body .toolbar-buttons-group, body .filter-actions {
    flex-wrap: wrap !important;
    flex-shrink: 1 !important;
    min-width: 0;
  }
}

/* ---- Phone -------------------------------------------------------------- */
@media (max-width: 640px) {
  body .card, body .panel, body .dw-panel,
  body .content .card, body .content .panel { padding: 12px; }
  body .card-head, body .card-header, body .pw-card-header { padding: 10px 12px; }

  /* Single column everywhere a grid was doing the arranging. */
  body .form-grid, body .form-grid-2, body .form-grid-3, body .form-grid-4,
  body .form-grid.cols-2, body .form-grid.cols-3, body .form-grid.cols-4,
  body .kpi-grid, body .stat-grid, body .summary-grid, body .detail-grid,
  body .pd-grid-2, body .pd-grid-3, body .grid-2, body .grid-3, body .grid-4 {
    grid-template-columns: 1fr;
  }

  body .s-icon, body .stat-icon, body .stat-icon-box, body .activity-icon,
  body .es-icon, body .icon-box, body .dashboard-card-icon { width: 30px; height: 30px; font-size: 13px; }

  /* Every action button gets a full share of the row rather than one button
     hogging the width and pushing the rest out. */
  body .toolbar-buttons-group > .btn,
  body .toolbar-buttons-group > button,
  body .filter-actions > .btn { flex: 1 1 auto; justify-content: center; min-width: 0; }

  /* ---- Tables ----
     The complaint this answers: at phone width a table kept its desktop column
     widths, so the visible slice was effectively one column and the rest lived
     off-screen behind a scrollbar nobody could see.

     Three changes, in order of effect:
       1. Cell padding and type come down, so MORE columns fit in the slice.
       2. A hard cap replaces the module min-widths (Purchase declares
          min-width:900px on a bare `table` selector, POS Management 980px) -
          those were sized for a desktop viewport and are what pushed the table
          off-screen.
       3. The first column sticks, so a row is still identifiable once the user
          scrolls sideways to reach the later columns.
     Horizontal scrolling is kept deliberately: a grid with ten columns is
     genuinely wide, and stacking it into cards loses the row-to-row comparison
     the grid exists for.

     Both container class names are covered - .table-wrap is the shared one,
     .table-container is Order Management's. */
  body table:not(.dw-mini-table) > tbody > tr > td,
  body table:not(.dw-mini-table) > thead > tr > th {
    padding: 8px 10px !important;
    font-size: 12.5px;
  }
  body table:not(.dw-mini-table) > tbody > tr > td { height: auto; min-height: 40px; }
  body table:not(.dw-mini-table) > thead > tr > th { height: auto; }

  body .table-wrap, body .table-container { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  /* `width: max-content` with a 100% floor: never narrower than the viewport,
     never wider than the content needs. Replaces a fixed desktop min-width
     without collapsing the columns. */
  body .table-wrap > table, body .table-container > table,
  body .table-wrap table[class], body .table-container table[class] {
    min-width: 100%;
    width: max-content;
  }

  /* Sticky row identity. Never on a table that opted out with .table-fit. */
  body .table-wrap:not(.table-fit) > table > thead > tr > th:first-child,
  body .table-container:not(.table-fit) > table > thead > tr > th:first-child {
    position: sticky; left: 0; z-index: 2;
    background: var(--surface-raised);
    box-shadow: 1px 0 0 var(--border-color);
  }
  body .table-wrap:not(.table-fit) > table > tbody > tr > td:first-child,
  body .table-container:not(.table-fit) > table > tbody > tr > td:first-child {
    position: sticky; left: 0; z-index: 1;
    background: var(--surface-card);
    box-shadow: 1px 0 0 var(--border-color);
  }

  /* Action buttons stay tappable rather than shrinking with the cell. */
  body .erp-actions .btn-icon, body .erp-actions .btn-xs { min-width: 30px; min-height: 30px; }

  /* Pagination stacks instead of overflowing. */
  body .pagination { flex-direction: column; align-items: stretch; gap: 8px; }
  body .pagination .page-info, body .pagination-info { text-align: center; }
}

/* ---- Small phone -------------------------------------------------------- */
@media (max-width: 430px) {
  body .card, body .panel, body .dw-panel,
  body .content .card, body .content .panel { padding: 10px; }
  body table:not(.dw-mini-table) > tbody > tr > td,
  body table:not(.dw-mini-table) > thead > tr > th { padding: 7px 8px !important; font-size: 12px; }
  body .page-header .btn, body .page-header .dashboard-action-btn { width: 100%; justify-content: center; }
}
