/* The number face, served from our own fonts/ folder — see fonts/fonts.css for
   why. An @import must come before every other rule in the sheet, hence line
   one. Relative to THIS file, so it resolves to /pos1/fonts/ from any page. */
@import url('fonts/fonts.css');

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

:root {
  --glass-bg: rgba(255, 255, 255, 0.38);
  --glass-border: rgba(100, 160, 220, 0.30);
  --glass-shadow: rgba(60, 100, 180, 0.18);
  --text-primary: #0d2a52;
  --text-secondary: rgba(30, 70, 130, 0.75);
  --accent: #1a5fa8;
  --accent2: #2980d4;

  /* House blue — names, headings and key identifiers.
     Deliberately a separate token from --accent even though the value matches:
     repairs.css and activerepairs.css both override --accent to orange, so
     var(--accent) does NOT resolve to blue on those pages. Use --brand-blue
     anywhere the colour itself is the point. */
  --brand-blue: #1a5fa8;

  /* ── The house "liquid" motion ────────────────────────────────────────────
     One curve for anything that ARRIVES and should feel like it settled rather
     than stopped: a panel dropping open, a sheet coming up, a search box
     unfolding. The 1.12 control point carries the value a little past its
     target and lets it come back — that overshoot is the whole effect.

     Written out by hand in three places in repairs.css before it had a name
     (the brand panel, the parts search, the toolbar); they all read it from
     here now, so the feel cannot drift between them.

     Not for fades. Overshooting past opacity 1 does nothing, and the curve
     just reads as a slow ease — use plain `ease` for those.

     Durations that go with it, from what already works:
       .42s  a panel or sheet arriving
       .52s  something unfolding along its own length
       .30s  a small control answering a press */
  --ease-liquid: cubic-bezier(.22, 1.12, .36, 1);

  /* House type stack: SF Mono, for everything.

     One face. It is self-hosted (the @import at the top of this file), so
     every page gets the same files on both laptops and nothing depends on
     Google Fonts being reachable. Two tokens are kept so UI text and figures
     can be told apart in the CSS, and so they could diverge again later
     without touching every rule; today they resolve to the same face. The
     fallbacks only matter if the files fail to load. */
  --font-ui:  'SF Mono', ui-monospace, Menlo, Consolas, 'Courier New', monospace;
  --font-num: 'SF Mono', ui-monospace, Menlo, Consolas, 'Courier New', monospace;

  /* Soft-material tokens — surfaces keep a hint of the backdrop but drop the
     blur, so contrast and render cost both improve. Nothing uses these unless a
     stylesheet opts in (see repairs/soft.css). */
  --surface:   rgba(255, 255, 255, 0.93);
  --surface-2: rgba(255, 255, 255, 0.97);
  --hairline:  rgba(120, 140, 170, 0.20);

  --e1: 0 1px 2px rgba(13, 42, 82, .05), 0 2px 8px rgba(13, 42, 82, .06);
  --e2: 0 2px 4px rgba(13, 42, 82, .06), 0 8px 20px rgba(13, 42, 82, .10);
  --e3: 0 24px 60px rgba(13, 42, 82, .22);
  --inset: inset 0 1px 3px rgba(13, 42, 82, .10);
}

html, body {
  height: 100%;
  font-family: var(--font-ui);
  color: var(--text-primary);
}

/* Base for every icon from icons.php. Lives here rather than in dashboard.css
   so the set works on any page that loads index.css — which is all of them.
   `color: inherit` is the whole point: the SVG fills with currentColor, so an
   icon takes the colour of whatever it sits in and follows the theme for free. */
.pos-icon {
  display: inline-block;
  vertical-align: middle;
  color: inherit;
  flex-shrink: 0;
}

/* The old photo background (1234.png) went on 2026-09-29: it painted for the
   half-second before apple.css arrived and read as an overlay flashing on
   every reload. The body starts on the theme's canvas from the first frame;
   a device on the dark theme says so on <html> before the body paints. */
body {
  background: #fdffff;   /* Business White trial (2026-09-29); was #f5f5f7 */
  min-height: 100vh;
  overflow-x: hidden;
}
html[data-boot-dark], html[data-boot-dark] body { background: #080808 !important; }


/* Main content wrapper */
.main-content {
  margin-left: 64px;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 90px 24px 32px;
}

/* Sidebar */

.sidenav {
  position: fixed;
  top: 0; left: 0;
  height: 100vh;
  width: 64px;
  /* 98, one step under the top bar's 99 (2026-09-23): the bar now runs over
     the rail's top 64px, and the two meet at the corner with the bar on top.
     Still above the page, which is where the rail's hover expansion needs to
     be. */
  z-index: 98;
  display: flex;
  flex-direction: column;
  /* ── The rail, rebuilt (Luis, 2026-09-21) ────────────────────────────────
     Flat #f5f5f7 with a hairline edge, in place of a translucent white over a
     blur and a blue-cast drop shadow. The blur was doing real work when the
     rail floated over content; it is a solid surface now, and blurring a solid
     colour only costs a compositor layer.

     The ground is the page's own tone deliberately — the rail is not a card
     sitting on the page, it is the edge of it. What lifts is the ACTIVE item,
     which is the one thing here that should read as raised. */
  background: rgb(245, 245, 247);
  box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.06);
  overflow: hidden;
  transition: width 0.38s cubic-bezier(0.4, 0, 0.2, 1);
}

.sidenav:hover {
  width: 220px;
}

/* Pinned open: the rail holds its full width and the page moves over to make
   room. sidenav.php puts the class on <html> from a choice saved on the device,
   before the rail is parsed, so a pinned rail is full width from the first
   frame. These three numbers — rail, topbar's left edge, content's left margin
   — are the only places the layout knows the rail's width; keep them together.
   The label rules mirror .sidenav:hover below, so labels stay put rather than
   fading in and out as the pointer crosses the rail. */
html.nav-pinned .sidenav      { width: 220px; }
/* Stays at 0 (2026-09-24): the bar runs corner to corner over the rail now,
   pinned or not — this used to push it out to 220px, which put the old
   "strip beside a column" layout back the moment the rail was pinned. */
html.nav-pinned .topbar       { left: 0; }
html.nav-pinned .main-content { margin-left: 220px; }
html.nav-pinned .nav-label,
html.nav-pinned .nav-badge    { opacity: 1; transform: translateX(0); }
html.nav-pinned .nav-section-label { opacity: 1; }

/* Logo spacer (brand moved to topbar) */
.nav-logo-spacer {
  /* The top bar runs over the rail's first 64px now (2026-09-23), so the
     icons start beneath it: the bar's height plus the 16px of air the rail
     always had above its first item. Change the bar's height and this moves
     with it — it is the one place the two geometries meet. */
  min-height: calc(64px + 16px);
}

/* Nav sections */
.nav-section {
  flex: 1;
  padding: 12px 0;
  overflow: hidden;
}

.nav-section-label {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-secondary);
  padding: 10px 0 6px 22px;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.2s ease 0.05s;
}

.sidenav:hover .nav-section-label {
  opacity: 1;
}

/* Nav items */
/* Each row is its own rounded tile rather than a full-bleed band, which is what
   lets the active one read as an object lying on the rail instead of a stripe
   painted across it.

   The 8px side margin is what makes a 64px rail still show a 48px tile — the
   icon stays centred in that 48 whether the rail is folded or open, so nothing
   shifts sideways when it expands. */
.nav-item {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 2px 8px;
  padding: 10px 0 10px 12px;
  cursor: pointer;
  border-radius: 14px;
  text-decoration: none;
  color: #6e6e73;
  white-space: nowrap;
  overflow: hidden;
  position: relative;
  background: transparent;
  transition: color .18s ease, background .18s ease, box-shadow .18s ease;
}

/* The orange left bar is gone with the orange. A rail that marks its place with
   a coloured stripe AND a tile is saying the same thing twice. */
.nav-item::before { content: none; }

.nav-item:hover {
  color: #1d1d1f;
  background: rgba(0, 0, 0, 0.04);
}

/* The one raised thing on the rail: white, above its ground, with the ink and
   the weight to match. Two shadows — a tight contact and a soft body — the same
   pair the checkout slabs use, scaled down. */
.nav-item.active {
  color: #1d1d1f;
  font-weight: 600;
  background: #ffffff;
  box-shadow: 0 1px 2px rgba(31, 45, 61, .10),
              0 6px 14px rgba(31, 45, 61, .10);
}

/* The icons are inline SVG on currentColor now, so the slot carries no
   treatment of its own. Everything here was for the PNGs it used to hold: a
   grayscale filter to mute them, a blue drop-shadow to fake depth, and an inset
   white ring to sit them in a dish. On a stroked glyph the filter greys a
   colour that is already inherited, and the shadow prints a blue ghost behind
   every line. */
.nav-icon {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: inherit;
}
/* Nothing to do: the glyph is currentColor, so it follows the row's own colour
   change and needs no rule of its own. Kept as a note because the selector
   existing and doing nothing is less confusing than it vanishing. */

/* ── Labels: plum into ink on the selected row (Luis, 2026-09-21) ────────────
   The gradient was blue into red, and it was on EVERY label all the time —
   what changed between a resting row and the current one was not the colour
   but a grayscale filter over it. That is why the resting labels read darker
   than the #6e6e73 the row is set to: they were not that grey at all, they
   were the blue-red ramp with its colour drained, which lands around #43.

   Two things are wanted instead, so they are separated:

   · at rest, the row's own #6e6e73 — inherited, so the label finally agrees
     with the icon beside it;
   · when selected, plum into ink.

   The mechanism is -webkit-text-fill-color, not the filter. The gradient stays
   painted underneath at all times and the fill colour is what hides or reveals
   it: opaque grey at rest covers it, transparent lets it through. Done the
   obvious way instead — gradient only on the selected rule — the change would
   snap, because a background going from a colour to a gradient does not
   interpolate. A fill COLOUR does, so the grey fades out over a quarter second
   and the plum comes up through it.

   The ramp holds plum to 35% before turning: these labels are one or two short
   words, and a ramp that starts turning immediately leaves no plum to see. */
.nav-label {
  font-size: 13px;
  font-weight: 500;
  background: linear-gradient(90deg, #6b3744 0%, #6b3744 35%, rgb(29, 29, 31) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: #6e6e73;
  opacity: 0;
  margin-left: 6px;
  transform: translateX(-6px);
  transition: opacity 0.22s ease 0.08s, transform 0.22s ease 0.08s,
              -webkit-text-fill-color 0.25s ease;
}
.nav-item:hover .nav-label,
.nav-item.active .nav-label {
  -webkit-text-fill-color: transparent;
}

.nav-badge {
  margin-left: auto;
  margin-right: 14px;
  font-size: 10px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 100px;
  background: rgba(26, 95, 168, 0.12);
  color: var(--accent);
  border: 1px solid rgba(26,95,168,0.2);
  opacity: 0;
  transition: opacity 0.2s ease 0.1s;
  white-space: nowrap;
}

.sidenav:hover .nav-label,
.sidenav:hover .nav-badge {
  opacity: 1;
  transform: translateX(0);
}

/* Divider */
.nav-divider {
  height: 1px;
  background: var(--glass-border);
  margin: 8px 14px;
}

/* Bottom user area */
.nav-user {
  border-top: 1px solid var(--glass-border);
  padding: 14px 0 14px 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  overflow: hidden;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.2s;
}

.nav-user:hover {
  background: rgba(26, 95, 168, 0.06);
}

.nav-user-avatar {
  width: 40px; height: 40px;
  border-radius: 50%;
  border: 1.5px solid rgba(26, 95, 168, 0.3);
  background: rgba(26, 95, 168, 0.12);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--accent);
  flex-shrink: 0;
}

.nav-user-info {
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 0.22s ease 0.08s, transform 0.22s ease 0.08s;
}

.sidenav:hover .nav-user-info {
  opacity: 1;
  transform: translateX(0);
}

.nav-user-name {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-primary);
  line-height: 1.2;
}

.nav-user-role {
  font-size: 10.5px;
  color: var(--text-secondary);
}



/* ── Header ── */
header {
  position: relative;
  z-index: 1;
  text-align: center;
  margin-bottom: 56px;
  animation: fadeDown 0.8s ease both;
}

header .eyebrow {
  font-family: var(--font-ui);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--accent2);
  margin-bottom: 10px;
}

header h1 {
  font-family: var(--font-ui);
  font-weight: 300;
  font-size: clamp(2.4rem, 5vw, 4rem);
  letter-spacing: -0.01em;
  line-height: 1.05;
  color: var(--text-primary);
}

header h1 em {
  font-style: italic;
  color: var(--accent);
}

/* ── Stats Row ── */
.stats-row {
  position: relative;
  z-index: 1;
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  justify-content: center;
  margin-bottom: 20px;
  width: 100%;
  max-width: 900px;
}

.stat-chip {
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  background: rgba(255, 255, 255, 0.40);
  border: 1px solid var(--glass-border);
  border-radius: 100px;
  padding: 10px 22px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  animation: fadeUp 0.7s ease both;
  transition: transform 0.2s ease, background 0.2s ease;
}

.stat-chip:hover {
  transform: translateY(-2px);
  background: rgba(255,255,255,0.55);
}

.stat-chip .dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.dot-dark   { background: #2d2d2d; box-shadow: 0 0 8px #2d2d2d88; }
.dot-red    { background: #d43030; box-shadow: 0 0 8px #d4303088; }
.dot-orange { background: #e07a20; box-shadow: 0 0 8px #e07a2088; }
.dot-green  { background: #00b87a; box-shadow: 0 0 8px #00b87a88; }
.dot-pink   { background: #1a5fa8; box-shadow: 0 0 8px #1a5fa888; }
.dot-blue   { background: #2980d4; box-shadow: 0 0 8px #2980d488; }
.dot-yellow { background: #c89000; box-shadow: 0 0 8px #c8900088; }

.chip-num { font-weight: 700; }
.chip-dark   { color: #2d2d2d; }
.chip-red    { color: #d43030; }
.chip-orange { color: #e07a20; }
.chip-green  { color: #00b87a; }
.chip-pink   { color: #1a5fa8; }
.chip-blue   { color: #2980d4; }
.chip-yellow { color: #c89000; }

/* ── Card Grid ── */
.grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 20px;
  width: 100%;
  max-width: 900px;
}

/* Glass card base */
.card {
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(7px);
-webkit-backdrop-filter: blur(7px);
border: 1px solid rgba(255, 255, 255, 1);
  padding: 28px;
  box-shadow: 0 8px 32px var(--glass-shadow), inset 0 1px 0 rgba(255,255,255,0.7);
  transition: transform 0.3s ease, box-shadow 0.3s ease, background 0.3s ease;
  animation: fadeUp 0.7s ease both;
}

.card:hover {
  transform: translateY(-6px) scale(1.01);
  background: rgba(255, 255, 255, 0.55);
  box-shadow: 0 16px 48px rgba(60, 100, 200, 0.22), inset 0 1px 0 rgba(255,255,255,0.8);
}

/* Staggered animation delays */
.card:nth-child(1) { animation-delay: 0.1s; }
.card:nth-child(2) { animation-delay: 0.2s; }
.card:nth-child(3) { animation-delay: 0.3s; }
.card:nth-child(4) { animation-delay: 0.4s; }
.card:nth-child(5) { animation-delay: 0.5s; }
.card:nth-child(6) { animation-delay: 0.6s; }

.stat-chip:nth-child(1) { animation-delay: 0.05s; }
.stat-chip:nth-child(2) { animation-delay: 0.1s; }
.stat-chip:nth-child(3) { animation-delay: 0.15s; }
.stat-chip:nth-child(4) { animation-delay: 0.2s; }

/* Sync dashboard button */
.sync-dash-btn {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(255, 255, 255, 0.25);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: var(--text-secondary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.25s ease;
  z-index: 2;
}
.sync-dash-btn:hover {
  background: rgba(26, 95, 168, 0.12);
  border-color: rgba(26, 95, 168, 0.3);
  color: var(--accent);
  transform: scale(1.1);
  box-shadow: 0 3px 12px rgba(26, 95, 168, 0.15);
}
.sync-dash-btn:active {
  transform: scale(0.92);
}
.sync-dash-btn.syncing svg {
  animation: syncSpin 0.7s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes syncSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Card elements */
.card-icon {
  font-size: 28px;
  margin-bottom: 14px;
  display: block;
}

/* Card tabs */
.card-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid rgba(100, 160, 220, 0.15);
  margin: -16px -20px 14px;
  padding: 0 20px;
}
.card-tab {
  padding: 10px 18px;
  font-size: 12px;
  font-weight: 600;
  font-family: var(--font-ui);
  color: var(--text-secondary);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}
.card-tab:hover {
  color: var(--text-primary);
}
.card-tab.active {
  color: var(--text-primary);
  border-bottom-color: var(--accent);
}
.card-tab-panel {
  display: none;
}
.card-tab-panel.active {
  display: block;
}

.card-label {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 6px;
}

.card-title {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 1.55rem;
  line-height: 1.2;
  margin-bottom: 10px;
}

.card-value {
  font-family: var(--font-ui);
  font-weight: 300;
  font-size: 2.8rem;
  line-height: 1;
  margin-bottom: 6px;
  color: var(--accent);
}

.card-value sup {
  font-size: 1rem;
  opacity: 0.7;
  vertical-align: super;
}

.card-desc {
  font-size: 13px;
  font-weight: 300;
  color: var(--text-secondary);
  line-height: 1.6;
}

/* Progress bar */
.progress-wrap {
  margin-top: 16px;
}
.progress-label {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--text-secondary);
  margin-bottom: 6px;
}
.progress-bar {
  height: 4px;
  border-radius: 4px;
  background: rgba(255,255,255,0.15);
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--accent), var(--accent2));
  transition: width 1.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Tag badges */
.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 14px;
}
.tag {
  font-size: 11px;
  font-weight: 500;
  padding: 4px 10px;
  border-radius: 100px;
  border: 1px solid rgba(26, 95, 168, 0.25);
  background: rgba(26, 95, 168, 0.08);
  color: var(--accent);
  letter-spacing: 0.04em;
}

/* Sparkline (pure CSS bars) */
.sparkline {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 36px;
  margin-top: 16px;
}
.spark-bar {
  flex: 1;
  border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent2) 100%);
  opacity: 0.55;
  transition: opacity 0.2s;
}
.spark-bar:hover { opacity: 0.9; }

/* Divider */
.card-divider {
  height: 1px;
  background: var(--glass-border);
  margin: 16px 0;
}

/* User row */
.user-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 1.5px solid rgba(26, 95, 168, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  background: rgba(26, 95, 168, 0.1);
  flex-shrink: 0;
}
.user-info .name {
  font-size: 13px;
  font-weight: 500;
}
.user-info .role {
  font-size: 11px;
  color: var(--text-secondary);
}

/* Wide card spanning 2 cols */
.card-wide {
  grid-column: span 2;
}

@media (max-width: 600px) {
  .card-wide { grid-column: span 1; }
}

/* ── Sales Table ── */
.table-wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 900px;
  margin-top: 28px;
  backdrop-filter: blur(28px) saturate(180%);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 20px;
  padding: 28px;
  box-shadow: 0 8px 32px var(--glass-shadow), inset 0 1px 0 rgba(255,255,255,0.7);
  animation: fadeUp 0.7s ease 0.65s both;
}

/* Three columns rather than two ends (Luis, 2026-09-15). Pushed apart with
   space-between, the pill sat hard against the right edge; centring it by any
   flex trick would only centre it in the space the title left over, so it
   would drift as the date and the count changed width. The two 1fr rails are
   equal by definition, so the middle column lands on the row's true centre.
   The third column holds nothing and exists to balance the first. */
.table-header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  margin-bottom: 20px;
}
/* The middle column holds the title AND the count, centred as a pair
   (Luis, 2026-09-16). The badge used to be the middle child on its own;
   it is nested now, so this centres the wrapper instead and the old
   `> .table-badge` rule would no longer match anything. */
.table-header > .table-head-mid {
  justify-self: center;
  display: flex;
  align-items: center;
  gap: 14px;
}
/* The title carries block margins of its own in some themes, which would
   drop it off the badge's centre line. */
.table-head-mid > .table-title { margin: 0; }
/* The other end of the row: the day, as a calendar page. Raised off the
   surface rather than sitting flat on it, because it is the one thing in this
   header you can press. The shadow is the affordance, so it deepens on hover
   and collapses on the press. */
/* ── The house hover label ──────────────────────────────────────────────────
 *
 * A small pill above the control, carrying its name. Replaces the browser's own
 * tooltip, which arrives a second late, in the system font, wherever the
 * pointer happens to be — this appears at once and where the control is.
 *
 * Copied from .mp-tab-label on the repairs checkout (repairs.css), which is
 * where it was first drawn; the geometry and the timings are the same so the
 * two cannot drift into looking merely similar.
 *
 *     <button class="pos-pop-host"> … <span class="pos-pop">Label</span></button>
 *
 * Put the real name in the span rather than in a title attribute. It stays in
 * the accessibility tree and still gives an icon-only button its accessible
 * name, which is what lets the title be removed rather than left to fire
 * underneath this a second later.
 *
 * The host must carry no filter and no transform: both make it the containing
 * block AND apply to descendants, so the label would pick up the host's shadow
 * and scale with its press. Hang the label off a clean wrapper in that case and
 * show it with a sibling selector.
 */
.pos-pop-host { position: relative; overflow: visible; }

.pos-pop {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  padding: 5px 10px;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 6px 18px rgba(31, 45, 61, 0.18), 0 0 0 1px rgba(31, 45, 61, 0.06);
  font-family: var(--font-ui, inherit);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: #1f2d3d;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(10px) scale(.72);
  filter: blur(7px);
  transform-origin: 50% 120%;
  transition: opacity .12s ease, transform .16s ease, filter .12s ease;
  z-index: 40;
}

.pos-pop-host:hover > .pos-pop,
.pos-pop-host:focus-visible > .pos-pop,
.pos-pop-trigger:hover ~ .pos-pop,
.pos-pop-trigger:focus-visible ~ .pos-pop {
  opacity: 1;
  transform: translateX(-50%) translateY(0) scale(1);
  filter: blur(0);
  /* The swell is on the way IN only. Reversing a .38s curve on the way out
     leaves the name hanging after the pointer has gone, which reads as lag
     rather than polish — the resting rule tidies it away in a third of that. */
  transition: opacity .2s ease,
              transform .38s var(--ease-liquid),
              filter .26s ease;
}

@media (prefers-reduced-motion: reduce) {
  .pos-pop { transition: opacity .1s ease; transform: translateX(-50%); filter: none; }
  .pos-pop-host:hover > .pos-pop,
  .pos-pop-trigger:hover ~ .pos-pop { transform: translateX(-50%); filter: none; }
}

/* The button and the calendar that hangs off it share one anchor, so the
   panel can be positioned against the button rather than against the header. */
.table-header > .cal-dock { justify-self: end; position: relative; }

.cal-dock > .cal-btn {
  display: inline-grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  line-height: 0;
  cursor: pointer;
  border-radius: 14px;
  /* Engraved, not raised (Luis, 2026-09-15), and both edges of the cut are
     white rather than one of them black (Luis, same day). The house engrave
     puts a dark wall up and left, which against this pale ground read as a
     smudge sitting under the corner rather than as depth. Two soft whites at
     opposing offsets keep the moulded edge and leave nothing grey behind.
     Written out rather than taken from --ap-engrave-filter because that token
     only exists under .apple-mode and this header is drawn in every theme.
     Hovering opens the cut instead of lifting the card — a thing set INTO a
     surface does not float up when you point at it. */
  filter: drop-shadow(-1.5px -1.5px 1.5px rgba(255, 255, 255, 0.90)) drop-shadow(1.5px 2px 1.5px rgba(255, 255, 255, 0.95));
  transition: transform .16s ease, filter .16s ease;
}
.cal-dock > .cal-btn:hover  { transform: scale(1.04); filter: drop-shadow(-2px -2px 2px rgba(255, 255, 255, 1)) drop-shadow(2px 2.5px 2px rgba(255, 255, 255, 1)); }
.cal-dock > .cal-btn:active { transform: scale(.97);  filter: drop-shadow(-1px -1px 1px rgba(255, 255, 255, 0.95)) drop-shadow(1px 1px 1px rgba(255, 255, 255, 0.90)); }
.cal-dock > .cal-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
  .cal-dock > .cal-btn { transition: none; }
  .cal-dock > .cal-btn:hover, .cal-dock > .cal-btn:active { transform: none; }
}

/* ── The calendar that hangs off the button (Luis, 2026-09-15) ─────────────
   A second view of the card's calendar, not a copy: index.php paints both
   grids from one render. The card below is left where it is on purpose —
   this is a trial of whether that space is better spent elsewhere.

   It grows OUT of the button. The origin is set half a button width in from
   the right and a little above the panel's own top edge, which is where the
   button physically is, so the panel appears to unfold from under it rather
   than to fade in beneath it. The overshoot in the curve and the blur clearing
   as it arrives are what make that read as liquid rather than as a zoom. */
.cal-pop {
  /* Fixed, and moved out to <body> by the script — .table-wrap is
     overflow:hidden and was slicing the last two rows of days off. Its top and
     left are written by place(), against the button. */
  position: fixed;
  z-index: 3000;
  width: 280px;
  opacity: 0;
  transform: scale(.34) translateY(-20px);
  filter: blur(7px);
  pointer-events: none;
  transition: opacity .18s ease,
              transform .42s cubic-bezier(.22, 1.16, .36, 1),
              filter .24s ease;
}
.cal-pop[hidden] { display: none; }
.cal-pop.is-open { opacity: 1; transform: scale(1) translateY(0); filter: blur(0); pointer-events: auto; }

.cal-pop-card {
  padding: 16px 15px 14px;
  border-radius: 18px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: 0 20px 48px rgba(13, 42, 82, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(26px) saturate(180%);
  -webkit-backdrop-filter: blur(26px) saturate(180%);
}

@media (prefers-reduced-motion: reduce) {
  .cal-pop { transition: opacity .12s ease; transform: none; filter: none; }
  .cal-pop.is-open { transform: none; }
}

/* Where the button used to land before it opened the calendar itself. Kept:
   the ring still marks the card when anything else sends you to it. */
.card-calendar.cal-flash { animation: calFlash 1.4s ease-out 1; }
@keyframes calFlash {
  0%   { box-shadow: 0 0 0 0 rgba(192, 52, 58, 0.55); }
  100% { box-shadow: 0 0 0 14px rgba(192, 52, 58, 0); }
}

.table-title {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 1.45rem;
  color: var(--text-primary);
}

.table-subtitle {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

.table-badge {
  font-size: 11px;
  font-weight: 500;
  padding: 5px 14px;
  border-radius: 100px;
  border: 1px solid rgba(26, 95, 168, 0.25);
  background: rgba(26, 95, 168, 0.08);
  color: var(--accent);
}

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

thead th {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-secondary);
  text-align: left;
  padding: 0 12px 12px 12px;
  border-bottom: 1px solid var(--glass-border);
}

thead th:last-child { text-align: right; }

tbody tr {
  transition: background 0.18s ease;
}

tbody tr:hover td {
  background: rgba(26, 95, 168, 0.05);
}

tbody tr:hover td:first-child { border-radius: 10px 0 0 10px; }
tbody tr:hover td:last-child  { border-radius: 0 10px 10px 0; }

tbody td {
  font-size: 13.5px;
  color: var(--text-primary);
  padding: 13px 12px;
  border-bottom: 1px solid rgba(100, 160, 220, 0.12);
  vertical-align: middle;
}

tbody tr:last-child td { border-bottom: none; }
tbody td:last-child { text-align: right; }

.td-rep {
  display: flex;
  align-items: center;
  gap: 10px;
}

.rep-avatar {
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid rgba(26, 95, 168, 0.25);
  background: rgba(26, 95, 168, 0.1);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px;
  font-weight: 700;
  flex-shrink: 0;
  color: var(--accent);
}

.rep-name   { font-weight: 500; font-size: 13.5px; line-height: 1.2; }
.rep-region { font-size: 11px; color: var(--text-secondary); }

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 500;
  padding: 3px 10px;
  border-radius: 100px;
}

.status-pill.won    { background: rgba(0,138,90,0.10); color: #007a50; border: 1px solid rgba(0,138,90,0.22); }
.status-pill.lost   { background: rgba(200,40,40,0.08); color: #b52020; border: 1px solid rgba(200,40,40,0.18); }
.status-pill.open   { background: rgba(26,95,168,0.08); color: var(--accent); border: 1px solid rgba(26,95,168,0.20); }
.status-pill.review { background: rgba(180,130,0,0.08); color: #8a6200; border: 1px solid rgba(180,130,0,0.20); }

.status-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.status-pill.won    .status-dot { background: #007a50; }
.status-pill.lost   .status-dot { background: #b52020; }
.status-pill.open   .status-dot { background: var(--accent); }
.status-pill.review .status-dot { background: #8a6200; }

.amount-val {
  font-family: var(--font-ui);
  font-size: 1.15rem;
  font-weight: 600;
}

.amount-pos { color: #007a50; }
.amount-neg { color: #b52020; }
.amount-neu { color: var(--text-primary); }

.table-footer-row td {
  border-top: 1px solid var(--glass-border);
  border-bottom: none;
  padding-top: 14px;
  font-size: 11.5px;
  color: var(--text-secondary);
  font-weight: 400;
}

.foot-total {
  font-family: var(--font-ui);
  font-size: 1.3rem;
  font-weight: 600;
  color: var(--accent);
  text-align: right;
}

/* Animations */
@keyframes fadeDown {
  from { opacity: 0; transform: translateY(-20px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Logout button ── */
.nav-logout {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 13px 0 13px 18px;
  cursor: pointer;
  text-decoration: none;
  color: rgba(180, 40, 40, 0.7);
  white-space: nowrap;
  overflow: hidden;
  border-top: 1px solid var(--glass-border);
  transition: color 0.2s ease, background 0.2s ease;
}

.nav-logout:hover {
  color: #b52020;
  background: rgba(200, 40, 40, 0.06);
}

.nav-logout .nav-label {
  font-size: 13px;
  font-weight: 400;
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 0.22s ease 0.08s, transform 0.22s ease 0.08s;
}

.sidenav:hover .nav-logout .nav-label {
  opacity: 1;
  transform: translateX(0);
}

/* ═══════════════════════════════════════════════════════════════
   TOPBAR
═══════════════════════════════════════════════════════════════ */

.topbar {
  position: fixed;
  top: 0;
  /* Corner to corner (Luis, 2026-09-23): the bar starts at the window's left
     edge and runs over the top of the rail, rather than starting beside it at
     64px. The frame's top edge should be one piece; a bar that begins where
     the rail ends reads as a strip next to a column. The rail's icons start
     below the bar — .nav-logo-spacer holds the 64px — and the rail sits one
     step under the bar in stacking so the bar wins at the corner. */
  left: 0;
  right: 0;
  height: 64px;
  z-index: 99;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  /* ── Ground: the bar is the rail turned sideways (Luis, 2026-09-21) ───────
     Same rgb(245,245,247), same reasoning. This was a pale blue wash over a
     backdrop blur; the blur earned its keep while the bar was translucent and
     content scrolled under it, but a solid colour has nothing to see through,
     so all it bought was a compositor layer on a fixed element that spans the
     window.

     The hairline is the only thing separating the bar from the page now, both
     being the same tone — the rail draws its edge the same way. Black at 6%
     rather than a blue: a tinted line on an untinted ground reads as a colour
     choice, and there is no longer any blue here for it to belong to. */
  /* ── Ground: the bar is the rail turned sideways (Luis, 2026-09-21) ───────
     Same rgb(245,245,247), same reasoning. This was a pale blue wash over a
     backdrop blur; the blur earned its keep while the bar was translucent and
     content scrolled under it, but a solid colour has nothing to see through.

     The hairline is the only thing separating the bar from the page, both
     being the same tone — the rail draws its edge the same way. Black at 6%
     rather than a blue: a tinted line on an untinted ground reads as a colour
     choice, and there is no blue here for it to belong to.

     2026-09-23: a day of other grounds was tried here — silver, ink, a light
     grey — and this theme came back to the canvas. The Apple theme, which is
     the one in daily use, took the ink bar instead (apple.css); the two
     themes now differ on purpose, because this one's pills and icons were
     drawn for a light ground and would shout on a dark one. */
  background: rgb(245, 245, 247);
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  padding: 0 28px;
  animation: fadeDown 0.6s ease both;
}

/* The two white diagonal wedges are gone with the wash. They were flanking a
   translucent bar with something opaque to sit the brand and the user badge
   on; against a flat ground they are just two white blobs covering 44% of it,
   and the point of the change is to see the ground.

   Left as empty rules rather than deleted: `.topbar > *` lifts every child to
   z-index 1 to clear these, and a reader finding that rule deserves to find
   what it was clearing. All three themes had already hidden them. */
.topbar::before,
.topbar::after { content: none; }

/* All topbar children sit above the background panels */
.topbar > * {
  position: relative;
  z-index: 1;
}

/* ── Left ── */
/* Four groups, left to right: the brand, the quick links, the bells and the
   user badge, and the search. The two END columns (.topbar-left and
   .topbar-end) flex equally from a zero basis, so whatever room is left over
   splits evenly between them and the two middle groups sit centred in the
   bar as one unit. The middle groups do not flex at all. */
.topbar-left {
  display: flex;
  align-items: center;
  gap: 16px;
  min-width: 0;
  flex: 1 1 0;
}
.topbar-end {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  min-width: 0;
  flex: 1 1 0;
}

.topbar-page-title {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.topbar-eyebrow {
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-secondary);
  line-height: 1;
}

.topbar-title {
  font-family: var(--font-ui);
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.1;
  white-space: nowrap;
}

/* ── Center ── */
.topbar-center {
  display: flex;
  align-items: center;
  gap: 0;
  flex: 0 0 auto;
  height: 100%;
  min-width: 0;
}

/* ── Right ── */
.topbar-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  min-width: 0;
  justify-content: flex-start;
  margin-left: 40px;   /* daylight between the quick links and the bells */
}

.topbar-sep {
  width: 1px;
  height: 26px;
  background: rgba(100, 160, 220, 0.22);
  margin: 0 4px;
}

/* ── Diagonal dividers ── */
.topbar-diag {
  width: 24px;
  height: 64px;
  position: relative;
  flex-shrink: 0;
}

.topbar-diag::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1.5px;
  background: rgba(255, 255, 255, 0.45);
  transform: skewX(-14deg);
  transform-origin: center;
}

/* ── Center action items ── */
.topbar-action {
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 18px;
  height: 100%;
  border: none;
  background: transparent;
  cursor: pointer;
  text-decoration: none;
  color: var(--text-primary);
}

/* Skewed hover fill — same skewX as dividers so angles match exactly */
.topbar-action::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -12px;
  right: -12px;
  background: rgba(255, 255, 255, 0);
  transform: skewX(-14deg);
  transition: background 0.2s ease;
  z-index: -1;
}

.topbar-action:hover::before {
  background: rgba(255, 255, 255, 0.18);
}

.topbar-action img {
  display: block;
  flex-shrink: 0;
  position: relative;
}

.topbar-action-label {
  font-family: var(--font-ui);
  font-size: 10.5px;
  font-weight: 500;
  white-space: nowrap;
  color: var(--text-primary);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  transition: color 0.2s;
}

.topbar-action:hover .topbar-action-label {
  color: var(--accent);
}

/* ── Brand ── */
.topbar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
/* Lined up with the corner of the page below it (Luis, 2026-10-15): the page
   starts where the rail ends — 64px, or 220px with the rail pinned open —
   and the bar's own left padding is 28px, so the logo moves the difference. */
.topbar .topbar-brand { margin-left: 36px; transition: margin-left .3s ease; }
html.nav-pinned .topbar .topbar-brand { margin-left: 192px; }

.topbar-brand-logo {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 2px 10px rgba(26, 95, 168, 0.18);
}

/* The name's gradient is a token so it can be swapped without touching the
   rule. Blue→orange is the default; <html data-brand="red"> or "black" picks a
   variant — topbar.php sets that attribute from a choice saved on the device
   (visit any page with ?brand=red, ?brand=black or ?brand=blue). Both variants
   end in the same orange/grey tail as the original so they read as the same
   mark in a different ink. Black on a dark theme would vanish into the bar, so
   there it turns to silver; the red is dark enough to hold on both. */
:root                    { --brand-grad: linear-gradient(90deg, #2563EB 0%, #2563EB 40%, #F97316 100%); }
html[data-brand="red"]   { --brand-grad: linear-gradient(90deg, #b91c1c 0%, #dc2626 40%, #f97316 100%); }
html[data-brand="black"] { --brand-grad: linear-gradient(90deg, #0b1220 0%, #1f2937 40%, #6b7280 100%); }
html[data-brand="black"] body.dark-mode { --brand-grad: linear-gradient(90deg, #f8fafc 0%, #e5e7eb 40%, #9ca3af 100%); }

.topbar-brand-name {
  display: block;
  font-family: var(--font-ui);
  /* 1.7rem, up from 1.5: the name had presence to spare in a 64px bar. The
     tracking comes in a hair because a monospace set this large runs wide.
     600 is the heaviest weight the SF Mono set has, so "bolder" is not on
     the table without a Bold file — size is what carries it. */
  font-size: 1.7rem;
  font-weight: 600;
  letter-spacing: -0.01em;
      background: var(--brand-grad);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    text-shadow: 0 1px 0 rgba(170, 170, 170, 0.29);
  line-height: 1.2;
  white-space: nowrap;
}

.topbar-brand-sub {
  display: block;
  font-family: var(--font-ui);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-secondary);
  line-height: 1.2;
}

/* ── Topbar Search Bar ──
   Collapsed to the button until it is wanted. The box used to fill the middle
   of the bar; now the button sits at the right end of the quick links and the
   field slides out of it on hover, on focus, or on a click — topbar.php puts
   .is-open on the wrap for all three and takes it off again when the pointer
   leaves an EMPTY field, so a search in progress never folds away under you.
   The open field is deliberately narrower than the old one (300px) and the
   button a size larger (42px): the button is the thing you aim for. */
.topbar-search-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  margin-right: 6px;
  flex: 0 0 auto;
  width: 44px;
  min-width: 0;
  padding: 0;
  border-radius: 50px;
  background: transparent;
  border: 1px solid transparent;
  transition: width 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.2s ease,
              border-color 0.2s ease, padding 0.2s ease, box-shadow 0.2s ease;
}
.topbar-search-wrap.is-open {
  width: 300px;
  padding: 2px 2px 2px 14px;
  background: #fff;
  border-color: var(--glass-border);
}
.topbar-search-wrap.is-open:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(26, 95, 168, 0.1);
}
/* The field is BARE inside the pill, in every theme. Each theme dresses text
   inputs its own way — a well in Neumorphic, a dish in Embossed, a tinted box
   in Aurora — and every one of them would paint that box inside the capsule:
   a square in a pill. Anchored to the two ids, (2,0,0), so no class-based
   theme rule can ever outrank it; the class form is kept for any copy of the
   bar that drops the ids. appearance:none also stops the browser painting its
   own field chrome, and the radius matches the capsule so that if anything
   ever does paint the field, it is the same shape as the pill around it. */
#searchWrap #topbarSearch,
.topbar .topbar-search-wrap .topbar-search-input {
  appearance: none !important;
  -webkit-appearance: none !important;
  background: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
  border: 0 !important;
  border-radius: 50px !important;
  outline: none !important;
}
.topbar-search-icon {
  color: var(--text-secondary);
  flex-shrink: 0;
  opacity: 0.6;
}
.topbar-search-input {
  border: none;
  background: transparent;
  padding: 0;
  font-size: 12.5px;
  font-family: var(--font-ui);
  color: var(--text-primary);
  outline: none;
  flex: 1 1 auto;
  width: 0;
  min-width: 0;
  opacity: 0;
  transition: opacity 0.18s ease 0.08s;
}
.topbar-search-wrap.is-open .topbar-search-input {
  width: auto;
  padding: 7px 0;
  opacity: 1;
}
.topbar-search-input::placeholder {
  color: var(--text-secondary);
  font-weight: 400;
}
.topbar-search-btn {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: linear-gradient(135deg, #2563EB 0%, #3B82F6 100%);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: all 0.2s ease;
  box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3);
}
.topbar-search-btn:hover {
  transform: scale(1.05);
  box-shadow: 0 3px 12px rgba(37, 99, 235, 0.4);
}

/* ── Search Dropdown ── */
/* Hangs off the RIGHT edge of the (now narrow) wrap and is wider than it, so
   results have the room they had when the box filled the bar. */
.search-dropdown {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 460px;
  max-width: calc(100vw - 120px);
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  border: 1px solid var(--glass-border);
  border-radius: 14px;
  box-shadow: 0 12px 40px rgba(60, 100, 180, 0.18);
  overflow: hidden;
  max-height: 420px;
  overflow-y: auto;
  z-index: 9999;
}
.search-dropdown.open { display: block; }
.topbar-search-wrap { position: relative; }

.search-group {
  padding: 6px 0;
}
.search-group + .search-group {
  border-top: 1px solid rgba(100, 160, 220, 0.12);
}
.search-group-title {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: rgba(30, 70, 130, 0.45);
  padding: 8px 16px 4px;
}
.search-item {
  display: block;
  padding: 8px 16px;
  text-decoration: none;
  transition: background 0.12s ease;
  cursor: pointer;
}
.search-item:hover {
  background: rgba(37, 99, 235, 0.05);
}
.search-item-line1 {
  font-size: 13px;
  font-weight: 600;
  color: #0d2a52;
}
.search-item-line2 {
  font-size: 11px;
  color: rgba(30, 70, 130, 0.5);
  margin-top: 1px;
}
.search-item mark {
  background: rgba(37, 99, 235, 0.15);
  color: #2563EB;
  border-radius: 2px;
  padding: 0 1px;
}
.search-tag {
  font-family: var(--font-num);
  font-size: 12px;
  font-weight: 600;
  color: #2563EB;
}
.search-empty {
  padding: 20px;
  text-align: center;
  color: rgba(30, 70, 130, 0.4);
  font-size: 13px;
}

/* ── IMEI Quick Check (legacy) ── */
.topbar-imei-check {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: 24px;
}

.topbar-imei-input {
  width: 180px;
  padding: 10px 16px;
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--glass-border);
  border-radius: 50px;
  color: var(--text-primary);
  font-size: 13px;
  font-family: var(--font-ui);
  outline: none;
  transition: all 0.25s ease;
  letter-spacing: 0.5px;
}
.topbar-imei-input::placeholder { color: var(--text-secondary); font-weight: 400; }
.topbar-imei-input:focus { background: rgba(255,255,255,0.9); border-color: var(--accent); }

.topbar-imei-select {
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--glass-border);
  border-radius: 50px;
  color: var(--text-primary);
  font-size: 12px;
  font-family: var(--font-ui);
  outline: none;
  cursor: pointer;
  transition: all 0.25s ease;
  -webkit-appearance: none;
  appearance: none;
  padding-right: 24px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23666' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
}
.topbar-imei-select:focus { background-color: rgba(255,255,255,0.9); border-color: var(--accent); }

.topbar-imei-btn {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--accent);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.25s ease;
  box-shadow: 0 2px 10px rgba(26, 95, 168, 0.3);
  flex-shrink: 0;
}
.topbar-imei-btn:hover { background: var(--accent2); transform: scale(1.05); }

/* Loading pulse on button */
.imei-btn-loading {
  animation: imeiPulse 1s ease-in-out infinite;
  pointer-events: none;
}
@keyframes imeiPulse {
  0%, 100% { box-shadow: 0 2px 10px rgba(26, 95, 168, 0.3); }
  50% { box-shadow: 0 2px 24px rgba(26, 95, 168, 0.7); transform: scale(1.1); }
}

/* ── IMEI Status Badge ── */
.imei-status-badge {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 50px;
  border: none;
  cursor: pointer;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 600;
  transition: all 0.3s ease;
  white-space: nowrap;
}

.imei-badge-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Processing state */
.imei-badge-processing {
  background: rgba(26, 95, 168, 0.1);
  color: var(--accent);
  border: 1px solid rgba(26, 95, 168, 0.2);
  pointer-events: none;
}
.imei-badge-processing .imei-badge-dot {
  background: var(--accent);
  animation: imeiBadgePulse 1.2s ease-in-out infinite;
}
@keyframes imeiBadgePulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.3; transform: scale(0.6); }
}

/* Ready state */
.imei-badge-ready {
  background: rgba(0, 138, 90, 0.1);
  color: #008a5a;
  border: 1px solid rgba(0, 138, 90, 0.25);
  animation: imeiBadgePop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.imei-badge-ready:hover {
  background: rgba(0, 138, 90, 0.18);
  transform: scale(1.05);
}
.imei-badge-ready .imei-badge-dot {
  background: #008a5a;
}
@keyframes imeiBadgePop {
  0% { transform: scale(0.8); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

/* Error state */
.imei-badge-error {
  background: rgba(181, 32, 32, 0.1);
  color: #b52020;
  border: 1px solid rgba(181, 32, 32, 0.2);
  cursor: pointer;
}
.imei-badge-error:hover {
  background: rgba(181, 32, 32, 0.18);
}
.imei-badge-error .imei-badge-dot {
  background: #b52020;
}

/* ── IMEI notification items ── */
.imei-notif-item { cursor: pointer; }
.imei-notif-item:hover { background: rgba(26,95,168,0.08) !important; }

/* ── IMEI disabled state ── */
.imei-input-disabled {
  opacity: 0.45;
  pointer-events: none;
  background: rgba(0,0,0,0.04) !important;
}

/* ── IMEI badge clear button ── */
.imei-badge-clear {
  display: none;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: none;
  background: rgba(0,0,0,0.12);
  color: #555;
  border-radius: 50%;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  margin-left: 4px;
  transition: background 0.2s, color 0.2s;
}
.imei-badge-clear:hover {
  background: rgba(180,30,30,0.18);
  color: #b52020;
}

/* ── IMEI Result Modal ── */
.imei-result-card {
  max-width: 520px;
}
.imei-result-body {
  margin-top: 16px;
  max-height: 60vh;
  overflow-y: auto;
}

.imei-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 40px 0;
  color: var(--text-secondary);
  font-size: 14px;
}
.imei-spinner {
  width: 36px;
  height: 36px;
  border: 3px solid rgba(26, 95, 168, 0.15);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: imeiSpin 0.8s linear infinite;
}
@keyframes imeiSpin {
  to { transform: rotate(360deg); }
}

.imei-result-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid rgba(0,0,0,0.05);
}
.imei-result-row:last-child { border-bottom: none; }

.imei-result-label {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
  text-transform: capitalize;
}
.imei-result-val {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  text-align: right;
  max-width: 60%;
  word-break: break-word;
}
.imei-val-good  { color: #008a5a; }
.imei-val-error { color: #b52020; }
.imei-val-warn  { color: #c07800; }

/* ── Icon button (bell) ── */
.topbar-icon-btn {
  position: relative;
  width: 40px; height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(100, 160, 220, 0.18);
  background: rgba(230, 238, 250, 0.45);
  cursor: pointer;
  font-size: 17px;
  display: flex; align-items: center; justify-content: center;
  transition: all 0.2s ease;
  flex-shrink: 0;
}

.topbar-icon-btn:hover {
  background: rgba(26, 95, 168, 0.10);
  border-color: rgba(26, 95, 168, 0.25);
}

.topbar-badge {
  position: absolute;
  top: 2px; right: 2px;
  min-width: 16px; height: 16px;
  border-radius: 100px;
  background: #e04a30;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  font-family: var(--font-ui);
  display: flex; align-items: center; justify-content: center;
  padding: 0 3px;
  line-height: 1;
  border: 2px solid rgba(255,255,255,0.95);
}

/* ── Notification bell shake ── */
@keyframes bell-shake {
  0%   { transform: rotate(0deg); }
  15%  { transform: rotate(14deg); }
  30%  { transform: rotate(-12deg); }
  45%  { transform: rotate(10deg); }
  60%  { transform: rotate(-8deg); }
  75%  { transform: rotate(4deg); }
  100% { transform: rotate(0deg); }
}
.topbar-icon-btn.shaking img {
  animation: bell-shake 0.6s ease-in-out 3;
  transform-origin: top center;
}

/* ── Notification dropdown ── */
.topbar-notif-wrap,
.topbar-user-wrap {
  position: relative;
}

.notif-dropdown,
.user-dropdown {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  width: 320px;
  backdrop-filter: blur(28px) saturate(180%);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  background: rgba(255,255,255,0.94);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  box-shadow: 0 12px 40px rgba(60,100,180,0.18), inset 0 1px 0 rgba(255,255,255,0.8);
  overflow: hidden;
  opacity: 0;
  transform: translateY(-8px) scale(0.97);
  pointer-events: none;
  transition: opacity 0.22s ease, transform 0.22s ease;
  z-index: 200;
}

.notif-dropdown.open,
.user-dropdown.open {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: all;
}

.notif-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px 10px;
  border-bottom: 1px solid var(--glass-border);
}

.notif-header-title {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: 0.01em;
}

.notif-header-count {
  font-size: 11px;
  font-weight: 500;
  color: var(--accent);
  background: rgba(26,95,168,0.09);
  border: 1px solid rgba(26,95,168,0.2);
  padding: 2px 8px;
  border-radius: 100px;
}

.notif-list { max-height: 280px; overflow-y: auto; }

.notif-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 16px;
  transition: background 0.15s;
  cursor: pointer;
}

.notif-item:hover { background: rgba(26,95,168,0.05); }

.notif-item.unread { background: rgba(26,95,168,0.04); }

.notif-item-icon {
  width: 32px; height: 32px;
  border-radius: 9px;
  background: rgba(26,95,168,0.09);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px;
  flex-shrink: 0;
}

.notif-item-body { flex: 1; min-width: 0; }

.notif-item-title {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-primary);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.notif-item-desc {
  font-size: 11.5px;
  color: var(--text-secondary);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.notif-item-time {
  font-size: 10.5px;
  color: var(--text-secondary);
  white-space: nowrap;
  flex-shrink: 0;
  padding-top: 2px;
}

.notif-footer {
  display: block;
  text-align: center;
  padding: 11px;
  font-size: 12px;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  border-top: 1px solid var(--glass-border);
  transition: background 0.15s;
}

.notif-footer:hover { background: rgba(26,95,168,0.05); }

/* ── The bell's real alerts ──
   Items are links now (each alert goes somewhere), and each carries a
   severity that tints its icon well: red for money problems, amber for
   things worth chasing, blue for review items. "Mark all read" sits in the
   header as a quiet text button — .pos-unthemed keeps the themes' button
   catch-alls from turning it into a pill. */
a.notif-item { text-decoration: none; color: inherit; }
.notif-item.sev-bad  .notif-item-icon { background: rgba(224, 74, 48, 0.14); }
.notif-item.sev-warn .notif-item-icon { background: rgba(202, 138, 4, 0.16); }
.notif-item.sev-info .notif-item-icon { background: rgba(26, 95, 168, 0.10); }
.notif-markall {
  margin-left: auto;
  border: 0; background: transparent;
  font: inherit; font-size: 11.5px; font-weight: 600;
  color: var(--accent); cursor: pointer;
  padding: 3px 8px; border-radius: 8px;
}
.notif-markall:hover { background: rgba(26, 95, 168, 0.08); }
.notif-header { gap: 10px; }
.notif-header .notif-header-count { margin-left: 0; }

/* ── User button ── */
.topbar-user-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  background: transparent;
  border: none;
  border-radius: 10px;
  padding: 5px 8px 5px 5px;
  cursor: pointer;
  transition: background 0.2s;
}

.topbar-user-btn:hover { background: rgba(26, 95, 168, 0.06); }

.topbar-avatar {
  width: 34px; height: 34px;
  border-radius: 50%;
  background: rgba(26,95,168,0.10);
  border: 2px solid rgba(26,95,168,0.18);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--accent);
  flex-shrink: 0;
}

.topbar-avatar-lg {
  width: 38px; height: 38px;
  font-size: 14px;
}

.topbar-user-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  text-align: left;
}

.topbar-user-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.2;
  white-space: nowrap;
}

.topbar-user-role {
  font-size: 10.5px;
  color: var(--text-secondary);
  line-height: 1;
  font-weight: 400;
}

.topbar-chevron {
  font-size: 16px;
  color: var(--text-secondary);
  line-height: 1;
  margin-left: 2px;
  transition: transform 0.2s;
}

/* ── User dropdown ── */
.user-dropdown { width: 210px; }

.user-dropdown-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 14px 12px;
  border-bottom: 1px solid var(--glass-border);
}

.user-dropdown-divider {
  height: 1px;
  background: var(--glass-border);
  margin: 4px 0;
}

.user-dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  font-size: 12.5px;
  font-weight: 400;
  color: var(--text-primary);
  text-decoration: none;
  transition: background 0.15s;
}

.user-dropdown-item:hover { background: rgba(26,95,168,0.06); }

.user-dropdown-logout {
  color: #b52020;
  padding-bottom: 12px;
}

.user-dropdown-logout:hover { background: rgba(200,40,40,0.06); }

/* ── Avatar photo support ── */
.topbar-avatar .avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  display: block;
}

/* When avatar has a photo, remove the text bg tint so image shows cleanly */
.topbar-avatar:has(.avatar-img) {
  background: transparent;
  border-color: rgba(26, 95, 168, 0.20);
  padding: 0;
  overflow: hidden;
}

/* ═══════════════════════════════════════════════════════════════
   SETTINGS MODAL
═══════════════════════════════════════════════════════════════ */

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 500;
  background: rgba(10, 30, 80, 0.18);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

.modal-overlay.open {
  opacity: 1;
  pointer-events: all;
}

.modal-card {
  width: 100%;
  max-width: 420px;
  backdrop-filter: blur(32px) saturate(200%);
  -webkit-backdrop-filter: blur(32px) saturate(200%);
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--glass-border);
  border-radius: 24px;
  padding: 32px;
  box-shadow: 0 24px 64px rgba(60, 100, 180, 0.22), inset 0 1px 0 rgba(255,255,255,0.9);
  transform: translateY(16px) scale(0.98);
  transition: transform 0.28s cubic-bezier(0.34,1.56,0.64,1);
}

.modal-overlay.open .modal-card {
  transform: translateY(0) scale(1);
}

/* Header */
.modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 24px;
}

.modal-eyebrow {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

.modal-title {
  font-family: var(--font-ui);
  font-size: 1.55rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.1;
}

.modal-close {
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 1px solid var(--glass-border);
  background: rgba(255,255,255,0.5);
  cursor: pointer;
  font-size: 13px;
  color: var(--text-secondary);
  display: flex; align-items: center; justify-content: center;
  transition: background 0.2s, color 0.2s;
  flex-shrink: 0;
}

.modal-close:hover {
  background: rgba(200,40,40,0.08);
  color: #b52020;
  border-color: rgba(200,40,40,0.2);
}

/* Toast */
.modal-toast {
  display: none;
  font-size: 12.5px;
  font-weight: 500;
  padding: 9px 14px;
  border-radius: 10px;
  margin-bottom: 18px;
}

.modal-toast.visible { display: block; }

.modal-toast.toast-ok {
  background: rgba(0,138,90,0.10);
  color: #007a50;
  border: 1px solid rgba(0,138,90,0.22);
}

.modal-toast.toast-err {
  background: rgba(200,40,40,0.08);
  color: #b52020;
  border: 1px solid rgba(200,40,40,0.18);
}

/* Avatar section */
.modal-avatar-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-bottom: 24px;
}

.modal-avatar-wrap {
  position: relative;
  width: 80px; height: 80px;
  border-radius: 50%;
  cursor: pointer;
}

.modal-avatar-img {
  width: 80px; height: 80px;
  border-radius: 50%;
  object-fit: cover;
  border: 2.5px solid var(--glass-border);
  display: block;
}

.modal-avatar-initials {
  width: 80px; height: 80px;
  border-radius: 50%;
  background: rgba(26,95,168,0.12);
  border: 2.5px solid rgba(26,95,168,0.25);
  display: flex; align-items: center; justify-content: center;
  font-size: 24px;
  font-weight: 700;
  color: var(--accent);
}

.modal-avatar-overlay {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(0,0,0,0.38);
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
  opacity: 0;
  transition: opacity 0.2s;
  cursor: pointer;
}

.modal-avatar-wrap:hover .modal-avatar-overlay { opacity: 1; }

.modal-avatar-hint {
  font-size: 11px;
  color: var(--text-secondary);
}

/* Tabs */
.modal-tabs {
  display: flex;
  gap: 4px;
  background: rgba(255,255,255,0.45);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 4px;
  margin-bottom: 22px;
}

.modal-tab {
  flex: 1;
  padding: 8px 12px;
  border: none;
  border-radius: 9px;
  background: transparent;
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 400;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 0.2s, color 0.2s;
}

.modal-tab.active {
  background: rgba(255,255,255,0.85);
  color: var(--text-primary);
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(60,100,180,0.12);
}

/* Tab panels */
.modal-tab-panel { display: none; }
.modal-tab-panel.active { display: block; }

/* Fields */
.modal-field {
  margin-bottom: 16px;
}

.modal-label {
  display: block;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 7px;
}

.modal-input {
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--glass-border);
  border-radius: 11px;
  background: rgba(255,255,255,0.55);
  font-family: var(--font-ui);
  font-size: 13.5px;
  color: var(--text-primary);
  outline: none;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
}

.modal-input:focus {
  border-color: var(--accent);
  background: rgba(255,255,255,0.85);
  box-shadow: 0 0 0 3px rgba(26,95,168,0.12);
}

.modal-pin-input {
  letter-spacing: 0.5em;
  font-size: 1.2rem;
  text-align: center;
}

/* Primary button */
.modal-btn-primary {
  width: 100%;
  padding: 13px;
  border: none;
  border-radius: 12px;
  background: linear-gradient(135deg, var(--accent), var(--accent2));
  color: #fff;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.06em;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(26,95,168,0.30);
  transition: opacity 0.2s, transform 0.15s;
  margin-top: 4px;
}

.modal-btn-primary:hover  { opacity: 0.9; transform: translateY(-1px); }
.modal-btn-primary:active { transform: scale(0.98); }

/* Logout form button — must look identical to dropdown links */
.user-dropdown-item.user-dropdown-logout[type="submit"] {
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: var(--font-ui);
}

/* ═══════════════════════════════════════════════════════════════
   DASHBOARD TWO-COLUMN LAYOUT
═══════════════════════════════════════════════════════════════ */

/* Override main-content — no longer centering, use full width */
.main-content {
  align-items: stretch;
}

.stats-row {
  max-width: none;
  width: 100%;
}

.dashboard-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  width: 100%;
  align-items: start;
}

/* Left column — table fills full height */
.dashboard-left {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.dashboard-left .table-wrap {
  margin-top: 0;
  flex: 1;
  max-width: none;
  width: 100%;
  /* Make table scrollable if rows overflow */
  overflow-y: auto;
  max-height: calc(100vh - 180px);
}

/* Right column — cards grid */
.dashboard-right {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.dashboard-right .grid {
  max-width: none;
  width: 100%;
  grid-template-columns: repeat(2, 1fr);
}

/* Pipeline card still spans both cols inside right */
.dashboard-right .card-wide {
  grid-column: span 2;
}

/* Responsive — stack on smaller screens */
@media (max-width: 1100px) {
  .dashboard-layout {
    grid-template-columns: 1fr;
  }

  .dashboard-left .table-wrap {
    max-height: none;
    overflow-y: visible;
  }

  .dashboard-right .grid {
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  }
}

/* ═══════════════════════════════════════════════════════════════
   SALES CALENDAR CARD
═══════════════════════════════════════════════════════════════ */

.card-calendar {
  padding: 20px 18px 18px;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Header row: prev / month-year / next */
.cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

.cal-nav {
  width: 32px; height: 32px;
  border-radius: 9px;
  border: 1px solid var(--glass-border);
  background: rgba(255,255,255,0.5);
  color: var(--accent);
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.18s, transform 0.12s;
  flex-shrink: 0;
}

.cal-nav:hover  { background: rgba(255,255,255,0.85); transform: scale(1.08); }
.cal-nav:active { transform: scale(0.92); }

.cal-month-year {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 1.1rem;
  color: var(--text-primary);
  letter-spacing: 0.01em;
  text-align: center;
  flex: 1;
}

/* Day name header row */
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  margin-bottom: 4px;
}

.cal-day-name {
  text-align: center;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  padding: 4px 0;
}

/* Days grid */
.cal-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
}

.cal-day {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  font-size: 12px;
  font-weight: 400;
  font-family: var(--font-ui);
  color: var(--text-primary);
  cursor: pointer;
  transition: background 0.15s, color 0.15s, transform 0.1s;
  border: 1px solid transparent;
  position: relative;
  user-select: none;
}

.cal-day:hover {
  background: rgba(26, 95, 168, 0.10);
  border-color: rgba(26, 95, 168, 0.18);
  transform: scale(1.1);
}

.cal-day.other-month {
  color: rgba(30, 70, 130, 0.28);
  cursor: default;
}

.cal-day.other-month:hover {
  background: transparent;
  border-color: transparent;
  transform: none;
}

.cal-day.today {
  background: rgba(26, 95, 168, 0.12);
  border-color: rgba(26, 95, 168, 0.30);
  color: var(--accent);
  font-weight: 600;
}

.cal-day.selected {
  background: linear-gradient(135deg, var(--accent), var(--accent2));
  color: #fff !important;
  font-weight: 600;
  border-color: transparent;
  box-shadow: 0 3px 12px rgba(26, 95, 168, 0.40);
  transform: scale(1.12);
}

.cal-day.selected:hover {
  transform: scale(1.14);
}

/* Dot indicator for days with sales data (future use) */
.cal-day .cal-dot {
  position: absolute;
  bottom: 3px;
  left: 50%;
  transform: translateX(-50%);
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--accent2);
}

.cal-day.selected .cal-dot { background: rgba(255,255,255,0.7); }

/* Selected date label */
.cal-selected-label {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--glass-border);
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-secondary);
  text-align: center;
  min-height: 20px;
  transition: color 0.2s;
}

.cal-selected-label span {
  color: var(--accent);
  font-weight: 600;
}

/* ── Revenue breakdown stats ── */
.rev-stats {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.rev-stat {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 10px;
  background: rgba(255,255,255,0.40);
  border: 1px solid var(--glass-border);
  transition: background 0.18s;
}

.rev-stat:hover { background: rgba(255,255,255,0.68); }

.rev-stat-icon {
  font-size: 18px;
  width: 32px; height: 32px;
  border-radius: 8px;
  background: rgba(26,95,168,0.08);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

.rev-stat-info {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex: 1;
  min-width: 0;
}

.rev-stat-label {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-secondary);
  letter-spacing: 0.01em;
}

.rev-stat-val {
  font-family: var(--font-ui);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text-primary);
}

/* ══ Cash Drawer card ══════════════════════════════════════════════════════════
   Replaced the Daily Bank card. Read-only mirror of the drawer — see
   drawer_card.php for why it has no entry form. */
#drawerCard { display: flex; flex-direction: column; }

.dc-head { display: flex; align-items: baseline; gap: 10px; }
.dc-eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--text-secondary);
}
.dc-open {
  margin-left: auto; display: inline-flex; align-items: center; gap: 2px;
  font-size: 12px; font-weight: 600; color: var(--brand-blue, #1a5fa8);
  text-decoration: none; opacity: .75; transition: opacity .15s;
}
.dc-open:hover { opacity: 1; }

.dc-balance {
  font-size: 2.2rem; font-weight: 700; color: var(--brand-blue, #1a5fa8);
  line-height: 1.05; margin-top: 6px;
}
.dc-sub { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.dc-sub b { font-weight: 700; color: var(--text-primary, #2c3542); }

/* In / Out / On loan. Equal columns so the two figures line up whether or not
   the loan column is there to make a third. */
.dc-flow { display: flex; gap: 10px; margin-top: 14px; }
.dc-flow-col { flex: 1 1 0; min-width: 0; }
.dc-flow-val { font-size: 1.1rem; font-weight: 700; white-space: nowrap; }
.dc-flow-lab {
  font-size: 10.5px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-secondary); margin-top: 1px;
}
.dc-in   { color: #008a5a; }
.dc-out  { color: #b52020; }
.dc-loan { color: #7c5cd6; }

.dc-rule {
  height: 1px; margin: 14px 0 12px;
  background: linear-gradient(90deg,
              rgba(120,140,170,0) 0%, rgba(120,140,170,.28) 12%,
              rgba(120,140,170,.28) 88%, rgba(120,140,170,0) 100%);
}

.dc-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--text-secondary);
  padding: 5px 0;
}
.dc-row-main  { flex: 1 1 auto; min-width: 0; }
.dc-row-main b { color: var(--text-primary, #2c3542); }
.dc-row-aside { flex: 0 0 auto; font-size: 11.5px; color: var(--text-secondary); opacity: .8; }
.dc-muted     { opacity: .8; }

/* The variance lamp. Colour is the whole signal here, so it repeats on the
   words as well — a dot alone is missed by anyone not looking for it. */
.dc-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.dc-ok    { color: #15803d; } .dc-dot.dc-ok    { background: #16a34a; }
.dc-over  { color: #1a5fa8; } .dc-dot.dc-over  { background: #1a5fa8; }
.dc-short { color: #b91c1c; } .dc-dot.dc-short { background: #dc2626; }
.dc-dot.dc-idle { background: #c3cddd; }
.dc-row b.dc-ok, .dc-row b.dc-over, .dc-row b.dc-short { font-weight: 700; }

.dc-faces { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.dc-faces .drawer-avatar {
  width: 22px; height: 22px; border-radius: 50%; object-fit: cover;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 8.5px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, #4a7fd0 0%, #7ba3e0 100%);
  box-shadow: 0 1px 3px rgba(26,95,168,.25);
}
.dc-more { font-size: 11px; font-weight: 700; color: var(--text-secondary); }


/* ── Openings by reason ─────────────────────────────────────────────────────
   A segmented ring in solid, flat colour with a soft lift under it — the same
   six colours as the chips above, which stay the legend, so the ring carries
   proportions and the chips carry names and counts. Neither repeats the
   other's job. */
#drawerCard { display: flex; flex-direction: column; }
.dc-div { margin: 14px 0 0; }

.dc-ring-wrap {
  position: relative;
  flex: 1 1 auto;
  min-height: 170px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Symmetric: the centre stack is positioned at 50% of this box, so uneven
     padding would put the figure off-centre inside the ring. */
  padding: 8px 0;
  /* Bleeds into the card's own padding. The drawing is mostly callout margin —
     the ring is barely half its width — so every pixel of extra canvas goes
     almost entirely into the ring. The outermost thing here is label text,
     which lands in the padding and is still well inside the card. */
  margin-left: -20px;
  margin-right: -20px;
}
/* Width-constrained now that the callouts sit either side: the drawing is
   half again as wide as it is tall, so sizing it by height would push the
   labels past the card's edges. */
.dc-ring {
  width: 100%;
  height: auto;
  max-height: 250px;
  display: block;
  overflow: visible;
}

/* PALETTE SETS `color`, NOT fill OR stroke.
   
   Setting both directly is what broke this: an arc needs stroke and a dot needs
   fill, so the shared rule set both — and `.dc-ring-seg[data-r="purchase"]` at
   (0,2,0) then outranked the `.dc-ring-seg { fill: none }` reset at (0,1,0).
   Every arc got filled, and a filled arc paints the region between itself and
   its chord: the ring came out as four fat blobs.
   
   With `color`, the palette says WHICH colour and the shape rules say WHICH
   PROPERTY uses it. They cannot fight because they set different things. */
.dc-ring-seg, .dc-ring-dot                     { color: #a8b6c9; }
.dc-ring-seg[data-r="change"],
.dc-ring-dot[data-r="change"]                  { color: #8fb0e6; }
.dc-ring-seg[data-r="purchase"],
.dc-ring-dot[data-r="purchase"]                { color: #f3b483; }
.dc-ring-seg[data-r="add"],
.dc-ring-dot[data-r="add"]                     { color: #86ccae; }
.dc-ring-seg[data-r="loan"],
.dc-ring-dot[data-r="loan"]                    { color: #b49ce4; }
.dc-ring-seg[data-r="refund"],
.dc-ring-dot[data-r="refund"]                  { color: #ea9db1; }
.dc-ring-seg[data-r="count"],
.dc-ring-dot[data-r="count"]                   { color: #85c8d4; }

/* An arc is stroked and must never paint its chord; a dot is filled and must
   never outline. */
.dc-ring-seg { stroke: currentColor; fill: none; }
.dc-ring-dot { fill: currentColor; stroke: none; }

.dc-ring-empty { stroke: rgba(120, 140, 170, .10); }

/* ── Callouts ───────────────────────────────────────────────────────────────
   A leader line out of each segment, ending in the reason's own dot and name.
   Same `color`-not-fill discipline as the segments: the palette says which
   colour, the shape rules say which property spends it. */
.dc-ring-lead, .dc-ring-ldot                   { color: #a8b6c9; }
.dc-ring-lead[data-r="change"],
.dc-ring-ldot[data-r="change"]                 { color: #8fb0e6; }
.dc-ring-lead[data-r="purchase"],
.dc-ring-ldot[data-r="purchase"]               { color: #f3b483; }
.dc-ring-lead[data-r="add"],
.dc-ring-ldot[data-r="add"]                    { color: #86ccae; }
.dc-ring-lead[data-r="loan"],
.dc-ring-ldot[data-r="loan"]                   { color: #b49ce4; }
.dc-ring-lead[data-r="refund"],
.dc-ring-ldot[data-r="refund"]                 { color: #ea9db1; }
.dc-ring-lead[data-r="count"],
.dc-ring-ldot[data-r="count"]                  { color: #85c8d4; }

/* The line is quieter than the dot it ends in — it is the pointing, not the
   reading. Round joins so the elbow does not come to a spike. */
.dc-ring-lead {
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .55;
}
.dc-ring-ldot { fill: currentColor; stroke: none; }

/* Engraved. SVG text does not reliably take text-shadow, so this is the same
   two offsets as the house --neu-engrave expressed as a filter: dark up-left,
   light down-right. neumorphic.css already keeps that pairing as its own token
   and swaps it in below, so the two cannot drift.

   The fill lightens to a slate at the same time. Engraving near-black text
   reads as a halo around dark letters rather than as letters pressed into the
   surface — the effect needs a mid tone to cut into. */
.dc-ring-lname {
  font-family: var(--font-ui);
  font-size: 11px; font-weight: 600;
  fill: #59657a;
  filter: drop-shadow(-1px -1px 1px rgba(63, 74, 86, .28))
          drop-shadow( 1px  1px 1px rgba(255, 255, 255, .95));
}

/* The caption under the figure gets the same treatment — the house pairing is
   a raised number over an engraved label, and the figure above is already
   raised. HTML, so it can use the shadow form directly. */
.dc-ring-cap-l {
  text-shadow: 1px 1px 1px rgba(255, 255, 255, .85),
              -1px -1px 1px rgba(63, 74, 86, .22);
}

/* Ticks inside the hole. Pale enough to be texture rather than a second ring
   competing with the segments for attention.

   It turns, slowly. transform-box: fill-box so the origin is the circle's own
   centre — the viewBox starts at a negative x to make room for the callouts,
   so "50% 50%" of the VIEWPORT is not the middle of the ring and the ticks
   would orbit rather than spin. 48s is about 7.5 degrees a second: visible if
   you watch it, invisible if you are reading the number. */
.dc-ring-ticks {
  stroke: rgba(120, 140, 170, .30);
  transform-box: fill-box;
  transform-origin: center;
  animation: dcTicksSpin 48s linear infinite;
}
@keyframes dcTicksSpin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .dc-ring-ticks { animation: none; }
}

/* The centre stack sits over the SVG. Centred on the WRAPPER, which is the
   same point the flex-centred SVG is centred on. */
.dc-ring-mid {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  pointer-events: none;
}
.dc-ring-fig {
  font-family: var(--font-ui);
  font-variant-numeric: tabular-nums;
  font-size: 30px; font-weight: 800;
  letter-spacing: -.02em; line-height: 1;
  color: var(--text-primary);
}
.dc-ring-cap-l {
  margin-top: 3px;
  font-family: var(--font-ui);
  font-size: 10.5px; font-weight: 600;
  letter-spacing: .02em;
  color: var(--text-secondary);
}

/* Nothing yet: the empty band keeps the card's height and shape before the
   first opening. */
.dc-ring-idle .dc-ring { opacity: .7; }
.dc-ring-note {
  position: absolute;
  font-size: 11.5px; font-weight: 600;
  color: var(--text-secondary);
}

/* Drawer avatars on the dashboard widget. The photo overlays the initials disc
   so a failed image uncovers the letters instead of showing a broken glyph —
   see avatar_html() in drawer/lib.php. */
.dc-faces .drawer-avatar { position: relative; overflow: hidden; }
.dc-faces .drawer-avatar > img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.dc-faces .drawer-avatar > .dav-ini { line-height: 1; }

/* ── User panel (topbar) ─────────────────────────────────────────────────────
   The user menu grew into a card: photo large on a soft blue disc, the name
   and role beside it, a facts block with three chips, then a 2×2 of tiles —
   two counts that link out, and the two actions. Widths are fixed so the
   panel keeps its shape whatever the numbers do. */
.user-dropdown.user-panel { width: 400px; padding: 14px; border-radius: 26px; }
.up-hero { position: relative; display: flex; align-items: center; justify-content: space-between; min-height: 150px; padding: 10px 6px 6px 8px; }
.up-hero-text { flex: 1 1 auto; min-width: 0; padding-right: 12px; }
.up-name { font-size: 22px; font-weight: 600; color: var(--text-primary); letter-spacing: -.3px; line-height: 1.15; word-break: break-word; }
.up-role { font-size: 13px; color: var(--text-secondary); margin-top: 3px; }
.up-id   { display: inline-block; margin-top: 8px; font-size: 11px; font-weight: 600; color: var(--accent); background: rgba(26,95,168,.10); padding: 2px 8px; border-radius: 999px; }
.up-photo { flex: 0 0 auto; width: 150px; height: 150px; display: flex; align-items: flex-end; justify-content: center;
  background: radial-gradient(circle at 50% 60%, rgba(120,190,240,.55), rgba(26,95,168,.10) 70%, transparent 71%); border-radius: 50%; }
.topbar-avatar.topbar-avatar-xl { width: 126px; height: 126px; font-size: 40px; border-width: 3px; margin-bottom: 8px; box-shadow: 0 10px 24px rgba(13,42,82,.18); }
.up-edit { position: absolute; top: 4px; right: 4px; width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--glass-border); background: rgba(255,255,255,.95); color: var(--text-primary); display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 12px rgba(13,42,82,.12); transition: transform .15s ease, color .15s ease; }
.up-edit svg { width: 16px; height: 16px; }
.up-edit:hover { transform: translateY(-1px); color: var(--accent); }
/* Its name bubble opens BELOW it and right-aligned (2026-10-09): above, it ran
   past the panel's top edge and the panel clips (overflow: hidden). */
.up-edit > .pos-pop { bottom: auto; top: calc(100% + 8px); left: auto; right: 0; transform: translateY(-8px) scale(.72); transform-origin: 90% 0; }
.up-edit.pos-pop-host:hover > .pos-pop, .up-edit.pos-pop-host:focus-visible > .pos-pop { transform: translateY(0) scale(1); }
@media (prefers-reduced-motion: reduce) { .up-edit > .pos-pop, .up-edit.pos-pop-host:hover > .pos-pop { transform: none; } }
.up-facts { margin-top: 10px; padding: 14px 14px 12px; border-radius: 20px; background: rgba(26,95,168,.07); }
.up-fact { display: flex; align-items: baseline; gap: 12px; font-size: 13px; padding: 3px 0; }
.up-fact span { flex: 0 0 116px; color: var(--text-secondary); }
.up-fact b { font-weight: 600; color: var(--text-primary); }
.up-chips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 12px; }
.up-chip { background: rgba(255,255,255,.92); border-radius: 14px; padding: 8px 10px; display: flex; flex-direction: column; gap: 2px; box-shadow: 0 1px 3px rgba(13,42,82,.06); }
.up-chip span { font-size: 10.5px; color: var(--text-secondary); }
.up-chip b { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.up-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
.up-tile { display: flex; flex-direction: column; justify-content: space-between; min-height: 104px; padding: 12px 14px; border-radius: 20px;
  background: rgba(255,255,255,.92); border: 1px solid var(--glass-border); text-decoration: none; color: var(--text-primary);
  transition: transform .15s ease, box-shadow .15s ease; }
.up-tile:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(13,42,82,.10); }
.up-tile-head { display: flex; align-items: center; justify-content: space-between; font-size: 14px; font-weight: 500; }
.up-arrow { width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--glass-border); display: inline-flex; align-items: center; justify-content: center; color: var(--text-primary); background: #fff; }
.up-arrow svg { width: 14px; height: 14px; }
.up-tile-num { font-size: 13px; color: var(--text-secondary); }
.up-tile-num b { font-family: var(--font-num, inherit); font-size: 34px; font-weight: 600; color: var(--text-primary); letter-spacing: -1px; line-height: 1; margin-right: 4px; }
.up-tile-sub { font-size: 12px; color: var(--text-secondary); }
.up-tile-logout { color: #b52020; }
.up-tile-logout .up-arrow { color: #b52020; border-color: rgba(181,32,32,.25); }
.up-tile-logout:hover { background: rgba(200,40,40,.06); }

/* ── Topbar notch wrapper ────────────────────────────────────────────────────
   Holds the quick links and the bells/badge together so a theme can draw one
   shape around them (neumorphic.css draws a tab). Layout only here: the two
   flanks still flex equally either side, so the group stays centred. */
.topbar-notch {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  height: 100%;
  min-width: 0;
}
/* The bells and the badge live in the end flank, centred between the notch and
   the search: the group takes auto margins on both sides and the search gives
   up its own, so the free space splits evenly either side of the group. */
.topbar-end { gap: 0; }
.topbar-end .topbar-right { margin: 0 auto; gap: 18px; }
.topbar-end .topbar-right .topbar-sep { margin: 0 6px; }
.topbar-end .topbar-search-wrap { margin-left: 0; }
/* The lens is positioned against the quick-link rail; it is painted only by
   the neumorphic sheet, so here it just has a home and stays hidden. */
.topbar-notch .topbar-center { position: relative; }
.topbar-lens { display: none; }

/* The single-colour quick-link icons topbar.php carries for the Liquid
   theme. Hidden everywhere; liquid.css shows them on its pages. */
.lq-ico { display: none; }

/* ── The card processing fee's switch (2026-09-15) ───────────────────────────
   On the cart summary row under Tax, on both checkouts: a small pill in the
   shape of the cart's Tax and Points toggles, so it reads as the same kind of
   control. ON is the armed state and the default; OFF waives the fee for this
   one sale and is re-armed by any change of payment method. */
.cf-toggle {
  margin-left: 8px;
  padding: 2px 8px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .06em;
  line-height: 1.6;
  cursor: pointer;
  vertical-align: middle;
  transition: background .15s ease, color .15s ease;
}
.cf-toggle.cf-on  { background: rgba(0, 138, 90, 0.14); color: #007a50; }
.cf-toggle.cf-off { background: rgba(214, 48, 49, 0.13); color: #c0392b; }   /* red when waived, like Points OFF (2026-09-25) */
.cf-toggle:hover  { filter: brightness(0.96); }

/* ── The Front Counter card (Luis, 2026-09-16) ──────────────────────────────
   Stands where the Sales Calendar card stood. House colours throughout: cash
   is the in-house green, card is plum, and the unpaid remainder takes the
   silver already used for cost — a third accent here would have made the ring
   look like it meant three KINDS of thing rather than three shares of one. */
.card-counter { display: flex; flex-direction: column; }
.card-counter.is-loading { opacity: .55; }

.cc-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 15px; }
.cc-txns { font-size: 11.5px; color: var(--text-secondary); }
.cc-txns b { font-size: 15px; font-weight: 700; color: var(--text-primary);
             font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }

/* The ring is the Office Drawer card's own chart, fetched as finished markup
   from dc_donut.php. Nothing here describes its geometry — only which colours
   the three shares spend, scoped to this card so the office palette is not
   touched. Cash is the in-house green, card is plum, and the unpaid remainder
   takes the silver already used for cost. */
.card-counter .dc-ring-seg[data-r="cash"],  .card-counter .dc-ring-dot[data-r="cash"],
.card-counter .dc-ring-lead[data-r="cash"], .card-counter .dc-ring-ldot[data-r="cash"],
.card-counter .dc-ring-lval[data-r="cash"]  { color: #3f7a68; }
.card-counter .dc-ring-seg[data-r="card"],  .card-counter .dc-ring-dot[data-r="card"],
.card-counter .dc-ring-lead[data-r="card"], .card-counter .dc-ring-ldot[data-r="card"],
.card-counter .dc-ring-lval[data-r="card"]  { color: #6b3744; }
.card-counter .dc-ring-seg[data-r="other"],  .card-counter .dc-ring-dot[data-r="other"],
.card-counter .dc-ring-lead[data-r="other"], .card-counter .dc-ring-ldot[data-r="other"],
.card-counter .dc-ring-lval[data-r="other"] { color: #8e9095; }

/* The amount under each name. Tabular figures so three callouts read as a
   column even though they sit at three different heights. */
.dc-ring-lval { fill: currentColor; font-size: 9.5px; font-weight: 700;
                font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }

.cc-ring-wrap { margin-top: 4px; }


/* Who rang the day's sales (Luis, 2026-09-16). Avatars only: the name is in
   the tooltip, and the initials circle stands in for anyone without a photo.
   The rows line up with the legend above so the amounts read down one column. */
.cc-people { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--glass-border); }
.cc-people[hidden] { display: none; }
.cc-people-cap { display: block; margin-bottom: 9px; font-size: 9px; font-weight: 600;
                 letter-spacing: .14em; text-transform: uppercase; color: var(--text-secondary); }
.cc-people-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.cc-people-list li { display: grid; grid-template-columns: 26px auto 1fr; column-gap: 9px;
                     align-items: center; font-size: 12.5px; }
.cc-face { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; display: block;
           box-shadow: 0 0 0 1px var(--glass-border); }
.cc-face-ini { display: grid; place-items: center; font-size: 9.5px; font-weight: 700;
               letter-spacing: .02em; color: var(--text-secondary); background: rgba(120, 140, 170, 0.16); }
.cc-people-list em { font-style: normal; font-size: 10.5px; color: var(--text-secondary); white-space: nowrap; }
.cc-people-list b { text-align: right; font-weight: 700; color: var(--text-primary);
                    font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }

/* The centre figure, resized for money. 30px is right for "5" on the Office
   Drawer card; "$1,433.62" at that size runs clean out through both sides of
   the ring. The hole is about 100px across, so this and the caption under it
   are sized to live inside it. */
.card-counter .dc-ring-fig  { font-size: 15.5px; letter-spacing: -.01em; }
.card-counter .dc-ring-cap-l { margin-top: 2px; font-size: 9px; letter-spacing: .1em; text-transform: uppercase; }

/* Drawer movement that was not a sale (Luis, 2026-09-16). Sits between the
   ring and the people, ruled off from both, and labelled — a figure this close
   to a takings total has to say plainly that it is not one. */
.cc-moves { display: grid; grid-template-columns: auto 1fr auto; column-gap: 9px;
            align-items: baseline; margin-top: 16px; padding-top: 14px;
            border-top: 1px solid var(--glass-border); font-size: 12.5px; }
.cc-moves[hidden] { display: none; }
.cc-moves > span { color: var(--text-secondary); white-space: nowrap; }
.cc-moves > em { font-style: normal; font-size: 10.5px; text-align: right;
                 color: var(--text-secondary); white-space: nowrap; }
.cc-moves-net { font-weight: 700; color: var(--text-primary);
                font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }
.cc-moves-net.down { color: #6b3744; }
.cc-moves-net.up   { color: #3f7a68; }

/* ── Which till rang it ───────────────────────────────────────────────────────
   A dot beside the order's time in the Customer column (Luis, 2026-09-16).
   The house colours, each doing the job it already does elsewhere: the front
   counter takes the in-house green, the back takes plum, the repair station
   silver. The office drawer gets the house sky blue — it was not asked for,
   but it accounts for about a third of the ledger, and leaving those rows bare
   would make "no dot" mean two different things: rung at the office, or never
   reached a till at all. */
.reg-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-left: 7px;
  /* The time it follows sits on the text baseline; a raw inline-block would
     hang off the bottom of it. */
  vertical-align: 0.05em;
  flex: 0 0 auto;
}
.reg-front  { background: #3f7a68; }   /* in-house green */
.reg-back   { background: #6b3744; }   /* plum */
.reg-repair { background: #8e9095; }   /* house silver */
.reg-main   { background: #5b8def; }   /* house sky blue */

.reg-key {
  display: flex;
  align-items: center;
  gap: 13px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.reg-key span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
/* In the key the dot leads its label, so the left margin that spaces it off
   the time in the table would only push it away from its own word. */
.reg-key .reg-dot { margin-left: 0; vertical-align: baseline; }

/* ── The table's category filter (Luis, 2026-09-18) ──────────────────────────
 *
 * A custom dropdown rather than a <select>, and not by preference. Luis asked
 * for rounded corners and the house liquid slide on the open panel, and a
 * native select's list is drawn by the operating system: no CSS reaches it, not
 * a radius, not a transition. The only way to round or animate that list is to
 * stop using it.
 *
 * The <select> is still here, hidden, holding the value. Everything that reads
 * the filter — loadTableData(), the change listener — goes on addressing
 * #salesKind exactly as before, and the widget sets .value and fires a real
 * change event. Nothing downstream knows the difference, which is why this
 * swap needed no changes to the query, the endpoint or the pager.
 */
.sales-filter { display: flex; align-items: center; position: relative; }
#salesKind { display: none !important; }   /* the value store, never drawn */

/* The trigger, which is the pill the <select> used to be. No !important here:
   apple.css claims :is(input, select, textarea) but not buttons, so a button
   escapes the rule that used to eat this element's background and caret. */
.sf-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: inherit;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  padding: 6px 10px;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}
.sf-btn:hover { border-color: rgba(107, 55, 68, 0.35); color: var(--text-primary); }
.sf-btn:focus-visible { outline: 2px solid rgba(107, 55, 68, 0.45); outline-offset: 1px; }
/* Filtering is a state worth seeing from across the room — otherwise a short
   table reads as a quiet day rather than as a filtered one. */
.sf-btn.is-on {
  color: #6b3744;
  border-color: rgba(107, 55, 68, 0.45);
  background: rgba(107, 55, 68, 0.06);
}

.sf-caret { width: 9px; height: 6px; flex: none; transition: transform .3s var(--ease-liquid); }
.sf-caret path { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.sales-filter:hover:not(.is-dismissed) .sf-caret,
.sales-filter:focus-within:not(.is-dismissed) .sf-caret { transform: rotate(180deg); }

/* The panel. The motion is the house one, lifted from .pos-pop: it swells in on
   --ease-liquid over .38s and is tidied away in a fraction of that. Reversing
   the long curve on the way out leaves the panel hanging after the choice is
   made, which reads as lag rather than polish.

   transform-origin is the top edge, under the button, so it unfolds downward
   from the thing that opened it instead of growing from its own middle. */
.sf-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  min-width: 100%;
  width: max-content;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.97);
  box-shadow: 0 10px 28px rgba(31, 45, 61, 0.18), 0 0 0 1px rgba(31, 45, 61, 0.07);
  z-index: 60;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(-8px) scale(.94);
  transform-origin: 50% 0;
  filter: blur(6px);
  transition: opacity .12s ease, transform .16s ease, filter .12s ease;
}
/* The 8px between the trigger and the panel belongs to neither of them, so a
   pointer travelling down from one to the other crossed dead space and the
   menu shut in its face. An invisible bridge over that gap — part of the
   panel, so hovering it keeps the wrapper hovered. */
.sf-panel::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: -10px;
  height: 10px;
}
/* Opened by the pointer, not by a click (Luis, 2026-09-18).

   :focus-within rides along with :hover so the keyboard and a touchscreen
   still reach it — tabbing to the trigger or tapping it opens the same
   panel, which a hover-only menu would leave unreachable.

   .is-dismissed is the one thing hover cannot express: after a choice the
   pointer is still sitting on the panel, so :hover is still true and it
   would stay open over the table. The class forces it shut and is cleared
   on the way out, so coming back opens it again. */
.sales-filter:hover:not(.is-dismissed) .sf-panel,
.sales-filter:focus-within:not(.is-dismissed) .sf-panel {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(-50%) translateY(0) scale(1);
  filter: blur(0);
  transition: opacity .2s ease,
              transform .38s var(--ease-liquid),
              filter .26s ease;
}

/* The rows. Readable case and size — this is a list to be read, not a label
   to be glanced at, so it drops the trigger's uppercase tracking. */
.sf-opt {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  background: transparent;
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: #1f2d3d;
  text-align: left;
  padding: 7px 12px;
  border-radius: 9px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .16s ease, color .16s ease;
}
.sf-opt:hover { background: rgba(107, 55, 68, 0.07); }
.sf-opt.is-sel { color: #6b3744; background: rgba(107, 55, 68, 0.10); }
.sf-opt:focus-visible { outline: 2px solid rgba(107, 55, 68, 0.45); outline-offset: -2px; }

@media (prefers-reduced-motion: reduce) {
  .sf-panel,
  .sales-filter:hover:not(.is-dismissed) .sf-panel,
  .sales-filter:focus-within:not(.is-dismissed) .sf-panel {
    transition: opacity .1s ease;
    transform: translateX(-50%);
    filter: none;
  }
  .sf-caret { transition: none; }
}

/* ── Awaiting deposit ─────────────────────────────────────────────────────────
   Acima sales that have not been paid into the bank yet (Luis, 2026-09-16).
   Plum, because that is the house colour for money owed rather than money in,
   and because nothing else on this dashboard is plum — the card has to be
   findable at a glance on the four days a year it appears. */
.card-parked { border-left: 3px solid #6b3744; }
.pk-head { display: flex; align-items: baseline; justify-content: space-between; }
.pk-count b { color: #6b3744; font-weight: 700; }
.pk-total {
  font-size: 22px; font-weight: 700; letter-spacing: -0.02em;
  color: #6b3744; margin-top: 6px;
}
.pk-total-cap {
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-secondary); margin-bottom: 10px;
}
.pk-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.pk-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 10px;
  align-items: center;
  padding: 9px 11px;
  border-radius: 12px;
  background: rgba(107, 55, 68, 0.05);
}
/* Past the two-to-three days Acima quotes, so it is worth chasing. */
.pk-row.pk-late { background: rgba(107, 55, 68, 0.12); }
.pk-who b { display: block; font-size: 12.5px; font-weight: 700; color: var(--text-primary); }
.pk-who em {
  display: block; font-style: normal; font-size: 10px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-secondary); margin-top: 2px;
}
.pk-amt { font-size: 13.5px; font-weight: 700; color: #6b3744; white-space: nowrap; }
.pk-btn, .pk-ok, .pk-cancel {
  grid-column: 1 / -1;
  border: 0; border-radius: 9px; cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 700;
  letter-spacing: .04em; padding: 7px 10px;
}
.pk-btn { background: #6b3744; color: #fff; }
.pk-btn:hover { filter: brightness(1.08); }
/* :not([hidden]) matters — a bare `display: flex` outranks the browser's own
   [hidden] rule, so the PIN row sat open on every line and the Confirm
   button was there before anyone asked for it. */
.pk-pin:not([hidden]) { grid-column: 1 / -1; display: flex; gap: 6px; align-items: center; }
.pk-pin-in {
  flex: 1 1 auto; min-width: 0; width: 100%;
  padding: 7px 10px; border-radius: 9px;
  border: 1px solid rgba(107, 55, 68, .35);
  background: #fff; font-family: inherit; font-size: 13px;
  letter-spacing: .3em; text-align: center;
}
.pk-pin-in:focus { outline: none; border-color: #6b3744; box-shadow: 0 0 0 2px rgba(107,55,68,.18); }
.pk-ok     { grid-column: auto; background: #3f7a68; color: #fff; }
.pk-cancel { grid-column: auto; background: rgba(120,140,170,.16); color: var(--text-secondary); }
.pk-msg { grid-column: 1 / -1; font-size: 11px; font-weight: 600; margin-top: 2px; }
.pk-msg.ok  { color: #3f7a68; }
.pk-msg.bad { color: #b52020; }


/* ── The Repair Sale menu (Luis, 2026-09-22) ─────────────────────────────────
   A trial on one quick link. The motion is the house one, the same as the
   dashboard's category filter (.sf-panel): the panel swells in on
   --ease-liquid over .38s from a blurred, slightly shrunken state under the
   pill, and is tidied away in a fraction of that on the way out. Reversing
   the long curve on exit leaves a menu hanging after the pointer has gone,
   which reads as lag rather than polish.

   The two rows arrive a beat apart — 40ms, then 80ms — so the panel reads as
   unfolding rather than appearing. It is a small thing and it is most of
   what "premium" means at this scale.

   Opened by :hover and :focus-within on the wrapper, so the keyboard and a
   touchscreen reach it: tabbing to the pill or tapping it opens the same
   panel a hover-only menu would keep from them. No script. */
.topbar-menu {
  position: relative;
  display: flex;
  align-items: center;
  height: 100%;
}

/* The pill keeps everything it had; the caret is the only addition, and it
   turns over on open on the same curve as the panel. */
.tm-caret {
  width: 9px;
  height: 6px;
  flex: none;
  margin-left: 2px;
  color: currentColor;
  opacity: .55;
  transition: transform .3s var(--ease-liquid), opacity .18s ease;
}
.tm-caret path { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.topbar-menu:hover .tm-caret,
.topbar-menu:focus-within .tm-caret { transform: rotate(180deg); opacity: .9; }

.tm-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  min-width: 100%;
  width: max-content;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.97);
  box-shadow: 0 10px 28px rgba(31, 45, 61, 0.18), 0 0 0 1px rgba(31, 45, 61, 0.07);
  z-index: 60;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(-8px) scale(.94);
  transform-origin: 50% 0;
  filter: blur(6px);
  transition: opacity .12s ease, transform .16s ease, filter .12s ease;
}
/* The 8px between pill and panel belongs to neither, so a pointer crossing
   it would shut the menu in its face. An invisible bridge over the gap, part
   of the panel, keeps the wrapper hovered on the way down. */
.tm-panel::before {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: -10px;
  height: 10px;
}
.topbar-menu:hover .tm-panel,
.topbar-menu:focus-within .tm-panel {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(-50%) translateY(0) scale(1);
  filter: blur(0);
  transition: opacity .2s ease,
              transform .38s var(--ease-liquid),
              filter .26s ease;
}

/* The rows: links, styled as the filter's rows are — a list to be read, so
   readable case and size, none of the pill's uppercase tracking. */
.tm-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px 9px 11px;
  border-radius: 10px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  text-decoration: none;
  color: #1f2d3d;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(-4px);
  transition: background-color .16s ease, color .16s ease,
              opacity .12s ease, transform .12s ease;
}
.tm-opt .tm-ico { width: 18px; height: 18px; flex: none; color: rgba(29, 29, 31, 0.55); transition: color .16s ease; }
.tm-opt:hover { background: rgba(107, 55, 68, 0.07); color: #6b3744; }
.tm-opt:hover .tm-ico { color: #6b3744; }
.tm-opt:focus-visible { outline: 2px solid rgba(107, 55, 68, 0.45); outline-offset: -2px; }

.topbar-menu:hover .tm-opt,
.topbar-menu:focus-within .tm-opt {
  opacity: 1;
  transform: translateY(0);
  transition: background-color .16s ease, color .16s ease,
              opacity .22s ease, transform .34s var(--ease-liquid);
}
.topbar-menu:hover .tm-opt:nth-child(1), .topbar-menu:focus-within .tm-opt:nth-child(1) { transition-delay: 0s, 0s, .04s, .04s; }
.topbar-menu:hover .tm-opt:nth-child(2), .topbar-menu:focus-within .tm-opt:nth-child(2) { transition-delay: 0s, 0s, .08s, .08s; }

@media (prefers-reduced-motion: reduce) {
  .tm-panel, .tm-opt, .tm-caret { transition: none !important; filter: none !important; }
}

/* The two tills in the top bar (Luis, 2026-09-22). Round buttons like the
   bells, but links, with a sprite glyph that shows in every theme. The count
   of today's ledger rows rides in a badge like the other bells' - green while
   the till is in service, red once it is closed out; hidden when it has no
   logs yet today. */
.topbar-icon-btn.topbar-drawer { text-decoration: none; }
.topbar-icon-btn .tb-ico { display: block; width: 22px; height: 22px; color: #1f2d3d; opacity: .72; transition: opacity .18s ease, color .18s ease; }
.topbar-icon-btn:hover .tb-ico { opacity: 1; }
.topbar-badge.drawer-badge.is-online { background: #3f7a68; }   /* in service */
.topbar-badge.drawer-badge.is-closed { background: #c02b22; }   /* closed out */

/* The topbar icons' pill opens DOWNWARD (Luis, 2026-09-22). The shared
   .pos-pop hangs above its host, which is right anywhere in the page but drops
   off the top of the screen on the fixed top bar. Scoped to the icon buttons:
   move it under the icon and slide it down instead of up. The shown state
   (.pos-pop-host:hover > .pos-pop) already resolves to translateY(0), so only
   the resting position and origin flip here. */
.topbar-icon-btn.pos-pop-host > .pos-pop {
  top: calc(100% + 8px);
  bottom: auto;
  transform: translateX(-50%) translateY(-10px) scale(.72);
  transform-origin: 50% -20%;
}

/* ── The top bar search's voice-wave icon (Luis, 2026-09-25) ────────────────
   Four bars that rise and fall out of step, like a voice being heard, and a
   pair of sparkles that pulse. Each bar scales on its own centre, so it
   grows both ways rather than up from the floor. Stills for reduced motion. */
.tb-voice .vb { transform-box: fill-box; transform-origin: center; animation: tbVoice 1.1s ease-in-out infinite; }
.tb-voice .vb1 { animation-delay: 0s; }
.tb-voice .vb2 { animation-delay: .18s; }
.tb-voice .vb3 { animation-delay: .36s; }
.tb-voice .vb4 { animation-delay: .54s; }
@keyframes tbVoice { 0%, 100% { transform: scaleY(1); } 50% { transform: scaleY(.45); } }
.tb-voice .vspark { transform-box: fill-box; transform-origin: center; animation: tbSpark 1.8s ease-in-out infinite; }
.tb-voice .vspark2 { animation-delay: .9s; }
@keyframes tbSpark { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(.55); opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .tb-voice .vb, .tb-voice .vspark { animation: none; } }

/* ── The search button OUTSIDE the field (Luis, 2026-09-25) ─────────────────
   The capsule used to be the wrap, with the button inside it at the right.
   Now the wrap is only a row: the field is its own white pill and the glass
   button sits beside it. Anchored to the ids so no theme's capsule rule
   (apple.css paints the open wrap white) can put the pill back round both. */
#searchWrap.is-open {
  width: auto !important;
  padding: 0 !important;
  gap: 10px !important;
  background: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
}
#searchWrap #topbarSearch {
  width: 280px !important;
  padding: 10px 18px !important;
  background: #ffffff !important;
  border: 1px solid rgba(0, 0, 0, 0.10) !important;
  border-radius: 999px !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04) !important;
  transition: border-color .15s ease, box-shadow .15s ease;
}
#searchWrap #topbarSearch:focus {
  border-color: var(--accent, #1a5fa8) !important;
  box-shadow: 0 0 0 3px rgba(26, 95, 168, 0.12) !important;
}
/* The wave icon larger in its button (Luis, 2026-09-25): 26px, up from 20,
   so the bars and sparkles read at a glance instead of as a smudge. */
.topbar-search-btn .tb-voice { width: 26px !important; height: 26px !important; }
/* The field larger, "SEARCH" centred, gone once you click in, and lifted
   off the bar with a faint top-to-bottom shade and a soft drop (Luis,
   2026-09-25). The full description moved to aria-label so a screen reader
   still hears what the box searches. */
#searchWrap #topbarSearch {
  width: 340px !important;
  padding: 12px 20px !important;
  font-size: 13px !important;
  background: linear-gradient(180deg, #ffffff 0%, #f6f7f9 100%) !important;
  border: 1px solid rgba(0, 0, 0, 0.12) !important;
  box-shadow: 0 2px 8px rgba(31, 45, 61, 0.10), 0 1px 2px rgba(31, 45, 61, 0.06), inset 0 1px 0 #ffffff !important;
}
#searchWrap #topbarSearch::placeholder { text-align: center; letter-spacing: .18em; font-weight: 600; color: #8e9095; }
#searchWrap #topbarSearch:focus::placeholder { color: transparent; }
/* Typed text starts from the centre, like the label (Luis, 2026-09-25). */
#searchWrap #topbarSearch { text-align: center !important; }
/* The wave icon back INSIDE the field, bare (Luis, 2026-09-25): no disc, no
   rim, no glass — just the glyph at the field's right end. Id-anchored with
   !important so the themes' button faces (apple.css's glass) cannot draw the
   disc back. The field pads both sides equally so the centred text stays
   centred with the icon sitting in its right margin. */
#searchWrap { position: relative !important; }
#searchWrap .topbar-search-btn {
  position: absolute !important;
  right: 14px !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  width: 30px !important;
  height: 30px !important;
  padding: 0 !important;
  background: none !important;
  border: 0 !important;
  box-shadow: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}
#searchWrap #topbarSearch { padding-left: 50px !important; padding-right: 50px !important; }

/* ── The search field's border glow, the Total Sales card's (Luis, 2026-09-25)
   Same three parts as #salesCard in dashboard.css: a plum edge, a soft outer
   glow that breathes, and one bright arc travelling the rim. An <input>
   cannot carry ::before/::after, so they hang off #searchWrap, which is
   exactly the field's size now that the button sits inside it. Its own
   keyframes and angle property — dashboard.css's only load on the dashboard,
   and this bar is on every page. */
@property --sb-ang { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
#searchWrap { border-radius: 999px !important; }
#searchWrap #topbarSearch { border-color: rgb(180, 157, 164) !important; }
#searchWrap::before,
#searchWrap::after {
  content: '';
  position: absolute;
  border-radius: 999px;
  pointer-events: none;
  z-index: 1;
}
#searchWrap::before {
  inset: 0;
  box-shadow: 0 0 16px 1px rgba(107, 55, 68, 0.28);
  animation: sbGlowPulse 3.8s ease-in-out infinite;
}
#searchWrap::after {
  inset: 0;
  padding: 1px;
  background: conic-gradient(from var(--sb-ang), transparent 0deg, rgb(118, 70, 82) 16deg, transparent 54deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: sbBorderRun 7s linear infinite;
  opacity: .85;
}
@keyframes sbGlowPulse { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
@keyframes sbBorderRun { to { --sb-ang: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  #searchWrap::before { animation: none; opacity: .5; }
  #searchWrap::after  { animation: none; opacity: .5; }
}
/* On Ink the dark plum would sink into the bar: a lighter plum arc and a
   rosier glow so the ring still shows. */
body.chrome-ink #searchWrap #topbarSearch { border-color: rgba(212, 170, 181, 0.55) !important; }
body.chrome-ink #searchWrap::before { box-shadow: 0 0 16px 1px rgba(212, 150, 166, 0.35); }
body.chrome-ink #searchWrap::after { background: conic-gradient(from var(--sb-ang), transparent 0deg, rgb(232, 180, 195) 16deg, transparent 54deg); }

/* ── Search in the middle, buttons at the end (Luis, 2026-09-25) ─────────────
   topbar.php now puts the search first in the end column. It takes the
   free space either side of it, so it sits centred between the quick links
   and the button group, and the bells and the user badge close the bar at
   the far right. The results drop down centred under the field. */
.topbar-end > #searchWrap { margin: 0 auto !important; }
.topbar-end > .topbar-right { margin: 0 !important; }
#searchWrap .search-dropdown { right: auto; left: 50%; transform: translateX(-50%); }
/* The field gives way before anything overlaps: it keeps its 340px when there
   is room and narrows (down to 170px) when the bar gets tight, instead of
   running over the quick links. */
.topbar-end > #searchWrap.is-open { flex: 0 1 340px !important; min-width: 170px; }
.topbar-end > #searchWrap #topbarSearch { width: 100% !important; min-width: 0; box-sizing: border-box; }
/* The end column sizes from its content (search + buttons) rather than an
   equal half, so when the bar is tight the quick links move toward the
   brand instead of sliding under the search. The brand never gives up its
   own width. */
.topbar > .topbar-left { flex: 1 1 0 !important; min-width: max-content !important; }
.topbar > .topbar-end { flex: 1 1 auto !important; min-width: 0 !important; }
/* Narrower screens: tighter spacing in the button group and a smaller floor
   for the search, so the field doesn't reach the quick links. */
@media (max-width: 1700px) {
  .topbar-end .topbar-right { gap: 10px !important; }
  .topbar-end .topbar-right .topbar-sep { margin: 0 2px !important; }
  .topbar-end > #searchWrap.is-open { min-width: 140px; margin: 0 14px !important; }
}
/* Under 1560px there is no room for the words: the quick links keep their
   icons (the name still shows as the tooltip) so nothing overlaps. */
@media (max-width: 1560px) {
  body .topbar .topbar-center .topbar-action .topbar-action-label { display: none !important; }
  body .topbar .topbar-center .topbar-action { padding: 0 14px !important; gap: 6px !important; }
}
/* Quick Quote (2026-10-09) is the third sale pill, and with its words on the
   bar only fits from 2000px: below that it is the tag alone, and its name is
   the fold-out's first row ("New quote"), so the bar ends where it did. */
@media (max-width: 1999px) {
  body .topbar .topbar-center #quoteMenu .topbar-action[aria-label="Quick Quote"] .topbar-action-label { display: none !important; }
  body .topbar .topbar-center #quoteMenu .topbar-action[aria-label="Quick Quote"] { padding: 0 14px !important; gap: 0 !important; }
}

/* Trade-in credit under a product on the daily sales table (2026-09-25):
   the row is recorded at the money received, this says what else was taken. */
.rep-tradein { font-size: 11px; color: #0b6b4f; margin-top: 2px; white-space: nowrap; }

/* The AI pill's name drops BELOW it: the pill sits at the very top of the
   screen, so the house label's usual place above would be cut off
   (2026-09-26). Same bubble, mirrored entrance. */
.ai-pill > .pos-pop.ai-pop { bottom: auto; top: calc(100% + 8px); transform: translateX(-50%) translateY(-10px) scale(.72); transform-origin: 50% -20%; }
.ai-pill:hover > .pos-pop.ai-pop, .ai-pill:focus-visible > .pos-pop.ai-pop { transform: translateX(-50%) translateY(0) scale(1); }
.ai-pill { position: relative; }
/* A discount under the amount on the daily sales table (2026-09-27). */
.val-sub.val-disc { color: #6b3744; font-weight: 700; }
/* The Dashboard glyph's bubble sits under it like the bell buttons' (Luis,
   2026-09-28): the bar is at the top of the window, so above has no room. */
.topbar-action[aria-label="Dashboard"].pos-pop-host > .pos-pop {
  top: calc(100% + 8px);
  bottom: auto;
  transform: translateX(-50%) translateY(-10px) scale(.72);
  transform-origin: 50% -20%;
}
.topbar-action[aria-label="Dashboard"].pos-pop-host:hover > .pos-pop,
.topbar-action[aria-label="Dashboard"].pos-pop-host:focus-visible > .pos-pop { transform: translateX(-50%) translateY(0) scale(1); }
/* ── The till buttons with their names on (Luis, 2026-09-28) ─────────────────
   Front/Back Drawer stop being bare round icons: a pill with the register's
   name over its state (Idle / Online · who / Closed out), the state in the
   badge's colours. Which of the two a laptop shows is decided in topbar.php
   from its station cookie. */
.topbar-icon-btn.topbar-drawer-labelled {
  width: auto;
  height: 40px;
  border-radius: 999px;
  padding: 0 14px 0 10px;
  gap: 8px;
  justify-content: flex-start;
}
.topbar-drawer-label {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  line-height: 1.05;
  text-align: left;
  font-family: var(--font-ui);
}
.topbar-drawer-label b { font-size: 11px; font-weight: 700; letter-spacing: .02em; color: var(--text-primary); white-space: nowrap; }
.topbar-drawer-label i { font-style: normal; font-size: 9.5px; font-weight: 600; color: var(--text-secondary); white-space: nowrap; }
.topbar-drawer-label i.is-online { color: #3f7a68 !important; }
.topbar-drawer-label i.is-closed { color: #c02b22 !important; }
/* The count hangs off the pill's corner, clear of the words (Luis, 2026-09-28). */
.topbar-icon-btn.topbar-drawer-labelled { padding-right: 16px; }
.topbar-icon-btn.topbar-drawer-labelled .topbar-badge { top: -6px; right: -4px; }
/* Three tills on one bar — the office and the repair station show the Office
   Drawer too (Luis, 2026-10-05). Under 1700px three labelled pills push the
   search down to a stub and the user button off the edge, so there they
   become icons with their counts, like the bells, and the name comes back in
   the house bubble on hover. Wider, the words stay and the bubble never shows. */
.topbar-drawer-labelled > .tb-drawer-pop { display: none; }
@media (max-width: 1700px) {
  .topbar-icon-btn.topbar-drawer-labelled.tb-drawer-3 { width: 40px !important; padding: 0 !important; gap: 0 !important; justify-content: center !important; }
  .topbar-drawer-labelled.tb-drawer-3 .topbar-drawer-label { display: none !important; }
  .topbar-drawer-labelled.tb-drawer-3 > .tb-drawer-pop { display: block; }
}
/* A refunded ticket's line under the product (2026-09-28), red like the money. */
.rep-refunded { font-size: 11px; color: #b3141d; font-weight: 700; margin-top: 2px; }
/* The three bells beside the brand (Luis, 2026-09-28), a group of their own
   between the name and the home glyph. */
.topbar-bells { display: flex; align-items: center; gap: 12px; margin-left: 14px; flex: 0 0 auto; }
.topbar-bells .notif-dropdown { left: 0; right: auto; }
/* Brand + bells as one side, the end column the other, both growing from
   zero so the notch (home glyph and the two sale pills) sits dead centre
   whatever the screen width (Luis, 2026-09-28). The bells live inside the
   brand box now, so they hug the name. */
.topbar-left { flex: 1 1 0 !important; min-width: 0; display: flex; align-items: center; }
.topbar-left .topbar-brand { flex: 0 0 auto !important; }
.topbar-bells { margin-left: 18px; }
/* Both sides grow from zero (a later rule had put the end column back to
   flex-basis auto, so it grew from its content and the notch drifted left). */
.topbar > .topbar-end  { flex: 1 1 0 !important; min-width: auto !important; }
.topbar > .topbar-left { flex: 1 1 0 !important; min-width: auto !important; }
/* min-width auto, not 0: flexbox's own floor at each side's content, so a
   tight window shrinks the search first and never lets it ride over the menu. */
/* The bells centred in the gap between the name and the menu (Luis, 2026-09-28). */
.topbar-left .topbar-bells { margin: 0 auto; }
/* ── The three bells' hover ring (Luis, 2026-09-29) ─────────────────────────
   The Daily Sales avatar's ring, on the bell buttons beside the brand: a thin
   green ring grows out of the disc and fades, while the pointer is on it.
   Still for anyone who asked their system for less motion. */
.topbar-bells .topbar-icon-btn::after {
  content: ''; position: absolute; inset: -3px; border-radius: 50%;
  border: 1.5px solid rgba(63, 122, 104, 0.75);
  opacity: 0; pointer-events: none; transform: scale(1);
}
.topbar-bells .topbar-icon-btn:hover::after { animation: tb-ring 1.6s ease-out infinite; }
@keyframes tb-ring { 0% { transform: scale(1); opacity: 0.7; } 100% { transform: scale(1.55); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .topbar-bells .topbar-icon-btn:hover::after { animation: none; opacity: 0.5; } }

/* ── Moving between pages (Luis, 2026-10-15) ────────────────────────────────
   "every click feels hard … even page reload". Each page is a real load, so
   the browser painted white and then slammed the next page in. With both
   pages opting in here (every POS page loads this sheet), the browser holds
   the old frame and cross-fades to the new one instead. The drawer pages did
   this first (drawer/app.css); this is the same setting for the rest.

   Only between pages: a reload or an address typed in never cross-fades, the
   browser's own rule. The repair checkout's panel fades in on a reload of its
   own (repairs/index.php). Where the browser cannot do it, the page simply
   loads as before. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .26s;
  animation-timing-function: cubic-bezier(.22, 1, .36, 1);
}

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}
