/*
 * Fonts, served from this computer.
 *
 * This file used to open with an @import to fonts.googleapis.com. A CSS
 * @import at the top of a stylesheet is RENDER-BLOCKING: the browser will
 * not paint until it resolves. On a shop PC that is offline, behind a
 * captive portal, or on slow DNS -- which is any shop during an ISP
 * outage -- every single page stalled waiting for a font server, and the
 * app is supposed to keep selling through exactly that.
 *
 * Latin subsets only, 251 KB for all nine faces, loaded from static/fonts.
 * font-display: swap so text is readable immediately either way.
 */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/IBMPlexMono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/IBMPlexMono-500.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/IBMPlexMono-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/Inter-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/Inter-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/Inter-600.woff2') format('woff2');
}
/* Chakra Petch carries only the wordmark. It is the brand face of the
   other 3E apps (the same three files ship in 3E Vault), so the "3E" in
   the corner reads as one family of programs; body text stays Inter. */
@font-face {
  font-family: 'Chakra Petch';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ChakraPetch-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Chakra Petch';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/ChakraPetch-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Chakra Petch';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/ChakraPetch-700.woff2') format('woff2');
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/SpaceGrotesk-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/SpaceGrotesk-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/SpaceGrotesk-700.woff2') format('woff2');
}
:root {
  --bg: #000000;
  --bg-raised: #141414;
  --bg-inset: #0A0A0A;
  --border: #3A3A3A;
  --text: #FFFFFF;
  --text-dim: #D0D0D0;
  --text-faint: #8C8C8C;
  --brass: #E00000;
  --brass-dim: #990000;
  --rust: #FF3B30;
  --rust-bg: #2E0000;
  --moss: #3FBF6B;
  --moss-bg: #0B2414;
  --rust-text: #FFFFFF;
  --moss-text: #BFF0CF;
  --brass-hover: #FF1A1A;
  --on-brass: #FFFFFF;
  --radius: 3px;
  --font-display: 'Space Grotesk', sans-serif;
  --font-body: 'Inter', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
}

a { color: var(--brass); text-decoration: none; }
a:hover { text-decoration: underline; }

.layout { display: flex; min-height: 100vh; }

/* Sidebar */
.sidebar {
  width: 220px;
  background: var(--bg-inset);
  border-right: 1px solid var(--border);
  padding: 24px 0;
  flex-shrink: 0;
  align-self: flex-start;
  position: sticky;
  top: 0;
  /* Above the page (2.46.0). A sticky element is its own stacking
     layer, so the rail's hover menus could rise no higher than the
     rail itself -- and the order sheets' sticky headers (z 30) and
     totals bars painted right over them. The rail now sits above
     everything in the page; only the Ctrl+K overlay and the
     confirmation toasts go over it. */
  z-index: 150;
  height: 100vh;
  overflow-y: auto;
  /* Explicit, not left to default: setting only overflow-y to a
     non-visible value makes the browser compute overflow-x as auto
     too, per the CSS overflow spec, even though this was never asked
     for. That silently turned the sidebar horizontally scrollable, and
     when the (now-removed) flyout widened the sidebar's own content
     box, the visible scroll position shifted sideways and took the
     whole nav rail out of view. */
  overflow-x: hidden;
}
.sidebar-brand {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 0.02em;
  color: var(--text);
  padding: 0 20px 20px 20px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 12px;
}
/* The wordmark is the shop's own logo artwork. Both versions are in
   the markup; theme.css shows the one whose lettering survives the
   active background (white ERP on dark themes, black ERP on light).
   Hidden by default so a page with no theme.css shows one logo, not
   two stacked. */
.brand-logo { display: none; width: 100%; max-width: 180px; height: auto; }
/* The emblem in the theme's own colours (2.46.0): two masks cut from the
   artwork, filled with --logo-accent ("3E" and the stripes) and
   --logo-text ("ERP"). */
.brand-emblem { position: relative; width: 100%; max-width: 180px; aspect-ratio: 480 / 107; }
.brand-emblem span {
  position: absolute; inset: 0;
  -webkit-mask: var(--mask) center / contain no-repeat;
          mask: var(--mask) center / contain no-repeat;
}
.brand-emblem .emblem-accent { background: var(--logo-accent); }
.brand-emblem .emblem-text { background: var(--logo-text); }

/* Every dialog in the theme's colours. Only three were styled, so the
   rest -- the split payment dialog among them -- came up browser-white
   on every theme. */
dialog {
  background: var(--bg-raised); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
}
dialog::backdrop { background: rgba(0,0,0,0.5); }

/* Form controls nobody styled get the theme too. Zero specificity
   (:where), so every existing rule still wins. */
:where(input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=color]):not([type=submit]):not([type=button]), select, textarea) {
  background: var(--bg-inset); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.brand-logo-on-dark { display: block; }
.sidebar nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  color: var(--text-dim);
  font-weight: 500;
  font-size: 13.5px;
  text-decoration: none;
  border-left: 3px solid transparent;
}
.sidebar nav a:hover { color: var(--text); background: var(--bg-raised); }
.sidebar nav a.active {
  color: var(--brass);
  border-left-color: var(--brass);
  background: var(--bg-raised);
}
.sidebar nav .icon { font-family: var(--font-mono); font-size: 13px; opacity: 0.8; }
.nav-badge {
  margin-left: auto;
  background: var(--rust-bg);
  color: var(--rust-text);
  border: 1px solid color-mix(in srgb, var(--rust) 40%, transparent);
  border-radius: 99px;
  font-size: 11px;
  font-weight: 600;
  padding: 0 7px;
  line-height: 1.6;
}

/* ---- the rail: headings that open a menu beside them ----------------
   Everyday pages sit on the rail. The rest live under three headings,
   and hovering (mouse) or tapping (tablet) one opens its menu to the
   right. The group heading is a <button>, not a link: it goes nowhere
   on its own, and a keyboard should treat it as the control it is. */
.sidebar nav.rail { display: flex; flex-direction: column; }
.rail-heading {
  padding: 14px 20px 6px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.rail-divider { height: 1px; background: var(--border); margin: 10px 20px; }

/* The heading and the links must look identical -- same padding, same
   left rule -- or the rail reads as two different lists. */
.sidebar nav .rail-group-head {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 20px; background: none; border: none;
  border-left: 3px solid transparent;
  color: var(--text-dim); font-family: var(--font-body);
  font-weight: 500; font-size: 13.5px; text-align: left; cursor: pointer;
}
/* An open menu keeps its heading lit while the modal it opened is showing. */
.sidebar nav .rail-group-head:hover,
.rail-group-head.menu-open { color: var(--text); background: var(--bg-raised); }
.sidebar nav .rail-group-head.active,
.rail-group-head.menu-open.active {
  color: var(--brass); border-left-color: var(--brass); background: var(--bg-raised);
}
.rail-arrow { margin-left: auto; opacity: 0.55; font-size: 15px; line-height: 1; }

/* The menu that opens beside its heading.
 *
 * position: FIXED, not absolute, and this is the whole reason the menu
 * was a centred dialog for a while. The sidebar scrolls
 * (overflow-y: auto), and per the CSS overflow spec a box that scrolls
 * on one axis clips on the other too -- so a menu positioned inside it
 * was cut off at the rail's edge, and a wide one could scroll the whole
 * rail sideways. Fixed is measured against the viewport instead, so no
 * ancestor's overflow can touch it. nav_rail.js sets top/left when it
 * opens, because fixed coordinates cannot be written in advance.
 *
 * Nothing above .rail-group may carry a transform, filter, contain or
 * will-change: any of those would make fixed behave like absolute again
 * and bring the clipping straight back.
 */
.rail-flyout {
  position: fixed; z-index: 200;
  min-width: 216px; max-width: min(320px, calc(100vw - 24px));
  max-height: calc(100vh - 24px); overflow-y: auto;
  padding: 6px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.rail-flyout[hidden] { display: none; }
.rail-flyout-title {
  padding: 4px 10px 8px; font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint);
}
.rail-flyout-row { display: flex; align-items: center; border-radius: 4px; }
.rail-flyout-row:hover { background: var(--bg-inset); }
.sidebar nav .rail-flyout-row a,
.rail-flyout-row a {
  flex: 1; padding: 8px 10px; border-left: none; font-size: 13px;
  color: var(--text); text-decoration: none;
}
.rail-flyout-row a:hover { background: none; }
.rail-flyout-row.active a { color: var(--brass); font-weight: 600; }
.rail-flyout-row form { margin: 0; }

/* The star. Faint until it is earned, brass once it is -- and it keeps
   its own hit area so a thumb aiming at the link never toggles it. */
.rail-star {
  background: none; border: none; cursor: pointer; padding: 6px 9px;
  font-size: 14px; line-height: 1; color: var(--text-faint);
}
.rail-star:hover { color: var(--brass); }
.rail-star.on { color: var(--brass); }

/* Main content. min-width: 0 matters: a flex child defaults to
   min-width auto, so one wide table would otherwise push the whole
   column wider than the window instead of scrolling inside its card. */
/* Centred once the window outgrows the content. The 1280px cap is
   there so a line of text never runs the width of an ultrawide monitor,
   but left-aligning what is left put the whole register against one
   edge with a field of empty beside it. margin auto splits the leftover
   space instead. It does nothing at ordinary widths, where there is no
   leftover space to split. */
.main {
  flex: 1;
  min-width: 0;
  padding: 28px 36px 60px 36px;
  max-width: 1280px;
  margin: 0 auto;
}

.page-header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 22px; flex-wrap: wrap; gap: 10px; }
.page-header h1 { font-family: var(--font-display); font-size: 22px; font-weight: 700; margin: 0; }
.page-sub { color: var(--text-dim); font-size: 13px; margin-top: 4px; }

/* Signature: stenciled alert banner */
.stencil-alert {
  border-left: 4px solid var(--alert-edge, var(--rust));
  background: var(--alert-bg, var(--rust-bg));
  color: var(--alert-text, var(--text));
  padding: 14px 18px;
  margin-bottom: 24px;
  border-radius: 0 var(--radius) var(--radius) 0;
}
.stencil-alert .stencil-title {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 13px;
  color: var(--alert-title, var(--rust-text));
  margin-bottom: 6px;
}
.stencil-alert ul { margin: 8px 0 0 0; padding: 0; list-style: none; }
.stencil-alert li {
  display: flex;
  justify-content: space-between;
  padding: 5px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--text) 6%, transparent);
  font-size: 13.5px;
}
.stencil-alert li:last-child { border-bottom: none; }
.stencil-alert .qty-badge {
  font-family: var(--font-mono);
  background: color-mix(in srgb, var(--alert-edge, var(--rust)) 25%, transparent);
  color: var(--alert-title, var(--rust-text));
  padding: 1px 8px;
  border-radius: var(--radius);
  font-size: 12px;
}
.stencil-alert.clear {
  border-left-color: var(--moss);
  background: var(--moss-bg);
}
.stencil-alert.clear .stencil-title { color: var(--moss-text); }

/* Cards / stat row */
.stat-row { display: flex; gap: 14px; margin-bottom: 24px; flex-wrap: wrap; }
.stat-card {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 18px;
  min-width: 140px;
}
.stat-card .num { font-family: var(--font-mono); font-size: 24px; font-weight: 600; color: var(--brass); }
.stat-card .label { font-size: 12px; color: var(--text-dim); margin-top: 2px; }

/* Tables. overflow-x is auto, not hidden: a cart table that outgrows a
   tablet must scroll sideways inside its card, because clipping it
   amputates whichever column is rightmost -- which is the Update/Remove
   buttons on checkout and the qty input on a return. */
.table-wrap { background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; -webkit-overflow-scrolling: touch; }
.bulk-action-bar {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  background: var(--bg-inset); border-bottom: 1px solid var(--border);
}
.bulk-action-bar[hidden] { display: none; }
.bulk-action-bar #bulk-count { font-size: 13px; color: var(--text-dim); margin-right: auto; }
table { width: 100%; border-collapse: collapse; }
th {
  text-align: left;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-faint);
  font-weight: 600;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-inset);
}
td { padding: 10px 14px; border-bottom: 1px solid var(--border); font-size: 13.5px; vertical-align: middle; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: color-mix(in srgb, var(--brass) 5%, transparent); }
.mono { font-family: var(--font-mono); }
.num-cell { font-family: var(--font-mono); text-align: right; }
.low-stock-row td { background: color-mix(in srgb, var(--rust) 8%, transparent); }

/* A count that just moved because of something done elsewhere. Brief and
   quiet: enough to catch the eye of someone already looking at the number,
   not enough to pull attention off whatever they were actually doing. */
.stock-just-changed { animation: stock-changed-flash 1.4s ease-out; }
@keyframes stock-changed-flash {
  0%   { color: var(--brass); font-weight: 700; }
  100% { color: inherit; }
}
@media (prefers-reduced-motion: reduce) {
  .stock-just-changed { animation: none; color: var(--brass); }
}

.tag { display: inline-block; padding: 2px 8px; border-radius: var(--radius); font-size: 11px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; }
.tag-firearm { background: color-mix(in srgb, var(--brass) 18%, transparent); color: var(--brass); }
.tag-ammo { background: color-mix(in srgb, var(--moss) 18%, transparent); color: var(--moss); }
.tag-needs-serial { background: color-mix(in srgb, var(--rust) 20%, transparent); color: var(--rust-text); }
.tag-instock { background: color-mix(in srgb, var(--moss) 18%, transparent); color: var(--moss); }
.tag-sold { background: color-mix(in srgb, var(--text-faint) 25%, transparent); color: var(--text-dim); }

/* Forms */
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; max-width: 720px; }
.form-grid.full { grid-template-columns: 1fr; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field.span-2 { grid-column: span 2; }
.field label { font-size: 12px; color: var(--text-dim); font-weight: 500; }
.field input, .field select, .field textarea {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 8px 10px;
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: 13.5px;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--brass);
}
.field.mono-field input { font-family: var(--font-mono); }
/* The same look for inputs outside a .field (inline forms, 2.45.0). */
.plain-inputs input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=range]):not([type=file]),
.plain-inputs select {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 9px;
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: 13.5px;
}
.plain-inputs input:focus, .plain-inputs select:focus { outline: none; border-color: var(--brass); }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid transparent;
  font-family: var(--font-body);
}
.btn-primary { background: var(--brass); color: var(--on-brass); }
.btn-primary:hover { background: var(--brass-hover); text-decoration: none; }
.btn-outline { background: transparent; border-color: var(--border); color: var(--text); }
.btn-outline:hover { border-color: var(--brass); color: var(--brass); text-decoration: none; }
.btn-danger { background: transparent; border-color: var(--rust); color: var(--rust); }
.btn-danger:hover { background: var(--rust); color: #fff; text-decoration: none; }
.btn-sm { padding: 5px 11px; font-size: 12px; }

.toolbar { display: flex; gap: 10px; margin-bottom: 18px; align-items: center; flex-wrap: wrap; }
.search-input {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 8px 12px;
  border-radius: var(--radius);
  font-size: 13.5px;
  min-width: 240px;
  flex: 1;
}
.filter-pills { display: flex; gap: 6px; flex-wrap: wrap; }
.filter-pill {
  padding: 6px 14px;
  border-radius: 14px;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 12.5px;
  cursor: pointer;
  background: transparent;
}
.filter-pill.active { border-color: var(--brass); color: var(--brass); background: color-mix(in srgb, var(--brass) 10%, transparent); }

.section-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15px;
  margin: 28px 0 12px 0;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

.empty-state { padding: 40px 20px; text-align: center; color: var(--text-dim); }
.empty-state .big { font-family: var(--font-display); font-size: 16px; color: var(--text); margin-bottom: 6px; }

/* Flash toasts. Fixed at the bottom corner so a confirmation never
   pushes the page down -- the button someone was reaching for used to
   jump exactly as they pressed it. */
.flash-stack {
  position: fixed;
  bottom: 18px;
  right: 18px;
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: min(480px, calc(100vw - 36px));
}
.flash {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px 10px 16px;
  border-radius: var(--radius);
  font-size: 13.5px;
  box-shadow: 0 10px 28px rgba(0,0,0,0.4);
}
.flash-text { overflow-wrap: anywhere; }
.flash-close {
  flex: none;
  margin-left: auto;
  background: none;
  border: 0;
  color: inherit;
  font-size: 17px;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
  opacity: 0.7;
}
.flash-close:hover { opacity: 1; }
.flash-close:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.flash-leaving { opacity: 0; transform: translateY(6px); transition: opacity 0.25s, transform 0.25s; }
@media (prefers-reduced-motion: reduce) { .flash-leaving { transition: none; } }
.flash-success { background: var(--moss-bg); color: var(--moss-text); border: 1px solid color-mix(in srgb, var(--moss) 30%, transparent); }
.flash-error { background: var(--rust-bg); color: var(--rust-text); border: 1px solid color-mix(in srgb, var(--rust) 30%, transparent); }

.breadcrumb { font-size: 12.5px; color: var(--text-faint); margin-bottom: 10px; }
.breadcrumb a { color: var(--text-dim); }

.compliance-note {
  font-size: 12px;
  color: var(--text-faint);
  border-top: 1px solid var(--border);
  margin-top: 20px;
  padding-top: 14px;
  line-height: 1.6;
}

/* Function search (command palette) */
/* A search bar, and only as tall as one. Everything in it is held to a
   single line: the label wrapping was what made this the tallest thing
   in the sidebar, and a shortcut cue that breaks across two lines stops
   reading as a key combination at all. */
.fs-trigger {
  margin: 0 20px 14px 20px;
  padding: 5px 10px;
  line-height: 1.5;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-dim);
  font-size: 12.5px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  overflow: hidden;
}
.fs-trigger:hover { border-color: var(--brass); color: var(--text); }
.fs-trigger:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
.fs-glyph { font-family: var(--font-mono); font-size: 13px; line-height: 1; opacity: 0.75; }
.fs-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fs-trigger kbd {
  font-family: var(--font-mono);
  font-size: 10px;
  background: var(--bg-inset);
  padding: 2px 5px;
  border-radius: 3px;
  border: 1px solid var(--border);
  white-space: nowrap;
  flex-shrink: 0;
}
#function-search-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.55);
  z-index: 400;
  align-items: flex-start;
  justify-content: center;
  padding: 12vh 16px 0;
}
.fs-palette {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 6px;
  width: 100%;
  max-width: 480px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
  overflow: hidden;
}
.fs-palette input {
  width: 100%;
  padding: 14px 16px;
  background: var(--bg-inset);
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-size: 15px;
  font-family: var(--font-body);
}
.fs-palette input:focus { outline: none; }
.fs-palette ul { list-style: none; margin: 0; padding: 6px; max-height: 320px; overflow-y: auto; }
.fs-result { padding: 10px 12px; border-radius: 4px; cursor: pointer; font-size: 13.5px; }
.fs-result:hover, .fs-result.fs-selected { background: color-mix(in srgb, var(--brass) 15%, transparent); color: var(--brass); }

/* Dashboard alert resolution menu */
.alert-list { list-style: none; margin: 0; padding: 0; }
.alert-row { display: flex; justify-content: space-between; align-items: center; padding: 6px 0; flex-wrap: wrap; gap: 4px 10px; }
.alert-menu-wrap { position: relative; }
.alert-menu {
  display: none; position: absolute; right: 0; top: 100%; margin-top: 4px;
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: 6px;
  min-width: 220px; z-index: 20; padding: 6px; box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.alert-menu.open { display: block; }
.alert-menu a, .alert-menu button, .alert-menu select {
  display: block; width: 100%; text-align: left; padding: 8px 10px; border-radius: 4px;
  background: none; border: none; color: var(--text); font-size: 13px; cursor: pointer;
  font-family: var(--font-body);
}
.alert-menu a:hover, .alert-menu button:hover { background: var(--bg-inset); }
.alert-menu form { margin: 0; }

/* Themes: the ones you can pick, and the editor that makes new ones. */
.theme-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.saved-theme {
  display: flex;
  align-items: center;
  gap: 4px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 3px 4px 3px 8px;
  background: var(--bg-inset);
}
/* A row of the actual colors, so a saved theme is recognisable at a
   glance rather than being a name you have to remember the look of. */
.theme-chips { display: inline-flex; gap: 2px; margin-right: 4px; }
.theme-chips i {
  width: 11px;
  height: 15px;
  border-radius: 2px;
  border: 1px solid rgba(0,0,0,0.35);
}

.color-editor {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0 16px;
  margin: 22px 0 8px;
  background: var(--bg-inset);
}
.color-editor > summary {
  cursor: pointer;
  padding: 13px 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-dim);
  list-style: none;
}
.color-editor > summary::-webkit-details-marker { display: none; }
.color-editor > summary::before { content: '▸ '; color: var(--brass); }
.color-editor[open] > summary::before { content: '▾ '; }
.color-editor > summary:hover { color: var(--text); }
.color-editor[open] { padding-bottom: 18px; }

/* Tabs, currently used to break Settings into readable pieces.
   Eighteen sections in one scroll meant hunting for the tax rate past
   the whole theme editor. */
.tabs {
  display: flex;
  align-items: stretch;
  gap: 2px;
  overflow-x: auto;
  border-bottom: 1px solid var(--border);
  margin: 0 0 24px;
  scrollbar-width: thin;
}
/* Two rows of tabs: the store's on top, the server's below. The stack
   owns the bottom rule and the margin; each row keeps a hairline so the
   rows read as rows, not one wrapped jumble. */
.tabs-stack { margin: 0 0 24px; border-bottom: 1px solid var(--border); }
.tabs-stack .tabs { margin: 0; border-bottom: none; }
.tabs-stack .tabs + .tabs { border-top: 1px solid var(--bg-raised); }
.tabs-stack .tab-strip-label { border-left: none; padding-left: 2px; min-width: 52px; }
.tabs-gap { flex: 1 1 auto; min-width: 12px; }
/* Group headings inside the strip: the store's settings, then the
   server's. Labels, not buttons -- they cannot take focus or a click. */
.tab-strip-label {
  flex: 0 0 auto;
  align-self: center;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text-faint);
  padding: 0 8px 0 12px;
  border-left: 1px solid var(--border);
  pointer-events: none;
}
.tab-strip-label:first-child { border-left: none; padding-left: 2px; }
.tab {
  flex: 0 0 auto;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 500;
  padding: 10px 14px;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  display: flex;
  align-items: center;
}
.tab:hover { color: var(--text); background: var(--bg-raised); }
.tab.is-active {
  color: var(--brass);
  border-bottom-color: var(--brass);
}
.tab:focus-visible { outline: 2px solid var(--brass); outline-offset: -2px; }
/* These two leave the page rather than switching a panel, so they say so
   and never take the selected look. */
.tab-link { color: var(--text-faint); }
.tab-link:hover { color: var(--brass); }

/* Panels are all visible until the script says otherwise, so the page is
   still entirely usable if the JS has not run or is switched off. */
[data-tabs="on"] .tab-panel { display: none; }
[data-tabs="on"] .tab-panel.is-open { display: block; }

/* Tablet and narrow screens.
   The menu becomes a strip across the top, not a stacked list. Stacked,
   fourteen nav items are about 560px of menu before the page begins --
   so a clerk on a counter tablet opened Checkout and had to scroll past
   the entire menu to reach the scan box, on every single sale. */
@media (max-width: 800px) {
  .layout { flex-direction: column; }
  /* Full width, never wider: with margin:auto in a column, the main area
     shrank to fit its widest table and pushed the page off a phone (2.53.0). */
  .main { width: 100%; box-sizing: border-box; }
  .sidebar {
    width: 100%;
    padding: 10px 0 0;
    border-right: none;
    border-bottom: 1px solid var(--border);
    position: sticky;      /* stays reachable once the page scrolls */
    top: 0;
    z-index: 150;
    background: var(--bg-inset);
  }
  .sidebar-brand {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    padding-bottom: 8px;
  }
  /* Everything onto one line. The version number is for whoever is
     setting the thing up, not for someone mid-sale, so it goes; the name
     and who is signed in stay. */
  .sidebar-brand br { display: none; }
  .brand-logo, .brand-emblem { max-width: 128px; }
  .sidebar-brand .mono { display: none; }

  .sidebar nav.rail {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 2px;
    padding: 0 12px 6px;
  }
  .sidebar nav .rail-group-head {
    width: auto; padding: 10px 14px; white-space: nowrap;
    border-left: none; border-bottom: 3px solid transparent;
  }
  .sidebar nav .rail-group-head.active {
    border-left-color: transparent; border-bottom-color: var(--brass);
  }
  .rail-divider { display: none; }
  .rail-heading { padding: 10px 6px 10px 12px; align-self: center; }
  .sidebar nav a {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 10px 14px;
    border-left: none;
    border-bottom: 3px solid transparent;
  }
  .sidebar nav a.active {
    border-left-color: transparent;
    border-bottom-color: var(--brass);
  }
  .fs-trigger { margin: 0 12px 10px; }

  .form-grid { grid-template-columns: 1fr; }
  .field.span-2 { grid-column: span 1; }
  .main { padding: 20px 16px 60px; }
  .search-input { min-width: 0; }
}

/* Phone-width, or a window snapped very small. Nothing new happens here
   beyond giving the content back the margins: everything that can wrap
   or scroll already does by this point. */
@media (max-width: 480px) {
  .rail-heading { display: none; }
  .main { padding: 16px 10px 48px; }
  .stat-card { flex: 1 1 40%; min-width: 110px; }
}

/* Folder picker for the backup destination. Browsing the STORE computer,
   not the tablet this page happens to be open on. */
#folder-picker {
  border: 1px solid var(--border);
  background: var(--bg-inset);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-top: 10px;
  max-width: 620px;
}
.picker-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.picker-shortcuts { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.picker-path {
  font-size: 12px;
  color: var(--text-dim);
  padding: 6px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 2px;
  word-break: break-all;
}
.picker-note { font-size: 12px; color: var(--text-faint); min-height: 16px; padding: 4px 0; }
.picker-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--bg);
}
.picker-row {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  /* Comfortably tappable -- this gets used standing up, on a tablet. */
  padding: 9px 12px;
  cursor: pointer;
}
.picker-row:last-child { border-bottom: 0; }
.picker-row:hover { background: var(--bg-raised); color: var(--brass); }
.picker-row:focus-visible { outline: 2px solid var(--brass); outline-offset: -2px; }
.picker-row::before { content: '📁  '; }
.picker-up::before { content: ''; }
.picker-foot { display: flex; align-items: center; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
.picker-writable { font-size: 12.5px; }
.picker-writable.ok { color: var(--moss); }
.picker-writable.bad { color: var(--rust); }
.picker-note.bad { color: var(--rust); }

/* Full restore browser. Recent snapshots stay inline; older ones open in a
   modal so recovery work can browse the whole folder without stretching
   the page. */
.restore-browser-callout {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  flex-wrap: wrap;
  max-width: 760px;
  padding: 14px 16px;
  margin-top: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-inset);
}
.restore-browser-label {
  font-size: 11px;
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-dim);
}
.restore-browser-path {
  margin-top: 4px;
  display: block;
  overflow-wrap: anywhere;
}
#restore-browser-modal {
  background: var(--bg-raised);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 20px;
  max-width: 780px;
  width: min(94vw, 780px);
  max-height: 84vh;
  overflow-y: auto;
}
#restore-browser-modal::backdrop { background: rgba(0,0,0,.5); }
.restore-browser-head,
.restore-browser-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.restore-browser-head > div {
  flex: 1 1 420px;
  min-width: 0;
}
#restore-browser-close {
  flex: 0 0 auto;
  align-self: flex-start;
}
.restore-browser-summary {
  margin: 12px 0;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 13.5px;
}
.restore-browser-empty {
  padding: 18px 0 6px;
  color: var(--text-dim);
}
.restore-browser-action {
  text-align: right;
  white-space: nowrap;
}
#restore-browser-open[aria-disabled="true"] {
  pointer-events: none;
  opacity: .6;
}

/* Picking which serial is going out the door, straight after scanning it
   at the register. */
.serial-pick {
  border: 1px solid var(--brass);
  background: var(--bg-inset);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 16px;
}
.serial-pick-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 10px;
}
.serial-list { list-style: none; margin: 0; padding: 0; }
.serial-list li {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 9px 0;
  border-top: 1px solid var(--border);
}
.serial-list li:first-child { border-top: 0; }
.serial-list .serial-number { font-size: 15px; font-weight: 600; flex: 1 1 160px; }
.serial-list .btn { margin-left: auto; }

/* The sign-in and first-run pages, which render without the sidebar.
   Without this the main column keeps the left margin the sidebar used to
   occupy, and the sign-in box sits oddly off-centre on a tablet. */
.main-bare {
  margin-left: 0;
  max-width: 620px;
  margin-right: auto;
}

/* The unencrypted-connection warning: red, full-width, and permanent for
   the life of the page -- it describes the wire, not an event. */
.insecure-banner {
  background: var(--rust-bg);
  border-bottom: 2px solid var(--rust);
  color: var(--rust-text);
  padding: 8px 18px;
  font-size: 13px;
  line-height: 1.45;
}
.insecure-banner strong { text-transform: uppercase; letter-spacing: .04em; margin-right: 6px; }

/* The phone-camera barcode scanner. The stage only exists while the
   camera is on; the video gets a sane size instead of the element's
   natural (huge) one. */
.camera-scan { margin: 10px 0 4px; }
.camera-scan-stage { margin-top: 8px; }
.camera-scan-holder {
  position: relative;
  display: inline-block;
  width: 100%;
  max-width: 420px;
  margin-bottom: 8px;
}
.camera-scan-stage video {
  display: block;
  width: 100%;
  border: 2px solid var(--brass);
  border-radius: 4px;
  background: #000;
}
/* The aiming line: hold the barcode under the red line. Detection only
   reads the band around it, so the line is a promise, not a picture. */
.camera-scan-aim {
  position: absolute;
  left: 6%;
  right: 6%;
  top: 50%;
  height: 0;
  border-top: 2px solid #e03131;
  box-shadow: 0 0 6px rgba(224, 49, 49, 0.8);
  pointer-events: none;
}

/* Miniature item photos beside names -- the list page and the cart.
   lazy-loaded, sized here so a huge upload still renders small. */
.thumb-mini {
  width: 32px;
  height: 32px;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--border);
  vertical-align: middle;
  margin-right: 8px;
  display: inline-block;
  background: var(--bg-inset);
}
.thumb-none { border-style: dashed; }
.name-with-thumb { white-space: nowrap; }
.name-with-thumb a, .name-with-thumb .serial-on-line { white-space: normal; }

/* The colour editor (2.46.2): each group of colours sits beside a live
   sample of exactly what those colours paint. */
.color-group { display: grid; grid-template-columns: minmax(0, 1fr) minmax(240px, 340px);
  gap: 16px; align-items: start; margin-bottom: 6px; }
.color-sample { border: 1px dashed var(--border); border-radius: 8px; padding: 10px 12px; font-size: 13px; }
.color-sample .sample-label { font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 6px; }
@media (max-width: 900px) { .color-group { grid-template-columns: 1fr; } }

/* Import / export progress (2.46.4, static/js/transfer_progress.js). */
#transfer-progress { display: none; position: fixed; inset: 0; z-index: 500;
  background: rgba(0,0,0,0.55); align-items: center; justify-content: center; }
#transfer-progress.open { display: flex; }
#transfer-progress .tp-box { width: min(460px, 92vw); background: var(--bg-raised); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px; padding: 18px 20px; box-shadow: 0 20px 60px rgba(0,0,0,0.5); }
#transfer-progress .tp-label { font-weight: 600; margin-bottom: 10px; }
#transfer-progress .tp-track { height: 14px; border-radius: 7px; background: var(--bg-inset);
  border: 1px solid var(--border); overflow: hidden; }
#transfer-progress .tp-bar { height: 100%; width: 0; background: var(--brass); transition: width .2s ease; }
#transfer-progress.working .tp-bar {
  background: repeating-linear-gradient(45deg, var(--brass) 0 14px, var(--brass-dim) 14px 28px);
  background-size: 40px 40px; animation: tp-move 1s linear infinite; }
@keyframes tp-move { from { background-position: 0 0; } to { background-position: 40px 0; } }
#transfer-progress .tp-detail { margin-top: 8px; font-size: 12.5px; color: var(--text-dim); }

/* Sign out beside the signed-in name (2.47.0) */
.who-row { display:inline-flex; align-items:center; gap:8px; flex-wrap:wrap; }
.who-signout { display:inline; margin:0; }
.who-signout button { font:inherit; font-size:10.5px; padding:1px 8px; border-radius:10px; cursor:pointer;
  background:transparent; color:var(--text-dim); border:1px solid var(--border); }
.who-signout button:hover { color:var(--text); border-color:var(--text-dim); }

/* Click-to-sort headings (2.47.0) */
th.th-sort { cursor:pointer; user-select:none; white-space:nowrap; }
th.th-sort:hover { color:var(--brass, var(--text)); }
th.th-sort::after { content:"\2195"; opacity:.28; font-size:.85em; margin-left:4px; }
th.th-sort.sorted-asc::after { content:"\25B2"; opacity:.9; }
th.th-sort.sorted-desc::after { content:"\25BC"; opacity:.9; }

/* Returns at the register (2.48.0): lines coming BACK are red. */
tr.line-returning td { background: color-mix(in srgb, var(--rust-bg) 70%, transparent); }
tr.line-returning td:first-child { box-shadow: inset 4px 0 0 var(--rust); }
.returning-tag { display:inline-block; font-family:var(--font-mono); font-size:10px; font-weight:700; letter-spacing:.06em;
  color:var(--rust-text); background:var(--rust-bg); border:1px solid var(--rust); border-radius:99px; padding:1px 7px; margin-top:3px; }
.returning-banner { margin:0 0 12px; padding:10px 14px; border-radius:8px; border:1px solid var(--rust);
  background:var(--rust-bg); color:var(--rust-text); }

/* Signing out / in (2.48.0) */
#switch-progress { position:fixed; inset:0; z-index:600; display:none; align-items:center; justify-content:center;
  background:rgba(0,0,0,.45); }
#switch-progress.open { display:flex; }
#switch-progress .tp-box { background:var(--bg-raised); color:var(--text); border:1px solid var(--border);
  border-radius:10px; padding:16px 20px; min-width:260px; }
#switch-progress .tp-track { height:8px; border-radius:99px; background:var(--bg-inset); overflow:hidden; margin-top:10px; }
#switch-progress .tp-bar { height:100%; width:40%; background:var(--brass); border-radius:99px;
  animation: sp-slide 0.9s ease-in-out infinite; }
@keyframes sp-slide { 0% { transform:translateX(-100%); } 100% { transform:translateX(250%); } }
