/* ==========================================================================
   APP SHELL LAYOUT: header, drawer/sidebar, content area, responsive nav
   ========================================================================== */

/* The shell itself never scrolls — it's pinned at exactly one viewport tall,
   nav and header included. .app-main (the content pane) is the only element
   with its own overflow-y, so scrolling it can never touch the sidebar. */
.app-shell { height: 100%; }
.app-body { height: 100%; }
.app-main-col {
  height: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* ---- Brand mark (square monogram used in sidebar + login) ---- */
.brand-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-md);
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-weight: var(--fw-semibold);
  font-size: 1.05rem;
  line-height: 1;
}

/* ---- Brand logo ---------------------------------------------------------
   The supplied artwork is fixed-colour: a purple (#811a5e) panel with white
   lettering, plus a purple "INFOCOM" wordmark and an amber tagline sitting
   on transparency beneath it. Measured against both themes, that purple is
   9.4:1 on white but only 2.0:1 on the dark surfaces — on the dark theme the
   INFOCOM wordmark and the panel's own edge stop reading.

   Inverting, filtering, recolouring and blend modes are all excluded, so the
   logo instead always sits on its own neutral white plate. The colour here
   is deliberately a literal, not a token: it must NOT follow the theme, or
   the problem comes straight back in dark mode. In the light theme every
   surface behind the logo is already white, so the plate is invisible and
   nothing about the current design changes; in the dark theme, and on the
   purple auth showcase panel, the plate is what keeps the artwork legible.

   Sizing is set on the PLATE, never on the <img>. The image keeps auto
   dimensions plus max-* clamps, so it can only ever be scaled down along its
   natural 2.4:1 aspect and can never be stretched or upscaled past 1:1. */
.logo-plate {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: #ffffff;
  border-radius: var(--radius-md);
  padding: var(--sp-1) var(--sp-2);
}
.logo-plate img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Width-led variants: the plate sets a width, the image's height follows its
   own aspect. Used where the logo is the primary brand element. */
.logo-plate-auth { width: 210px; }
.logo-plate-showcase { width: 176px; }
.logo-plate-nav { width: 140px; }

/* Height-led variant: the header has a fixed 56px bar, so here the vertical
   size is the constraint and the width follows. */
.logo-plate-header { height: 36px; }

/* Compact square mark, shown INSTEAD of the lockup on phones.
   The 2.4:1 lockup is 83px wide in a 56px bar, and at 360-390px that width
   came straight out of the page title: "Barcode / Serial Records" was being
   truncated to fit. The square crop costs 36px instead, which gives the
   title its room back while the brand stays on screen. */
.logo-plate-mark { width: 36px; height: 36px; padding: 2px; }

/* ---- Top header ---- */
.app-header {
  /* A fixed-height, non-scrolling sibling of .app-main within the flex
     column — position:sticky isn't needed since .app-main-col itself never
     scrolls, only .app-main below does. */
  flex-shrink: 0;
  z-index: 500;
  height: var(--header-h);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0 var(--sp-4);
}
.app-header .menu-btn {
  background: none; border: none; cursor: pointer;
  width: var(--touch-target); height: var(--touch-target);
  display: flex; align-items: center; justify-content: center;
  color: var(--color-text);
  border-radius: var(--radius-md);
  flex-shrink: 0;
}
.app-header .menu-btn:hover { background: var(--color-surface-raised); }
.app-header .page-title {
  flex: 1;
  min-width: 0;
  font-weight: var(--fw-semibold);
  font-size: var(--fs-base);
  letter-spacing: var(--tracking-tight);
  /* At 360px the title shares the bar with two 44px controls. Truncating
     beats wrapping: a two-line header would change the shell's height. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.app-header .header-spacer { flex: 1; }

/* The profile control. Was a decorative div; it is now a real button that
   opens the profile sheet, which is where logout and change-password live on
   a phone — the drawer is no longer the only route to them. */
.app-header .user-chip {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-shrink: 0;
  background: none;
  border: none;
  font-family: inherit;
  text-align: right;
  cursor: pointer;
  min-height: var(--touch-target);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--radius-full);
  transition: background var(--transition-fast);
}
.app-header .user-chip:hover { background: var(--color-surface-raised); }
.app-header .avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--color-primary-light); color: var(--color-primary-dark);
  display: flex; align-items: center; justify-content: center;
  font-weight: var(--fw-semibold); font-size: var(--fs-sm); flex-shrink: 0;
}
/* A photo fills the round .avatar in place of initials, cropped to the circle
   without distortion. Same rule works in both themes - it is just an image. */
.avatar-img {
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: cover;
  display: block;
}
.nav-link.is-busy { opacity: 0.6; cursor: progress; }
.nav-link:disabled { opacity: 0.6; cursor: not-allowed; }

/* Small avatar used in the user-management list, beside a name. */
.avatar-sm {
  width: 30px; height: 30px; border-radius: var(--radius-full);
  background: var(--color-primary-light); color: var(--color-primary-dark);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: var(--fw-semibold); font-size: var(--fs-xs); flex-shrink: 0;
}
.cell-user { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; }

.app-header .user-meta { display: none; }
@media (min-width: 640px) {
  .app-header .user-meta { display: block; text-align: right; }
}
.app-header .user-name { font-size: var(--fs-sm); font-weight: var(--fw-semibold); line-height: 1.2; }
.app-header .user-role { font-size: var(--fs-xs); color: var(--color-text-muted); line-height: 1.2; }

/* ---- Drawer / Sidebar nav ---- */
.nav-backdrop {
  position: fixed; inset: 0;
  background: var(--color-scrim);
  z-index: 600;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-base);
}
.nav-backdrop.open { opacity: 1; pointer-events: auto; }

.app-nav {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: 84%;
  max-width: 300px;
  background: var(--color-nav-bg);
  border-right: 1px solid var(--color-nav-border);
  z-index: 700;
  display: flex;
  flex-direction: column;
  transform: translateX(-100%);
  transition: transform var(--transition-base);
}
.app-nav.open { transform: translateX(0); }

.app-nav .nav-brand {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-4);
  border-bottom: 1px solid var(--color-nav-border);
}
.app-nav .nav-brand-word { min-width: 0; display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; }
.app-nav .nav-brand-text {
  color: var(--color-text);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-sm);
  letter-spacing: var(--tracking-tight);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.app-nav .nav-brand-sub {
  color: var(--color-text-faint);
  font-size: var(--fs-xs);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.app-nav .nav-close {
  margin-left: auto;
  background: none; border: none; color: var(--color-text-muted);
  width: var(--touch-target); height: var(--touch-target); border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  flex-shrink: 0;
}
.app-nav .nav-close:hover { background: var(--color-surface-raised); }
@media (min-width: 1024px) { .app-nav .nav-close { display: none; } }

.app-nav .nav-scope {
  padding: var(--sp-4) var(--sp-4) var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-faint);
}

.app-nav .nav-links { flex: 1; overflow-y: auto; padding: var(--sp-1) var(--sp-3) var(--sp-3); }

/* .nav-link is a STANDALONE component, not a drawer-only one.
   It was originally scoped to `.app-nav .nav-link`, which meant the same
   markup reused in the profile sheet picked up none of it: Change Password
   and Log Out rendered as bare blue anchors with no gap between icon and
   label. Unscoping it fixes every current and future reuse at once, rather
   than copying the rules into the sheet. */
.nav-link {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 10px var(--sp-3);
  border-radius: var(--radius-md);
  color: var(--color-nav-text);
  font-weight: var(--fw-medium);
  font-size: var(--fs-base);
  min-height: var(--touch-target);
  margin-bottom: 2px;
  cursor: pointer;
}
.nav-link:hover { background: var(--color-surface-raised); text-decoration: none; color: var(--color-text); }
.nav-link .icon { flex-shrink: 0; color: var(--color-text-faint); }
.nav-link:hover .icon { color: var(--color-text); }
.nav-link.active { background: var(--color-nav-bg-active); color: var(--color-nav-text-active); font-weight: var(--fw-semibold); }
.nav-link.active .icon { color: var(--color-primary); }

.app-nav .nav-footer {
  padding: var(--sp-3);
  border-top: 1px solid var(--color-nav-border);
}
.app-nav .nav-footer .nav-link { color: var(--color-text-muted); }
.app-nav .nav-footer .nav-link .icon { color: var(--color-text-faint); }
.app-nav .nav-footer .nav-link:hover { background: var(--color-danger-bg); color: var(--color-danger); }
.app-nav .nav-footer .nav-link:hover .icon { color: var(--color-danger); }

/* Desktop: persistent sidebar, no backdrop/close, header shifts */
@media (min-width: 1024px) {
  .app-header .menu-btn.mobile-only { display: none; }
  .app-header .logo-plate.mobile-only { display: none; }
  /* Both brand variants go when the sidebar takes over. */
  .nav-backdrop { display: none; }
  .app-nav {
    position: static;
    transform: none;
    height: 100%;
    width: var(--sidebar-w);
    flex-shrink: 0;
  }
  .app-body { display: flex; }
  .app-main-col { flex: 1; }
}

/* Phones get the square mark; from 640px there is room for the full
   lockup beside a full-length page title. */
.app-header .logo-plate-header { display: none; }
@media (min-width: 640px) {
  .app-header .logo-plate-header { display: inline-flex; }
  .app-header .logo-plate-mark { display: none; }
}

/* ---- Main content ---- */
.app-main {
  /* The one scrolling element in the whole shell — see .app-shell above.
     flex:1 sizes it along the column's main axis (height); max-width/margin
     size and center it along the cross axis (width) — independent concerns,
     no conflict. */
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--sp-4);
  max-width: var(--content-max);
  margin: 0 auto;
  width: 100%;

  /* NO bottom padding. A position:sticky child is clamped to its parent's
     CONTENT box, so any bottom padding here becomes a permanent gap under
     the sticky action bar - it would hang that far above the bottom of the
     scroll port and stay there at every scroll position, which is exactly
     how the SAVE LIST bar came to look unpinned.

     The trailing breathing room the padding used to provide is applied to
     the last child instead (below), where it cannot affect stickiness. */
  padding-bottom: 0;
}
@media (min-width: 640px) {
  .app-main { padding: var(--sp-6); padding-bottom: 0; }
}

/* Breathing room at the end of the scroll, as content rather than container
   padding. Skipped when the last child is the sticky bar, which is meant to
   sit flush against the bottom. */
.app-main > :last-child:not(.sticky-actions) { margin-bottom: var(--sp-6); }

/* ---- Sticky bottom action bar (mobile scanning workflow) ----

   A SINGLE ROW on a phone, not a stack. Stacked, three full-width buttons
   came to roughly 340px — on a 390px screen that permanently covered the
   barcode field this bar exists to serve, which made the app's core workflow
   unusable while looking perfectly tidy in isolation.

   So: the primary action takes the remaining width and keeps its label; the
   secondary actions collapse to icon-only squares (their labels live in
   aria-label, see .btn-label below). That is also the right hierarchy —
   SAVE LIST is what the operator is here to do. */
.sticky-actions {
  position: sticky;
  bottom: 0;
  /* Above Tom Select's control (which sets its own stacking context) but
     below its open dropdown at 60 — so the bar covers the combobox while it
     is closed, and the list still opens over the bar when it is not. The
     shell's own layers (header 500, drawer 700, modal 900) stay clear above. */
  z-index: 50;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding: var(--sp-3) var(--sp-4);
  /* Full-bleed sideways (negative left/right margins cancel .app-main's
     padding), but ZERO bottom margin.

     It used to be calc(-1 * var(--sp-9)) to eat the container's bottom
     padding. That broke the pin: a sticky element resolves `bottom` against
     its own MARGIN box, so a -48px bottom margin parked the bar 48px above
     the bottom of the scroll port and left it there at every scroll
     position - visibly floating, with a strip of page showing underneath. */
  margin: var(--sp-5) calc(-1 * var(--sp-4)) 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--sp-2);
  box-shadow: var(--shadow-md);
}
@media (min-width: 640px) {
  .sticky-actions { margin: var(--sp-5) calc(-1 * var(--sp-6)) 0; }
}

/* The primary action absorbs the leftover width. */
.sticky-actions .btn { width: auto; flex: 0 0 auto; }
.sticky-actions .btn-primary { flex: 1 1 auto; min-width: 0; }

/* Secondary actions: square icon buttons on a phone, labelled from 640px up
   where the row has room for words. */
.sticky-actions .btn-secondary,
.sticky-actions .btn-ghost {
  padding: 0 var(--sp-3);
  min-width: var(--tap-comfortable);
}
@media (max-width: 639px) {
  .sticky-actions .btn-label { display: none; }
  .sticky-actions .btn-secondary .icon,
  .sticky-actions .btn-ghost .icon { margin: 0; }
}
@media (min-width: 640px) {
  .sticky-actions .btn { flex: 1 1 auto; }
  .sticky-actions .btn-secondary,
  .sticky-actions .btn-ghost { padding: 0 var(--sp-5); }
}

/* ---- Login page ---- */
/* Split-screen: a showcase panel grounded in what the product actually does
   (scanning, receipts) alongside the sign-in form, so the first screen reads
   as "built for this business" rather than a card floating on empty grey. */
.auth-page {
  /* body no longer scrolls (see base.css) — this page is its own scroll
     pane, same pattern as .app-main on the app-shell pages, so a short
     phone screen can still scroll to the demo-account list below the fold. */
  height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
}
@media (min-width: 1024px) {
  .auth-page { flex-direction: row; overflow: hidden; }
}

.auth-form-panel {
  flex: 1;
  display: flex;
  align-items: center;
  align-items: safe center; /* falls back to plain `center` above where unsupported */
  justify-content: center;
  padding: var(--sp-5);
}
@media (min-width: 1024px) {
  .auth-form-panel { overflow-y: auto; padding: var(--sp-8); }
}

/* Fade-out on successful login runs via anime.js (see login.js) rather than
   a CSS transition, so it shares one animation engine with the rest of the
   app's motion. */
@keyframes shake-card {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(3px); }
  30%, 50%, 70% { transform: translateX(-6px); }
  40%, 60% { transform: translateX(6px); }
}
.shake-card { animation: shake-card 400ms cubic-bezier(.36,.07,.19,.97) both; }
@media (prefers-reduced-motion: reduce) { .shake-card { animation: none; } }
.auth-card {
  width: 100%;
  max-width: 400px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: var(--sp-7) var(--sp-6);
}

/* ---- Showcase panel (hidden below 1024px — the form alone carries mobile) ---- */
.auth-showcase {
  display: none;
}
@media (min-width: 1024px) {
  .auth-showcase {
    display: flex;
    flex-direction: column;
    flex: 1 1 46%;
    max-width: 560px;
    padding: var(--sp-8) var(--sp-7);
    overflow-y: auto;
    color: #fff;
    background:
      radial-gradient(circle at 15% 8%, rgba(255,255,255,0.08), transparent 40%),
      linear-gradient(160deg, var(--color-primary-dark) 0%, var(--color-primary) 65%, #17337e 130%);
  }
}
.auth-showcase-brand { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-7); }
.auth-showcase-brand .logo-plate { box-shadow: var(--shadow-sm); }
.auth-showcase-brand span { font-weight: var(--fw-semibold); font-size: var(--fs-md); letter-spacing: var(--tracking-tight); }
.brand-mark-invert { background: rgba(255,255,255,0.16); }
.auth-showcase-heading {
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-tight);
  line-height: 1.2;
  margin-bottom: var(--sp-3);
  max-width: 20ch;
}
.auth-showcase-sub { color: rgba(255,255,255,0.82); font-size: var(--fs-sm); line-height: 1.5; margin-bottom: var(--sp-6); max-width: 38ch; }

/* A CSS-drawn barcode with an animated scan beam sweeping across it — the
   product's core action (scanning), rendered rather than described. */
.scan-visual {
  position: relative;
  height: 84px;
  border-radius: var(--radius-md);
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  overflow: hidden;
  margin-bottom: var(--sp-6);
}
.scan-visual-bars {
  position: absolute;
  inset: 18px 24px;
  background-image: repeating-linear-gradient(
    90deg,
    rgba(255,255,255,0.9) 0px, rgba(255,255,255,0.9) 3px,
    transparent 3px, transparent 8px,
    rgba(255,255,255,0.9) 8px, rgba(255,255,255,0.9) 9px,
    transparent 9px, transparent 15px,
    rgba(255,255,255,0.9) 15px, rgba(255,255,255,0.9) 19px,
    transparent 19px, transparent 24px,
    rgba(255,255,255,0.9) 24px, rgba(255,255,255,0.9) 26px,
    transparent 26px, transparent 33px
  );
  background-size: 33px 100%;
}
.scan-visual-beam {
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  top: 0;
  background: #fff;
  box-shadow: 0 0 10px 2px rgba(255,255,255,0.8);
  animation: scan-beam-sweep 2.4s ease-in-out infinite;
}
@keyframes scan-beam-sweep {
  0%, 100% { top: 14px; opacity: 0.9; }
  50% { top: 66px; opacity: 0.5; }
}
@media (prefers-reduced-motion: reduce) {
  .scan-visual-beam { animation: none; top: 40px; }
}

.receipt-card {
  background: var(--color-surface);
  color: var(--color-text);
  border-radius: var(--radius-md);
  padding: var(--sp-4) var(--sp-5);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm);
  margin-bottom: var(--sp-7);
}
.receipt-card-title { font-weight: var(--fw-semibold); margin-bottom: var(--sp-3); }
.receipt-card-row {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: 3px 0;
  color: var(--color-text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--fs-xs);
}
.receipt-card-divider { border-top: 1px dashed var(--color-border); margin: var(--sp-2) 0; }
.receipt-card-total { color: var(--color-text); font-weight: var(--fw-semibold); font-family: var(--font-family); font-size: var(--fs-sm); }

.auth-showcase-features { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: auto; }
.auth-showcase-features li { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-sm); color: rgba(255,255,255,0.92); }
.auth-showcase-features .icon { flex-shrink: 0; color: rgba(255,255,255,0.85); }
.auth-brand { display: flex; flex-direction: column; align-items: center; margin-bottom: var(--sp-6); text-align: center; }
.auth-brand .brand-mark { width: 48px; height: 48px; font-size: 1.4rem; border-radius: var(--radius-lg); margin-bottom: var(--sp-4); }
/* The logo IS the heading on these screens: the <h1> wraps it and takes its
   accessible name from the alt text, so the heading outline is unchanged
   while the wordmark is not printed twice. */
.auth-brand .auth-brand-logo { margin-bottom: var(--sp-3); line-height: 0; }
/* On register / change-password the <h1> is the PAGE heading ("Create
   Company Account"), not the brand, so there the logo sits above it as a
   plain image and the heading is left alone. */
.auth-brand > .logo-plate { margin-bottom: var(--sp-4); }
.auth-brand h1 { font-size: var(--fs-lg); letter-spacing: var(--tracking-tight); margin-bottom: 4px; }
.auth-brand p { color: var(--color-text-muted); font-size: var(--fs-sm); margin: 0; }
.auth-demo {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--color-border);
}
.auth-demo-title {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--color-primary); margin-bottom: var(--sp-3); text-align: center;
}
.auth-demo-title .icon { color: var(--color-primary); }
.demo-account-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: pointer;
  margin-bottom: var(--sp-2);
  text-align: left;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.demo-account-btn:hover { border-color: var(--color-primary); background: var(--color-primary-50); }
.demo-account-btn .role-name { font-weight: var(--fw-semibold); font-size: var(--fs-sm); }
.demo-account-btn .role-email { font-size: var(--fs-xs); color: var(--color-text-muted); }

.auth-footer-links { display: flex; justify-content: space-between; align-items: center; margin-top: var(--sp-2); font-size: var(--fs-sm); }

/* ==========================================================================
   BOTTOM NAVIGATION (below 1024px)

   A flex SIBLING of .app-main inside .app-main-col, not a fixed overlay.
   That matters: because .app-main is the only scrolling element and it is
   flex:1, adding the bar below it makes the scroll area shrink by exactly
   the bar's height. Nothing needs bottom padding, nothing hides behind it,
   and .sticky-actions on the scan screen keeps sticking to the bottom of
   the scroll area — which is now just above the bar — with no change.

   A position:fixed bar would have required padding-bottom on every page and
   a second correction on every sticky element.

   The items are generated from the SAME NAV_BY_ROLE map that builds the
   drawer (see layout.js), so a role can never gain a destination here that
   it does not already have there.
   ========================================================================== */
.bottom-nav {
  flex-shrink: 0;
  display: flex;
  align-items: stretch;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  /* Clears the home indicator on phones that have one. */
  padding-bottom: env(safe-area-inset-bottom, 0px);
  z-index: 400;
}
@media (min-width: 1024px) {
  /* The sidebar takes over; a tab bar as well would be two navigations. */
  .bottom-nav { display: none; }
}

.bottom-nav-item {
  flex: 1 1 0;
  min-width: 0;
  min-height: var(--bottomnav-h);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: var(--sp-2) 2px;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-text-muted);
  text-decoration: none;
  font-family: inherit;
  /* 12px is below the app's --fs-xs floor, and deliberately so: this is the
     one place the label is a caption under an icon rather than something you
     read. Going larger truncates "Companies" at 360px, which is worse. */
  font-size: 12px;
  font-weight: var(--fw-medium);
  line-height: 1.1;
  transition: color var(--transition-fast);
}
.bottom-nav-item:hover { text-decoration: none; color: var(--color-text); }
.bottom-nav-item .icon { width: 22px; height: 22px; color: var(--color-text-faint); transition: color var(--transition-fast); }
.bottom-nav-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bottom-nav-item.active { color: var(--color-primary-dark); font-weight: var(--fw-semibold); }
.bottom-nav-item.active .icon { color: var(--color-primary); }
/* A short bar above the active tab — enough to locate yourself at a glance,
   without the coloured pill that would fight the cards below it. */
.bottom-nav-item.active::before {
  content: "";
  position: absolute;
  top: 0;
  width: 28px;
  height: 3px;
  border-radius: 0 0 var(--radius-full) var(--radius-full);
  background: var(--color-primary);
}
.bottom-nav-item { position: relative; }

/* The core workflow gets the one piece of emphasis in the bar. Restrained on
   purpose: a tinted chip behind the icon, not a raised floating circle. */
.bottom-nav-item.is-primary .icon {
  color: var(--color-primary);
}
.bottom-nav-item.is-primary .bottom-nav-icon-wrap {
  background: var(--color-primary-50);
  border-radius: var(--radius-md);
  padding: 3px 10px;
}
.bottom-nav-item.is-primary.active .bottom-nav-icon-wrap {
  background: var(--color-primary);
}
.bottom-nav-item.is-primary.active .icon { color: var(--color-on-primary); }

/* ---- Profile sheet (opened from the header avatar) ---- */
.profile-sheet-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding-bottom: var(--sp-4);
  margin-bottom: var(--sp-2);
  border-bottom: 1px solid var(--color-border);
}
.profile-sheet-head .avatar {
  width: 48px; height: 48px;
  border-radius: var(--radius-full);
  background: var(--color-primary-50);
  color: var(--color-primary-dark);
  display: flex; align-items: center; justify-content: center;
  font-weight: var(--fw-semibold);
  font-size: var(--fs-md);
  flex-shrink: 0;
}
.profile-sheet-meta { min-width: 0; }
.profile-sheet-name { font-weight: var(--fw-semibold); font-size: var(--fs-md); overflow-wrap: break-word; }
.profile-sheet-sub { font-size: var(--fs-sm); color: var(--color-text-muted); overflow-wrap: break-word; }
.profile-sheet-actions { display: flex; flex-direction: column; gap: var(--sp-1); }
.profile-sheet-actions .nav-link { width: 100%; }

/* ---- Responsive helpers ---- */
.hide-mobile { display: none; }
@media (min-width: 640px) { .hide-mobile { display: initial; } }
.hide-desktop { display: initial; }
@media (min-width: 640px) { .hide-desktop { display: none; } }

/* ==========================================================================
   THEME TOGGLE

   Two forms of the same control:
   - Default: a full-width row inside the profile sheet, styled as a .nav-link
     with a switch on the right — it sits among Change Password and Log Out
     and reads as one of them.
   - .theme-toggle-compact: an icon-only button for the login and
     change-password screens, which have no menu to put a row in.

   Both are real <button>s with aria-pressed, so keyboard and screen-reader
   users get the state, not just the picture.
   ========================================================================== */
.theme-toggle {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--touch-target);
  background: none;
  border: none;
  font-family: inherit;
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  color: var(--color-nav-text);
  cursor: pointer;
  text-align: left;
}
.theme-toggle .icon { color: var(--color-text-faint); }
.theme-toggle:hover { background: var(--color-surface-raised); color: var(--color-text); }
.theme-toggle:hover .icon { color: var(--color-text); }
.theme-toggle-label { flex: 1; min-width: 0; }
.theme-toggle-icon { display: flex; flex-shrink: 0; }

/* The switch is decorative — the button itself carries the state — so it is
   aria-hidden and sized to read at a glance rather than to be aimed at. */
.theme-toggle-switch {
  flex-shrink: 0;
  width: 42px;
  height: 24px;
  border-radius: var(--radius-full);
  background: var(--color-border-strong);
  padding: 3px;
  display: flex;
  transition: background var(--transition-base);
}
.theme-toggle-knob {
  width: 18px;
  height: 18px;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-base);
}
.theme-toggle[aria-pressed="true"] .theme-toggle-switch { background: var(--color-primary); }
.theme-toggle[aria-pressed="true"] .theme-toggle-knob { transform: translateX(18px); }
@media (prefers-reduced-motion: reduce) {
  .theme-toggle-switch, .theme-toggle-knob { transition: none; }
}

/* Compact form: floats top-right of the auth screens. Fixed rather than
   absolute so it stays put while the card scrolls on a short phone. */
.theme-toggle-compact {
  position: fixed;
  top: var(--sp-3);
  right: var(--sp-3);
  z-index: 100;
  width: var(--touch-target);
  height: var(--touch-target);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.theme-toggle-compact:hover { color: var(--color-text); border-color: var(--color-border-strong); }
.theme-toggle-compact .icon { color: currentColor; }
/* Clear of the split-screen showcase panel, which starts at 1024px. */
@media (min-width: 1024px) {
  .theme-toggle-compact { top: var(--sp-4); right: var(--sp-4); }
}

/* ---- Registration + auth secondary actions ----
   The registration card is taller and denser than the login card, so it gets
   a wider maximum and a section rhythm. Everything else here is shared with
   the login screen. */
.auth-card-wide { max-width: 520px; }

.form-section-title {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-faint);
  padding-bottom: var(--sp-2);
  margin: var(--sp-5) 0 var(--sp-4);
  border-bottom: 1px solid var(--color-border);
}
.form-section-title:first-of-type { margin-top: 0; }

.register-notice {
  background: var(--color-info-bg);
  color: var(--color-info);
  border-radius: var(--radius-md);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  line-height: var(--lh-base);
}

.register-done { text-align: center; }
.register-done .modal-title { margin-bottom: var(--sp-2); }
.register-done p { margin-bottom: var(--sp-5); line-height: var(--lh-base); }

/* "New company? Create Company Account" under the login form, and its
   counterpart on the registration screen. */
.auth-alt-action {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  margin-top: var(--sp-5);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--color-border);
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}
.auth-alt-action a {
  font-weight: var(--fw-semibold);
  /* A link acting as a secondary action still needs a real touch target. */
  min-height: var(--touch-target);
  display: inline-flex;
  align-items: center;
}
