/* Gearbox — the shell every area wears.

   Linked BEFORE each area's own stylesheet, so an area can still override a
   shared rule. What belongs here is chrome that is not any area's: the sidebar,
   the topbar, the user card.

   IT DEFINES THE THEME (2026-08-01, the stylesheet merge). The :root tokens,
   the dark-mode overrides and every component whose definition already agreed
   across the four areas live HERE, once — the area files keep only what is
   genuinely theirs (Purchasing's coverage colors, the chart palette, page
   rules). Before the merge each area carried its own copy of the theme, and
   `--border` — an alias only Sales declared while templates in every area used
   it — drew near-black rules in three areas, because CSS drops a declaration
   with an undefined custom property and renders on, silently.
   `tests/test_shared_css.py` now checks every bare var() in every stylesheet
   AND template resolves against this file or the file's own declarations.

   ── The sidebar replaced a thin hover-out rail ────────────────────────────
   The rail switched AREAS and nothing else; each area then carried its own top
   nav for its own pages. That is two navigation systems for one question, and
   it put the areas somewhere you had to discover by hovering. One sidebar holds
   both levels — areas, and their pages beneath — which is also what makes the
   merge visible rather than something a person has to be told about.
*/

:root {
  --sidebar-w: 224px;
  --sidebar-w-collapsed: 52px;
  /* The navy brand band's height — sidebar head AND topbar, which meet at the
     sidebar edge and must read as one continuous band. */
  --topbar-h: 56px;
}

/* ── Layout ──────────────────────────────────────────────────────────────── */

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: var(--sidebar-w);
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-right: 1px solid var(--line);
  z-index: 60;
  transition: width .16s ease, transform .2s ease;
}

.app-body {
  margin-left: var(--sidebar-w);
  min-height: 100vh;
  transition: margin-left .16s ease;
}
.app-body.no-sidebar { margin-left: 0; }

/* Collapsed: icons only. The class is set on <html> before first paint by the
   inline script in base.html, so the sidebar never flashes open then snaps. */
html.sidebar-collapsed .sidebar { width: var(--sidebar-w-collapsed); }
html.sidebar-collapsed .app-body { margin-left: var(--sidebar-w-collapsed); }
html.sidebar-collapsed .sidebar-search,
html.sidebar-collapsed .nav-area-label,
html.sidebar-collapsed .nav-chevron,
html.sidebar-collapsed .nav-group-label,
html.sidebar-collapsed .nav-area-body,
html.sidebar-collapsed .nav-area.open .nav-area-body,
html.sidebar-collapsed .sidebar-theme-label,
html.sidebar-collapsed .user-text,
html.sidebar-collapsed .user-chevron { display: none; }
html.sidebar-collapsed .sidebar-collapse svg { transform: rotate(180deg); }
html.sidebar-collapsed .nav-area-head,
html.sidebar-collapsed .user-card { justify-content: center; padding-left: 0; padding-right: 0; }
html.sidebar-collapsed .sidebar-theme { justify-content: center; }
/* Collapsed, the 52px rail can't fit the NPW mark and the collapse button in a
   row — the button alone stays, centered, since it is the way back. The
   GEARBOX wordmark lives on the topbar now and is unaffected. */
html.sidebar-collapsed .sidebar-head .brand { display: none; }
html.sidebar-collapsed .sidebar-head { justify-content: center; padding: 0; }

/* ── Head ────────────────────────────────────────────────────────────────── */

/* The navy brand band, split across the two panels that meet at the top: the
   sidebar head carries the NPW mark, the topbar carries the gear + GEARBOX
   wordmark and the page title. Same height, same navy, same 2px red rule, so
   they read as ONE band — the old topbar's graphics, with the rail beneath.
   (A single-panel version was tried first and 224px could not fit the mark,
   the wordmark and the collapse button without clipping.) */
.sidebar-head {
  display: flex;
  align-items: center;
  gap: 8px;
  height: var(--topbar-h);
  padding: 0 10px;
  border-bottom: 2px solid var(--red);
  background: var(--navy, #0F1554);
  /* Cover the sidebar's own hairline so the band runs unbroken into the
     topbar beside it. */
  margin-right: -1px;
  position: relative;
  z-index: 1;
}
.sidebar .brand {
  display: flex;
  align-items: center;
  text-decoration: none;
  overflow: hidden;
  flex: 1;
}
.sidebar-head .brand,
.sidebar-head .sidebar-collapse { color: #fff; }
.sidebar-head .sidebar-collapse { border-color: rgba(255,255,255,.28); }
.sidebar-head .sidebar-collapse:hover { background: rgba(255,255,255,.14); color: #fff; }
.sidebar .brand-logo { flex-shrink: 0; height: 32px; width: auto; }

.sidebar-collapse {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.sidebar-collapse:hover { background: var(--hover-bg); color: var(--ink); }
.sidebar-collapse svg { transition: transform .16s ease; }

/* ── Search ──────────────────────────────────────────────────────────────── */

.sidebar-search {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 7px 8px;
  padding: 0 7px;
  height: 28px;
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--muted);
}
.sidebar-search:focus-within { border-color: var(--red); }
.sidebar-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  outline: none;
}
.sidebar-search kbd {
  font: inherit;
  font-size: 10px;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 1px 4px;
  white-space: nowrap;
}
/* The hint is for a keyboard, so it goes away when there is not one. */
@media (max-width: 900px) { .sidebar-search kbd { display: none; } }

/* ── Nav ─────────────────────────────────────────────────────────────────── */

.sidebar-nav { flex: 1; overflow-y: auto; overscroll-behavior: contain;
               padding: 2px 6px 8px; }

.nav-area + .nav-area { margin-top: 2px; }

.nav-area-head {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 5px 7px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  text-align: left;
}
.nav-area-head:hover { background: var(--hover-bg); }
.nav-area-dot {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 20px; height: 20px;
  border-radius: 5px;
  background: var(--hover-bg);
  color: var(--muted);
  font-size: 10px;   /* the letter fallback, for an area with no icon */
  font-weight: 700;
}
.nav-area-dot .nav-icon { display: block; }
.nav-area.open .nav-area-dot { background: var(--red); color: #fff; }
.nav-area-label { flex: 1; }
.nav-chevron { color: var(--muted); transition: transform .16s ease; }
.nav-area.open .nav-chevron { transform: rotate(180deg); }

.nav-area-body { display: none; padding: 1px 0 4px 7px; }
.nav-area.open .nav-area-body { display: block; }

.nav-group-label {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 8px 2px 11px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--muted);
}
.nav-group-label.accent { color: var(--red); }
.nav-live-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--red);
  animation: npw-pulse 2s ease-in-out infinite;
}
@keyframes npw-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .35 } }

.nav-link {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px 4px 11px;
  margin-left: 9px;
  border-left: 1px solid var(--line);
  color: var(--muted);
  text-decoration: none;
  font-size: 12.5px;
  line-height: 1.35;
  border-radius: 0 6px 6px 0;
}
.nav-link .nav-icon { flex-shrink: 0; opacity: .8; }
.nav-link.active .nav-icon, .nav-link:hover .nav-icon { opacity: 1; }
.nav-link-label { min-width: 0; }
/* "Beta"/"New" pill after a nav label — set via NavItem.badge. */
.nav-badge {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 6px 2px;
  border-radius: 8px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  vertical-align: 1px;
  background: var(--red, #C8102E);
  color: #fff;
}
html.sidebar-collapsed .nav-badge { display: none; }
.nav-link:hover { background: var(--hover-bg); color: var(--ink); }
.nav-link.active {
  color: var(--red);
  font-weight: 600;
  border-left-color: var(--red);
  background: var(--hover-bg);
}
.nav-empty { padding: 12px; color: var(--muted); font-size: 12.5px; }

/* ── Foot ────────────────────────────────────────────────────────────────── */

.sidebar-foot { border-top: 1px solid var(--line); padding: 8px; }

.sidebar-theme {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 6px 8px;
  margin-bottom: 6px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.sidebar-theme:hover { background: var(--hover-bg); color: var(--ink); }
.sidebar-theme .icon-sun { display: none; }
[data-theme="dark"] .sidebar-theme .icon-sun { display: block; }
[data-theme="dark"] .sidebar-theme .icon-moon { display: none; }
/* The label names the destination, like the icon: moon + "Dark Mode" in light
   mode, sun + "Light Mode" in dark. */
.sidebar-theme .mode-to-light { display: none; }
[data-theme="dark"] .sidebar-theme .mode-to-light { display: inline; }
[data-theme="dark"] .sidebar-theme .mode-to-dark { display: none; }

.user-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  outline-offset: 2px;
}
.user-card:hover { background: var(--hover-bg); }
.user-avatar {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}
.user-text { display: flex; flex-direction: column; min-width: 0; flex: 1; line-height: 1.25; }
.user-name { font-size: 12.5px; font-weight: 600; color: var(--ink); }
.user-email {
  font-size: 10.5px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-chevron { color: var(--muted); flex-shrink: 0; transition: transform .16s ease; }
.user-card.open .user-chevron { transform: rotate(180deg); }

/* Opens UPWARD — the card sits at the bottom of the viewport, so a menu
   dropping down would open off-screen. */
.user-menu {
  display: none;
  flex-direction: column;
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  min-width: 240px;
  padding: 5px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 9px;
  box-shadow: var(--shadow);
  z-index: 70;
}
.user-card.open .user-menu { display: flex; }
/* Wider than the sidebar on purpose — the labels carry a second line of
   explanation, and a 224px column would wrap every one of them. */
.user-menu { width: max(248px, 100%); }
html.sidebar-collapsed .user-menu { left: 0; width: 248px; }

.user-menu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 9px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.user-menu-item:hover { background: var(--hover-bg); }
.user-menu-item svg { flex-shrink: 0; color: var(--muted); }
.user-menu-item span { display: flex; flex-direction: column; line-height: 1.3;
                       min-width: 0; }
.user-menu-item strong, .user-menu-item small { white-space: nowrap; }
.user-menu-item strong { font-size: 13px; font-weight: 600; }
.user-menu-item small { font-size: 10.5px; color: var(--muted); }
.user-menu-signout { color: var(--red); }
.user-menu-signout svg { color: var(--red); }
.user-menu form { margin: 0; }

/* ── Settings shell ──────────────────────────────────────────────────────── */
/* The area tabs across the top of every Settings tab body. Underline tabs
   rather than pills so they read as a level ABOVE each screen's own pill row
   (Sales' six sections, Productivity's Administration | Targets). */

.settings-area-tabs {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 8px 24px 0;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.settings-area-caption {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--muted);
  margin-right: 14px;
  padding-bottom: 9px;
}
.settings-area-tab {
  padding: 6px 14px 9px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.settings-area-tab:hover { color: var(--ink); }
.settings-area-tab.active { color: var(--red); border-bottom-color: var(--red); }

/* ── Change-request floating action button ───────────────────────────────── */
/* The widget is `platform/_change_request.html`, included from platform/base.html
   for EVERY area — so this has to live here. It sat in the Sales stylesheet
   until 2026-08-09, which meant Purchasing, Pricing and Productivity rendered
   the button's markup with none of its rules: no `position: fixed`, so instead
   of floating over the page it landed unstyled at the bottom of the document,
   below the fold, where nobody found it. The modal it opens was already
   platform-owned (.modal-overlay/.modal-box/.stack/.form-row) — only the button
   was left behind, which is why the feature looked Sales-only rather than
   broken. */
.cr-fab {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 16px;
  border: none;
  border-radius: 999px;
  background: var(--accent, #DC2626);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .25);
  transition: transform .12s, box-shadow .12s;
}
.cr-fab:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0, 0, 0, .3); }
.cr-fab svg { flex-shrink: 0; }
@media (max-width: 640px) {
  .cr-fab span { display: none; }
  .cr-fab { padding: 13px; }
}

/* ── Topbar ──────────────────────────────────────────────────────────────── */
/* Thin, and mostly a home for the mobile hamburger. The nav moved to the side,
   so there is little left for it to do — an area puts a period picker or an
   export button in `topbar_right`. */

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: var(--topbar-h);
  padding: 0 16px;
  background: var(--navy, #0F1554);
  border-bottom: 2px solid var(--red);
  color: #fff;
}

/* The gear + GEARBOX wordmark — the old topbar's graphics, back on the
   topbar. The gate strokes in the gear pick up currentColor (white here). */
.topbar-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-shrink: 0;
  color: #fff;
}
.topbar-brand .gearbox-icon { width: 28px; height: 28px; }
.topbar-brand .brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.topbar-brand .brand-name { font-weight: 800; font-size: 15px; letter-spacing: 1.2px;
                            font-style: italic; }
.topbar-brand .brand-tag { font-size: 8.5px; letter-spacing: .8px;
                           text-transform: uppercase;
                           color: rgba(255,255,255,.72); white-space: nowrap; }
/* A quiet divider between the wordmark and the page's name. */
.topbar-brand::after {
  content: "";
  width: 1px;
  height: 22px;
  margin-left: 4px;
  background: rgba(255,255,255,.22);
}

.topbar-crumb { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.crumb-area {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: rgba(255,255,255,.6);
}
.crumb-area::after { content: "/"; margin-left: 7px; opacity: .5; }
.topbar-title {
  font-weight: 600;
  font-size: 14.5px;
  color: #fff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px;
                color: rgba(255,255,255,.85); }

/* Subscribe — lives on the navy band, so it dresses like the band. */
.btn-subscribe {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 12px;
  border: 1px solid rgba(255,255,255,.32);
  border-radius: 7px;
  background: transparent;
  color: #fff;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.btn-subscribe:hover { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.55); }

/* The panel action cluster — [excel] [pdf] [home+] [mail+] — one grammar for
   every panel in every area, injected by platform.js. Quiet until the panel
   is hovered: affordances, not headlines. */
.panel-actions {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  position: relative;
}
.panel-sub-btn {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px 7px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  text-decoration: none;
  opacity: .55;
}
.panel:hover .panel-sub-btn, .kpi-strip:hover .panel-sub-btn { opacity: 1; }
.panel-sub-btn:hover { color: var(--red); border-color: var(--red); background: var(--hover-bg); }
/* The ⋯ overflow: the same icons, one click away, when the head is tight. */
.panel-actions-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  display: flex;
  gap: 5px;
  padding: 6px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow) 0 6px 18px;
  z-index: 50;
}
.panel-actions-menu[hidden] { display: none; }
.panel-actions-menu .panel-sub-btn { opacity: 1; }
/* ── Report mode (?report=1) ──────────────────────────────────────────────────
   Chrome-free rendering for the report worker's Chromium capture and the
   homepage tiles' iframes. PLATFORM-owned: these selectors are all shell
   chrome, and while they lived in Sales' style.css every non-Sales tile
   rendered its full sidebar/topbar inside the iframe — the other areas never
   loaded the rules. Everything hidden here is navigation or a control that
   does nothing in a PNG or a tile; the filter bar deliberately STAYS, because
   it names the period the figures cover. */
.report-mode .sidebar,
.report-mode .sidebar-backdrop,
.report-mode .topbar,
.report-mode .impersonate-bar,
.report-mode .loading-overlay,
.report-mode .nav-toggle,
.report-mode .btn-export,
.report-mode .theme-toggle,
.report-mode .cr-fab,
.report-mode .modal-overlay,
.report-mode .panel-actions,
/* Period pills, year pickers and tab strips are all .slicer-row. They do
   nothing in a still, and the heading already names the period. The h1 and
   its subtitle live outside .slicer-row and stay. */
.report-mode .slicer-row,
/* The sales pages carry their controls in different wrappers than the
   warehouse pages, so hiding .slicer-row alone left period dropdowns, view
   toggles, month tabs and every per-panel "..." menu in the capture. Nothing
   clickable does anything in a still. Date-range chips are NOT controls and
   deliberately survive — they name the window the figures cover. */
.report-mode main.page-body button,
.report-mode main.page-body select,
.report-mode .filter-select,
.report-mode .filter-label,
.report-mode .tab-btn,
.report-mode .tbl-menu-btn,
.report-mode .seg-btn,
.report-mode a.btn-primary,
.report-mode a.btn-ghost { display: none !important; }

/* The topbar and sidebar are out, so the body clears neither. */
.report-mode .page-body { padding-top: 16px; }
.report-mode .app-body,
html.report-mode .app-body { margin-left: 0 !important; }

/* Screenshots are stills: hover/transition states can only render as a
   half-applied effect mid-capture. */
.report-mode * { transition: none !important; animation: none !important; }

/* Focus mode (?focus=…): one panel, edge to edge — homepage tiles render
   through this. The pin button is noise inside a tile. */
.focus-hidden { display: none !important; }
body.panel-focus .page-body { padding: 8px 10px; }
body.panel-focus .panel { margin: 0 !important; }
body.panel-focus .panel-sub-btn { display: none; }

/* ── My Homepage ─────────────────────────────────────────────────────────── */
/* The pinned-tiles grid. Tiles are same-origin iframes of the source pages in
   report+focus trim — genuinely LIVE, at the honest cost of a page render
   per tile (lazy-loaded, so below-the-fold tiles wait their turn). */
.home-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 16px;
  padding: 16px 24px 40px;
}
.home-tile { display: flex; flex-direction: column; min-height: 0;
             grid-column: span var(--tile-span, 6); }
.home-tile-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
}
.home-tile-title { font-weight: 700; font-size: 13.5px; min-width: 0;
                   overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-tile-title a { color: var(--ink); text-decoration: none; }
.home-tile-title a:hover { color: var(--red); }
.home-tile-actions { margin-left: auto; display: flex; gap: 4px; }
.home-tile iframe {
  width: 100%;
  height: var(--tile-h, 440px);   /* per-tile, persisted from Edit mode */
  border: 0;
  border-top: 1px solid var(--line);
  background: var(--bg);
}
/* Width IS the tile's column span (3–12 of the 12 tracks), dragged from the
   resize corner in Edit mode and snapped to whole tracks. Narrow screens
   ignore spans — every tile gets the full row, so a quarter-width tile can't
   shrink to a stamp. */
@media (max-width: 900px) {
  .home-grid { grid-template-columns: 1fr; }
  .home-tile { grid-column: 1 / -1; }
}
/* Rows size to their own tile, not the tallest neighbour. */
.home-grid { align-items: start; }
.home-empty { max-width: 560px; margin: 60px auto; text-align: center; }
.home-tile-range { font-family: ui-monospace, monospace; font-size: 10px; }
.home-range-chips .btn-ghost-sm { padding: 2px 7px; font-size: 10.5px; }
.home-range-chips .active-range { color: var(--red); border-color: var(--red); }
.home-editing .home-tile { cursor: grab; outline: 1px dashed var(--line); }
.home-editing .home-tile.dragging { opacity: .55; cursor: grabbing; }
/* Edit mode grows a native corner drag handle; the observer in home.html
   translates the dragged height into --tile-h and the dragged width into a
   snapped --tile-span, and persists both. */
.home-editing .home-tile { resize: both; overflow: hidden;
                           min-height: 220px; min-width: 200px; }
/* Iframes swallow the pointer mid-drag — a drag over one never reaches the
   grid's dragover, so without this tiles could only be dragged by their heads
   and dropped on the gaps between neighbours. */
.home-editing .home-tile iframe { pointer-events: none; }
@media (max-width: 700px) { .home-grid { padding: 12px; } }

/* The homepage entry pinned above the area tree. */
.nav-home {
  margin: 6px 2px 2px;
  border-left: 0;
  font-weight: 600;
  color: var(--ink);
}
/* Collapsed, it minimizes to its icon like every area head. It needs saying
   here because its label class is .nav-link-label — the link sits OUTSIDE
   the area tree, so none of the .nav-area-* collapse rules reach it. */
html.sidebar-collapsed .nav-home .nav-link-label { display: none; }
html.sidebar-collapsed .nav-home {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}

.nav-toggle {
  display: none;
  place-items: center;
  width: 34px; height: 34px;
  border: 1px solid rgba(255,255,255,.28);
  border-radius: 7px;
  background: transparent;
  color: #fff;
  cursor: pointer;
}

.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .45);
  z-index: 55;
}

/* ── Mobile ──────────────────────────────────────────────────────────────── */
/* An off-canvas drawer, not a hidden sidebar. Everything the sidebar does on a
   desktop it does here — areas, pages, search, theme, and the user card with
   both admin destinations. The warehouse and store managers who live in
   Productivity and Store Ops are on phones more than laptops, so a nav that
   quietly dropped half its entries below 900px would drop them for the people
   who use it most. */

@media (max-width: 900px) {
  .sidebar {
    transform: translateX(-100%);
    width: min(84vw, 300px);
    box-shadow: var(--shadow);
  }
  body.sidebar-open .sidebar { transform: none; }
  body.sidebar-open .sidebar-backdrop { display: block; }

  /* Collapsed is a desktop idea — there is no room for an icon rail on a
     phone, so the drawer always opens at full width regardless of the
     remembered desktop state. */
  html.sidebar-collapsed .sidebar { width: min(84vw, 300px); }
  html.sidebar-collapsed .sidebar-search,
  html.sidebar-collapsed .nav-area-label,
  html.sidebar-collapsed .nav-chevron,
  html.sidebar-collapsed .nav-group-label,
  html.sidebar-collapsed .sidebar-theme-label,
  html.sidebar-collapsed .user-text,
  html.sidebar-collapsed .user-chevron { display: revert; }
  html.sidebar-collapsed .sidebar-head .brand { display: flex; }
  html.sidebar-collapsed .sidebar-head { justify-content: flex-start; padding: 0 10px; }
  html.sidebar-collapsed .nav-area.open .nav-area-body { display: block; }
  html.sidebar-collapsed .nav-area-head,
  html.sidebar-collapsed .user-card { justify-content: flex-start; padding-left: 8px; padding-right: 8px; }

  .app-body, html.sidebar-collapsed .app-body { margin-left: 0; }
  .nav-toggle { display: grid; }
  .sidebar-collapse { display: none; }
}

/* On a phone the page's name matters more than repeating the wordmark beside
   it — the gear alone keeps the identity and the title keeps its room. */
@media (max-width: 560px) {
  .topbar-brand .brand-text { display: none; }
  .topbar-brand::after { display: none; }
}


/* ═══ Shared theme — hoisted from the four area stylesheets (2026-08-01).   Tokens + every component whose definition already agreed across all   four areas, plus the adjudicated winners for the ones that had   drifted (GEARBOX-MIGRATION.md §0b Job B). An area file may still   override any of this — it loads later — but a rule that lands here   is the definition, and the area copies are deleted. ═══ */

:root {
  --amber:     #b45309;
  --bg:        #F0F2F7;
  --blue:      #1d4ed8;
  --border:    var(--line);
  --danger:    #b91c1c;
  --green:     #15803d;
  --hover-bg:  #eef1fa;
  --ink:       #1a2036;
  --line:      #dde3ef;
  --muted:     #64748b;
  --navy:      #0F1554;
  --navy-d:    #0a0f3d;
  --panel:     #ffffff;
  --panel-alt: var(--panel-r);
  --panel-r:   #f7f8fc;
  --red:       #DC2626;
  --red-l:     #ef4444;
  --row-good:  #f0fdf4;
  --row-risk:  #fef2f2;
  --shadow:    rgba(0,0,0,0.08);
}

[data-theme="dark"] {
  --bg:        #0d1021;
  --border:    var(--line);
  --hover-bg:  #1e2440;
  --ink:       #e2e8f6;
  --line:      #252c45;
  --muted:     #8892aa;
  --panel:     #141828;
  --panel-alt: var(--panel-r);
  --panel-r:   #1a1f35;
  --row-good:  rgba(21,128,61,0.10);
  --row-risk:  rgba(185,28,28,0.12);
  --shadow:    rgba(0,0,0,0.35);
}

/* Gearbox brand icon — used by the sidebar brand and the auth card. */
.gearbox-icon { width: 30px; height: 30px; display: block; flex-shrink: 0; }
.gearbox-icon .gear-ring { transform-origin: 24px 24px; transition: transform 0.5s ease; }
.brand:hover .gearbox-icon .gear-ring { transform: rotate(45deg); }

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "Inter", "Segoe UI", ui-sans-serif, system-ui, -apple-system, sans-serif;
  font-size: 14px;
  line-height: 1.5;
}

a { color: inherit; text-decoration: none; }

h1, h2, h3 { margin: 0; font-weight: 700; }

h1 { font-size: 24px; }

h2 { font-size: 16px; }

h3 { font-size: 15px; }

p  { color: var(--muted); margin: 4px 0 0; }

.auth-brandmark {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 8px 0 2px;
  color: var(--ink);         /* shift-gate strokes pick this up */
}

.auth-brandmark .gearbox-icon { width: 34px; height: 34px; }

.auth-brandmark .auth-title {
  font-size: 22px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
}

.auth-tagline {
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  font-style: italic;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 26px;
}

.loading-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  background: rgba(15, 21, 84, 0.55);
  backdrop-filter: blur(2px);
}

.loading-overlay.active { display: flex; }

.gearset { position: relative; width: 104px; height: 78px; }

.gearset .gear { position: absolute; display: block; }

.gearset .gear-big {
  width: 64px; height: 64px;
  left: 0; top: 14px;
  animation: gear-spin 2.4s linear infinite;
}

.gearset .gear-small {
  width: 42px; height: 42px;
  left: 60px; top: 0;
  animation: gear-spin-rev 1.575s linear infinite; /* 42/64 of the big gear's period — meshed ratio */
}

@keyframes gear-spin     { to { transform: rotate(360deg); } }

@keyframes gear-spin-rev { from { transform: rotate(22.5deg); } to { transform: rotate(-337.5deg); } }

.loading-text {
  font-size: 12px;
  font-weight: 700;
  font-style: italic;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #fff;
}


.dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 16px;
  background: none;
  border: none;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
  transition: background 0.12s;
}

.dropdown-item:hover { background: var(--hover-bg); }

.dropdown-item svg { color: var(--muted); flex-shrink: 0; }

.dropdown-signout { color: var(--danger); }

.dropdown-signout svg { color: var(--danger); }

.page-body {
  padding: 0 0 40px;
}

.alert {
  padding: 12px 20px;
  margin: 12px 24px;
  border-radius: 8px;
  font-weight: 500;
  background: #dbeafe;
  color: #1e40af;
  border-left: 4px solid #3b82f6;
}

.alert.error {
  background: #fef2f2;
  color: var(--danger);
  border-left-color: var(--danger);
}

.alert.success {
  background: #f0fdf4;
  color: var(--green);
  border-left-color: var(--green);
}

.filter-form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}

.filter-group {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.filter-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.filter-select {
  height: 36px;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0 10px;
  background: var(--panel);
  color: var(--ink);
  font-size: 13px;
  min-width: 140px;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.filter-select:focus {
  border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(15,21,84,0.1);
}

input.filter-select { min-width: 120px; }

.hidden { display: none !important; }

.kpi-strip {
  display: flex;
  gap: 0;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  padding: 0 24px;
  overflow-x: auto;
}

.kpi-card:last-child { border-right: 0; }

.kpi-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin-bottom: 4px;
}

.kpi-value {
  font-size: 26px;
  font-weight: 800;
  line-height: 1.1;
  color: var(--ink);
}

.kpi-value.navy   { color: var(--navy); }

.kpi-value.red    { color: var(--danger); }

.kpi-value.green  { color: var(--green); }

.kpi-value.amber  { color: var(--amber); }

.kpi-sub {
  font-size: 11px;
  color: var(--muted);
  margin-top: 3px;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 18px;
}

.panel-head h2 { margin: 0; }

.panel-grid { display: grid; gap: 18px; }

.panel-grid.two { grid-template-columns: repeat(2, minmax(0,1fr)); }

table { width: 100%; border-collapse: collapse; }

td.num, th.num { text-align: right; }

td.bold { font-weight: 700; }

td.small, .small { font-size: 12px; }

td.empty { color: var(--muted); text-align: center; padding: 24px; font-style: italic; }

table.dense th,
table.dense td { padding: 7px 8px; font-size: 12px; }

.btn-primary {
  height: 36px;
  padding: 0 18px;
  background: var(--navy);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s;
  white-space: nowrap;
}

.btn-primary:hover { background: var(--navy-d); }

.btn-primary.btn-full { width: 100%; height: 42px; }

.btn-primary-sm {
  height: 28px;
  padding: 0 12px;
  background: var(--navy);
  color: #fff;
  border: none;
  border-radius: 5px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}

.btn-ghost-sm {
  height: 28px;
  padding: 0 10px;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 5px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.btn-danger-sm {
  height: 28px;
  padding: 0 10px;
  background: var(--row-risk);
  color: var(--danger);
  border: 1px solid rgba(185,28,28,0.25);
  border-radius: 5px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}

.btn-danger-sm:hover { background: #fee2e2; }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 700;
}

.badge-blue  { background: #dbeafe; color: #1e40af; }

.badge-red   { background: #fee2e2; color: var(--danger); }

.badge-green { background: #dcfce7; color: #166534; }

.badge-gray  { background: #f1f5f9; color: #475569; }

.auth-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 36px 32px;
  width: 100%;
  max-width: 400px;
  box-shadow: 0 4px 24px rgba(0,0,0,0.08);
}

.auth-logo {
  text-align: center;
  line-height: 1;
  margin-bottom: 6px;
}

.auth-logo-img {
  height: 52px;
  width: auto;
  object-fit: contain;
}

.auth-title {
  text-align: center;
  font-size: 16px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 28px;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

@keyframes modalIn {
  from { transform: translateY(-14px); opacity: 0; }
  to   { transform: translateY(0);     opacity: 1; }
}

.modal-icon-wrap { color: var(--amber); margin-bottom: 14px; }

.modal-title {
  font-size: 20px;
  font-weight: 800;
  color: var(--navy);
  margin: 0 0 10px;
}

.modal-body {
  font-size: 14px;
  color: var(--muted);
  line-height: 1.65;
  margin: 0 0 26px;
}

.modal-body strong { color: var(--ink); }

.modal-actions { display: flex; gap: 10px; justify-content: center; }

.modal-overlay[hidden] { display: none; }

.modal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 18px;
}

.modal-close {
  background: none;
  border: none;
  font-size: 18px;
  cursor: pointer;
  color: var(--muted);
  line-height: 1;
  padding: 0 4px;
}

.modal-close:hover { color: var(--ink); }

.impersonate-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 24px;
  background: #92400e;
  color: #fef3c7;
  font-size: 13px;
  font-weight: 500;
  border-bottom: 1px solid #b45309;
}

[data-theme="dark"] .impersonate-bar {
  background: #78350f;
  border-bottom-color: #92400e;
}

.impersonate-bar strong { color: #ffffff; }

.impersonate-stop {
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.35);
  color: #fef3c7;
  font-size: 12px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 5px;
  cursor: pointer;
  transition: background 0.15s;
}

.impersonate-stop:hover { background: rgba(255,255,255,0.25); }

.admin-page {
  max-width: 1300px;
  margin: 0 auto;
  padding: 20px 24px;
}

.page-title-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 18px;
}

.form-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}

.stack { display: flex; flex-direction: column; gap: 12px; }

.required { color: var(--red); }

/* ── Adjudicated: these had drifted per-area; one winner each. ── */

.filter-bar {
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  padding: 12px 24px;
}

.panel-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}

.kpi-card {
  flex: 1;
  min-width: 140px;
  padding: 16px 20px;
  border-right: 1px solid var(--line);
}

/* ── Frozen panes ────────────────────────────────────────────────────────── */
/* `th` below has carried `position: sticky; top: 0` for a long time and it did
   NOTHING, which is worth writing down before somebody deletes the fix as
   redundant.
   `overflow-x: auto` makes overflow-y compute to `auto` as well, so .table-wrap
   — not the page — is the sticky header's scrollport. With no bound on its
   height that scrollport never scrolls vertically, so the header sat perfectly
   still relative to a box that only ever moved with the page, and rode off the
   top along with it.
   Bounding the height is what gives the header something to stick to. A table
   shorter than the bound is untouched: no inner scrollbar, full height, looks
   exactly as it did. A table taller than the viewport could never be read whole
   anyway, and is precisely the case a frozen header exists for. */
.table-wrap {
  overflow: auto;
  max-height: calc(100vh - var(--topbar-h) - 88px);
}

th, td { padding: 10px 10px; border-bottom: 1px solid var(--line); text-align: left; }

th {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  /* Opaque, and load-bearing: body rows scroll visibly THROUGH a translucent
     sticky header. */
  background: var(--panel-r);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 3;
}

/* The identity column, frozen against a sideways scroll — opt-in with
   `class="table-wrap freeze-col"`, because on a table whose first column is a
   24px drill toggle freezing it would pin the +/- button and let the name it
   belongs to scroll away. `freeze-col-2` freezes the toggle AND the name.
   The opaque base sits on the ROW, and the frozen cell inherits it, so a page's
   own row tint (.row-total, .pnl-group-row, .ops-computed, …) still paints over
   the top instead of being erased by an opaque cell background. `:where()`
   contributes no specificity, which is what keeps those page rules winning. */
.table-wrap.freeze-col tbody tr,
.table-wrap.freeze-col-2 tbody tr { background-color: var(--panel); }

:where(.table-wrap.freeze-col) tbody td:first-child,
:where(.table-wrap.freeze-col-2) tbody td:nth-child(-n + 2) {
  position: sticky;
  z-index: 2;
  background-color: inherit;
}
:where(.table-wrap.freeze-col) thead th:first-child,
:where(.table-wrap.freeze-col-2) thead th:nth-child(-n + 2) {
  position: sticky;
  z-index: 4;                      /* over the sticky header AND the frozen column */
}
:where(.table-wrap.freeze-col) tbody td:first-child,
:where(.table-wrap.freeze-col) thead th:first-child,
:where(.table-wrap.freeze-col-2) tbody td:first-child,
:where(.table-wrap.freeze-col-2) thead th:first-child { left: 0; }
/* The toggle cell is 24px wide, so the name column pins just past it. */
:where(.table-wrap.freeze-col-2) tbody td:nth-child(2),
:where(.table-wrap.freeze-col-2) thead th:nth-child(2) { left: 24px; }

/* Two-row headers (`table.col-groups`, in style.css) set their own
   `z-index: 1` at a specificity this file's `th` rule cannot reach, so on the
   CSR and Inside Sales grids the frozen column (z-index 2) would paint OVER the
   sticky header where the two cross. Restated here, above both. */
.table-wrap.freeze-col table.col-groups thead th,
.table-wrap.freeze-col-2 table.col-groups thead th { z-index: 3; }
.table-wrap.freeze-col table.col-groups thead th:first-child,
.table-wrap.freeze-col-2 table.col-groups thead th:nth-child(-n + 2) { z-index: 4; }

/* A capture is a still of the WHOLE table — an inner scrollport would crop it
   to one viewport and mail out a table with its bottom cut off. Same for print.
   Only the HEIGHT bound is lifted: `overflow-x: auto` stays, because the
   worker's auto-fit measures `scrollWidth - clientWidth` on `.table-wrap` to
   decide how wide to re-render, and a wrap set to `overflow: visible` reports no
   horizontal overflow — the widening would stop happening and wide tables would
   go back to being silently cut off in the mail. (overflow-y: visible beside
   overflow-x: auto computes back to auto, which is the pre-frozen-panes
   behaviour exactly: a scrollport with no height bound never scrolls.) */
.report-mode .table-wrap,
html.report-mode .table-wrap { max-height: none; overflow-y: visible; }
.report-mode th,
html.report-mode th { position: static; }

@media print {
  .table-wrap { max-height: none; overflow-y: visible; }
  th { position: static; }
}

.btn-export {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 14px;
  height: 34px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  font-size: 13px;
  font-weight: 700;
  color: var(--navy);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s;
}

.btn-export:hover { background: var(--hover-bg); border-color: var(--navy); }

.muted     { color: var(--muted); }

.row-actions { display: flex; gap: 6px; flex-wrap: wrap; }
/* One straight rank of buttons — for wide tables (Users) where the 2x2
   bunching read as clutter. The cell grows; the table already scrolls. */
.row-actions.nowrap { flex-wrap: nowrap; }
.row-actions.nowrap .btn-ghost-sm,
.row-actions.nowrap .btn-danger-sm { white-space: nowrap; }

.btn-ghost {
  height: 36px;
  padding: 0 16px;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  transition: background 0.15s;
}

.btn-ghost:hover { background: var(--hover-bg); }

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 900;
  background: rgba(15,21,84,0.50);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-card {
  background: var(--panel);
  border-radius: 14px;
  padding: 40px 44px 36px;
  width: 380px;
  max-width: 92vw;
  text-align: center;
  box-shadow: 0 24px 64px rgba(0,0,0,0.22);
  animation: modalIn 0.18s ease;
}

.modal-box {
  background: var(--panel);
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.25);
  padding: 24px;
  width: 420px;
  max-width: 95vw;
  max-height: 92vh;              /* tall modals scroll inside themselves… */
  overflow-y: auto;
  overscroll-behavior: contain;  /* …without scrolling the page behind */
}

.auth-wrap {
  /* Signed out there is no topbar at all; signed in (change-password) the
     shell's is var(--topbar-h). Clearing the taller case centers both. */
  min-height: calc(100vh - var(--topbar-h));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
}

