/* =====================================================================
   Theme tokens
   Direction (RTL for fa / LTR for en) comes ONLY from the <html dir="">
   attribute set in public/js/i18n.js — nothing in this file hardcodes a
   direction, so both languages render correctly. Anywhere a rule needs to
   be direction-aware, use logical properties (inset-inline-start,
   border-inline-end, text-align:start, etc.) instead of left/right.

   ONE accent. The brand orange is the only hue that carries meaning;
   positive/danger exist purely as money-safety signals. Never introduce a
   fourth hue — derive tints with color-mix() from the tokens below so a
   value cannot drift off-palette.

   `--primary` is the text-safe accent (>= 4.5:1 on the page surface) and
   `--accent-fill` the saturated brand orange used for filled areas, which
   always carries `--on-accent` (dark) text, never white.
   ===================================================================== */
:root,
[data-theme="light"] {
  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-alt: #f4f5f8;
  --surface-hover: #ebedf2;
  --text: #15181e;
  --text-muted: #5e6675;
  --border: #e3e6ec;
  --border-strong: #cfd4de;

  --primary: #b45309;
  --primary-hover: #8f4108;
  --primary-soft: #fdf1e2;
  --accent-fill: #ff9a00;
  --accent-fill-hover: #ef8e00;
  --accent-line: #f0c48a;
  --on-accent: #1d1400;
  --nav-icon: #e08600;

  --danger: #bb2d3b;
  --danger-soft: #fceaec;
  --success: #12794f;
  --success-soft: #e4f3eb;
  --warning: #96620c;
  --warning-soft: #fbf1e0;

  /* Analogous warm ramp anchored on the brand orange: separation comes from
     tone, not hue. Light cards need the ramp to darken; the dark theme below
     reverses it. Every stop clears 3:1 against its own card. */
  --chart-1: #c08718;
  --chart-2: #b46312;
  --chart-3: #a14213;
  --chart-4: #87321d;
  --chart-5: #6d2a24;
  --chart-6: #532427;

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-md: 0 6px 16px -4px rgba(16, 24, 40, 0.12);
  --shadow-lg: 0 18px 40px -12px rgba(16, 24, 40, 0.22);
  /* A docked bar separates with a hairline and its own blur; there is no
     floating edge left for a drop shadow to describe. */
  --tabbar-bg: rgb(255 255 255 / 82%);
  --tabbar-edge: rgb(16 24 40 / 10%);
  --scrollbar-thumb: rgb(16 24 40 / 20%);
  --scrollbar-thumb-hover: rgb(16 24 40 / 34%);
  /* Hue-neutral depth: white on top, black at the bottom. Tints nothing, so
     it reads the same in every theme. */
  --sheen: linear-gradient(180deg, rgb(255 255 255 / 60%) 0%, rgb(255 255 255 / 0%) 46%, rgb(0 0 0 / 3%) 100%);

  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-pill: 999px;
  --sidebar-width: 244px;
  --motion: 150ms;
  color-scheme: light;
}
[data-theme="dark"] {
  --bg: #0f1116;
  --surface: #181b21;
  --surface-alt: #1f232b;
  --surface-hover: #272c36;
  --text: #e9ebf0;
  --text-muted: #949dac;
  --border: #292e38;
  --border-strong: #3a414f;

  --primary: #ff9a00;
  --primary-hover: #ffae33;
  --primary-soft: rgba(255, 154, 0, 0.14);
  --accent-fill: #ff9a00;
  --accent-fill-hover: #ffae33;
  --accent-line: rgba(255, 154, 0, 0.45);
  --on-accent: #1d1400;
  --nav-icon: #ff9a00;

  --danger: #ff6b6b;
  --danger-soft: rgba(255, 107, 107, 0.14);
  --success: #3ecf8e;
  --success-soft: rgba(62, 207, 142, 0.14);
  --warning: #e0a53c;
  --warning-soft: rgba(224, 165, 60, 0.14);

  --chart-1: #ffd88c;
  --chart-2: #ffb457;
  --chart-3: #ff8c1a;
  --chart-4: #ee6d29;
  --chart-5: #d6533a;
  --chart-6: #b83f45;

  /* Depth on dark comes from a lighter surface and a hairline, not a shadow
     that nothing can see. Only overlays keep one. */
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: 0 24px 48px -12px rgba(0, 0, 0, 0.7);
  --tabbar-bg: rgb(34 38 47 / 86%);
  --tabbar-edge: rgb(255 255 255 / 13%);
  --scrollbar-thumb: rgb(255 255 255 / 18%);
  --scrollbar-thumb-hover: rgb(255 255 255 / 32%);
  --sheen: linear-gradient(180deg, rgb(255 255 255 / 4%) 0%, rgb(255 255 255 / 0%) 46%, rgb(0 0 0 / 10%) 100%);
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { height: 100%; overflow-x: hidden; }
/* A permanent grey gutter next to full-bleed app chrome reads as a bug, so
   the bar is slim on desktop and hidden entirely on touch, where the
   platform already draws a fading overlay one. */
* { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) transparent; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: var(--radius-pill); border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover); background-clip: content-box; }
@media (max-width: 900px) {
  * { scrollbar-width: none; }
  ::-webkit-scrollbar { width: 0; height: 0; }
}
body {
  margin: 0;
  font-family: 'Vazirmatn', -apple-system, 'Segoe UI', Tahoma, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 13.5px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
/* Figures line up in columns and stop jittering as values change. */
body { font-variant-numeric: tabular-nums; }
a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Persian letterforms join, so negative tracking smears them — keep it at 0
   and stay at 600 or below; 700+ fills the counters on dark surfaces. */
h1, h2, h3, h4 { margin: 0 0 0.5em; font-weight: 600; letter-spacing: 0; }
h1 { font-size: 20px; line-height: 1.35; }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
h4 { font-size: 13.5px; }
p { margin: 0 0 0.75em; }
hr { border: none; border-top: 1px solid var(--border); margin: 16px 0; }
.muted { color: var(--text-muted); }
.bi { line-height: 1; }
/* Latin codes (REP-1405-000009) must never break across lines inside an RTL
   cell, and must not be reordered by the bidi algorithm. */
.code { direction: ltr; unicode-bidi: isolate; white-space: nowrap; }

input, select, textarea, button { font-family: inherit; font-size: 13.5px; }
input, select, textarea {
  width: 100%; padding: 9px 12px; margin: 4px 0 12px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--text);
  min-height: 38px;
  transition: border-color var(--motion), box-shadow var(--motion);
}
select {
  appearance: none;
  padding-inline-end: 32px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 17px) calc(50% + 2px), calc(100% - 12px) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
:dir(rtl) select { background-position: 12px calc(50% + 2px), 17px calc(50% + 2px); }
input:hover, select:hover, textarea:hover { border-color: var(--border-strong); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft);
}
input::placeholder, textarea::placeholder { color: var(--text-muted); opacity: .85; }
label { display: block; font-size: 12px; font-weight: 500; color: var(--text-muted); margin-bottom: 2px; }
textarea { min-height: 80px; resize: vertical; }

/* iOS Safari auto-zooms the whole page when focusing an input with
   font-size under 16px (e.g. the autofocused login username field),
   and the zoom persists across SPA navigation, hiding the sidebar toggle. */
@media (max-width: 640px) {
  input, select, textarea { font-size: 16px; }
}

/* ===== Loading spinner ===== */
.loading { display: flex; align-items: center; justify-content: center; min-height: 200px; }
.spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--border); border-top-color: var(--primary);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ===== Buttons ===== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 15px; min-height: 38px;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--surface); color: var(--text); cursor: pointer; font-size: 13px;
  font-weight: 500; white-space: nowrap;
  transition: background var(--motion), border-color var(--motion), color var(--motion), box-shadow var(--motion);
}
.btn:hover { background: var(--surface-hover); border-color: var(--border-strong); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--primary-soft); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
/* The brand orange is a mid-tone: white on it measures under 3:1, so filled
   accent surfaces always take dark text. */
.btn-primary { background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent); font-weight: 600; }
.btn-primary:hover { background: var(--accent-fill-hover); border-color: var(--accent-fill-hover); color: var(--on-accent); }
.btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { background: var(--danger); border-color: var(--danger); filter: brightness(1.08); }
.btn-secondary { background: var(--surface-alt); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn-ghost:hover { background: var(--surface-hover); color: var(--text); border-color: transparent; }
.btn-sm { padding: 4px 10px; min-height: 30px; font-size: 12px; }
.btn-block { width: 100%; justify-content: center; }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; background: none; border: none; border-radius: 50%;
  font-size: 18px; cursor: pointer; color: var(--text-muted);
  transition: background var(--motion), color var(--motion);
}
.icon-btn:hover { background: var(--surface-hover); color: var(--text); }


/* ===== App shell ===== */
.app-shell { display: flex; min-height: 100vh; }
.sidebar {
  width: var(--sidebar-width); background: var(--surface);
  border-inline-end: 1px solid var(--border);
  padding: 14px 0 20px; flex-shrink: 0;
  display: flex; flex-direction: column;
}
.sidebar-brand {
  font-size: 15px; font-weight: 600; padding: 6px 18px 16px; display: flex; align-items: center; gap: 10px;
  color: var(--text); min-width: 0;
}
.sidebar-brand-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The mark is the one always-on brand surface: a filled squircle rather than
   a loose glyph, so the sidebar has a fixed anchor point. */
.sidebar-brand .bi {
  flex: 0 0 30px; width: 30px; height: 30px; border-radius: 9px;
  display: grid; place-items: center;
  font-size: 16px; background: var(--accent-fill); color: var(--on-accent);
}
.sidebar nav { display: flex; flex-direction: column; gap: 1px; padding: 0 10px; overflow-y: auto; }
.nav-link {
  position: relative;
  padding: 8px 10px; border-radius: var(--radius-sm); color: var(--text-muted);
  display: flex; gap: 11px; align-items: center; font-size: 13px; font-weight: 500;
  transition: background var(--motion), color var(--motion);
}
/* Icons keep the brand accent even when the row itself is active/hovered. */
.nav-link .bi { font-size: 15px; width: 18px; text-align: center; flex-shrink: 0; color: var(--nav-icon); }
.nav-link > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-link:hover { background: var(--surface-alt); color: var(--text); text-decoration: none; }
/* Solid fill rather than a tint: with twenty rows in the rail, the current
   page has to be findable in one glance. The icon flips to the dark ink too,
   since brand orange on brand orange would disappear. */
.nav-link.active { background: var(--accent-fill); color: var(--on-accent); font-weight: 600; }
.nav-link.active .bi { color: var(--on-accent); }
.nav-link.active:hover { background: var(--accent-fill-hover); color: var(--on-accent); }
/* Sentence-case section label, never all-caps. The rule above it does the
   grouping; the label only names the group, so it stays quieter than a nav
   row. Its colour is the muted text warmed with a little brand orange —
   derived with color-mix so it cannot drift off-palette, and deliberately not
   the accent itself, which in this rail means "you are here". */
.nav-section {
  margin-top: 10px;
  padding: 12px 12px 6px;
  border-top: 1px solid var(--border);
  font-size: 11px; font-weight: 600;
  color: color-mix(in srgb, var(--primary) 38%, var(--text-muted));
}

/* Collapsible nav group (e.g. Individuals > Customers / Suppliers). The
   toggle is a <button>, so it needs the font/width resets a link doesn't. */
.nav-group { display: flex; flex-direction: column; gap: 1px; }
.nav-group-toggle {
  width: 100%; background: none; border: 0; font-family: inherit; cursor: pointer;
  text-align: start;
}
.nav-chevron { margin-inline-start: auto; font-size: 11px !important; color: var(--text-muted) !important; transition: transform var(--motion); }
.nav-group.open .nav-chevron { transform: rotate(180deg); }
/* Collapsed by default; grid-template-rows animates to a content-sized height
   without hard-coding one. The single inner wrapper is required -- multiple
   direct children would land in auto-sized implicit rows and never collapse. */
.nav-sub { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .18s ease; }
.nav-sub-inner { overflow: hidden; display: flex; flex-direction: column; gap: 1px; }
.nav-group.open .nav-sub { grid-template-rows: 1fr; }
.nav-sub-link { padding-inline-start: 30px; font-size: 12.5px; }
.nav-sub-link .bi { font-size: 13px; }

.main-col { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
  display: flex; align-items: center; gap: 10px; padding: 10px 20px; background: var(--surface);
  border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 10; min-height: 56px;
}
.topbar-spacer { flex: 1; }
/* Only shown once the sidebar collapses, where nothing else names the shop. */
.topbar-brand { display: none; font-size: 14px; font-weight: 600; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-date { font-size: 12.5px; font-weight: 500; color: var(--text-muted); white-space: nowrap; }
.topbar-user {
  display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 500;
  color: var(--text); text-decoration: none; padding: 4px 10px 4px 4px;
  border-radius: var(--radius-pill); transition: background var(--motion);
}
:dir(rtl) .topbar-user { padding: 4px 4px 4px 10px; }
.topbar-user:hover { background: var(--surface-alt); text-decoration: none; }
/* Initial chip instead of a generic silhouette: it identifies the account
   and gives the bar a second, smaller brand touchpoint. */
.topbar-user .bi {
  flex: 0 0 28px; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 16px; background: var(--surface-alt); color: var(--text-muted);
}
#view { padding: 24px; flex: 1; max-width: 1400px; width: 100%; margin: 0 auto; }
.sidebar-backdrop { display: none; }

/* ===== Mobile tab bar =====
   Below the sidebar breakpoint the rail becomes a drawer, which is too slow
   for the four screens the shop lives in all day. A floating bar puts those
   within thumb reach and its last tab opens the drawer for everything else,
   so nothing in the menu becomes unreachable. */
.tabbar { display: none; }
@media (min-width: 901px) {
  #sidebar-toggle { display: none; }
}
@media (max-width: 900px) {
  /* The tab bar replaces the hamburger entirely — two affordances for the
     same drawer is one too many. */
  #sidebar-toggle { display: none; }
  .topbar-brand { display: block; }
  .tabbar {
    display: block; position: fixed; z-index: 28;
    inset-inline: 0; bottom: 0;
    background: var(--tabbar-bg);
    border-top: 1px solid var(--tabbar-edge);
    backdrop-filter: blur(18px) saturate(150%);
    -webkit-backdrop-filter: blur(18px) saturate(150%);
    /* The bottom band and the iOS home-indicator inset do the same job, so
       take whichever is larger instead of stacking them. */
    padding-bottom: max(22px, env(safe-area-inset-bottom, 0px));
  }
  /* Icons sit high in the bar; the label gets the band underneath. */
  .tabbar ul { display: flex; list-style: none; margin: 0; padding: 8px 4px 0; }
  .tabbar li { flex: 1 1 0; min-width: 0; }
  .tab-link {
    display: flex; flex-direction: column; align-items: center; gap: 6px;
    width: 100%; padding: 0 2px; border: 0; background: none; cursor: pointer;
    font-family: inherit; font-size: 11px; font-weight: 500;
    color: var(--text-muted); text-decoration: none;
    transition: color var(--motion);
  }
  .tab-link:hover, .tab-link:focus-visible { text-decoration: none; color: var(--text); outline: none; }
  .tab-link .bi {
    width: 40px; height: 30px; border-radius: 10px; display: grid; place-items: center;
    font-size: 17px; transition: background var(--motion), color var(--motion);
  }
  .tab-link.active { color: var(--primary); }
  .tab-link.active .bi { background: var(--accent-fill); color: var(--on-accent); }
  /* Persian descenders need the full line box; a tight line-height here was
     shaving the bottom off words like پذیرش. */
  .tab-label { width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; line-height: 1.7; }
  /* Clear the bar so the last row of every page stays reachable. */
  #view { padding-bottom: calc(73px + max(22px, env(safe-area-inset-bottom, 0px))); }
  .toast-host { bottom: calc(73px + max(22px, env(safe-area-inset-bottom, 0px))); }
}
@media (max-width: 900px) {
  .sidebar {
    position: fixed; inset-block: 0; inset-inline-start: 0; z-index: 30;
    transition: transform .2s ease; box-shadow: var(--shadow-lg);
    overflow-y: auto; -webkit-overflow-scrolling: touch;
  }
  :dir(ltr) .sidebar { transform: translateX(-100%); }
  :dir(rtl) .sidebar { transform: translateX(100%); }
  .sidebar.open { transform: translateX(0); }
  .sidebar-backdrop.open {
    display: block; position: fixed; inset: 0; background: rgba(9, 11, 15, 0.55); z-index: 29;


  }
}

/* ===== Page header / toolbar ===== */
.page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; flex-wrap: wrap; gap: 10px; }
.page-header h1 { display: flex; align-items: center; gap: 10px; margin: 0; }
.page-sub { margin: 2px 0 0; font-size: 12.5px; color: var(--text-muted); }
/* Filters are a single field of controls, not loose inputs on the page. */
.toolbar {
  display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap; align-items: center;
  padding: 10px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.toolbar input, .toolbar select, .toolbar .jdp-trigger { width: auto; min-width: 190px; margin: 0; }
.toolbar > label { margin: 0; white-space: nowrap; }
/* A label and its control wrap as one unit, instead of the label stranding
   itself at the end of the previous line. */
.filter-field { display: flex; align-items: center; gap: 7px; }
.filter-field > label { margin: 0; white-space: nowrap; }
.toolbar-grow { flex: 1 1 220px; }
/* Pages that split their filters over two bars still read as one control
   surface rather than two stacked cards. */
.toolbar + .toolbar { margin-top: -18px; border-top: none; border-start-start-radius: 0; border-start-end-radius: 0; }
.toolbar:has(+ .toolbar) { border-end-start-radius: 0; border-end-end-radius: 0; margin-bottom: 0; }
.panel + .toolbar, .pos-cart + .toolbar { margin-top: 14px; }
.header-actions { display: flex; gap: 8px; }

/* Section band: gives a long page a spine instead of one undifferentiated
   wall of cards. */
.section { margin-bottom: 26px; }
.section-title {
  display: flex; align-items: baseline; gap: 8px;
  margin: 0 0 12px; font-size: 12.5px; font-weight: 600; color: var(--text-muted);
}
.section-title::after { content: ''; flex: 1; height: 1px; background: var(--border); }

/* ===== Cards / stats / charts ===== */
.cards-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 12px; margin-bottom: 22px; }
/* Counters are small and uniform — they are a scoreboard, not headlines. */
.counter-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(134px, 1fr)); gap: 10px; }
.stat-card {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px 16px;
  transition: border-color var(--motion), background var(--motion), transform var(--motion);
}
.stat-card::after { content: ''; position: absolute; inset: 0; background: var(--sheen); pointer-events: none; }
.stat-card.clickable { cursor: pointer; }
.stat-card.clickable:hover { border-color: var(--accent-line); transform: translateY(-1px); }
.stat-value { font-size: 20px; font-weight: 600; line-height: 1.25; }
.stat-label { color: var(--text-muted); font-size: 12px; font-weight: 400; margin-top: 3px; }
/* Icon chip sits opposite the figure so a grid of cards can be scanned by
   shape before anyone reads a single number. */
.stat-icon {
  position: absolute; top: 12px; inset-inline-end: 12px;
  width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center;
  font-size: 13px; background: var(--surface-alt); color: var(--text-muted);
}
.stat-card--counter { padding: 12px 14px; }
.stat-card--counter .stat-value { font-size: 22px; }
/* Exactly one brand-filled card per screen, reserved for the figure the shop
   opens the page to read. */
.stat-card--hero { background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent); }
.stat-card--hero .stat-value { font-size: 26px; font-weight: 600; }
.stat-card--hero .stat-label { color: var(--on-accent); opacity: .72; }
.stat-card--hero .stat-icon { background: rgb(0 0 0 / 14%); color: var(--on-accent); }
.stat-card--hero.clickable:hover { background: var(--accent-fill-hover); border-color: var(--accent-fill-hover); }
.hero-grid { display: grid; grid-template-columns: minmax(230px, 1.35fr) repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }

.charts-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; }
/* Short breakdowns sit three-up rather than leaving an orphan on its own row. */
.charts-grid--compact { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.chart-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; }
.chart-card h3 { margin-bottom: 14px; color: var(--text); }
.bar-chart { display: flex; flex-direction: column; gap: 9px; }
.bar-row { display: grid; grid-template-columns: 88px 1fr 66px; align-items: center; gap: 10px; font-size: 12px; }
.bar-label { color: var(--text-muted); white-space: nowrap; }
.bar-value { text-align: end; white-space: nowrap; }
.bar-track { background: color-mix(in srgb, var(--accent-fill) 16%, transparent); border-radius: var(--radius-pill); height: 7px; overflow: hidden; }
/* Keeps a sliver visible at 0 so the row still reads as a bar, not a blank. */
.bar-fill { background: var(--accent-fill); height: 100%; border-radius: var(--radius-pill); min-width: 3px; }
.rank-list { list-style: none; padding: 0; margin: 0; counter-reset: rank; }
.rank-list li {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 13px;
}
.rank-list li::before {
  counter-increment: rank; content: counter(rank, persian);
  flex: 0 0 20px; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center; font-size: 11px;
  background: var(--surface-alt); color: var(--text-muted);
}
.rank-list li > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-list li > b { font-weight: 500; }
.rank-list li:last-child { border-bottom: none; }

/* Empty states read as a deliberate "nothing here yet", not a broken card. */
.empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: 18px 16px; color: var(--text-muted); text-align: center; font-size: 12.5px;
}
.empty-state .bi { font-size: 22px; opacity: .45; }


/* ===== Tables ===== */
/* Wrapper injected by router.js after every render. Columns keep their natural
   width and the grid scrolls, instead of hyphen-breaking REP-1405-000009 over
   three lines to make everything fit. */
.table-wrap {
  overflow-x: auto; overscroll-behavior-x: contain;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.data-table { width: 100%; border-collapse: collapse; background: var(--surface); }
.data-table th, .data-table td { padding: 11px 14px; border-bottom: 1px solid var(--border); text-align: start; font-size: 13px; white-space: nowrap; }
.data-table th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface-alt); font-weight: 500; font-size: 12px; color: var(--text-muted);
}
.data-table tbody tr { transition: background var(--motion); }
.data-table tbody tr:hover { background: var(--surface-alt); }
.data-table tr.clickable { cursor: pointer; }
.data-table tr.row-warning td { background: var(--danger-soft); }
.data-table tr:last-child td { border-bottom: none; }
/* Long free text is the exception that may wrap, capped so one verbose note
   cannot push the money columns off screen. */
.data-table td.wrap, .data-table td[data-wrap] { white-space: normal; max-width: 320px; }
/* A secondary identifier under its main one, instead of a wide inline pair. */
.cell-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }
.data-table .btn-sm { margin-inline-end: 4px; }

/* Data tables become stacked cards on narrow screens instead of scrolling
   horizontally (which is a poor mobile experience). Each <td> shows its
   column header as a label via the `data-label` attribute set in JS.
   This block must stay AFTER the base .data-table rules above so its
   overrides win the cascade (equal specificity, later source order). */
@media (max-width: 700px) {
  .table-wrap { border: none; border-radius: 0; background: none; overflow-x: visible; }
  .data-table thead { display: none; }
  .data-table, .data-table tbody, .data-table tr, .data-table td { display: block; width: 100%; }
  .data-table { background: none; border-radius: 0; }
  .data-table tr {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    margin-bottom: 10px; padding: 4px 14px;
  }
  .data-table td {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 9px 0; border-bottom: 1px solid var(--border); text-align: end; white-space: normal;
  }
  .data-table td:last-child { border-bottom: none; }
  .data-table td:empty { display: none; }
  .data-table td::before {
    content: attr(data-label); font-weight: 500; font-size: 12px; color: var(--text-muted);
    text-align: start; flex-shrink: 0;
  }
  .data-table td[data-label=""]::before, .data-table td:not([data-label])::before { content: none; }

  /* Simple item/select/input checklists just stack as a labeled card,
     using the first cell (item name) as the visual label. */
  .checklist-table, .checklist-table tbody, .checklist-table tr, .checklist-table td { display: block; width: 100%; }
  .checklist-table tr {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
    padding: 8px 10px; margin-bottom: 8px;
  }
  .checklist-table td { padding: 4px 0; }
  .checklist-table td:first-child { font-weight: 500; font-size: 13px; }
}


/* ===== Expandable record list =====
   Progressive disclosure for record lists: the summary line carries only what
   gets scanned, and the rest opens in place so checking one record costs no
   page load. The collapse animates through grid-template-rows, which reaches
   a content-sized height without hard-coding one. */
.list-count { font-size: 12px; color: var(--text-muted); margin: 0 0 8px; }
.list-more { display: flex; justify-content: center; margin-top: 12px; }
.stack-list {
  list-style: none; margin: 0; padding: 0;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden;
}
.stack-item + .stack-item { border-top: 1px solid var(--border); }
.stack-summary {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 13px 16px; border: 0; background: none; cursor: pointer;
  font-family: inherit; text-align: start; color: var(--text);
  transition: background var(--motion);
}
.stack-summary:hover { background: var(--surface-alt); }
.stack-summary:focus-visible { outline: none; background: var(--surface-alt); box-shadow: inset 0 0 0 2px var(--accent-fill); }
.stack-item.open .stack-summary { background: var(--surface-alt); }
.stack-id { flex: 1 1 auto; min-width: 0; }
.stack-title { display: block; font-size: 13.5px; font-weight: 600; }
.stack-sub { display: block; font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Column flex, so flex-end resolves to the inline end and the block sits
   opposite the title in both directions. */
.stack-meta { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.stack-note { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.stack-note-alert { color: var(--primary); }
.stack-chevron { flex: 0 0 auto; font-size: 12px; color: var(--text-muted); transition: transform var(--motion); }
.stack-item.open .stack-chevron { transform: rotate(180deg); }

.stack-detail { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .2s ease; }
.stack-item.open .stack-detail { grid-template-rows: 1fr; }
.stack-detail-inner { overflow: hidden; }
.stack-detail-body { padding: 0 16px 16px; }
.pair-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 20px;
  margin: 0; padding: 10px 14px;
  background: var(--surface-alt); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.pair { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 5px 0; font-size: 12.5px; }
.pair + .pair { border-top: 1px solid color-mix(in srgb, var(--border) 60%, transparent); }
.pair dt { color: var(--text-muted); flex: 0 0 auto; }
.pair dd { margin: 0; min-width: 0; text-align: end; overflow-wrap: anywhere; }
.pair-wide { grid-column: 1 / -1; }
.pair-wide dd { text-align: start; }
.stack-actions { display: flex; gap: 8px; margin-top: 12px; }
.stack-actions .btn { flex: 1; }

/* ===== Panels / detail grid ===== */
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; }
.panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px; }
.panel h3 { margin-bottom: 14px; }
.panel.full-width { grid-column: 1 / -1; }
.panel-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.panel-row.full-width { grid-column: 1 / -1; }
.row { padding: 6px 0; font-size: 13px; border-bottom: 1px solid var(--border); display: flex; gap: 12px; justify-content: space-between; align-items: baseline; }
.row:last-child { border-bottom: none; }
.row b { color: var(--text-muted); font-weight: 400; }
/* A summed row carries the weight its inputs do not. */
.row-total { border-top: 1px solid var(--border-strong); padding-top: 9px; margin-top: 3px; font-size: 14px; font-weight: 600; }
.row-total b { color: var(--text); font-weight: 600; }
.settle-form { margin-top: 16px; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.simple-list { list-style: none; padding: 0; margin: 0; }
.simple-list li { padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.simple-list li:last-child { border-bottom: none; }
.inline-fields { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.inline-fields input, .inline-fields select { width: auto; margin: 0; }
.pick-row { padding: 9px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); margin-bottom: 6px; display: flex; justify-content: space-between; align-items: center; cursor: pointer; transition: background var(--motion), border-color var(--motion); }
.pick-row:hover { background: var(--surface-alt); border-color: var(--accent-line); }
.checkbox-item { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--text); }
.checkbox-item input { width: auto; margin: 0; }
/* Box first, then its text: a stacked label above a lone checkbox reads as
   two unrelated controls. `width:auto` undoes the full-width input default,
   which otherwise stretches the box across the panel. */
.check-row {
  display: flex; align-items: center; gap: 9px; cursor: pointer;
  margin: 0 0 12px; padding: 9px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-alt);
  font-size: 13px; font-weight: 400; color: var(--text);
  transition: border-color var(--motion);
}
.check-row:hover { border-color: var(--border-strong); }
.check-row input[type="checkbox"] {
  flex: 0 0 auto; width: 17px; height: 17px; min-height: 0; margin: 0;
  accent-color: var(--accent-fill); cursor: pointer;
}
.radio-group { display: flex; flex-wrap: wrap; gap: 12px; }
.radio-item { display: flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 500; color: var(--text); cursor: pointer; }
.radio-item input { width: auto; margin: 0; }
/* ===== Dropdown calendar date picker (public/js/jalaliPicker.js) ===== */
.jdp { position: relative; display: inline-block; }
.jdp-trigger {
  display: inline-flex; align-items: center; gap: 8px; min-width: 170px; width: 100%;
  padding: 9px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); font-size: 14px; cursor: pointer; text-align: start;
  transition: border-color .15s, box-shadow .15s;
}
.jdp-trigger:hover { border-color: var(--primary); }
.jdp.open .jdp-trigger { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.jdp-label { flex: 1; }
.jdp-popup {
  position: absolute; top: calc(100% + 6px); inset-inline-start: 0; z-index: 150;
  width: 280px; padding: 10px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.jdp-popup[hidden] { display: none; }
.jdp-head { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; }
.jdp-title { flex: 1; text-align: center; font-size: 13.5px; font-weight: 700; }
.jdp-nav {
  width: 30px; height: 30px; flex-shrink: 0; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--text);
  font-size: 15px; line-height: 1; cursor: pointer;
}
.jdp-nav:hover { background: var(--surface-alt); border-color: var(--primary); }
.jdp-weekdays, .jdp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.jdp-weekdays span { text-align: center; font-size: 11px; font-weight: 700; color: var(--text-muted); padding: 3px 0; }
.jdp-cell {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: none; color: var(--text); font-size: 13px; cursor: pointer;
}
.jdp-cell.is-empty { cursor: default; }
.jdp-cell:not(.is-empty):hover { background: var(--surface-alt); }
/* Today is a landmark you scan for, so it gets the accent outright rather
   than a hairline outline. A selected day still outranks it below. */
.jdp-cell.is-today { background: var(--primary-soft); border-color: var(--accent-fill); color: var(--primary); font-weight: 600; }
.jdp-cell.is-selected { background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent); font-weight: 600; }
.jdp-foot { display: flex; gap: 8px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.jdp-foot .btn { flex: 1; }

/* Anchored dropdowns get cut off / overflow on narrow screens, so the popup
   becomes a centred sheet with a backdrop and bigger tap targets instead. */
@media (max-width: 640px) {
  .jdp, .jdp-trigger { width: 100%; }
  .jdp.open::before { content: ''; position: fixed; inset: 0; background: rgba(16, 20, 30, 0.45); z-index: 149; }
  .jdp-popup {
    /* the base rule's inset-inline-start maps to `right` in RTL, which would
       over-constrain (and so cancel) the physical left/transform centring */
    position: fixed; top: 50%; inset-inline-start: auto; right: auto; left: 50%;
    transform: translate(-50%, -50%);
    width: min(330px, calc(100vw - 32px)); padding: 14px;
  }
  .jdp-cell { font-size: 15px; }
  .jdp-nav { width: 36px; height: 36px; }
}

.checkbox-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
/* The native control's button and "No file chosen" come from browser chrome
   and stay English, so the real input is clipped away and the label does the
   talking. Clipped rather than display:none to keep it focusable. */
.file-field {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  margin: 4px 0 12px; padding: 7px 10px;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface-alt);
  transition: border-color var(--motion);
}
.file-field:hover { border-color: var(--accent-line); }
.file-field input[type="file"] { position: absolute; width: 1px; height: 1px; padding: 0; margin: 0; opacity: 0; clip-path: inset(50%); }
.file-field input[type="file"]:focus-visible + .file-btn { box-shadow: 0 0 0 3px var(--primary-soft); }
.file-btn {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  padding: 5px 12px; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--border);
  font-size: 12.5px; font-weight: 500; color: var(--text);
}
.file-name { font-size: 12.5px; color: var(--text-muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.checklist-table { width: 100%; }
.checklist-table td { padding: 5px 8px; }
.photo-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.photo-grid img { width: 100px; height: 100px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border); }

/* Inline edit inside a data cell: the same control as any form field, sized
   to the column so the row stays one line high. */
.cell-input { width: 96px; margin: 0; padding: 5px 8px; min-height: 32px; font-size: 12.5px; }
.cell-input-wide { width: 124px; }
.cell-input:disabled { background: var(--surface-alt); color: var(--text-muted); cursor: not-allowed; }

/* ===== Badges =====
   Four tones, not a rainbow: neutral for parked work, accent for anything in
   motion, positive and danger only where money or a dead end is at stake.
   Every value is derived from a token, so no light-theme hex can leak into
   the dark theme the way the old peach/cream pills did. */
.badge {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  padding: 3px 10px; border-radius: var(--radius-pill);
  font-size: 11.5px; font-weight: 500; line-height: 1.5;
  background: var(--surface-alt); color: var(--text-muted);
  border: 1px solid transparent;
}
/* Parked: waiting on someone or something outside the workshop. */
.status-received,
.status-waiting_inspection,
.status-waiting_parts,
.status-waiting_approval { background: var(--surface-alt); color: var(--text); border-color: var(--border-strong); }
/* On the bench right now. */
.status-diagnosing,
.status-repairing,
.status-testing { background: var(--primary-soft); color: var(--primary); }
.status-ready_pickup,
.status-delivered { background: var(--success-soft); color: var(--success); }
.status-cancelled,
.status-unrepairable { background: var(--danger-soft); color: var(--danger); }
/* Semantic badge variants, used for financial status and payment direction. */
.badge-success { background: var(--success-soft); color: var(--success); }
.badge-danger { background: var(--danger-soft); color: var(--danger); }
.badge-warning { background: var(--primary-soft); color: var(--primary); }
.text-success { color: var(--success); }
.text-danger { color: var(--danger); }


/* ===== Forms / login / track ===== */
.login-page, .track-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; background: var(--bg); }
.login-card, .track-card { background: var(--surface); border-radius: var(--radius-lg); padding: 32px; width: 100%; max-width: 400px; box-shadow: var(--shadow-md); border: 1px solid var(--border); }
.login-card h1, .track-card h1 { text-align: center; margin-bottom: 22px; font-size: 18px; }
.login-logo {
  width: 52px; height: 52px; margin: 0 auto 16px; border-radius: 16px;
  background: var(--accent-fill); color: var(--on-accent);
  display: flex; align-items: center; justify-content: center; font-size: 24px;
}
.track-status { font-size: 15px; font-weight: 600; padding: 12px; border-radius: var(--radius); text-align: center; margin-bottom: 14px; background: var(--primary-soft); color: var(--primary); }

/* Credentials are ASCII, so the login fields run LTR inside the RTL shell
   while their labels stay right-aligned with the rest of the UI. */
.password-field { position: relative; }
.password-field input { padding-right: 40px; }
.password-toggle {
  position: absolute; top: 4px; bottom: 12px; right: 3px; width: 34px;
  display: flex; align-items: center; justify-content: center;
  padding: 0; border: none; background: none; cursor: pointer;
  color: var(--text-muted); font-size: 16px;
  border-radius: var(--radius-sm);
  transition: color .15s, background-color .15s;
}
.password-toggle:hover { color: var(--text); background: var(--primary-soft); }
.password-toggle:focus-visible { outline: none; color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.hint { font-size: 12px; color: var(--text-muted); }
.timeline { list-style: none; padding: 0; margin: 0; }
.timeline li { padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.timeline li:last-child { border-bottom: none; }

/* ===== Wizard ===== */
.voice-intake { display: flex; align-items: flex-start; gap: 12px; padding: 12px 14px; margin-bottom: 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.voice-intake-body { flex: 1; min-width: 0; }
.voice-mic {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 17px;
  background: var(--accent-fill); border: 1px solid var(--accent-fill); color: var(--on-accent);
  transition: background var(--motion), border-color var(--motion), box-shadow var(--motion);
}
.voice-mic:hover { box-shadow: 0 0 0 4px var(--primary-soft); }
.voice-mic.recording { background: #c0392b; border-color: #c0392b; animation: voice-pulse 1.2s ease-in-out infinite; }
@keyframes voice-pulse { 50% { box-shadow: 0 0 0 7px rgba(192, 57, 43, 0); } 0%, 100% { box-shadow: 0 0 0 0 rgba(192, 57, 43, .45); } }
.voice-transcript { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--border); font-size: 13px; line-height: 1.6; }
.voice-filled { color: var(--success, #2e7d32); }
@media (prefers-reduced-motion: reduce) { .voice-mic.recording { animation: none; } }

/* Wizard: vertical timeline beside the form. `inset-inline` keeps the rail on
   the correct side under both LTR and RTL without a mirrored rule set. */
.wizard-layout { display: grid; grid-template-columns: 150px 1fr; gap: 10px; align-items: start; }
.wizard-main { min-width: 0; }

.wizard-timeline { position: relative; list-style: none; margin: 0; padding: 2px 0; }
.wizard-timeline::before {
  content: ''; position: absolute; top: 14px; bottom: 14px; inset-inline-start: 9px;
  width: 2px; background: var(--border);
}
.wizard-step {
  position: relative; display: flex; align-items: center; gap: 8px;
  padding: 5px 0; font-size: 10.5px; font-weight: 600; color: var(--text-muted);
  transition: color .15s;
}
.wizard-step.clickable { cursor: pointer; }
.wizard-step.clickable:hover { color: var(--primary); }
.wizard-step-marker {
  flex: 0 0 20px; width: 20px; height: 20px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); border: 2px solid var(--border);
  font-size: 9.5px; line-height: 1; color: var(--text-muted); z-index: 1;
  transition: background .15s, border-color .15s, color .15s;
}
.wizard-step-label { min-width: 0; line-height: 1.3; }

.wizard-step.done { color: var(--success); }
.wizard-step.done .wizard-step-marker { background: var(--success); border-color: var(--success); color: #fff; }
.wizard-step.active { color: var(--primary); font-weight: 600; }
.wizard-step.active .wizard-step-marker {
  background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* Stack above the form on narrow screens, where a fixed rail costs too much
   width; the numbered markers still carry the progress. */
@media (max-width: 820px) {
  .wizard-layout { grid-template-columns: 1fr; gap: 10px; }
  .wizard-timeline { display: flex; overflow-x: auto; gap: 4px; padding-bottom: 6px; }
  .wizard-timeline::before { top: 13px; bottom: auto; height: 2px; inset-inline: 12px; width: auto; }
  .wizard-step { flex: 0 0 auto; flex-direction: column; gap: 4px; text-align: center; width: 70px; font-size: 9.5px; }
  .wizard-step-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 100%; }
}

.wizard-nav { display: flex; justify-content: space-between; margin-top: 18px; }

/* ===== Expenses summary ===== */
.expense-summary { display: grid; grid-template-columns: 1fr 240px; gap: 16px; align-items: start; margin-bottom: 16px; }
.expense-totals .stat-value { font-size: 24px; font-weight: 600; line-height: 1.2; }
.expense-totals .stat-label { color: var(--text-muted); font-size: 12px; margin-bottom: 10px; }
.expense-legend { list-style: none; margin: 0; padding: 0; }
.expense-legend li { display: flex; align-items: center; gap: 8px; padding: 5px 0; font-size: 13px; border-top: 1px solid var(--border); }
.legend-swatch { width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto; }
.legend-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.legend-value { font-weight: 500; white-space: nowrap; }
.legend-share { color: var(--text-muted); width: 38px; text-align: end; white-space: nowrap; }
.expense-chart { display: flex; flex-direction: column; align-items: center; }
.pie-chart { width: 100%; max-width: 180px; height: auto; }
.pie-chart path { stroke: var(--surface); stroke-width: 1.5; }
.expense-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.sortable:hover { color: var(--primary); }
th.sortable.sorted { color: var(--primary); }
.sort-arrow { font-size: 9px; margin-inline-start: 4px; }
@media (max-width: 800px) { .expense-summary { grid-template-columns: 1fr; } }

/* ===== POS ===== */
.pos-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
.pos-cart { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px; }
.pos-totals { margin-top: 14px; }
.pos-picked { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 10px; margin-bottom: 8px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-alt); }
@media (max-width: 800px) { .pos-layout { grid-template-columns: 1fr; } }

/* ===== Modal / Toast ===== */
.modal-overlay { position: fixed; inset: 0; background: rgba(9, 11, 15, 0.6); backdrop-filter: blur(3px); display: flex; align-items: center; justify-content: center; z-index: 100; padding: 20px; }
.modal { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 24px; width: 100%; max-width: 480px; max-height: 90vh; overflow: auto; box-shadow: var(--shadow-lg); }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
.toast-host { position: fixed; bottom: 20px; inset-inline-start: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 200; }
.toast {
  display: flex; align-items: center; gap: 8px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 11px 16px; box-shadow: var(--shadow-lg);
  opacity: 0; transform: translateY(10px); transition: all .2s; font-size: 13px; font-weight: 500;
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast-success { border-inline-start: 3px solid var(--success); }
.toast-error { border-inline-start: 3px solid var(--danger); }
.alert { padding: 11px 15px; border-radius: var(--radius-sm); margin: 10px 0; font-size: 13px; font-weight: 500; }
.alert-success { background: var(--success-soft); color: var(--success); }
.alert-error { background: var(--danger-soft); color: var(--danger); }

#print-area { display: none; }

/* =====================================================================
   Phone overrides
   Deliberately the LAST block in the file. These share their specificity
   with the component rules above, so anywhere earlier in the source they
   silently lose the cascade — which is exactly what used to happen to the
   .cards-grid and .toolbar overrides.
   ===================================================================== */
@media (max-width: 640px) {
  #view { padding: 14px; padding-bottom: calc(73px + max(22px, env(safe-area-inset-bottom, 0px))); }
  .topbar { padding: 8px 12px; gap: 8px; }
  .btn-label { display: none; }
  .topbar-date { display: none; }
  .topbar-user-name { max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  #logout-btn { padding: 8px; min-height: 36px; }
  .page-header h1 { font-size: 18px; }
  .detail-grid, .charts-grid { grid-template-columns: 1fr; }
  .grid2 { grid-template-columns: 1fr; }
  .hero-grid { grid-template-columns: 1fr; }
  .toolbar { flex-direction: column; align-items: stretch; padding: 10px; }
  .toolbar input, .toolbar select, .toolbar .jdp-trigger, .toolbar .btn { min-width: 0; width: 100%; }
  /* The toolbar stacks here, so a flex-basis meant for a row would become a
     220px-tall search box. */
  .toolbar-grow { flex: 0 0 auto; }
  .filter-field { width: 100%; }
  .filter-field .jdp { flex: 1 1 auto; min-width: 0; }
  .counter-grid { grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); gap: 8px; }
  .cards-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
  .stat-icon { display: none; }
  .stat-value { font-size: 17px; }
  .stat-card--hero .stat-value { font-size: 22px; }
  .pos-cart, .panel, .chart-card { padding: 14px; }
  .login-card, .track-card { padding: 24px; }
  .section { margin-bottom: 20px; }
}
