/* css/style.css
 * Complete design system for CFG_SYSTEM.
 * - :root custom properties for colour, spacing, radius, shadow, font, layout
 * - Neutral greys + ONE accent colour (ink #111827 — the same ink used by
 *   the login rail, the sidebar active row, every primary button and the
 *   logout control. There is no second accent; status colours (green /
 *   amber / red) are reserved for data, never for chrome.)
 * - Semantic landmarks only, no div soup
 * - Desktop grid: 260px sidebar + fluid main + 300px aside
 * - Sticky <header> and sticky <thead>
 * - Status badges: green / amber / red
 * - Light theme only (no dark mode)
 * - Print stylesheet for clean A4
 * - No frameworks, no Bootstrap, no Tailwind
 */

:root {
  --color-bg: #f4f5f7;
  --color-surface: #ffffff;
  --color-text: #1f2933;
  --color-text-muted: #6b7280;
  --color-border: #e5e7eb;
  --color-primary: #111827;
  --color-primary-hover: #374151;
  --color-primary-bg: #e7e9ed;
  --color-success: #16a34a;
  --color-warning: #d97706;
  --color-danger: #dc2626;
  --color-danger-bg: #fef2f2;
  --color-warning-bg: #fffbeb;
  --color-success-bg: #f0fdf4;
  --radius: 8px;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
  --sidebar-w: 260px;
  --aside-w: 300px;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --space-xs: 0.25rem;
  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;
}

/* -------------------------------------------------------------------------
   Layout shell
   ------------------------------------------------------------------------- */

/* One box model for every page (index.php does not include header.php, so
   it cannot rely on that partial's own copy of this rule). */
*, *::before, *::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  background: var(--color-bg);
  color: var(--color-text);
  line-height: 1.5;
  min-height: 100vh;
}

/* Skip link for keyboard users. */
.skip-link {
  position: absolute;
  top: -100%;
  left: 1rem;
  background: var(--color-primary);
  color: #fff;
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius);
  z-index: 100;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 0; }.skip-link:focus-visible {
  outline: 2px solid var(--color-primary); outline-offset: 2px;
}

/* Visually hidden but still read by screen readers (header search label). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Sticky header. */
.app-header {
  position: sticky;
  top: 0;
  /* Above the mobile drawer (z-index 60) so the menu button that opens it
     stays clickable while the drawer is open. */
  z-index: 70;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  padding: var(--space-sm) var(--space-md);
}
.app-header__inner {
  max-width: 1440px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-md);
}
.app-header__brand {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}
.brand { font-weight: 700; font-size: 1.1rem; }
/* No search box in the header anymore. The actions group (user menu +
   logout) is pushed flush to the RIGHT edge with margin-left: auto — it
   was previously parked next to the brand only because the search field
   occupied the space between them. */
.app-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-left: auto;
}
.icon-btn {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-xs) var(--space-sm);
  cursor: pointer;
  color: var(--color-text);
}
.icon-btn:hover { background: var(--color-primary-bg); }

/* Sidebar: a fixed left rail at every width, with its OWN toggle button
   in the sidebar-head strip at the top (not in the page header). Wide:
   the ‹/› chevron collapses/expands the rail (the toggle stays visible
   in the head strip so it can be reopened). Narrow (≤900px): the rail
   becomes an off-canvas drawer; its toggle button (styled as ✕ in drawer
   mode) closes it, since the drawer covers the page header. */
/* Sidebar shell: fixed rail at all widths. The head strip is a sibling of
   the nav, so it never moves with the drawer transform. */
.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: var(--sidebar-w);
  max-width: 86vw;
  height: 100vh; height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  z-index: 80;
  transform: translateX(0);
  transition: transform 0.22s ease, width 0.22s ease;
}

.sidebar-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  min-height: 52px;
  padding: var(--space-sm) var(--space-md);
  border-bottom: 1px solid var(--color-border);
  background: inherit;
}

/* The brand stub in the head strip — logo mark + wordmark, sized for the
   rail. Collapsed, the wordmark hides and only the logo mark stays (see
   body.sidebar-collapsed rules below). */
.sidebar-brand-mini {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  min-width: 0;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  color: var(--color-text);
}
/* Logo mark: monogram badge drawn in CSS (no image file). The collapsed
   rail shrinks it to 24px — see body.sidebar-collapsed rules below. */
.sidebar-brand-mini__logo {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  background: var(--color-primary);
  color: #fff;
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
}

/* Single source of truth for the button. */
.sidebar-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
}
.sidebar-toggle:hover { background: var(--color-primary-bg); color: var(--color-primary); }
.sidebar-toggle:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; }
.sidebar-toggle .chev { transition: transform 0.2s ease; }

/* The nav scrolls; the head strip does not. */
.sidebar-nav-inner {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.sidebar nav { padding: var(--space-md); }

/* ---- Wide: collapse the rail down to a 40px strip that keeps the
   toggle reachable. The header padding and the main/footer margins drop
   to 40px to match, so everything sits flush against the rail edge —
   the header connects to the sidebar instead of hiding under it. ---- */
@media (min-width: 901px) {
  body.sidebar-collapsed .sidebar {
    width: 40px;
    overflow: hidden;
    transform: none;
  }
  body.sidebar-collapsed .sidebar-nav-inner,
  body.sidebar-collapsed .sidebar nav { display: none; }
  /* Head stacks vertically so the logo mark sits above the toggle in the
     40px rail — logo stays visible when collapsed, the CFG wordmark hides. */
  body.sidebar-collapsed .sidebar-head {
    flex-direction: column;
    justify-content: center;
    gap: 6px;
    padding-left: 1px;
    padding-right: 1px;
  }
  body.sidebar-collapsed .sidebar-brand-mini__text { display: none; }
  body.sidebar-collapsed .sidebar-brand-mini__logo {
    width: 24px;
    height: 24px;
    font-size: 0.8rem;
  }
  body.sidebar-collapsed .chev { transform: rotate(180deg); }

  .main, .app-footer { margin-left: var(--sidebar-w); }
  .app-header { padding-left: var(--sidebar-w); }
  .main, .app-footer, .app-header {
    transition: margin-left 0.22s ease, padding-left 0.22s ease;
  }
  body.sidebar-collapsed .main,
  body.sidebar-collapsed .app-footer { margin-left: 40px; }
  body.sidebar-collapsed .app-header { padding-left: 40px; }
}

/* ---- Narrow: off-canvas drawer, closed unless .is-open ----
   The panel itself must fully hide when closed: its background goes
   transparent, the nav slides off-canvas, and only the toggle button
   stays parked at the top-left corner (fixed over the page header,
   which reserves room for it with padding-left: 60px). Opening slides
   the white nav panel back in with the head bar on top. */
@media (max-width: 900px) {
  .sidebar {
    overflow: hidden;
    background: transparent;
    border-right: none;
    box-shadow: none;
    pointer-events: none;
    transform: none;
  }
  .sidebar.is-open {
    background: var(--color-surface);
    box-shadow: var(--shadow-md);
    pointer-events: auto;
  }
  /* Head strip: transparent while closed (no stray rule across the
     page); white with a bottom rule once the drawer is open. */
  .sidebar-head { border-bottom: none; }
  .sidebar.is-open .sidebar-head { border-bottom: 1px solid var(--color-border); }
  .sidebar-brand-mini { display: none; }
  /* Toggle: floats over the header at the top-left while the drawer is
     closed; drops back into the head bar when it is open. */
  .sidebar-toggle {
    position: fixed;
    top: 6px;
    left: 6px;
    z-index: 3;
    pointer-events: auto;
    box-shadow: var(--shadow-sm);
    border-color: var(--color-primary);
    color: var(--color-primary);
    background: var(--color-primary-bg);
    width: 44px;
    height: 44px;
  }
  .sidebar.is-open .sidebar-toggle { position: static; box-shadow: none; }
  /* Chevron points "close" only once the drawer is actually open. */
  .sidebar.is-open .chev { transform: rotate(180deg); }
  /* Nav panel owns the white background and slides off-canvas; the
     sidebar's overflow: hidden clips it while it is parked. */
  .sidebar-nav-inner {
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    background: var(--color-surface);
    flex: 1 0 auto;
  }
  .sidebar.is-open .sidebar-nav-inner { transform: translateX(0); }
  /* Keep the header brand clear of the floating toggle. */
  .app-header { padding-left: 60px; }
  .branch-list { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
  .branch-link { white-space: nowrap; }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar, .sidebar-toggle .chev, .main, .app-footer, .app-header { transition: none; }
}

body.sidebar-collapsed .sidebar-toggle .chev { transform: rotate(180deg); }
.sidebar-toggle[data-open-menu="true"] .chev { transform: rotate(180deg); }

/* The nav body lives inside the padded region below the head strip. */
.sidebar nav {
  padding: var(--space-md);
  overflow-y: auto;
}

.branch-list { list-style: none; margin: 0; padding: 0; }
.branch-link {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--color-text);
  font-weight: 500;
  transition: background 0.15s ease;
}
.branch-link:hover { background: var(--color-bg); }
/* Active branch: the SAME ink every primary control uses — a solid fill
   with reversed text, not a tinted chip inside an outline box. */
.branch-link.is-active,
.branch-link.is-active:hover {
  background: var(--color-primary);
  color: #fff;
}
.branch-link__icon { display: flex; color: var(--color-text-muted); }
.branch-link.is-active .branch-link__icon { color: #fff; }
/* Long branch names truncate to ONE line with an ellipsis instead of
   wrapping into two (flex children default to min-width: auto, so the
   0 is what lets the title shrink below its content width). */
.branch-link { min-width: 0; }
.branch-link__title {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Main content. The rail is fixed and full-height, so the content (and
   footer) reserve its width all the way to the top — no offset for a
   page header, since the rail covers the full viewport height. */
.main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
/* Content fills the whole main area edge to edge and stays centred.
   The old 1200px cap plus a phantom 300px aside margin (there is no
   aside on the branch pages) pinned the KPI cards to the left with a
   dead strip on the right. */.content {
  padding: var(--space-xl);
  width: 100%;
  margin: 0 auto;
}
/* Report-style summary layout, modeled after the Daily Sales Board PDF
   in file/Consebido_Food_Group_Daily_Sales_Board_Report_Sep2026.pdf:
   a report header strip, then the summary cards/charts, then a footer
   strip with the last-updated and generated timestamps. */
.content--report {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}
.report-head {
  position: sticky;
  top: 52px;
  z-index: 60;
  background: var(--color-bg);
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-lg);
  padding-top: var(--space-sm);
  padding-bottom: var(--space-md);
  border-bottom: 2px solid var(--color-text);
}
.report-kicker {
  margin: 0 0 var(--space-xs);
  font-family: var(--font);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--color-primary);
}
.report-head h1 {
  margin: 0;
  font-size: 2rem;
  font-weight: 800;
  letter-spacing: -0.02em;
}
/* Month stepper above the report title — ‹ Prev | current period | Next ›.
   Previously unstyled (no rule existed for these classes at all), so the
   links rendered as bare inline anchors with no hit area or affordance. */
.report-head__period-nav {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
  flex-wrap: wrap;
}
.report-period-nav__controls {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-xs) 0;
}
.report-period-nav__btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.report-period-nav__btn:hover {
  background: var(--color-primary-bg);
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.report-period-nav__btn:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
/* Rendered as a <span> when there is no month to step to (start/end of
   range): same footprint as the button, just inert. */
.report-period-nav__btn--disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
  pointer-events: none;
}
.report-period-nav__current {
  padding: 6px 12px;
  border: 1px solid var(--color-primary);
  border-radius: var(--radius);
  background: var(--color-primary-bg);
  color: var(--color-primary);
  font-family: var(--font);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.report-head__meta {
  display: flex;
  gap: var(--space-lg);
  align-items: flex-start;
  flex: 0 0 auto;
}
.report-meta {
  margin: 0;
  font-size: 0.85rem;
  color: var(--color-text-muted);
  line-height: 1.4;
}
.report-meta__label {
  display: block;
  font-family: var(--font);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--color-text);
  margin-bottom: 2px;
}
.report-foot {
  display: flex;
  gap: var(--space-xl);
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-border);
  margin-top: var(--space-sm);
}
.report-foot__line {
  margin: 0;
  font-size: 0.82rem;
  color: var(--color-text-muted);
  line-height: 1.4;
}
.report-foot__label {
  display: block;
  font-family: var(--font);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--color-text);
  margin-bottom: 2px;
}
/* --- Daily Sales Board report format (file/format.pdf) ------------------ */
.report-sub {
  margin: var(--space-xs) 0 0;
  font-size: 0.92rem;
  color: var(--color-text-muted);
}
/* Stat tile row: PDF's MONTH-TO-DATE GROSS / AVERAGE / DAY / … blocks —
   label on top, big number, two small sub-lines below. */
.report-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-md);
}
.report-stat {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-md) var(--space-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.report-stat__label {
  font-family: var(--font);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--color-text-muted);
}
.report-stat__value {
  font-size: 1.9rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
  line-height: 1.15;
}
.report-stat__sub {
  font-size: 0.78rem;
  color: var(--color-text-muted);
}
/* Section heading between the chart and the detail table. */
.report-section-title {
  margin: var(--space-sm) 0 0;
  font-family: var(--font);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--color-text);
  padding-bottom: var(--space-xs);
  border-bottom: 1px solid var(--color-border);
}
/* EOD gross vs daily target chart (inline SVG). */
.report-chart {
  margin: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-md) var(--space-lg) var(--space-sm);
  box-shadow: var(--shadow-sm);
}
.report-chart__svg { display: block; width: 100%; height: auto; }
.chart-svg__grid { stroke: var(--color-border); stroke-width: 1; }
.chart-svg__axis { stroke: var(--color-text-muted); stroke-width: 1.25; }
.chart-svg__ytick,
.chart-svg__xtick {
  fill: var(--color-text-muted);
  font-size: 11px;
  font-family: var(--font);
}
/* Chart data palette — blue / green / orange / red. The ink accent
   (--color-primary) is for chrome only; series lines are never black. */
.chart-svg__gross {
  fill: none;
  stroke: #2563eb;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.chart-svg__target {
  fill: none;
  stroke: var(--color-danger);
  stroke-width: 2;
  stroke-dasharray: 6 5;
}
/* Group report: one solid line per store (file/format.pdf page 1). */
.chart-svg__store {
  fill: none;
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.chart-svg__store--1 { stroke: #2563eb; }
.chart-svg__store--2 { stroke: var(--color-success); }
.chart-svg__store--3 { stroke: #f97316; }
.chart-svg__store--4 { stroke: var(--color-danger); }
.chart-svg__store--5 { stroke: #7c3aed; }
.report-chart__legend {
  display: flex;
  gap: var(--space-lg);
  align-items: center;
  flex-wrap: wrap;
  padding-top: var(--space-xs);
  font-size: 0.78rem;
  color: var(--color-text-muted);
}
.report-chart__key::before {
  content: "";
  display: inline-block;
  width: 22px;
  height: 0;
  border-top: 3px solid #2563eb;
  margin-right: 6px;
  vertical-align: middle;
}
.report-chart__key--target::before {
  border-top: 2px dashed var(--color-danger);
}
.report-chart__key--store1::before { border-top-color: #2563eb; }
.report-chart__key--store2::before { border-top-color: var(--color-success); }
.report-chart__key--store3::before { border-top-color: #f97316; }
.report-chart__key--store4::before { border-top-color: var(--color-danger); }
.report-chart__key--store5::before { border-top-color: #7c3aed; }
.report-chart__note { margin-left: auto; }
/* Detail table — same table styles, plus variance/total emphasis. */
.report-table-wrap { border-radius: var(--radius); }
/* Operating Expenses + Cost of Labor — the two line-item tables sit side by
   side, each keeping its own section heading. Stacks on narrow/print widths. */
.report-tables-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg);
  align-items: start;
}
.report-tables-split__col { min-width: 0; }
@media (max-width: 900px) {
  .report-tables-split { grid-template-columns: 1fr; }
}
.report-table tfoot td {
  font-weight: 700;
  background: var(--color-bg);
  border-top: 2px solid var(--color-text);
  border-bottom: none;
}
.report-variance.is-negative { color: var(--color-danger); }
/* Group summary row for a branch with no sales data in the window. */
.report-table__nodata td { color: var(--color-text-muted); font-style: italic; }
.status-badge--on    { background: var(--color-success-bg); color: var(--color-success); }
.status-badge--below { background: var(--color-warning-bg); color: var(--color-warning); }
/* Empty state shown instead of the chart/table when a branch has no
   daily_sales rows (the stat tiles above it still render). */
.report-empty {
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-lg);
  color: var(--color-text-muted);
  font-size: 0.9rem;
}
.report-empty p { margin: 0 0 var(--space-xs); }
.report-empty p:last-child { margin-bottom: 0; }
.report-empty strong { color: var(--color-text); }
@media (max-width: 760px) {
  .report-head { flex-direction: column; }
  .report-head__meta { flex-wrap: wrap; gap: var(--space-md); }
  .report-stat__value { font-size: 1.5rem; }
}

/* Second content section (Record Movement) — no extra top padding, the
   .movement-panel's own margin supplies the gap, matching the old layout. */
.content--movement { padding-top: 0; }
h1 { font-size: 1.6rem; margin: 0 0 var(--space-md); }
h2 { font-size: 1.2rem; margin: 0 0 var(--space-sm); }

/* KPI cards: a wrapping flex row so EVERY row stretches edge to edge
   (a grid left an empty cell — and a dead strip to the right — on the
   short last row of 11 cards). flex: 1 1 auto makes the inner row from
   render_kpi_cards() fill its wrapper when one is present. */
.kpi-row {
  display: flex;
  flex-wrap: wrap;
  flex: 1 1 auto;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.kpi-card {
  /* Basis must exceed the widest card's min-content (the ₱ values at
     1.5rem ≈ 223px) or content width — not the basis — decides how many
     cards fit per row. 258px resolves 11 cards to 4+4+3 at 1440px both
     with the sidebar open (1099px available) and collapsed (1319px),
     and flex-grow stretches every row edge to edge. */
  flex: 1 1 258px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-lg);
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  box-shadow: var(--shadow-sm);
}
.kpi-card__icon { display: flex; color: var(--color-text-muted); }
.kpi-card--warning .kpi-card__icon { color: var(--color-warning); }
.kpi-card--danger .kpi-card__icon { color: var(--color-danger); }
.kpi-card--value .kpi-card__icon,
.kpi-card--info .kpi-card__icon { color: var(--color-primary); }
.kpi-card__label { color: var(--color-text-muted); font-size: 0.85rem; }
.kpi-card__value { font-size: 1.5rem; font-weight: 700; }
.kpi-card--value .kpi-card__value { color: var(--color-primary); }
.kpi-card--warning .kpi-card__value { color: var(--color-warning); }
.kpi-card--danger .kpi-card__value { color: var(--color-danger); }
.kpi-card--info .kpi-card__value { color: var(--color-success); }

/* Summary charts (pure CSS, no library). */
.chart-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}
.chart {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-md);
  box-shadow: var(--shadow-sm);
}
.chart__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--space-sm);
}
.chart__label { font-size: 0.82rem; color: var(--color-text-muted); font-weight: 600; }
.chart__value { font-size: 1.15rem; font-weight: 700; color: var(--color-text); }
.chart--value .chart__value { color: var(--color-primary); }
.chart__track {
  height: 14px;
  background: var(--color-bg);
  border-radius: 999px;
  overflow: hidden;
}
.chart__fill {
  height: 100%;
  background: #2563eb;
  border-radius: 999px;
  transition: width 0.3s ease;
}
.chart__axis {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-xs);
  font-size: 0.68rem;
  color: var(--color-text-muted);
}
.dots { display: flex; align-items: center; justify-content: space-between; margin-top: var(--space-sm); gap: var(--space-xs); }
.dot {
  width: 12px; height: 12px;
  border-radius: 999px;
  background: var(--color-border);
  transition: background 0.2s ease;
}
.dot--yes { background: var(--color-success); box-shadow: 0 0 0 2px var(--color-success-bg); }
.dot--no { background: var(--color-border); }
.dot--yes:hover, .dot--no:hover { opacity: 0.8; }

/* Toolbar + search. */
.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md);
  flex-wrap: wrap;
  margin-bottom: var(--space-md);
}
.search-wrap { position: relative; }
.search-wrap input {
  width: 260px;
  padding: var(--space-sm) var(--space-md) var(--space-sm) 2.2rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
}
.search-wrap::before {
  content: "";
  position: absolute;
  left: var(--space-sm);
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  pointer-events: none;
  background: no-repeat center / contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
}

/* Filters. */
.filters {
  margin-bottom: var(--space-md);
  padding: var(--space-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.filters__row { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
.filters__row select,
.filters__row input {
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
}

/* Table. */
.table-scroll { overflow-x: auto; }
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.inventory-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.inventory-table th,
.inventory-table td {
  padding: var(--space-sm) var(--space-md);
  text-align: left;
  border-bottom: 1px solid var(--color-border);
}
.inventory-table thead {
  position: sticky;
  top: 0;
  background: var(--color-surface);
  z-index: 2;
}
.inventory-table tbody tr:hover { background: var(--color-bg); }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.status-badge {
  display: inline-block;
  padding: var(--space-xs) var(--space-sm);
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
}
.status-badge--in-stock     { background: var(--color-success-bg);  color: var(--color-success); }
.status-badge--low-stock    { background: var(--color-warning-bg);  color: var(--color-warning); }
.status-badge--out-of-stock { background: var(--color-danger-bg); color: var(--color-danger); }
.status-badge--unknown      { background: var(--color-border); color: var(--color-text-muted); }

/* Table footer: alerts + actions + pagination. */
.table-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md);
  margin-top: var(--space-lg);
}
.table-foot__alerts { display: flex; gap: var(--space-md); flex-wrap: wrap; }
.alert {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius);
  font-size: 0.85rem;
  font-weight: 600;
}
.alert--danger { background: var(--color-danger-bg); color: var(--color-danger); }
.alert--warning { background: var(--color-warning-bg); color: var(--color-warning); }
.alert--success { background: var(--color-success-bg); color: var(--color-success); }

.table-foot__actions {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
  flex-wrap: wrap;
}
.filters-group { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
.filters-group input,
.filters-group select {
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
}

/* Pagination. */
.pagination { display: flex; align-items: center; gap: var(--space-sm); }
.pagination a { text-decoration: none; color: var(--color-primary); }
.pagination__current { color: var(--color-text-muted); }
.pagination__count { color: var(--color-text-muted); font-weight: 400; }

/* Record movement form. */
.movement-panel {
  margin-top: var(--space-xl);
  padding: var(--space-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.movement-form { display: flex; flex-direction: column; gap: var(--space-sm); max-width: 560px; }
.movement-form__row { display: flex; flex-direction: column; gap: var(--space-xs); }
.movement-form__row label { font-size: 0.82rem; color: var(--color-text-muted); }
.movement-form__row input,
.movement-form__row select {
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
}
.movement-form__actions { display: flex; gap: var(--space-sm); align-items: center; }
.movement-feedback { color: var(--color-text-muted); font-size: 0.85rem; min-height: 1.2em; }

/* Buttons. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.btn:hover { background: var(--color-bg); }
.btn--primary { background: var(--color-primary); border-color: var(--color-primary); color: #fff; }
.btn--primary:hover { background: var(--color-primary-hover); }
.btn--ghost { background: transparent; }
.btn--danger { background: var(--color-danger); border-color: var(--color-danger); color: #fff; }

/* Auth (login). Two flat planes, no floating sheet: an ink brand rail with
   a numbered branch index on the left, plain white space and a form on the
   right. Everything here is drawn from the same tokens the dashboard uses
   (ink accent, --radius borders, .btn--primary) — the sign-in page and the
   signed-in app are one palette. Narrow: the rail collapses to a compact
   header strip above the form. */
.login-page {
  background: var(--color-surface);
  --login-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}
.login-wrap {
  position: relative;
  min-height: 100vh;
  display: grid;
  grid-template-columns: minmax(340px, 400px) 1fr;
  grid-template-rows: 1fr;
}

/* ---- Left rail ---- */
.login-brand {
  position: relative;
  overflow: hidden;
  background: #111827;
  color: #e5e7eb;
  padding: 40px 36px;
  display: flex;
  flex-direction: column;
}
/* Faint ledger ruling gives the panel texture without gradients/glow. */
.login-brand::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.04) 0,
    rgba(255, 255, 255, 0.04) 1px,
    transparent 1px,
    transparent 28px
  );
  pointer-events: none;
}
.login-brand > * { position: relative; }
.login-brand__monogram {
  width: 52px;
  height: 52px;
  border: 1.5px solid #374151;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font);
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.12em;
  color: #ffffff;
  margin-bottom: var(--space-lg);
}
.login-brand__mark {
  margin: 0 0 var(--space-lg);
  font-family: var(--font);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: #9ca3af;
}
.login-brand__statement {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: #f9fafb;
}
.login-brand__list {
  list-style: none;
  margin: auto 0 0; /* pushes the index + foot to the bottom */
  padding: 0;
  display: flex;
  flex-direction: column;
  font-size: 0.92rem;
  color: #d1d5db;
  border-top: 1px solid #1f2937;
}
.login-brand__list li {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
  padding: 10px 0;
  border-bottom: 1px solid #1f2937;
}
.login-brand__num {
  font-family: var(--font);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  color: #6b7280;
}
.login-brand__foot {
  margin: var(--space-lg) 0 0;
  font-family: var(--font);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: #6b7280;
}

/* ---- Right: the form ---- */
.login-panel {
  box-sizing: border-box; /* padding must count toward width, or the sheet
                             overflows its column between ~760px and ~1000px */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--space-xl) clamp(var(--space-lg), 7vw, 5rem);
  max-width: 602px; /* 440px content + 2 × 5rem padding */
  width: 100%;
  margin: 0 auto;
}
.login-panel__head h1 {
  margin: 0 0 var(--space-xs);
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.login-hint {
  margin: 0 0 var(--space-lg);
  color: var(--color-text-muted);
  font-size: 0.9rem;
  max-width: 44ch;
}

.login-error {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border: 1px solid #fecaca;
  border-left: 3px solid var(--color-danger);
  border-radius: 0;
  padding: var(--space-sm) var(--space-md);
  font-size: 0.9rem;
  margin: 0 0 var(--space-md);
}

.login-form { display: flex; flex-direction: column; gap: var(--space-md); }
.login-form .field { display: flex; flex-direction: column; gap: 6px; }
/* Field labels: plain sentence case at body-ish size — the way a form
   someone actually maintains is labelled, not a tracked-out caption. */
.login-form label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text);
}
.login-form input[type="text"],
.login-form input[type="password"] {
  box-sizing: border-box; /* width:100% must include padding+border or the
                             fields spill past the sheet on narrow screens */
  width: 100%;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 1rem;
}
.login-form input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-primary-bg); }

/* Password field + eye toggle. */
.password-box { position: relative; }
.password-box input { padding-right: 2.6rem; }
.pwd-toggle {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 30px;
  border: none;
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  border-radius: var(--radius);
}
.pwd-toggle:hover { color: var(--color-text); background: var(--color-bg); }
.pwd-toggle:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; }
.icon-eye-off { display: none; }

/* The sign-in button IS .btn--primary — the same ink fill, border radius,
   weight and hover the rest of the system uses. Only the width differs. */
.login-submit {
  margin-top: var(--space-xs);
  width: 100%;
  justify-content: center;
  font-size: 0.95rem;
}
.login-submit:active { transform: translateY(1px); }

/* ---- Login loading overlay — flips on at submit and stays up until the
   next page paints. The background IS the project image file
   (image/image.png); CSS URLs resolve against THIS stylesheet, so
   ../image/image.png works from any page depth. A scrim dims the photo so
   the spinner and label stay readable over any part of it. ---- */
.login-loading {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  background: url('../image/image.png') center center / cover no-repeat;
}
/* Author display beats the UA's [hidden] rule — restate it here. */
.login-loading[hidden] { display: none; }
.login-loading::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(17, 24, 39, 0.72);
}
.login-loading__card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  color: #fff;
  text-align: center;
}
.login-loading__spinner {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  border: 4px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  animation: login-spin 0.8s linear infinite;
}
@keyframes login-spin { to { transform: rotate(360deg); } }
.login-loading__text {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
@media (prefers-reduced-motion: reduce) {
  .login-loading__spinner { animation-duration: 1.6s; }
}
.login-panel__foot {
  margin-top: var(--space-xl);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md);
  font-family: var(--font);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-md);
  flex-wrap: wrap;
  width: 100%;
}

/* ---- Standalone auth card (frontend/login_card.php) ----
   Kept on the same palette as index.php's sign-in page: flat sheet, ink
   primary button, no background image behind the form. */
.auth-card {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-surface);
  overflow: hidden;
}

.auth-card__content {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 420px;
  padding: var(--space-lg);
}

.auth-card h1 {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-md);
  color: var(--color-text);
}

.auth-card .error {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border: 1px solid #fecaca;
  border-left: 3px solid var(--color-danger);
  padding: var(--space-sm) var(--space-md);
  font-size: 0.9rem;
  margin: 0 0 var(--space-md);
  border-radius: 0;
}

.auth-card .login-form { display: flex; flex-direction: column; gap: var(--space-md); }
.auth-card .field { display: flex; flex-direction: column; gap: 6px; }
.auth-card label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text);
}
.auth-card input[type="text"],
.auth-card input[type="password"] {
  width: 100%;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 1rem;
}
.auth-card input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-primary-bg); }



/* Narrow */
@media (max-width: 760px) {
  .login-sheet { min-height: 100vh; }
  .login-wrap { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .login-brand {
    flex-direction: row;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
  }
  .login-brand::before { display: none; }
  .login-brand__monogram {
    width: 40px;
    height: 40px;
    font-size: 0.8rem;
    margin-bottom: 0;
    flex: 0 0 auto;
  }
  .login-brand__mark { margin: 0; }
  .login-brand__statement,
  .login-brand__list,
  .login-brand__foot { display: none; }
  .login-panel { padding: var(--space-xl) var(--space-md); }

  .auth-card__content { max-width: 100%; padding: var(--space-md); }
}

/* Footer. */
.app-footer {
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding: var(--space-md) var(--space-md);
}
.app-footer__inner {
  max-width: 1440px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  gap: var(--space-md);
  font-size: 0.85rem;
  color: var(--color-text-muted);
  flex-wrap: wrap;
}
.footer-meta { font-family: var(--font); font-size: 0.8rem; }

/* -------------------------------------------------------------------------
   Logout: header trigger, confirmation dialog, sign-out veil.
   All motion sits behind prefers-reduced-motion — see the block at the end.
   ------------------------------------------------------------------------- */
.logout-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--color-text-muted);
}
/* Sign-out is chrome, not an error: it hovers the exact same way every
   other control in the header does (ink text on the graphite tint) so
   there is no second colour in the system. Red stays with real data
   states — failed login, low stock, negative variance. */
.logout-btn:hover {
  color: var(--color-primary);
  background: var(--color-primary-bg);
  border-color: var(--color-primary);
}
.logout-btn[disabled] { opacity: 0.6; cursor: wait; }

.modal[hidden] { display: none; }
.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
}
.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(17, 24, 39, 0.55);
  animation: modal-fade-in 0.18s ease both;
}
.modal__panel {
  position: relative;
  width: 100%;
  max-width: 420px;
  padding: var(--space-xl) var(--space-lg) var(--space-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  text-align: center;
  animation: modal-pop-in 0.22s cubic-bezier(0.2, 0.8, 0.3, 1) both;
}
.modal.is-closing .modal__backdrop { animation: modal-fade-out 0.16s ease both; }
.modal.is-closing .modal__panel { animation: modal-pop-out 0.16s ease both; }
.modal__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  margin-bottom: var(--space-md);
  border-radius: 50%;
  background: var(--color-primary-bg);
  color: var(--color-primary);
}
.modal__title {
  margin: 0 0 var(--space-sm);
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.modal__text {
  margin: 0 0 var(--space-lg);
  color: var(--color-text-muted);
  font-size: 0.92rem;
}
.modal__actions {
  display: flex;
  gap: var(--space-sm);
  justify-content: flex-end;
  flex-wrap: wrap;
}
.modal__actions .btn { flex: 1 1 auto; justify-content: center; }

/* While the veil is up the page behind it is frozen: no scroll, no clicks. */
body.is-signing-out { overflow: hidden; }

/* Full-screen veil shown once logout is confirmed. */
.signout-veil[hidden] { display: none; }
.signout-veil {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  /* Image background (the project image file) under a dark scrim, so the
     spinner and label read over any part of it — mirrors .login-loading.
     CSS URLs resolve against this stylesheet, so ../image works from any
     page depth. */
  background:
    linear-gradient(rgba(17, 24, 39, 0.8), rgba(17, 24, 39, 0.8)),
    url('../image/image.png') center center / cover no-repeat;
  color: #f9fafb;
  opacity: 0;
  animation: modal-fade-in 0.28s ease 0.04s both;
}
.signout-veil__text {
  font-family: var(--font);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
}
.signout-veil__spinner {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.22);
  border-top-color: #ffffff;
  animation: spin 0.7s linear infinite;
}

@keyframes modal-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes modal-pop-in {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to { opacity: 1; transform: none; }
}
@keyframes modal-pop-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(8px) scale(0.97); }
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Empty state. */
.empty-state { color: var(--color-text-muted); padding: var(--space-xl); text-align: center; }

/* Focus visible. */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Reduced motion: keep every state change, drop the movement. The veil must
   stay opaque — it starts at opacity 0 and only the animation fills it in. */
@media (prefers-reduced-motion: reduce) {
  .modal__backdrop,
  .modal__panel { animation: none; opacity: 1; transform: none; }
  .signout-veil { animation: none; opacity: 1; }
  .signout-veil__spinner { animation-duration: 1.6s; }
}

/* -------------------------------------------------------------------------
   Print (clean A4 for one branch summary).
   ------------------------------------------------------------------------- */

@media print {
  .app-header,
  .sidebar,
  .movement-panel,
  .table-foot,
  .skip-link { display: none; }
  .main { margin: 0; max-width: 100%; }
  .content { padding: 0; }
  .inventory-table { font-size: 0.85rem; }
  .status-badge { border: 1px solid var(--color-border); }
  .table-wrap { border: none; }
}
