/* Preplyst brand tokens (brand guidelines v1 · 2026). Paper is the default theme; Night shift
   (body.theme-dark) redefines the same tokens rather than overriding individual components, so a
   component written against tokens is correct in both themes by construction. Status colours
   (fresh / discard / expired) are signals, never palette: product only, always word + glyph. */
:root {
  --paper: #fafaf8;
  --paper-raised: #ffffff;
  --paper-deep: #f2f1ec;
  --hover: #f2f1ec;
  --ink: #15131a;
  --ink-muted: #5c5a66;
  --line: #e6e4df;
  --line-strong: #5c5a66;

  --spark: #6344f5;
  --spark-hover: #5233e0;
  --spark-soft: #ece8ff;
  --on-spark: #ffffff;
  --zest: #dff26b;
  --on-zest: #15131a;

  --fresh: #1a6a47;
  --fresh-soft: #dcf3e6;
  --discard: #935a12;
  --discard-soft: #fbecd0;
  --expired: #b3261e;
  --expired-soft: #fde0dd;

  /* The printed label is white stock and black ink in both themes. */
  --label-stock: #ffffff;
  --label-ink: #000000;

  --shadow-card: 0 1px 2px rgba(21, 19, 26, 0.04), 0 6px 20px rgba(21, 19, 26, 0.05);
  --shadow-label: 0 2px 6px rgba(21, 19, 26, 0.08), 0 24px 48px rgba(52, 30, 170, 0.22);
  --shadow-pop: 0 12px 32px rgba(21, 19, 26, 0.14);

  --radius-sm: 10px;
  --radius-md: 18px;
  --radius-lg: 28px;
  --radius-pill: 999px;
  --radius: var(--radius-sm);

  --font-display: "Geist", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body: var(--font-display);
  --font-mono: "Geist Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
}

body.theme-dark {
  --paper: #0e0d11;
  --paper-raised: #18171c;
  --paper-deep: #09080b;
  --hover: #232129;
  --ink: #f4f3ef;
  --ink-muted: #a9a6b2;
  --line: #2b2931;
  --line-strong: #6f6c78;

  --spark: #a794ff;
  --spark-hover: #b9aaff;
  --spark-soft: #26214a;
  --on-spark: #0e0d11;
  --zest: #d4ea5c;

  --fresh: #7fd4a7;
  --fresh-soft: #13301f;
  --discard: #f0bc6c;
  --discard-soft: #36280f;
  --expired: #ff8f85;
  --expired-soft: #3b1816;

  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.5), 0 6px 20px rgba(0, 0, 0, 0.35);
  --shadow-pop: 0 12px 32px rgba(0, 0, 0, 0.55);
  color-scheme: dark;
}

* { box-sizing: border-box; }
/* Hard backstop against the page itself ever scrolling sideways (most commonly on mobile, where a
   fixed-width element somewhere is wider than the viewport) -- every legitimately-wide thing
   (tables, dropdown panels) already scrolls inside its own overflow-x:auto container. */
html { overflow-x: hidden; }
body { margin: 0; max-width: 100vw; overflow-x: hidden; font-family: var(--font-body); font-size: 0.9375rem; line-height: 1.6; background: var(--paper); color: var(--ink); -webkit-font-smoothing: antialiased; }
a { color: inherit; }
h1 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.035em; line-height: 1.15; font-size: 1.75rem; margin: 0; }
h2 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.025em; line-height: 1.25; font-size: 1.25rem; margin: 0 0 0.5rem; }
h3 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.02em; }
p { margin: 0; }
.mono { font-family: var(--font-mono); font-weight: 500; }
:focus-visible { outline: 2px solid var(--spark); outline-offset: 2px; }

table { width: 100%; border-collapse: collapse; text-align: left; font-size: 0.875rem; }
th, td { padding: 0.625rem 1rem; }
thead { border-bottom: 1px solid var(--line); color: var(--ink-muted); font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
tbody tr { border-bottom: 1px solid var(--line); }
tbody tr:last-child { border-bottom: none; }
.tenant-name-btn {
  background: none; border: none; padding: 0; margin: 0; font: inherit; font-weight: 600;
  color: inherit; cursor: pointer; text-align: left;
}
.tenant-name-btn:hover { color: var(--spark); text-decoration: underline; }

label { display: block; font-size: 0.875rem; font-weight: 500; color: var(--ink); }
input, select, textarea { margin-top: 0.375rem; width: 100%; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); padding: 0.625rem 0.75rem; font-size: 0.9375rem; font-family: var(--font-body); background: var(--paper-raised); color: var(--ink); }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--spark); outline-offset: -1px; border-color: var(--spark); }
input[type="checkbox"] { width: auto; margin-top: 0; accent-color: var(--spark); }
.checkbox-row { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: var(--ink); }

button { cursor: pointer; border: none; border-radius: var(--radius-sm); font-family: var(--font-body); font-weight: 500; font-size: 0.9375rem; }
/* These classes land on <a> tags as often as <button>s, so they carry their own base styling
   regardless of element type. In the app every button takes radius-sm; pills are for the
   marketing site only (.btn-pill). */
.btn-primary, .btn-outline, .btn-danger { cursor: pointer; border-radius: var(--radius-sm); font-family: var(--font-body); font-weight: 500; font-size: 0.9375rem; line-height: 1.2; text-decoration: none; }
.btn-primary { background: var(--spark); color: var(--on-spark); padding: 0.625rem 1.125rem; display: inline-flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; }
.btn-primary:hover { background: var(--spark-hover); }
.btn-primary:disabled { opacity: 0.55; cursor: default; }
.btn-outline { background: var(--paper-raised); border: 1px solid var(--line-strong); color: var(--ink); padding: 0.5rem 0.875rem; display: inline-flex; align-items: center; gap: 0.375rem; }
.btn-outline:hover { background: var(--hover); }
.btn-danger { background: transparent; border: 1px solid var(--expired); color: var(--expired); padding: 0.375rem 0.625rem; font-size: 0.8125rem; display: inline-flex; align-items: center; gap: 0.375rem; }
.btn-danger:hover { background: var(--expired-soft); }
.btn-pill { border-radius: var(--radius-pill); }
.btn-icon { display: inline-flex; width: 1rem; height: 1rem; flex-shrink: 0; }
.btn-icon svg { width: 100%; height: 100%; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

.error-text { color: var(--expired); font-size: 0.875rem; }
.success-text { color: var(--spark); font-size: 0.875rem; }
.card { border: 1px solid var(--line); background: var(--paper-raised); border-radius: var(--radius-md); padding: 1.5rem; box-shadow: var(--shadow-card); }
.form-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 640px) { .form-grid { grid-template-columns: 1fr 1fr; } }
.table-wrap { margin-top: 1.5rem; overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--paper-raised); box-shadow: var(--shadow-card); }

/* Opt-in (add class="mobile-cards" to a .table-wrap) turns a data table into a stacked list of
   cards below the phone breakpoint -- each <td> needs a data-label="Column Name" attribute (set by
   the page's row-rendering JS) so its value can be paired with a label the way the header row
   normally would. */
@media (max-width: 640px) {
  .table-wrap.mobile-cards { border: none; background: none; box-shadow: none; overflow-x: visible; }
  .table-wrap.mobile-cards table, .table-wrap.mobile-cards tbody, .table-wrap.mobile-cards tr, .table-wrap.mobile-cards td { display: block; width: 100%; }
  .table-wrap.mobile-cards thead { display: none; }
  .table-wrap.mobile-cards tr { background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-md); padding: 0.25rem 1rem; margin-bottom: 0.75rem; box-shadow: var(--shadow-card); }
  .table-wrap.mobile-cards tr:last-child { margin-bottom: 0; }
  .table-wrap.mobile-cards td { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.5rem 0; border-bottom: 1px solid var(--line); text-align: right; }
  .table-wrap.mobile-cards td:last-child { border-bottom: none; }
  .table-wrap.mobile-cards td:empty { display: none; }
  .table-wrap.mobile-cards td::before {
    content: attr(data-label); flex-shrink: 0; text-align: left;
    font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-muted);
  }
}

.spinner { width: 1rem; height: 1rem; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; display: inline-block; animation: spin 0.75s linear infinite; opacity: 0.75; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Full-screen branded loading overlay for sign-in/out and act-as transitions -- see
   loadingScreen.js. Always spark with the white mark, like the app icon, regardless of theme. */
.loading-screen { position: fixed; inset: 0; z-index: 100; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.25rem; background: #6344f5; color: #ffffff; }
.loading-screen-mark { width: 5rem; height: 5rem; }
.loading-screen-spinner { width: 1.75rem; height: 1.75rem; border: 3px solid #ffffff; border-right-color: transparent; border-radius: 50%; animation: spin 0.75s linear infinite; opacity: 0.85; }
.loading-screen-message { margin: 0; font-size: 0.9375rem; color: rgba(255, 255, 255, 0.9); }

/* Status chips -- the on-screen day dot. Reserved strictly for "is this in date": a pill with the
   word in data caps, a glyph, and its colour pair. Circle = fresh, triangle = discard soon,
   square = expired -- fresh and expired sit at similar lightness, so the shape carries the
   meaning for colour-blind staff. */
.status-chip { display: inline-flex; align-items: center; gap: 0.4375rem; padding: 0.25rem 0.75rem; border-radius: var(--radius-pill); font-family: var(--font-mono); font-size: 0.75rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1.4; white-space: nowrap; }
.status-chip::before { content: ""; flex-shrink: 0; width: 0.5625rem; height: 0.5625rem; background: currentColor; }
.status-fresh { background: var(--fresh-soft); color: var(--fresh); }
.status-fresh::before { border-radius: 50%; }
.status-discard-soon { background: var(--discard-soft); color: var(--discard); }
.status-discard-soon::before { clip-path: polygon(50% 4%, 100% 96%, 0 96%); width: 0.625rem; }
.status-expired { background: var(--expired-soft); color: var(--expired); }
.status-expired::before { border-radius: 1px; width: 0.5rem; height: 0.5rem; }

/* Printer connectivity pills -- a separate component from .status-chip on purpose: green/amber/red
   only ever mean "in date", so a printer being online is spark, never green. */
.printer-chip { display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.1875rem 0.625rem; font-size: 0.75rem; font-weight: 600; font-family: var(--font-mono); letter-spacing: 0.02em; border-radius: var(--radius-pill); border: 1px solid transparent; }
.printer-chip--online, .printer-chip--offline { gap: 0.375rem; }
.printer-chip--online::before, .printer-chip--offline::before { content: ""; width: 0.4375rem; height: 0.4375rem; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.printer-chip--online { background: var(--spark-soft); color: var(--spark); }
.printer-chip--offline { background: var(--paper-deep); color: var(--ink-muted); border-color: var(--line); }
.printer-chip--pending { background: var(--paper-deep); color: var(--ink-muted); border-color: var(--line); border-style: dashed; }
.printer-chip--default { background: transparent; color: var(--ink); border-color: var(--line-strong); }

/* A small neutral metadata pill (machine name, agent version). */
.info-chip { display: inline-flex; align-items: center; padding: 0.125rem 0.5625rem; font-size: 0.75rem; font-family: var(--font-mono); border-radius: var(--radius-pill); background: var(--paper-deep); border: 1px solid var(--line); color: var(--ink-muted); }

/* App shell: sidebar layout shared by the tenant app and the platform/partner portals */
.shell { min-height: 100vh; }
@media (min-width: 1024px) { .shell { display: flex; height: 100vh; } }
.sidebar { display: flex; flex-direction: column; border-bottom: 1px solid var(--line); background: var(--paper-raised); }
/* Fixed at exactly one viewport tall, with .main scrolling independently within its own box,
   rather than position:sticky -- html's overflow-x:hidden forces its overflow-y to compute as
   auto, which breaks sticky's containing-block calculation in some browsers. */
@media (min-width: 1024px) { .sidebar { height: 100vh; width: 14rem; flex-shrink: 0; border-bottom: none; border-right: 1px solid var(--line); } }
.sidebar { transition: width 0.15s ease; }
.sidebar-header { padding: 1.25rem 1.25rem 0.75rem; display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem; }
/* min-width:0 (not overflow:hidden) keeps these flex children from forcing the sidebar wider --
   overflow:hidden would also clip the location-switcher dropdown panel. */
.sidebar-header-text { min-width: 0; flex: 1; display: flex; flex-direction: column; align-items: flex-start; gap: 0.625rem; }
/* The co-branded lockup from the master artwork (mark + wordmark + "by SparkSystems" byline, all
   one image -- see icons.js's logoLockupWithAttribution); collapsed, it swaps to the mark alone
   (below 96px wide the guide says to drop the wordmark). Taller than the wordmark-only lockup
   (the byline adds height below it), so this needs a bigger height than that alone would to keep
   "preplyst" itself from reading smaller than before. */
.sidebar-lockup { display: block; height: 2.75rem; }
.sidebar-logo { display: none; flex-shrink: 0; width: 2.25rem; height: 2.25rem; }
.sidebar-brand-text { min-width: 0; width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; }
.sidebar-pill-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.375rem; max-width: 100%; }
/* Which portal / tenant you're in, as a pill. */
.sidebar-sub { display: inline-flex; max-width: 100%; align-items: center; padding: 0.1875rem 0.625rem; font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-muted); background: var(--paper-deep); border: 1px solid var(--line); border-radius: var(--radius-pill); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-sub:empty { display: none; }
.sidebar-sub--platform { color: var(--spark); background: var(--spark-soft); border-color: transparent; }
.sidebar-sub--partner { color: var(--paper); background: var(--ink); border-color: transparent; }
/* Which environment this is -- a platform setting (see manageSettings.js), not a build-time flag,
   since Dev and Production are already entirely separate databases: set once in Dev's, leave
   Production's blank, done. Amber/warning-toned (reusing the label's own "discard soon" color)
   since its whole job is to catch the eye if someone's not sure which instance they're on. */
.sidebar-env-pill { display: inline-flex; align-items: center; padding: 0.1875rem 0.625rem; font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--discard); background: var(--discard-soft); border-radius: var(--radius-pill); white-space: nowrap; }
/* The login screen's version sits on the solid violet brand panel, not the sidebar's paper
   background -- a tinted-white pill reads better there than the sidebar's amber. */
.sidebar-env-pill--onspark { color: #ffffff; background: rgba(255, 255, 255, 0.16); }
/* Location switcher: a branded dropdown rather than a native <select>, styled as another row of
   the sidebar's own menu. */
.sidebar-location-switcher { position: relative; align-self: stretch; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.sidebar-location-summary {
  display: flex; align-items: center; gap: 0.625rem; width: 100%;
  border: none; background: none; padding: 0.5rem 0.75rem; border-radius: var(--radius-sm);
  font-family: var(--font-body); font-size: 0.875rem; font-weight: 500;
  color: var(--ink); cursor: pointer; list-style: none; user-select: none;
}
.sidebar-location-summary:hover { background: var(--hover); }
.sidebar-location-summary::-webkit-details-marker { display: none; }
.sidebar-location-icon { flex-shrink: 0; display: inline-flex; width: 1.25rem; height: 1.25rem; color: var(--ink-muted); }
.sidebar-location-icon svg { width: 100%; height: 100%; }
.sidebar-location-value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
.sidebar-location-caret { flex-shrink: 0; color: var(--ink-muted); }
.sidebar-location-switcher[open] .sidebar-location-caret { transform: rotate(180deg); }
.sidebar-location-panel {
  position: absolute; z-index: 30; top: calc(100% + 0.375rem); left: 0; width: max(100%, 12rem);
  display: flex; flex-direction: column; padding: 0.25rem; background: var(--paper-raised); border: 1px solid var(--line);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-pop); max-height: 16rem; overflow-y: auto;
}
.sidebar-location-option {
  display: block; width: 100%; text-align: left; background: none; border: none; border-radius: 6px;
  padding: 0.5rem 0.625rem; font-family: var(--font-body); font-size: 0.875rem; font-weight: 500; color: var(--ink); cursor: pointer;
}
.sidebar-location-option:hover { background: var(--hover); }
.sidebar-location-option.active { background: var(--spark-soft); color: var(--spark); font-weight: 600; }
/* Sits in the footer action row but pushed to the far right, since it's a rail-level control
   rather than an account action like its row-mates. */
.collapse-toggle { color: var(--ink-muted); margin-left: auto; }
.collapse-toggle svg { transition: transform 0.15s ease; }
.mobile-menu-toggle { display: none; flex-shrink: 0; background: none; border: 1px solid var(--line); border-radius: var(--radius-sm); width: 2.25rem; height: 2.25rem; align-items: center; justify-content: center; color: var(--ink); }
.mobile-menu-toggle svg { width: 1.25rem; height: 1.25rem; }
.sidebar-body { display: contents; }
/* min-height:0 lets this column-flex item shrink below its content height so overflow-y:auto
   actually kicks in; overflow-x stays visible so absolutely-positioned flyouts aren't clipped. */
.sidebar-nav { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 0.125rem; padding: 0.5rem 0.75rem; overflow-x: visible; overflow-y: auto; }
.sidebar-nav { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.sidebar-nav::-webkit-scrollbar { width: 6px; }
.sidebar-nav::-webkit-scrollbar-track { background: transparent; }
.sidebar-nav::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.sidebar-nav::-webkit-scrollbar-thumb:hover { background: var(--ink-muted); }
/* Groups a long flat nav into a few short labeled sections -- purely opt-in (see sidebar.js). */
.nav-group-heading { margin: 0; padding: 0.875rem 0.75rem 0.25rem; font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-muted); }
.nav-group-heading:first-child { padding-top: 0.25rem; }
.sidebar-nav a { padding: 0.5rem 0.75rem; border-radius: var(--radius-sm); font-size: 0.9375rem; font-weight: 500; color: var(--ink-muted); text-decoration: none; white-space: nowrap; display: flex; align-items: center; gap: 0.75rem; }
.nav-icon { display: inline-flex; width: 1.375rem; height: 1.375rem; flex-shrink: 0; }
.nav-icon svg { width: 100%; height: 100%; }
.sidebar-nav a:hover { background: var(--hover); color: var(--ink); }
.sidebar-nav a.active { background: var(--spark-soft); color: var(--spark); }

/* A pure group label (no page of its own) -- its children live behind a click, in a small modal
   popup (see sidebar.js's openNavGroupPopup). */
.nav-group-label {
  width: 100%; padding: 0.5rem 0.75rem; border: none; background: none; font: inherit; border-radius: var(--radius-sm);
  font-size: 0.9375rem; font-weight: 500; color: var(--ink-muted); text-align: left;
  display: flex; align-items: center; gap: 0.75rem; cursor: pointer;
}
.nav-group-label:hover { background: var(--hover); color: var(--ink); }
.nav-group-label.has-active-child { color: var(--spark); font-weight: 600; }
.nav-group-caret { margin-left: auto; flex-shrink: 0; font-size: 0.75rem; color: var(--ink-muted); }
.sidebar-footer { border-top: 1px solid var(--line); padding: 1rem 1.25rem; }
.sidebar-footer .name { font-size: 0.875rem; font-weight: 600; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-footer .role { font-size: 0.8125rem; color: var(--ink-muted); margin: 0; }
.sidebar-footer-actions { margin-top: 0.75rem; display: flex; gap: 0.5rem; }
.sidebar-footer-actions .footer-action-btn { width: 2.25rem; height: 2.25rem; padding: 0; display: flex; align-items: center; justify-content: center; flex-shrink: 0; border-color: var(--line); }
.sidebar-footer-actions .footer-action-btn svg { width: 1.125rem; height: 1.125rem; }
.sidebar-footer-actions .theme-toggle-btn { background: var(--spark-soft); border-color: transparent; color: var(--spark); }
.impersonation-banner { background: var(--ink); color: var(--paper); padding: 0.5rem 1.5rem; font-size: 0.8125rem; text-align: center; }
.impersonation-banner a { color: inherit; text-decoration: underline; }
/* A platform-wide notice (see manageSettings.js), shown across every logged-in page in all three
   portals -- never on the public login screen, which reads the same settings endpoint but only
   ever looks at environmentLabel (see login.js). */
.notice-banner { background: var(--discard-soft); color: var(--discard); padding: 0.625rem 1.5rem; font-size: 0.875rem; font-weight: 500; text-align: center; border-bottom: 1px solid var(--line); }
/* min-width:0 stops a wide table from pushing .main (and the page) into horizontal scroll instead
   of staying contained in .table-wrap's own overflow-x:auto. */
.main { flex: 1; min-width: 0; padding: 2.25rem 2rem; }
@media (max-width: 640px) { .main { padding: 1.25rem 1rem; } }
@media (min-width: 1024px) { .main { height: 100vh; overflow-y: auto; } }
.main-inner { width: 100%; }

/* Collapsed: icon-only sidebar, desktop only. */
@media (min-width: 1024px) {
  .sidebar.collapsed { width: 4.75rem; }
  .sidebar.collapsed .sidebar-header { justify-content: center; padding: 1rem 0.5rem; }
  .sidebar.collapsed .sidebar-header-text { align-items: center; }
  .sidebar.collapsed .sidebar-lockup { display: none; }
  .sidebar.collapsed .sidebar-logo { display: block; }
  .sidebar.collapsed .sidebar-brand-text, .sidebar.collapsed .nav-label, .sidebar.collapsed .nav-group-caret, .sidebar.collapsed .nav-group-heading, .sidebar.collapsed .sidebar-footer .name, .sidebar.collapsed .sidebar-footer .role, .sidebar.collapsed .theme-toggle-btn, .sidebar.collapsed .support-btn, .sidebar.collapsed .sign-out-btn, .sidebar.collapsed .download-app-btn { display: none; }
  .sidebar.collapsed .sidebar-nav a { justify-content: center; padding: 0.625rem; }
  .sidebar.collapsed .collapse-toggle { margin-left: 0; }
  .sidebar.collapsed .collapse-toggle svg { transform: rotate(180deg); }
  .sidebar.collapsed .sidebar-footer { display: flex; justify-content: center; }
  .sidebar.collapsed .sidebar-footer-actions { margin-top: 0; }
}

/* Mobile (<1024px): a hamburger opens the nav+footer as a dropdown overlay instead of a block
   that pushes the page content down. */
@media (max-width: 1023.98px) {
  .collapse-toggle { display: none; }
  .mobile-menu-toggle { display: flex; }
  .sidebar { position: relative; }
  .sidebar-body {
    display: none; position: absolute; top: 100%; left: 0; right: 0; z-index: 30;
    flex-direction: column; background: var(--paper-raised); border-top: 1px solid var(--line);
    box-shadow: var(--shadow-pop); max-height: calc(100vh - 4rem); overflow-y: auto;
  }
  .sidebar.mobile-open .sidebar-body { display: flex; }
  .sidebar-header { padding: 0.625rem 1rem; align-items: center; }
  .sidebar-header-text { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0.625rem; }
  .sidebar-lockup { height: 2.125rem; }
  .sidebar-brand-text { flex-direction: row; flex-wrap: wrap; align-items: center; width: auto; flex: 1; }
  .sidebar-location-switcher { width: auto; flex-basis: 100%; }
}

/* Auth screens: spark brand panel + form. On mobile the brand panel's copy comes first as
   ordinary page content, with the sign-in form below it. */
.auth-page { min-height: 100vh; display: flex; flex-direction: column; background: var(--paper); }
@media (min-width: 900px) { .auth-page { flex-direction: row; } }
.auth-brand-panel { display: flex; order: 1; background: #6344f5; color: #ffffff; padding: 2rem 1.5rem; flex-direction: column; justify-content: space-between; gap: 2rem; }
@media (min-width: 900px) { .auth-brand-panel { width: 44%; padding: 3.5rem; order: 0; } }
.auth-brand-mark { display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; }
/* Co-branded lockup (mark + wordmark + "by SparkSystems" byline, one image) -- taller than a
   wordmark-only lockup would be at the same size, since the byline adds height below it. */
.auth-brand-mark .lockup { display: block; height: 5.5rem; }
.auth-brand-copy h2 { font-size: clamp(2.25rem, 4vw, 3.25rem); font-weight: 600; letter-spacing: -0.045em; line-height: 1.02; color: #ffffff; margin-bottom: 1.25rem; }
.auth-brand-copy p { font-size: 1.125rem; color: rgba(255, 255, 255, 0.9); line-height: 1.55; max-width: 28rem; }
.auth-brand-panel .foot-note { font-size: 0.8125rem; color: rgba(255, 255, 255, 0.85); line-height: 1.5; max-width: 30rem; }
/* The one zest moment on a light page: a marker swipe under a single headline word, ink on top. */
.zest-swipe { background: linear-gradient(transparent 60%, var(--zest) 60%, var(--zest) 94%, transparent 94%); padding: 0 0.06em; margin: 0 -0.06em; }
/* On a solid spark surface the guide's own cover sets the word in zest instead (5.3:1) -- white
   text over a lime swipe wouldn't read. */
.zest-word { color: #dff26b; }

.auth-form-panel { flex: 1; order: 2; display: flex; align-items: center; justify-content: center; padding: 2rem 1.5rem; }
@media (min-width: 900px) { .auth-form-panel { order: 0; } }
.auth-card { width: 100%; max-width: 24rem; }
.auth-card .mobile-brand { display: block; height: 2rem; margin-bottom: 2rem; }
.auth-card h1 { font-size: 1.75rem; }
.auth-card .subtitle { margin-top: 0.375rem; font-size: 0.9375rem; color: var(--ink-muted); }
.auth-card form { margin-top: 1.75rem; display: flex; flex-direction: column; gap: 1rem; }
.auth-card button[type="submit"] { width: 100%; justify-content: center; padding: 0.75rem; }
.auth-page .disclaimer-fine-print { margin-top: 1.75rem; font-size: 0.8125rem; color: var(--ink-muted); line-height: 1.5; }

/* The compliance disclaimer -- small, ink-muted, readable, never hidden. */
.disclaimer { border: 1px solid var(--line); background: var(--paper-deep); color: var(--ink-muted); border-radius: var(--radius-sm); padding: 0.75rem 1rem; font-size: 0.8125rem; line-height: 1.5; }

/* Print Labels' form -- a single generously-sized card, the main event on the page. */
.print-form { margin-top: 1rem; padding: 2rem; display: flex; flex-direction: column; gap: 1.5rem; }
.print-form label { font-size: 0.9375rem; }
.print-form select, .print-form input { font-size: 1rem; padding: 0.6875rem 0.875rem; }
.print-form-hint { margin-top: 0.375rem; font-size: 0.8125rem; color: var(--ink-muted); }
.print-form-submit { justify-content: center; gap: 0.625rem; padding: 1rem; font-size: 1.0625rem; }
.print-form-submit svg { width: 1.375rem; height: 1.375rem; flex-shrink: 0; }

/* Tap/click a card instead of opening a native <select>. */
.print-product-grid { margin-top: 0.75rem; display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: 0.625rem; max-height: 18rem; overflow-y: auto; padding: 0.125rem 0.25rem 0.125rem 0.125rem; }
.print-product-card {
  display: flex; flex-direction: column; align-items: center; gap: 0.5rem; text-align: center;
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-md); padding: 1rem 0.75rem;
  font-family: var(--font-body); font-weight: 500; font-size: 0.875rem; color: var(--ink);
}
.print-product-card:hover { border-color: var(--spark); }
.print-product-card.active { border-color: var(--spark); background: var(--spark-soft); color: var(--spark); }
.print-product-card-icon { width: 1.5rem; height: 1.5rem; color: var(--spark); }
.print-product-card-icon svg { width: 100%; height: 100%; }
.print-product-card-name { line-height: 1.25; word-break: break-word; }

.print-form-row { display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
@media (min-width: 480px) { .print-form-row { grid-template-columns: 1fr 1fr; } }
/* A tactile +/- stepper instead of a bare number input. */
.print-qty-stepper { margin-top: 0.375rem; display: flex; align-items: stretch; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); overflow: hidden; width: fit-content; }
.print-qty-btn { width: 2.75rem; background: var(--paper-deep); border: none; border-radius: 0; font-size: 1.25rem; font-weight: 600; color: var(--ink); cursor: pointer; }
.print-qty-btn:hover { background: var(--hover); }
.print-qty-value { width: 3.5rem; display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-size: 1.125rem; font-weight: 600; background: var(--paper-raised); }

/* The dashboard's actual data -- at-a-glance counts, then what needs action. */
.dash-stats { margin-top: 1.5rem; display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 640px) { .dash-stats { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .dash-stats { grid-template-columns: repeat(5, 1fr); } }
.dash-stat { display: flex; flex-direction: column; align-items: flex-start; gap: 1rem; background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-md); padding: 1.25rem; box-shadow: var(--shadow-card); }
.dash-stat-icon { flex-shrink: 0; width: 1.5rem; height: 1.5rem; color: var(--ink-muted); }
.dash-stat-icon svg { width: 100%; height: 100%; }
/* Counts are data, so they're set in mono. */
.dash-stat-value { font-family: var(--font-mono); font-weight: 600; font-size: 2rem; letter-spacing: -0.02em; line-height: 1; }
.dash-stat-label { margin-top: 0.375rem; font-size: 0.875rem; color: var(--ink-muted); }
.dash-stat--brand { background: var(--spark); border-color: transparent; color: var(--on-spark); }
.dash-stat--brand .dash-stat-icon, .dash-stat--brand .dash-stat-label { color: var(--on-spark); }
.dash-stat--soon .dash-stat-icon { color: var(--discard); }
.dash-stat--expired .dash-stat-icon { color: var(--expired); }

.dash-attention-wrap { margin-top: 2rem; }

.settings-grid { margin-top: 1rem; display: grid; grid-template-columns: 1fr; gap: 1.25rem; align-items: start; }
@media (min-width: 900px) { .settings-grid { grid-template-columns: repeat(2, 1fr); } }

/* Dashboard quick-action tiles. */
.dashboard-quick-card { display: block; text-decoration: none; transition: border-color 0.15s ease; }
.dashboard-quick-card:hover { border-color: var(--spark); }
.dashboard-quick-card h2 { margin: 0; font-size: 1.0625rem; }
.dashboard-quick-card p { margin-top: 0.375rem; font-size: 0.875rem; color: var(--ink-muted); }

/* Print labels: hidden on screen, shown only in the print dialog. Six layouts (see labelSizes.js's
   `layout` field and labelPrinting.js) share their DOM shape -- name/seq/rule/key-val
   rows/discard-by, arranged either stacked or side-by-side -- but every one of the 11 physical
   sizes gets its own dedicated `.label--size-*` block below, with its own hand-set padding, gaps
   and font sizes. Nothing here is scaled or inherited from a sibling that happens to share the
   same `layout`: a shared cqmin/container-query scale used to make the 4"x6" large size and the
   2-1/8"x4" default (both "tall") derive their type from the same formula, and that indirection is
   exactly what caused values to blow past the printed edge -- a fully explicit block per size has
   no cross-size math to get wrong. */
.print-area { display: none; }
/* Size comes from the tenant's chosen label stock (see Settings) -- printLabels() sets these two
   custom properties on #print-area before rendering; the fallback values are the DYMO 30334
   default so a label still renders sanely if that's ever skipped. */
/* overflow:hidden is deliberate -- content that still doesn't fit gets clipped rather than
   spilling out past the printed box's edge (which just looks broken on paper, with no border
   around the part that escaped). Each size's block below is hand-fitted to its own stock so this
   should rarely trigger; anything that still can (a long product name, a long staff name) gets
   shrunk further per-label by fitLabelText() in labelPrinting.js before printing, so content is
   never silently ellipsis-truncated when a smaller font would actually fit. */
/* Designed for a one-colour direct-thermal printer: label-ink on label-stock, no brand colour
   (it would print black anyway, and a label that relies on colour fails the moment the stock
   changes). Hierarchy comes from size and weight only -- so no greys either, which a thermal head
   can only dither. */
.label { width: var(--label-width, 2.125in); height: var(--label-height, 4in); overflow: hidden; border: 1.5px solid #000; display: flex; flex-direction: column; justify-content: flex-start; background: #fff; color: #000; font-family: var(--font-mono); line-height: 1.3; }
.label-body { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
/* The body grows to push the discard bar down, but its own rows never compress -- a squeezed name
   box would read as overflow to fitLabelText and get shrunk for no reason. */
.label-body > * { flex-shrink: 0; }
.label-header { display: flex; align-items: center; }
.label-mark { display: block; flex-shrink: 0; }
.label .name { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.02em; line-height: 1.02; text-transform: uppercase; min-width: 0; flex: 1; }
.label-rule { border-top: 1.5px dashed #000; }
.label-row { display: flex; justify-content: space-between; align-items: baseline; min-width: 0; }
.label-key { text-transform: uppercase; letter-spacing: 0.04em; font-weight: 500; white-space: nowrap; flex-shrink: 0; }
.label-val { font-weight: 600; text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* An out-of-range reading can't be red on a one-colour printer -- heavier and underlined instead. */
.label-val-unsafe { font-weight: 700; text-decoration: underline; text-decoration-thickness: 2px; }
.label-note { margin: 0; font-weight: 600; text-transform: uppercase; }
.label-allergen-icons { display: flex; align-items: center; flex-wrap: wrap; }
.label-allergen-icon { display: block; }

/* The discard-by bar -- a heavy reversed bar, never dropped and never shrunk out, on any size (FDA
   Food Code §3-501.17: the date/time it must be discarded is the one thing this whole feature
   exists to put on the sticker). print-color-adjust:exact is load-bearing: browsers drop
   background colours when printing by default, which would leave white text on white stock. */
.label-discard { background: #000; color: #fff; font-weight: 600; text-align: center; -webkit-print-color-adjust: exact; print-color-adjust: exact; flex-shrink: 0; }
.label-discard-caption { display: block; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; font-size: 0.8em; white-space: nowrap; }
.label-discard-none { background: #fff; color: #000; border: 1.5px solid #000; font-weight: 500; }
/* The value's date and time each take their own line by default -- a narrow bar or side panel
   stacks them rather than cutting the time off. Only the wide 4" stock (below) has the room to
   run caption, date and time along one line. */
.label-discard-value { display: block; font-weight: 600; line-height: 1.1; }
/* max-width caps a centred block at its panel's width, so text that doesn't fit shows up as overflow
   to fitLabelText instead of silently running past the panel edge. */
.label-discard-value, .label-discard-caption { max-width: 100%; overflow: hidden; }
.label-discard-value .d, .label-discard-value .t { display: block; white-space: nowrap; }
/* "Big" variant: a column by default (caption over the value), a row on the 4" stock. */
.label-discard-big { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.15em; }
.label-discard-big .label-discard-caption { font-size: inherit; }
/* Prep takes a full row wherever rows run two across -- with its weekday it's the longest value. */
.label-meta-grid > .label-row:first-child { grid-column: 1 / -1; }
/* Allergens, then the mark and the job's codes, below the bar. */
.label-after { display: flex; flex-direction: column; gap: 0.25em; padding: 0.4em 0 0.45em; flex-shrink: 0; }
.label-foot { display: flex; align-items: center; justify-content: space-between; gap: 0.5em; padding-top: 0.35em; border-top: 1.5px dashed #000; font-size: 0.85em; font-weight: 500; white-space: nowrap; }
/* Per the guide: the solid mark in label ink, 6mm, dot omitted -- fixed, not scaled per size. */
.label .label-foot .label-mark { width: 6mm; height: 4.5mm; }
.label-body > .label-foot { margin-top: auto; }
/* 2-column key/val grid (or 1-column, per size below) -- minmax(0, ...) and not a bare 1fr, or a
   value long enough to need shrinking (a temperature, a long staff name) forces the *track* wider
   than the label instead of shrinking to fit it -- a grid item's automatic minimum size is its
   content size unless the track itself is clamped to 0, so without this the content blows straight
   through the label's own overflow:hidden edge instead of ellipsizing/shrinking in place. */
.label-meta-grid { display: grid; }

/* ============================================================================================
   2-1/8" x 4" (default) -- DYMO 30334, "tall" layout. The reference size everything else is
   hand-tuned relative to. */
.label--size-2125x4 { padding: 0.6rem 0.6rem 0; font-size: 0.75rem; }
.label--size-2125x4 .label-body { gap: 0.3rem; }
.label--size-2125x4 .label-header { gap: 0.375rem; }
.label--size-2125x4 .label-mark { width: 0.9rem; height: 0.9rem; }
.label--size-2125x4 .name { font-size: 1.3125rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-2125x4 .label-rule { margin: 0.1rem 0; }
.label--size-2125x4 .label-row { gap: 0.375rem; }
.label--size-2125x4 .label-key { font-size: 0.6875rem; }
.label--size-2125x4 .label-val { font-size: 0.75rem; }
.label--size-2125x4 .label-note { font-size: 0.625rem; }
.label--size-2125x4 .label-allergen-icons { gap: 0.25rem; margin-top: 0.15rem; }
.label--size-2125x4 .label-allergen-icon { width: 0.875rem; height: 0.875rem; }
.label--size-2125x4 .label-discard { margin: 0.45rem -0.6rem 0; padding: 0.4rem 0.6rem; font-size: 0.875rem; }
.label--size-2125x4 .label-discard-big { padding: 0.5rem 0.6rem; }
.label--size-2125x4 .label-discard-caption { font-size: 0.75rem; }
.label--size-2125x4 .label-discard-value { font-size: 1.375rem; }
.label--size-2125x4 .label-meta-grid { grid-template-columns: minmax(0, 1fr); gap: 0.2rem 0; }

/* ============================================================================================
   1-1/8" x 3-1/2" -- DYMO 30252, "narrowTall" layout. Tight but tall enough for the full stacked
   info set; no room to spare for a 2-column grid or allergen icon images. */
.label--size-1125x35 { padding: 0.4rem; font-size: 0.8125rem; }
.label--size-1125x35 .label-body { gap: 0.25rem; }
.label--size-1125x35 .label-header { gap: 0.3rem; }
.label--size-1125x35 .label-mark { width: 0.75rem; height: 0.75rem; }
.label--size-1125x35 .name { font-size: 1.0625rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.label--size-1125x35 .label-row { gap: 0.3rem; }
.label--size-1125x35 .label-key { font-size: 0.625rem; }
.label--size-1125x35 .label-val { font-size: 0.6875rem; }
.label--size-1125x35 .label-note { font-size: 0.5625rem; }
.label--size-1125x35 .label-discard { font-size: 0.875rem; padding: 0.4rem; }

/* ============================================================================================
   1" x 2-1/8" (small) -- DYMO 30336, "narrowTallMini" layout, the shortest portrait stock. Only
   what's essential: what it is, when it was prepped, discard-by -- everything else lives on the
   product record and every taller size instead of getting clipped by the overflow:hidden backstop. */
.label--size-1x2125 { padding: 0.3rem; font-size: 0.75rem; justify-content: center; }
.label--size-1x2125 .label-body { gap: 0.2rem; justify-content: center; }
.label--size-1x2125 .label-header { gap: 0.2rem; }
.label--size-1x2125 .label-mark { width: 0.85rem; height: 0.85rem; }
.label--size-1x2125 .name { font-size: 0.9375rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.label--size-1x2125 .label-row { gap: 0.25rem; }
.label--size-1x2125 .label-key { font-size: 0.5625rem; }
.label--size-1x2125 .label-val { font-size: 0.625rem; }
.label--size-1x2125 .label-discard { font-size: 0.8125rem; padding: 0.35rem; margin: 0.35rem -0.3rem 0; }

/* ============================================================================================
   4" x 6" (large) -- Zebra 4x6/Rollo 4x6, "tall" layout. Real space to spare over the 2-1/8"x4"
   default: a single-column meta grid (one field per line) at a noticeably bigger size, rather than
   the same 2-column crowding just because it shares the "tall" DOM shape. */
.label--size-4x6 { padding: 1rem 1rem 0; font-size: 1.125rem; }
.label--size-4x6 .label-body { gap: 0.6rem; }
.label--size-4x6 .label-header { gap: 0.6rem; }
.label--size-4x6 .label-mark { width: 1.75rem; height: 1.75rem; }
.label--size-4x6 .name { font-size: 2.25rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-4x6 .label-rule { margin: 0.25rem 0; }
.label--size-4x6 .label-row { gap: 0.5rem; }
.label--size-4x6 .label-key { font-size: 1rem; }
.label--size-4x6 .label-val { font-size: 1.375rem; }
.label--size-4x6 .label-note { font-size: 0.9375rem; }
.label--size-4x6 .label-allergen-icons { gap: 0.4rem; margin-top: 0.2rem; }
.label--size-4x6 .label-allergen-icon { width: 1.375rem; height: 1.375rem; }
.label--size-4x6 .label-discard { margin: 0.75rem -1rem 0; padding: 0.7rem 1rem; font-size: 1.375rem; }
.label--size-4x6 .label-discard-big { gap: 0.2rem; padding: 0.8rem 1rem; }
.label--size-4x6 .label-discard-value .d, .label--size-4x6 .label-discard-value .t { display: inline; }
.label--size-4x6 .label-discard-caption { font-size: 1.0625rem; }
.label--size-4x6 .label-discard-value { font-size: 1.875rem; }
.label--size-4x6 .label-meta-grid { grid-template-columns: minmax(0, 1fr); gap: 0.5rem 0; }

/* ============================================================================================
   4" x 4" -- Rollo 4x4, "square" layout. As wide as 4x6 but noticeably shorter -- still enough
   height to spare for a single-column meta grid at a bigger size, just tighter vertical spacing. */
.label--size-4x4 { padding: 0.9rem 0.9rem 0; font-size: 1rem; }
.label--size-4x4 .label-body { gap: 0.4rem; }
.label--size-4x4 .label-header { gap: 0.5rem; }
.label--size-4x4 .label-mark { width: 1.4rem; height: 1.4rem; }
.label--size-4x4 .name { font-size: 1.75rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-4x4 .label-rule { margin: 0.2rem 0; }
.label--size-4x4 .label-row { gap: 0.4rem; }
.label--size-4x4 .label-key { font-size: 0.875rem; }
.label--size-4x4 .label-val { font-size: 1.125rem; }
.label--size-4x4 .label-note { font-size: 0.8125rem; }
.label--size-4x4 .label-allergen-icons { gap: 0.3rem; margin-top: 0.15rem; }
.label--size-4x4 .label-allergen-icon { width: 1.125rem; height: 1.125rem; }
.label--size-4x4 .label-discard { margin: 0.6rem -0.9rem 0; padding: 0.55rem 0.9rem; font-size: 1.125rem; }
.label--size-4x4 .label-discard-big { flex-direction: row; align-items: baseline; justify-content: space-between; gap: 0.6rem; padding: 0.6rem 0.9rem; }
.label--size-4x4 .label-discard-value .d, .label--size-4x4 .label-discard-value .t { display: inline; }
.label--size-4x4 .label-discard-caption { font-size: 0.8125rem; }
.label--size-4x4 .label-discard-value { font-size: 1.5rem; }
.label--size-4x4 .label-meta-grid { grid-template-columns: minmax(0, 1fr); gap: 0.35rem 0; }

/* ============================================================================================
   4" x 2" -- Zebra 4x2/Rollo, "wide" layout. Landscape stock with real size to work with: details
   in a left column, discard-by as its own dedicated panel on the right. */
.label--size-4x2 { flex-direction: row; align-items: stretch; gap: 0.5rem; padding: 0.5rem 0.55rem; font-size: 0.8125rem; }
.label--size-4x2 .label-body { flex: 1; min-width: 0; justify-content: center; gap: 0.25rem; }
.label--size-4x2 .label-header { gap: 0.4rem; }
.label--size-4x2 .label-mark { width: 1rem; height: 1rem; }
.label--size-4x2 .name { font-size: 1.1875rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-4x2 .label-rule { margin: 0.15rem 0; }
.label--size-4x2 .label-row { gap: 0.4rem; }
.label--size-4x2 .label-key { font-size: 0.75rem; }
.label--size-4x2 .label-val { font-size: 0.875rem; }
.label--size-4x2 .label-note { font-size: 0.6875rem; }
.label--size-4x2 .label-allergen-icons { gap: 0.25rem; margin-top: 0.1rem; }
.label--size-4x2 .label-allergen-icon { width: 0.9375rem; height: 0.9375rem; }
.label--size-4x2 .label-discard { flex-shrink: 0; width: 32%; margin: 0; display: flex; align-items: center; justify-content: center; }
.label--size-4x2 .label-discard-big { flex-direction: column; gap: 0.2rem; }
.label--size-4x2 .label-discard-caption { font-size: 0.75rem; }
.label--size-4x2 .label-discard-value { font-size: 1.25rem; }
.label--size-4x2 .label-meta-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.15rem 0.5rem; }

/* ============================================================================================
   3" x 2" -- Rollo 3x2, "wide" layout. Same shape as 4x2, less width to spend, so type and gaps
   tighten up accordingly. */
.label--size-3x2 { flex-direction: row; align-items: stretch; gap: 0.4rem; padding: 0.45rem 0.5rem; font-size: 0.75rem; }
.label--size-3x2 .label-body { flex: 1; min-width: 0; justify-content: center; gap: 0.2rem; }
.label--size-3x2 .label-header { gap: 0.35rem; }
.label--size-3x2 .label-mark { width: 0.9rem; height: 0.9rem; }
.label--size-3x2 .name { font-size: 1.0625rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-3x2 .label-rule { margin: 0.15rem 0; }
.label--size-3x2 .label-row { gap: 0.35rem; }
.label--size-3x2 .label-key { font-size: 0.6875rem; }
.label--size-3x2 .label-val { font-size: 0.8125rem; }
.label--size-3x2 .label-note { font-size: 0.625rem; }
.label--size-3x2 .label-allergen-icons { gap: 0.2rem; margin-top: 0.1rem; }
.label--size-3x2 .label-allergen-icon { width: 0.875rem; height: 0.875rem; }
.label--size-3x2 .label-discard { flex-shrink: 0; width: 32%; margin: 0; display: flex; align-items: center; justify-content: center; }
.label--size-3x2 .label-discard-big { flex-direction: column; gap: 0.15rem; }
.label--size-3x2 .label-discard-caption { font-size: 0.6875rem; }
.label--size-3x2 .label-discard-value { font-size: 1.1875rem; }
.label--size-3x2 .label-meta-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.1rem 0.45rem; }

/* ============================================================================================
   2" x 3" -- "tall" layout, smaller than the 2-1/8"x4" default. Slightly tighter all around; still
   the full 2-column grid + big banner since it's a comfortable portrait size, just not a large one. */
.label--size-2x3 { padding: 0.5rem 0.5rem 0; font-size: 0.6875rem; }
.label--size-2x3 .label-body { gap: 0.25rem; }
.label--size-2x3 .label-header { gap: 0.3rem; }
.label--size-2x3 .label-mark { width: 0.8rem; height: 0.8rem; }
.label--size-2x3 .name { font-size: 1.125rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-2x3 .label-rule { margin: 0.1rem 0; }
.label--size-2x3 .label-row { gap: 0.3rem; }
.label--size-2x3 .label-key { font-size: 0.625rem; }
.label--size-2x3 .label-val { font-size: 0.6875rem; }
.label--size-2x3 .label-note { font-size: 0.5625rem; }
.label--size-2x3 .label-allergen-icons { gap: 0.2rem; margin-top: 0.1rem; }
.label--size-2x3 .label-allergen-icon { width: 0.75rem; height: 0.75rem; }
.label--size-2x3 .label-discard { margin: 0.4rem -0.5rem 0; padding: 0.35rem 0.5rem; font-size: 0.75rem; }
.label--size-2x3 .label-discard-big { padding: 0.4rem 0.5rem; }
.label--size-2x3 .label-discard-caption { font-size: 0.625rem; }
.label--size-2x3 .label-discard-value { font-size: 1.125rem; }
.label--size-2x3 .label-meta-grid { grid-template-columns: minmax(0, 1fr); gap: 0.15rem 0; }

/* ============================================================================================
   2-1/4" x 1-1/4" (small) -- Rollo, "narrowWide" layout. ~1-1/4" tall thermal roll: the discard
   panel is the full label height, not just tall relative to a text column next to it. */
.label--size-225x125 { flex-direction: row; align-items: stretch; gap: 0.4rem; padding: 0.3rem 0.4rem; font-size: 0.6875rem; }
.label--size-225x125 .label-body { flex: 1; min-width: 0; justify-content: center; gap: 0.15rem; }
.label--size-225x125 .label-header { gap: 0.25rem; }
.label--size-225x125 .label-mark { width: 0.8rem; height: 0.8rem; }
.label--size-225x125 .name { font-size: 0.875rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.label--size-225x125 .label-row { gap: 0.3rem; }
.label--size-225x125 .label-key { font-size: 0.5625rem; }
.label--size-225x125 .label-val { font-size: 0.625rem; }
.label--size-225x125 .label-note { font-size: 0.5625rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-225x125 .label-discard { flex-shrink: 0; width: 40%; margin: 0; display: flex; align-items: center; justify-content: center; text-align: center; line-height: 1.15; font-size: 0.8125rem; }

/* ============================================================================================
   2" x 1" (small) -- Zebra 2x1/Rollo, "narrowWide" layout. The shortest thermal roll at 1" tall. */
.label--size-2x1 { flex-direction: row; align-items: stretch; gap: 0.35rem; padding: 0.25rem 0.35rem; font-size: 0.625rem; }
.label--size-2x1 .label-body { flex: 1; min-width: 0; justify-content: center; gap: 0.125rem; }
.label--size-2x1 .label-header { gap: 0.2rem; }
.label--size-2x1 .label-mark { width: 0.7rem; height: 0.7rem; }
.label--size-2x1 .name { font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.label--size-2x1 .label-row { gap: 0.25rem; }
.label--size-2x1 .label-key { font-size: 0.5rem; }
.label--size-2x1 .label-val { font-size: 0.5625rem; }
.label--size-2x1 .label-note { font-size: 0.5rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-2x1 .label-discard { flex-shrink: 0; width: 40%; margin: 0; display: flex; align-items: center; justify-content: center; text-align: center; line-height: 1.15; font-size: 0.6875rem; }

/* ============================================================================================
   3" x 1" (small) -- Zebra 3x1/Rollo, "narrowWide" layout. Same 1" height as 2x1, just more width
   to give the name/discard panel a little extra room. */
.label--size-3x1 { flex-direction: row; align-items: stretch; gap: 0.35rem; padding: 0.25rem 0.4rem; font-size: 0.625rem; }
.label--size-3x1 .label-body { flex: 1; min-width: 0; justify-content: center; gap: 0.125rem; }
.label--size-3x1 .label-header { gap: 0.25rem; }
.label--size-3x1 .label-mark { width: 0.75rem; height: 0.75rem; }
.label--size-3x1 .name { font-size: 0.8125rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.label--size-3x1 .label-row { gap: 0.3rem; }
.label--size-3x1 .label-key { font-size: 0.5rem; }
.label--size-3x1 .label-val { font-size: 0.625rem; }
.label--size-3x1 .label-note { font-size: 0.5rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.label--size-3x1 .label-discard { flex-shrink: 0; width: 40%; margin: 0; display: flex; align-items: center; justify-content: center; text-align: center; line-height: 1.15; font-size: 0.6875rem; }

/* Allergen picker: a text-only multi-select dropdown, used on both the product create form and
   the inline edit row. */
.allergen-dropdown { position: relative; margin-top: 0.375rem; }
.allergen-dropdown-summary {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--paper-raised); padding: 0.625rem 0.75rem;
  font-size: 0.9375rem; color: var(--ink); cursor: pointer; list-style: none; user-select: none;
}
.allergen-dropdown-summary::-webkit-details-marker { display: none; }
.allergen-dropdown-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.allergen-dropdown-caret { flex-shrink: 0; color: var(--ink-muted); }
.allergen-dropdown[open] .allergen-dropdown-caret { transform: rotate(180deg); }
.allergen-dropdown-panel {
  position: absolute; z-index: 20; top: calc(100% + 0.375rem); left: 0; min-width: 100%;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.25rem 0.75rem;
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-sm); box-shadow: var(--shadow-pop);
  padding: 0.625rem 0.75rem; max-height: 14rem; overflow-y: auto;
}
.allergen-option { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; font-weight: 400; color: var(--ink); cursor: pointer; white-space: nowrap; }
.allergen-option input { width: auto; margin: 0; flex-shrink: 0; }

/* Location picker: same dropdown shell as the allergen picker, single column, plus a top "all
   locations" row that's mutually exclusive with picking specific ones -- an empty selection IS
   "every location" at the data level. */
.location-picker .allergen-dropdown-panel { grid-template-columns: 1fr; }
.location-picker-all {
  display: block; width: 100%; text-align: left; background: none; border: none; padding: 0.3rem 0;
  font-family: var(--font-body); font-size: 0.875rem; font-weight: 600; color: var(--ink-muted); cursor: pointer;
}
.location-picker-all.active { color: var(--spark); }
.location-picker-divider { border-top: 1px solid var(--line); margin: 0.25rem 0; }

/* Reports: printed as a plain letterhead page via the browser's own print dialog (no PDF library
   needed -- "Save as PDF" is a standard destination there) rather than the small sticker stock
   .print-area uses, so it gets its own print container and layout. */
.report-print-area { display: none; }
.report-header { display: flex; align-items: center; gap: 0.75rem; border-bottom: 1.5px solid black; padding-bottom: 0.75rem; margin-bottom: 1rem; }
.report-header img { height: 1.75rem; width: auto; }
.report-header h1 { font-size: 1.5rem; color: black; }
.report-header p { font-size: 0.8125rem; color: #333; margin-top: 0.125rem; }
.report-print-area table { font-size: 0.75rem; }
.report-print-area th, .report-print-area td { padding: 0.375rem 0.5rem; border-bottom: 1px solid #ccc; color: black; }
.report-print-area thead { background: none; color: #333; }
.report-disclaimer { margin-top: 1.5rem; font-size: 0.6875rem; color: #555; border-top: 1px solid #ccc; padding-top: 0.75rem; }

@media print {
  body * { visibility: hidden; }
  .print-area, .print-area *, .report-print-area, .report-print-area * { visibility: visible; }
  .print-area { display: flex; flex-wrap: wrap; gap: 0.5rem; position: absolute; top: 0; left: 0; }
  .report-print-area { display: block; position: absolute; top: 0; left: 0; width: 100%; padding: 0.4in; }
}

/* Branded pop-out notifications: replace both the native form-validation bubble and plain alert()
   dialogs. Always an ink card in both themes; the left border and icon carry the meaning. Success
   is spark, never green -- green only ever means "in date". */
.toast-container { position: fixed; top: 1.25rem; right: 1.25rem; z-index: 100; display: flex; flex-direction: column; gap: 0.625rem; max-width: min(24rem, calc(100vw - 2rem)); }
.toast { display: flex; align-items: flex-start; gap: 0.625rem; background: #15131a; color: #f4f3ef; padding: 0.75rem 0.875rem; border-left: 4px solid; border-radius: var(--radius-sm); box-shadow: var(--shadow-pop); font-size: 0.875rem; line-height: 1.45; animation: toast-in 0.15s ease; }
body.theme-dark .toast { background: #26242c; }
.toast-error { border-color: #ff8f85; }
.toast-success { border-color: #a794ff; }
.toast-icon { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 1.25rem; height: 1.25rem; border-radius: 50%; font-size: 0.75rem; font-weight: 700; margin-top: 0.0625rem; }
.toast-error .toast-icon { background: #ff8f85; color: #15131a; }
.toast-success .toast-icon { background: #a794ff; color: #15131a; }
.toast-message { flex: 1; }
.toast-close { flex-shrink: 0; background: none; border: none; color: #a9a6b2; font-size: 1.125rem; line-height: 1; padding: 0; }
.toast-close:hover { color: #ffffff; }
.toast-out { animation: toast-out 0.2s ease forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(-0.5rem); } to { opacity: 1; transform: translateY(0); } }
@keyframes toast-out { to { opacity: 0; transform: translateX(1rem); } }

.field-invalid { outline: 2px solid var(--expired); outline-offset: -1px; border-color: var(--expired); }

/* Branded replacement for the browser's native confirm() dialog -- see confirmDialog.js. */
.confirm-backdrop { position: fixed; inset: 0; background: rgba(14, 13, 17, 0.55); z-index: 200; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.confirm-dialog { background: var(--paper-raised); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow-pop); padding: 1.5rem; width: min(92vw, 26rem); }
/* Reuses the confirm dialog's overlay+card for a multi-field form popout -- just wider, and
   scrollable if the form is taller than the viewport. */
.modal-dialog-wide { width: min(92vw, 44rem); max-height: 90vh; overflow-y: auto; }
.modal-close-btn { padding: 0.3rem; width: 2rem; height: 2rem; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.modal-close-btn svg { width: 1.1rem; height: 1.1rem; }
.row-open-btn svg { width: 0.9rem; height: 0.9rem; display: block; }
.confirm-dialog-message { font-size: 0.9375rem; line-height: 1.55; color: var(--ink); white-space: pre-line; }
.confirm-dialog-actions { display: flex; justify-content: flex-end; gap: 0.75rem; margin-top: 1.25rem; }
.confirm-dialog-actions .btn-danger { padding: 0.625rem 1rem; font-size: 0.9375rem; }
.nav-group-popup-current { border-color: var(--spark); color: var(--spark); font-weight: 600; }

.support-dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.support-dialog-header h2 { font-size: 1.125rem; }
.support-dialog-header .support-close-btn { padding: 0.3rem; width: 2rem; height: 2rem; flex-shrink: 0; }
.support-dialog-body { margin-top: 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.support-row {
  display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0.875rem; border-radius: var(--radius-sm);
  border: 1px solid var(--line); color: inherit; text-decoration: none;
}
.support-row:hover { border-color: var(--spark); }
.support-row-icon { flex-shrink: 0; width: 1.25rem; height: 1.25rem; color: var(--spark); }
.support-row-icon svg { width: 100%; height: 100%; }
.support-row-label { display: block; font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-muted); }
.support-row-value { display: block; font-size: 0.9375rem; font-weight: 500; word-break: break-word; }
.support-provided-by { font-size: 0.8125rem; color: var(--ink-muted); text-align: center; margin-top: 0.25rem; }

/* Kiosk: a chrome-less, large-tap-target print station meant to stay open on a wall-mounted
   tablet -- a persistent left icon rail, a centered main column, and a centered modal sheet,
   everything sized for a finger rather than a mouse pointer. */
/* height:100vh + overflow:hidden caps the whole kiosk at exactly one screen, so the rail and main
   each scroll inside their own box instead of the page growing. */
.kiosk-shell { height: 100vh; overflow: hidden; display: flex; flex-direction: column; background: var(--paper); }
.kiosk-topbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; padding: 1rem 1.5rem; border-bottom: 1px solid var(--line); background: var(--paper-raised); }
.kiosk-brand { display: flex; align-items: center; gap: 1rem; min-width: 0; }
.kiosk-brand-mark { width: 2.5rem; height: 2.5rem; flex-shrink: 0; }
.kiosk-tenant { font-family: var(--font-mono); font-size: 0.75rem; font-weight: 600; color: var(--ink-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.kiosk-topbar h1 { margin-top: 0.125rem; }
/* Kiosk buttons are tapped with a finger -- every one needs a real touch target. */
.kiosk-exit { padding: 0.75rem 1.25rem; font-size: 1rem; min-height: 3rem; }
.kiosk-exit svg, .kiosk-confirm-btn svg { width: 1.125rem; height: 1.125rem; flex-shrink: 0; }
.kiosk-icon-btn { width: 3rem; height: 3rem; padding: 0; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.kiosk-icon-btn svg { width: 1.375rem; height: 1.375rem; }

/* Full-screen "which location is this?" gate shown before the kiosk itself. */
.kiosk-location-prompt { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 2rem 1.5rem; background: var(--paper); }
.kiosk-location-prompt-card { width: 100%; max-width: 34rem; text-align: center; }
.kiosk-location-prompt-card .kiosk-tenant { text-align: center; }
.kiosk-location-prompt-hint { margin-top: 0.5rem; font-size: 1rem; color: var(--ink-muted); }
.kiosk-location-grid { margin-top: 2rem; display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 1rem; }
.kiosk-location-btn { background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow-card); padding: 1.5rem 1.25rem; font-family: var(--font-display); font-weight: 600; letter-spacing: -0.02em; font-size: 1.125rem; color: var(--ink); }
.kiosk-location-btn:hover, .kiosk-location-btn:active { border-color: var(--spark); background: var(--spark-soft); color: var(--spark); }
.kiosk-location-prompt-card #kiosk-location-signout, .kiosk-location-prompt-card > .btn-outline { margin-top: 2rem; }

.kiosk-body { flex: 1; display: flex; min-height: 0; }

/* Left rail: one column of big icon tiles (categories, then Batches/Queue/History). */
.kiosk-rail { flex-shrink: 0; width: 7.5rem; overflow-y: auto; padding: 1rem 0.625rem; display: flex; flex-direction: column; gap: 0.5rem; border-right: 1px solid var(--line); background: var(--paper-raised); }
.kiosk-rail { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.kiosk-rail::-webkit-scrollbar { width: 6px; }
.kiosk-rail::-webkit-scrollbar-track { background: transparent; }
.kiosk-rail::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.kiosk-rail::-webkit-scrollbar-thumb:hover { background: var(--ink-muted); }
/* The dynamically-inserted category buttons live inside this wrapper div -- it needs its own flex
   column so they're stretched/centered the same as the rail's direct children. */
#kiosk-rail-categories { display: flex; flex-direction: column; gap: 0.5rem; }
/* A touchscreen never shows a hover state before the tap, so a kiosk control needs to look
   tappable at rest -- a visible border, always on. */
.kiosk-rail-item { position: relative; background: none; border: 1px solid var(--line); border-radius: var(--radius-md); padding: 0.75rem 0.25rem; display: flex; flex-direction: column; align-items: center; gap: 0.4rem; color: var(--ink-muted); }
.kiosk-rail-item:active { border-color: var(--spark); }
.kiosk-rail-icon { width: 3.25rem; height: 3.25rem; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; color: #ffffff; flex-shrink: 0; }
.kiosk-rail-icon svg { width: 1.625rem; height: 1.625rem; }
.kiosk-rail-icon-all { background: var(--spark); color: var(--on-spark); }
.kiosk-rail-label { font-size: 0.75rem; font-weight: 600; text-align: center; line-height: 1.2; word-break: break-word; }
.kiosk-rail-item.active { color: var(--spark); border-color: var(--spark); background: var(--spark-soft); }
.kiosk-rail-item:active .kiosk-rail-icon { transform: scale(0.96); }
.kiosk-rail-divider { border-top: 1px solid var(--line); margin: 0.375rem 0.75rem; }
.kiosk-badge { position: absolute; top: 0.25rem; right: 0.5rem; background: var(--ink); color: var(--paper); font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600; padding: 0.05rem 0.4rem; border-radius: var(--radius-pill); }

/* Main column: centered, generously padded. */
.kiosk-main { flex: 1; min-width: 0; overflow-y: auto; padding: 2rem clamp(1rem, 3vw, 3rem); }
.kiosk-main-inner { width: 100%; }
.kiosk-main-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.kiosk-main-header h2 { font-size: 2rem; letter-spacing: -0.04em; margin: 0; }
.kiosk-search { width: 18rem; max-width: 100%; font-size: 1rem; padding: 0.75rem 0.875rem; margin-top: 0; }

.kiosk-section { margin-bottom: 2rem; }
.kiosk-section-title { font-size: 1.25rem; margin-bottom: 0.75rem; }
.kiosk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); gap: 1rem; }
.kiosk-tile { background: var(--paper-raised); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow-card); padding: 1.5rem 1.25rem; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 0.5rem; min-height: 7.5rem; }
.kiosk-tile:active, .kiosk-tile:hover { border-color: var(--spark); }
.kiosk-tile-icon { width: 2.25rem; height: 2.25rem; color: var(--spark); }
.kiosk-tile-icon svg { width: 100%; height: 100%; }
.kiosk-tile-name { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.02em; font-size: 1.25rem; line-height: 1.15; }
.kiosk-tile-meta { font-family: var(--font-mono); font-size: 0.75rem; font-weight: 600; color: var(--ink-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.kiosk-loading { color: var(--ink-muted); font-size: 1rem; grid-column: 1 / -1; padding: 1rem 0; }
.kiosk-tile-queue { align-items: stretch; }
.kiosk-tile-queue .kiosk-confirm-btn { margin-top: 0.5rem; width: 100%; justify-content: center; padding: 0.75rem; font-size: 1rem; }
.kiosk-queue-actions { display: flex; justify-content: flex-end; margin-bottom: 1rem; }

.kiosk-history-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.75rem; }
.kiosk-history-item { background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow-card); padding: 1rem 1.25rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.kiosk-history-name { font-weight: 600; font-size: 1.0625rem; }
.kiosk-history-meta { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--ink-muted); margin-top: 0.125rem; }

/* Print sheet: a centered modal so it reads as the one clear next action. */
.kiosk-backdrop { position: fixed; inset: 0; background: rgba(14, 13, 17, 0.55); z-index: 40; }
.kiosk-sheet { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 41; background: var(--paper-raised); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-pop); padding: 2rem; width: min(90vw, 30rem); }
.kiosk-sheet-close { position: absolute; top: 0.875rem; right: 0.875rem; background: none; border: 1px solid var(--line); border-radius: var(--radius-sm); width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center; color: var(--ink-muted); }
.kiosk-sheet-close svg { width: 1.375rem; height: 1.375rem; }
.kiosk-sheet-name { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.035em; font-size: 1.875rem; padding: 0 2.5rem; text-align: center; line-height: 1.1; }
.kiosk-sheet-temps { text-align: center; font-family: var(--font-mono); font-size: 0.8125rem; color: var(--ink-muted); margin-top: 0.375rem; min-height: 1.2em; }
.kiosk-stepper { display: flex; align-items: center; justify-content: center; gap: 2rem; margin: 1.5rem 0; }
.kiosk-step-btn { width: 4rem; height: 4rem; font-size: 2rem; background: var(--paper-deep); border: 1px solid var(--line); border-radius: var(--radius-md); color: var(--ink); display: flex; align-items: center; justify-content: center; }
.kiosk-step-btn:active { background: var(--hover); }
.kiosk-qty-value { font-family: var(--font-mono); font-weight: 600; font-size: 2.5rem; min-width: 3.5rem; text-align: center; }
.kiosk-temp-row { margin-bottom: 1.5rem; }
.kiosk-temp-row label { text-align: center; }
.kiosk-temp-row input { font-size: 1.25rem; padding: 0.875rem; text-align: center; font-family: var(--font-mono); }
.kiosk-print-btn { width: 100%; justify-content: center; padding: 1.125rem; font-size: 1.125rem; font-weight: 600; }
.kiosk-print-btn svg { width: 1.25rem; height: 1.25rem; flex-shrink: 0; }

/* Below tablet width, the rail becomes a slim icon-only strip. */
@media (max-width: 640px) {
  .kiosk-rail { width: 5.5rem; }
  .kiosk-rail-label { display: none; }
  .kiosk-main-header { flex-direction: column; align-items: stretch; }
  .kiosk-search { width: 100%; }
}

/* ============================================================
   Public marketing home page (landing.js, "/" for a signed-out
   visitor only) -- everything namespaced under .landing-*.
   Always the Paper theme: it never gets body.theme-dark.
   ============================================================ */
.landing { max-width: 76rem; margin: 0 auto; padding: 0 1.5rem; }
.landing-nav { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.5rem 0; }
.landing-nav-lockup { display: block; height: 2rem; }
.landing-nav-links { display: flex; align-items: center; gap: 0.5rem; }
.landing .btn-primary, .landing .btn-outline { border-radius: var(--radius-pill); }
.landing .btn-outline { border-color: var(--ink); }

.landing-hero { display: grid; grid-template-columns: 1fr; gap: 3rem; align-items: center; padding: 3rem 0 5rem; }
@media (min-width: 960px) { .landing-hero { grid-template-columns: 1.05fr 1fr; gap: 4rem; padding: 4.5rem 0 6rem; } }
.landing-eyebrow { font-family: var(--font-mono); font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--spark); margin: 0 0 1.25rem; }
/* display-xl: 88/84, 600, -0.05em -- scaled down fluidly on narrower screens. */
.landing-hero h1 { font-size: clamp(3rem, 7.2vw, 5.5rem); line-height: 0.96; letter-spacing: -0.05em; font-weight: 600; margin: 0 0 1.5rem; }
.landing-lead { font-size: 1.1875rem; line-height: 1.6; color: var(--ink-muted); max-width: 32rem; }
.landing-cta-row { display: flex; gap: 0.75rem; margin-top: 2.25rem; flex-wrap: wrap; }
.landing-cta-row .btn-primary, .landing-cta-row .btn-outline { padding: 0.9375rem 1.75rem; font-size: 1rem; }

/* The hero art: a real printed-label mockup (label-stock and label-ink, never brand colour) lifted
   with shadow-label on a spark-soft panel, feeding down out of an implied printer slot on load. */
.landing-hero-panel { position: relative; background: var(--spark-soft); border-radius: var(--radius-lg); min-height: 26rem; display: flex; justify-content: center; padding: 3.25rem 1.5rem 3rem; overflow: hidden; }
.landing-printer-slot { position: absolute; top: 1.75rem; left: 50%; transform: translateX(-50%); width: min(19rem, 80%); height: 0.625rem; border-radius: var(--radius-pill); background: var(--ink); opacity: 0.9; }
.landing-label-feed { position: relative; z-index: 1; transform: rotate(-1.5deg); transform-origin: top center; }
.landing-label-feed .mock-label { animation: label-feed 300ms ease-out both; }
@keyframes label-feed { from { transform: translateY(-110%); } to { transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) { .landing-label-feed .mock-label { animation: none; } }

/* The label mockup itself -- same hierarchy as the real printed label: item name, mono rows, the
   reversed DISCARD BY bar (largest data on the label), allergens, then mark + location code. */
.mock-label { width: 17rem; background: var(--label-stock); color: var(--label-ink); border-radius: var(--radius-md); box-shadow: var(--shadow-label); padding: 1.375rem 1.375rem 1rem; font-family: var(--font-mono); }
.mock-label-name { font-family: var(--font-display); font-weight: 700; font-size: 1.75rem; letter-spacing: -0.03em; line-height: 1; text-transform: uppercase; margin: 0 0 1rem; }
.mock-label-row { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.8125rem; font-weight: 500; line-height: 1.75; text-transform: uppercase; }
.mock-label-row span:last-child { font-weight: 600; }
.mock-label-discard { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; margin: 1rem -1.375rem 0; padding: 0.875rem 1.375rem; background: var(--label-ink); color: var(--label-stock); }
.mock-label-discard-caption { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; }
.mock-label-discard-value { font-size: 1.5rem; font-weight: 600; letter-spacing: -0.02em; white-space: nowrap; }
.mock-label-note { margin-top: 0.875rem; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }
.mock-label-foot { display: flex; align-items: center; justify-content: space-between; margin-top: 0.875rem; padding-top: 0.75rem; border-top: 1.5px dashed var(--label-ink); font-size: 0.6875rem; font-weight: 500; }
.mock-label-foot .mock-label-mark { width: 1.25rem; height: 0.9375rem; }

/* Bento, not bullet points: one big spark tile, one zest stat, one ink tile, the rest plain. */
.landing-section { padding: 4rem 0; }
.landing-section-head { max-width: 40rem; margin-bottom: 2.5rem; }
.landing-section-head h2 { font-size: clamp(2.25rem, 4.6vw, 3.25rem); line-height: 1.04; letter-spacing: -0.04em; margin: 0 0 1rem; }
.landing-section-head p { font-size: 1.125rem; color: var(--ink-muted); line-height: 1.6; }
.landing-bento { display: grid; grid-template-columns: 1fr; gap: 1.25rem; }
@media (min-width: 760px) { .landing-bento { grid-template-columns: 1.3fr 1fr 1fr; grid-auto-rows: minmax(13rem, auto); } }
.bento-tile { border-radius: var(--radius-lg); padding: 1.75rem; display: flex; flex-direction: column; justify-content: space-between; gap: 1.5rem; background: var(--paper-raised); border: 1px solid var(--line); box-shadow: var(--shadow-card); }
.bento-tile h3 { font-size: 1.375rem; line-height: 1.2; margin: 0; }
.bento-tile p { font-size: 0.9375rem; line-height: 1.55; color: var(--ink-muted); margin: 0; }
.bento-tile-icon { width: 1.5rem; height: 1.5rem; color: var(--ink); }
.bento-tile-icon svg { width: 100%; height: 100%; }
@media (min-width: 760px) { .bento-tile--hero { grid-row: span 2; } }
.bento-tile--hero { background: var(--spark); border-color: transparent; color: #ffffff; }
.bento-tile--hero h3 { font-size: clamp(2rem, 3.6vw, 2.75rem); line-height: 1.02; letter-spacing: -0.04em; }
.bento-tile--hero p, .bento-tile--hero .bento-tile-icon { color: rgba(255, 255, 255, 0.92); }
.bento-tile--zest { background: var(--zest); border-color: transparent; color: var(--on-zest); }
.bento-tile--zest p { color: var(--on-zest); }
.bento-tile--ink { background: var(--ink); border-color: transparent; color: var(--paper); }
.bento-tile--ink p { color: #a9a6b2; }
.bento-stat { font-family: var(--font-mono); font-weight: 600; font-size: 3.25rem; letter-spacing: -0.03em; line-height: 1; }

/* Label cards: things that are items (here, the three steps) borrow the die-cut label -- radius-md
   corners, a dotted perforation along the top, a hairline border and a slight marketing-only tilt. */
.landing-steps { display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
@media (min-width: 760px) { .landing-steps { grid-template-columns: repeat(3, 1fr); } }
.label-card { position: relative; background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow-card); padding: 2rem 1.5rem 1.5rem; transform: rotate(-1.5deg); }
.label-card:nth-child(2) { transform: rotate(1deg); }
.label-card::before { content: ""; position: absolute; top: 0.75rem; left: 1.25rem; right: 1.25rem; border-top: 2px dotted var(--line-strong); opacity: 0.45; }
.label-card-step { display: inline-flex; font-family: var(--font-mono); font-size: 0.75rem; font-weight: 600; color: var(--spark); background: var(--spark-soft); border-radius: var(--radius-pill); padding: 0.1875rem 0.625rem; margin-bottom: 1rem; }
.label-card h3 { font-size: 1.25rem; margin: 0 0 0.5rem; }
.label-card p { font-size: 0.9375rem; color: var(--ink-muted); line-height: 1.55; margin: 0; }
.label-card-data { margin-top: 1.25rem; font-family: var(--font-mono); font-size: 0.8125rem; color: var(--ink); border-top: 1px solid var(--line); padding-top: 0.875rem; line-height: 1.8; }
.label-card-data div { display: flex; justify-content: space-between; gap: 1rem; }

/* Closing band on ink, one sentence and the actions again. */
.landing-close { margin: 2rem 0 4rem; border-radius: var(--radius-lg); background: var(--ink); color: var(--paper); padding: clamp(2.5rem, 6vw, 4.5rem); display: grid; gap: 2rem; align-items: end; }
@media (min-width: 860px) { .landing-close { grid-template-columns: 1.4fr 1fr; } }
.landing-close h2 { font-size: clamp(2.5rem, 5.5vw, 4rem); line-height: 0.98; letter-spacing: -0.05em; margin: 0; }
.landing-close p { color: #a9a6b2; font-size: 1.0625rem; line-height: 1.6; margin: 0 0 1.5rem; }
.landing-close .btn-primary { background: #a794ff; color: #0e0d11; }
.landing-close .btn-primary:hover { background: #b9aaff; }
.landing-close .btn-outline { background: transparent; color: #f4f3ef; border-color: #6f6c78; }
.landing-close .btn-outline:hover { background: #26242c; }

.landing-footer { display: grid; gap: 1.25rem; padding: 2.5rem 0 3rem; border-top: 1px solid var(--line); font-size: 0.8125rem; color: var(--ink-muted); }
@media (min-width: 760px) { .landing-footer { grid-template-columns: auto 1fr auto; align-items: center; gap: 2rem; } }
/* Taller than a wordmark-only lockup would need, since the co-branded version's "by SparkSystems"
   byline adds height below "preplyst" -- same reasoning as the sidebar/login versions. */
.landing-footer-lockup { display: block; height: 2rem; }
.landing-footer-disclaimer { max-width: 44rem; line-height: 1.55; }
.landing-footer a { font-weight: 600; color: var(--ink); }
