/* Embello Hub - utility-first, mobile-first.
   Brand: charcoal #23282D + Embello orange #F27E3F on cool paper #F5F6F8.
   Carbon-copy of the Lordwell Hub design system, retokenised for Embello. */

:root {
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bot: env(safe-area-inset-bottom, 0px);

  /* Light theme (default) */
  --ink:        #23282D;
  --ink-soft:   #485666;
  --ink-mute:   #8A94A6;
  --cream:      #F5F6F8;
  --cream-deep: #ECEEF1;
  --coral:      #F27E3F;
  --coral-deep: #E0662A;
  --coral-soft: #FCE4D0;
  --line:       #E3E7EC;

  /* Surface tokens (used by cards / sheets in dark mode flips) */
  --surface:        #FFFFFF;     /* card backgrounds */
  --surface-2:      #F5F6F8;     /* nested cards / chrome */
  --surface-3:      #EDEFF2;     /* hover / subtle highlight */
  --text:           var(--ink);
  --text-soft:      var(--ink-soft);
  --text-mute:      var(--ink-mute);
  --shadow-card:    0 1px 0 rgba(40,47,55,0.04), 0 4px 14px rgba(40,47,55,0.06);
}

/* Dark theme - opt in by setting data-theme="dark" on <html>.
   Re-points the same brand tokens to darker equivalents, plus the new
   surface tokens get inverted. Existing components that use var(--ink),
   var(--cream) etc. flip automatically. */
[data-theme="dark"] {
  --ink:        #F4F6F8;    /* primary text → near-white cream */
  --ink-soft:   #AEB6C0;
  --ink-mute:   #79818C;
  --cream:      #14171B;    /* page background → near-black */
  --cream-deep: #1C2026;    /* nested chrome */
  --coral:      #F79452;    /* slightly brighter coral on dark */
  --coral-deep: #F27E3F;
  --coral-soft: #3A2A1A;
  --line:       #2A2F36;

  --surface:    #1C2026;    /* card */
  --surface-2:  #14171B;
  --surface-3:  #2A2F36;
  --text:       var(--ink);
  --text-soft:  var(--ink-soft);
  --text-mute:  var(--ink-mute);
  --shadow-card: 0 1px 0 rgba(0,0,0,0.3), 0 4px 14px rgba(0,0,0,0.4);

  color-scheme: dark;
}
/* Card background colour driven by surface var - many components use
   bg-white via Tailwind; we override that to use the var in dark mode. */
[data-theme="dark"] .card,
[data-theme="dark"] .bg-white { background:var(--surface) !important; color:var(--text); }
[data-theme="dark"] .bg-cream { background:var(--cream) !important; }
[data-theme="dark"] .bg-cream-deep { background:var(--cream-deep) !important; }
[data-theme="dark"] .text-ink { color:var(--ink) !important; }
[data-theme="dark"] .text-ink-soft { color:var(--ink-soft) !important; }
[data-theme="dark"] .text-ink-mute { color:var(--ink-mute) !important; }
[data-theme="dark"] .border-line { border-color:var(--line) !important; }
[data-theme="dark"] .divide-line > * + * { border-color:var(--line) !important; }
[data-theme="dark"] input, [data-theme="dark"] textarea, [data-theme="dark"] select {
  background:var(--surface-3); color:var(--text); border-color:var(--line);
}
[data-theme="dark"] input::placeholder, [data-theme="dark"] textarea::placeholder {
  color:var(--ink-mute);
}
[data-theme="dark"] body { background:var(--cream); color:var(--text); }

html, body { -webkit-tap-highlight-color: transparent; overscroll-behavior-y: none; }
/* iOS Safari only honours text-size-adjust reliably on the html element -
   without it, Safari's text autosizing inflates fonts on some layouts. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { font-feature-settings: "ss01","cv11"; -webkit-text-size-adjust: 100%; }

/* ── Remove 300ms tap delay on all interactive elements ─────────────────── */
a, button, label, .btn, .row, .tb-tab, .tt-tab, .assignee-chip,
.type-sel-btn, [role="button"], input[type="checkbox"], input[type="radio"] {
  touch-action: manipulation;
}

/* Prevent text selection during swipe/tap gestures on UI chrome */
.bottom-nav, .app-header, .btn, .tb-tab, .tt-tab, .type-sel-btn, .assignee-chip {
  user-select: none; -webkit-user-select: none;
}

/* Brand caret colour inside every input */
input, textarea, select { caret-color: var(--coral); }

/* Brand wordmark - uses the actual SVG */
.wordmark-img { height: 22px; width: auto; display: block; }

/* Status pills */
.pill { display:inline-flex; align-items:center; gap:.35rem; padding:.18rem .55rem; border-radius:999px; font-size:.72rem; font-weight:600; line-height:1; }
.pill-ok      { background:#E5F1EA; color:#205C3A; }
.pill-warn    { background:#FAEDD7; color:#7A4E10; }
.pill-danger  { background:#FFE0E0; color:#9B2A2A; }
.pill-info    { background:#E2E6EC; color:var(--ink); }
.pill-muted   { background:#EFEAD9; color:#564A29; }
.pill-coral   { background:var(--coral-soft); color:#9B2A2A; }
.pill-ink     { background:var(--ink); color:#fff; }

/* Card */
.card { background:#fff; border:1px solid var(--line); border-radius:14px; box-shadow:0 1px 0 rgba(40,47,55,.04), 0 4px 14px rgba(40,47,55,.06); }

/* Tap-target row */
.row { display:flex; align-items:center; gap:.75rem; padding:.85rem 1rem; min-height:64px; transition:background .1s ease; -webkit-tap-highlight-color:transparent; }
.row:active { background: var(--cream-deep); }
.row + .row { border-top:1px solid #EFE8D5; }

/* Buttons */
.btn { display:inline-flex; align-items:center; justify-content:center; gap:.5rem; text-decoration:none; padding:.85rem 1rem; border-radius:12px; font-weight:600; min-height:48px; transition: transform .08s ease, background .12s, border-color .12s, opacity .12s; -webkit-tap-highlight-color:transparent; }
.btn:active { transform: scale(.97); opacity: .88; }
.btn-primary { background:#23282D; color:#fff; }
.btn-primary:hover { background:#1A2128; }
.btn-coral   { background:var(--coral); color:#fff; }
.btn-coral:hover { background:var(--coral-deep); }
.btn-ghost   { background:#EDEFF2; color:#23282D; }
.btn-outline { background:#fff; border:1.5px solid #D8CFB6; color:#23282D; }
.btn-danger  { background:#B43A3A; color:#fff; }
.btn-block   { width:100%; }
.btn[disabled] { opacity:.45; pointer-events:none; }

/* Dark-mode button overrides - the rules above hard-pin colours to the
   light palette so the cream/ink tokens don't flip and produce cream-on-cream
   ghost text in dark mode. These rules handle the dark variant explicitly. */
[data-theme="dark"] .btn-primary {
  background: #F4F6F8; color: #14171B;
}
[data-theme="dark"] .btn-primary:hover { background: #fff; }
[data-theme="dark"] .btn-outline {
  background: transparent; border-color: #3A434F; color: #F4F6F8;
}
[data-theme="dark"] .btn-outline:hover { background: rgba(255,255,255,.04); }
[data-theme="dark"] .btn-ghost {
  background: #2A2F36; color: #F4F6F8;
}
[data-theme="dark"] .btn-coral { background: #F27E3F; color: #fff; }

/* Force the segmented-control + inline-styled toggle buttons in customer-list
   to play nicely in dark mode. Anywhere a button uses inline white bg + ink
   text we override here. */
[data-theme="dark"] button.js-mode[style*="background: rgb(255, 255, 255)"],
[data-theme="dark"] button.js-mode[style*="background:#fff"] {
  background: #2A2F36 !important; color: #F4F6F8 !important;
}

/* Modern segmented control - used for pill-style two/three-up toggles
   (e.g. View as / All vs Pipeline). Replaces the old inline-style approach
   so it themes correctly. Markup:
     <div class="seg" role="tablist">
       <button class="seg-btn is-active" data-v="a">A</button>
       <button class="seg-btn" data-v="b">B</button>
     </div>
*/
.seg {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 4px;
  padding: 4px;
  border-radius: 14px;
  background: #EDE7D9;
  border: 1px solid rgba(40,47,55,.06);
}
.seg-btn {
  appearance: none;
  border: none;
  background: transparent;
  font: inherit;
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: -.005em;
  color: #8A94A6;
  padding: .55rem .5rem;
  min-height: 36px;
  border-radius: 10px;
  cursor: pointer;
  transition: background .18s ease, color .18s ease, box-shadow .18s ease, transform .08s ease;
  -webkit-tap-highlight-color: transparent;
  display: inline-flex; align-items: center; justify-content: center; gap: .35rem;
  white-space: nowrap;
}
.seg-btn:active { transform: scale(.97); }
.seg-btn.is-active {
  background: #fff;
  color: #23282D;
  box-shadow: 0 1px 0 rgba(40,47,55,.04), 0 2px 8px rgba(40,47,55,.10);
}
[data-theme="dark"] .seg {
  background: #181D23;
  border-color: rgba(255,255,255,.04);
}
[data-theme="dark"] .seg-btn { color: #8A9099; }
[data-theme="dark"] .seg-btn.is-active {
  background: #2A2F36;
  color: #F4F6F8;
  box-shadow: 0 1px 0 rgba(0,0,0,.4), 0 2px 8px rgba(0,0,0,.25);
}

/* Dropdown <select> - has to fight the browser's native dark-mode rendering.
   The base rule on line 65 sets background/color; this adds the chevron and
   tightens borders so it doesn't look like a cream brick in dark mode. */
[data-theme="dark"] select,
[data-theme="dark"] .input,
[data-theme="dark"] .select,
[data-theme="dark"] .textarea {
  background: #1C2026 !important;
  color: #F4F6F8 !important;
  border-color: #2A2F36 !important;
}
[data-theme="dark"] select option {
  background: #1C2026; color: #F4F6F8;
}

/* ─────────────────────────────────────────────────────────────────────────
   DARK-MODE BROAD SWEEP
   The codebase has ~100 inline `style="background:#fff"` and a handful of
   CSS rules with hardcoded #fff that don't flip via the .bg-white override
   alone. This block catches them via attribute selectors + named-class
   overrides so the dark theme is actually usable everywhere.
   Edge cases that need to stay light (e.g. PDFs, the dark gradient profit
   strip with intentionally white text) are explicitly NOT matched here.
   ───────────────────────────────────────────────────────────────────── */

/* CSS-class surfaces that use hardcoded #fff in their default rule */
[data-theme="dark"] .stat,
[data-theme="dark"] .row,
[data-theme="dark"] .input,
[data-theme="dark"] .select,
[data-theme="dark"] .textarea {
  background: var(--surface) !important;
  border-color: var(--line) !important;
  color: var(--ink) !important;
}
[data-theme="dark"] .stat .num,
[data-theme="dark"] .stat .lbl,
[data-theme="dark"] .row,
[data-theme="dark"] .row .text-ink,
[data-theme="dark"] .row [class*="font-"] { color: var(--ink) !important; }
[data-theme="dark"] .stat .lbl { color: var(--ink-mute) !important; }
[data-theme="dark"] .row + .row { border-color: var(--line) !important; }
[data-theme="dark"] .row:active { background: var(--surface-2) !important; }

/* Inline white / cream surfaces - flip to the dark card surface */
[data-theme="dark"] [style*="background:#fff"],
[data-theme="dark"] [style*="background: #fff"],
[data-theme="dark"] [style*="background:white"],
[data-theme="dark"] [style*="background: white"],
[data-theme="dark"] [style*="background:#FFFFFF"],
[data-theme="dark"] [style*="background:#F5F6F8"],
[data-theme="dark"] [style*="background:#FAF6EC"],
[data-theme="dark"] [style*="background:#EDEFF2"],
[data-theme="dark"] [style*="background:#EDEBE6"],
[data-theme="dark"] [style*="background:#EDE7D9"],
[data-theme="dark"] [style*="background:#EDE9E0"],
[data-theme="dark"] [style*="background:#F0EAD6"],
[data-theme="dark"] [style*="background:#ECEEF1"],
[data-theme="dark"] [style*="background:#FCFAF3"] {
  background: var(--surface) !important;
}

/* Inline coral-tint pills / banners - keep the coral feel but flip darker */
[data-theme="dark"] [style*="background:#FFF1F0"],
[data-theme="dark"] [style*="background:#FFEDE5"],
[data-theme="dark"] [style*="background:#FFE0E0"],
[data-theme="dark"] [style*="background:#FCE4D0"] {
  background: rgba(255,107,107,.10) !important;
}

/* Inline gradient backgrounds that start with #FFF1F0 (the pipeline summary
   already has a dedicated class but other places use raw gradients). */
[data-theme="dark"] [style*="linear-gradient(135deg,#FFF1F0"],
[data-theme="dark"] [style*="linear-gradient(135deg, #FFF1F0"] {
  background: linear-gradient(135deg, rgba(255,107,107,.12) 0%, rgba(255,107,107,.06) 100%) !important;
}

/* Inline cream borders */
[data-theme="dark"] [style*="border:1px solid #E3E7EC"],
[data-theme="dark"] [style*="border: 1px solid #E3E7EC"],
[data-theme="dark"] [style*="border:1px solid #EFE8D5"],
[data-theme="dark"] [style*="border: 1px solid #EFE8D5"],
[data-theme="dark"] [style*="border:1px solid #ddd8d0"],
[data-theme="dark"] [style*="border:1px solid #D8CFB6"],
[data-theme="dark"] [style*="border:1px solid #FCE4D0"],
[data-theme="dark"] [style*="border:2px solid #FECACA"],
[data-theme="dark"] [style*="border-color:#EFE8D5"] {
  border-color: var(--line) !important;
}

/* Inline dark text colours (#2A2E37, #23282D, #485666) need to flip
   when their surface flips - otherwise dark-on-dark. Skip elements that
   live inside a deliberately-dark gradient banner; those keep #fff text. */
[data-theme="dark"] [style*="color:#2A2E37"],
[data-theme="dark"] [style*="color: #2A2E37"],
[data-theme="dark"] [style*="color:#23282D"],
[data-theme="dark"] [style*="color: #23282D"],
[data-theme="dark"] [style*="color:#1C2228"] {
  color: var(--ink) !important;
}
[data-theme="dark"] [style*="color:#485666"],
[data-theme="dark"] [style*="color: #485666"] {
  color: var(--ink-soft) !important;
}

/* Sheet / modal panels often use raw #fff. Catch those too. */
[data-theme="dark"] .sheet-panel,
[data-theme="dark"] .modal-panel,
[data-theme="dark"] [class*="sheet"] [style*="background"] {
  background: var(--surface) !important;
  color: var(--ink);
}

/* Bottom nav surface in dark - make sure it's not still semi-transparent white */
[data-theme="dark"] .bottom-nav {
  background: rgba(22,26,31,.9) !important;
  border-color: rgba(255,255,255,.08) !important;
}

/* Task-board filter chips + tabs use a `.tb-tab` / `.tt-tab` class with
   hardcoded cream backgrounds. */
[data-theme="dark"] .tb-tab,
[data-theme="dark"] .tt-tab,
[data-theme="dark"] .type-sel-btn,
[data-theme="dark"] .assignee-chip {
  background: #1C2026 !important;
  color: #AEB6C0 !important;
  border-color: #2A2F36 !important;
}
[data-theme="dark"] .tb-tab.is-active,
[data-theme="dark"] .tt-tab.is-active,
[data-theme="dark"] .type-sel-btn.is-active,
[data-theme="dark"] .assignee-chip.is-active,
[data-theme="dark"] .tb-tab[aria-current="page"],
[data-theme="dark"] [aria-selected="true"] {
  background: #2A2F36 !important;
  color: #F4F6F8 !important;
}

/* The task-card class uses hardcoded #fff via inline-style block in
   tasks-list.js (`.task-card { background:#fff }`). */
[data-theme="dark"] .task-card {
  background: var(--surface) !important;
  border-color: var(--line) !important;
  color: var(--ink);
}

/* Pipeline summary banner (Customers → Pipeline view).
   In light mode: warm coral-tint card. In dark mode: deep coral tint that
   still feels like the "hot" pipeline strip but isn't a white brick. */
.pipeline-summary {
  padding: 14px;
  background: linear-gradient(135deg,#FFF1F0 0%,#FFEDE5 100%);
  border: 1px solid #FCE4D0;
}
.pipeline-summary .ps-title { font-weight: 800; color: #2A2E37; }
.pipeline-summary .ps-sub   { font-size: .74rem; color: #485666; }
.pipeline-summary .ps-stats { display:flex; gap:10px; font-size:.72rem; font-weight:700; color:#485666; }
[data-theme="dark"] .pipeline-summary {
  background: linear-gradient(135deg, rgba(255,107,107,.12) 0%, rgba(255,107,107,.06) 100%);
  border-color: rgba(255,107,107,.22);
}
[data-theme="dark"] .pipeline-summary .ps-title { color: #FAEEEA; }
[data-theme="dark"] .pipeline-summary .ps-sub,
[data-theme="dark"] .pipeline-summary .ps-stats { color: #AEB6C0; }

/* Postcode "filter" pill input - keeps its compact look but flips bg in dark. */
.postcode-pill {
  display: flex; align-items: center; gap: 8px;
  background: #fff;
  border: 1px solid #ddd8d0;
  border-radius: 10px;
  padding: 6px 10px;
}
.postcode-pill input {
  flex: 1; border: none; outline: none; background: transparent;
  font-size: .85rem; color: var(--ink); text-transform: uppercase; min-width: 0;
}
[data-theme="dark"] .postcode-pill {
  background: #1C2026;
  border-color: #2A2F36;
}
[data-theme="dark"] .postcode-pill input { color: #F4F6F8; }

/* Inline "Edit" mini pill (used on profile + a few other places). */
.mini-pill {
  font-size: .68rem; font-weight: 700; color: #485666;
  background: #F0EAD6; border: none; border-radius: 6px;
  padding: 2px 7px; cursor: pointer; white-space: nowrap;
  transition: background .12s, color .12s;
}
.mini-pill:hover { background: #E6DEC4; }
[data-theme="dark"] .mini-pill {
  background: #2A2F36; color: #AEB6C0;
}
[data-theme="dark"] .mini-pill:hover { background: #353D47; color: #F4F6F8; }

/* Field label above each filter dropdown - slight contrast bump in dark. */
.field-label {
  font-size: .62rem; font-weight: 800;
  color: #8A94A6; letter-spacing: .06em; text-transform: uppercase;
  display: block; margin-bottom: 3px;
}
[data-theme="dark"] .field-label { color: #8A9099; }

/* Inputs */
.input, .select, .textarea {
  width:100%; padding:.8rem .9rem; border-radius:12px; border:1.5px solid #D8CFB6;
  background:#fff; color:var(--ink); font-size:16px; min-height:48px;
  transition: border-color .15s, box-shadow .15s;
  -webkit-appearance: none; appearance: none;
}
.input:focus, .select:focus, .textarea:focus {
  outline:none; border-color:var(--coral); box-shadow:0 0 0 3px rgba(255,107,107,.12);
}
.label { font-size:.8rem; font-weight:600; color:var(--ink-soft); margin-bottom:.35rem; display:block; }

/* Bottom nav - slides away when keyboard opens */
.bottom-nav {
  /* Floating pill: detached from the edges, lifted above the home indicator. */
  position: fixed;
  bottom: calc(var(--safe-bot) + 12px);
  left: 14px; right: 14px;
  background: rgba(255,255,255,.86);
  backdrop-filter: saturate(180%) blur(24px);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  border: 1px solid rgba(0,0,0,.06);
  border-radius: 24px;
  box-shadow: 0 10px 34px rgba(40,47,55,.20), 0 2px 8px rgba(40,47,55,.10);
  z-index: 50;
  height: 64px;
  min-height: 64px;
  align-items: stretch;
  overflow: hidden;
  transition: transform .22s cubic-bezier(.4,0,.2,1);
  will-change: transform;
}

/* Regular nav items */
.bottom-nav a,
.bottom-nav button.bn-item {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: 8px 4px 10px;
  color: #A09890; font-size: 10.5px; font-weight: 700;
  letter-spacing: .01em; text-decoration: none;
  background: none; border: none; cursor: pointer;
  position: relative; transition: color .15s;
}
.bottom-nav a[aria-current="page"],
.bottom-nav button.bn-item[aria-current="page"] { color: var(--coral); }

/* Coral dot indicator under active label */
.bottom-nav a[aria-current="page"]::after,
.bottom-nav button.bn-item[aria-current="page"]::after {
  content: '';
  position: absolute;
  bottom: 5px;
  left: 50%; transform: translateX(-50%);
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--coral);
}

/* Nav icon - no background, just the icon */
.nav-icon {
  width: 30px; height: 30px;
  border-radius: 8px;
  display: grid; place-items: center;
  font-size: 1.15rem; line-height: 1;
  color: #A09890;
  transition: color .15s, transform .1s;
}
.bottom-nav a[aria-current="page"] .nav-icon,
.bottom-nav button.bn-item[aria-current="page"] .nav-icon {
  color: var(--coral);
  background: transparent;
  transform: scale(1.08);
}

/* FAB - elevated coral button in centre */
.bn-fab-wrap {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding-bottom: 10px;
  gap: 3px;
}
.bn-fab-btn {
  width: 50px; height: 50px;
  border-radius: 16px;
  background: var(--coral);
  color: #fff;
  display: grid; place-items: center;
  font-size: 1.6rem; font-weight: 300; line-height: 1;
  box-shadow: 0 4px 18px rgba(255,107,107,.45), 0 1px 4px rgba(255,107,107,.25);
  border: none; cursor: pointer;
  transform: translateY(-10px);
  transition: transform .15s, box-shadow .15s;
  flex-shrink: 0;
}
.bn-fab-btn:active {
  transform: translateY(-10px) scale(.92);
  box-shadow: 0 2px 8px rgba(255,107,107,.35);
}

/* Long-press feedback (because iOS Safari has no haptic API).
   `.is-pressing` paints a ring that fills during the 420 ms long-press
   window; `.is-fired` plays a quick coral-glow pop when the long-press
   triggers and the palette opens. */
.bn-fab-btn.is-pressing {
  transform: translateY(-10px) scale(1.08);
  box-shadow:
    0 0 0 6px rgba(255,107,107,.18),
    0 0 0 12px rgba(255,107,107,.08),
    0 4px 18px rgba(255,107,107,.45);
  transition: transform .42s ease-out, box-shadow .42s ease-out;
}
.bn-fab-btn.is-fired {
  animation: lw-fab-fire .38s ease-out;
}
@keyframes lw-fab-fire {
  0%   { transform: translateY(-10px) scale(1.18);
         box-shadow: 0 0 0 14px rgba(255,107,107,.35), 0 0 0 28px rgba(255,107,107,.0), 0 4px 18px rgba(255,107,107,.6); }
  60%  { transform: translateY(-10px) scale(.96);
         box-shadow: 0 0 0 0 rgba(255,107,107,.0), 0 4px 18px rgba(255,107,107,.45); }
  100% { transform: translateY(-10px) scale(1);
         box-shadow: 0 4px 18px rgba(255,107,107,.45), 0 1px 4px rgba(255,107,107,.25); }
}
.bn-fab-label {
  font-size: 10.5px; font-weight: 700;
  color: var(--coral);
  letter-spacing: .01em;
  margin-top: -2px;
}

/* Header */
.app-header {
  padding-top: calc(var(--safe-top) + 12px);
  padding-bottom: 12px;
  background: linear-gradient(180deg, var(--cream) 0%, var(--cream) 70%, rgba(250,247,240,0));
  position: sticky; top:0; z-index: 30;
}

/* Cold-start skeletons paint full-screen straight into #app (router.js)
   BEFORE the shell + its safe-area-aware .app-header mount, so on a
   notched iPhone in standalone mode the skeleton's title slides under the
   status-bar clock. Reserve the inset here. Scoped to the direct child of
   #app so warm navigations (skeleton nested under #app-main, already below
   .app-header) don't get a double gap. */
#app > .with-bn { padding-top: var(--safe-top); }

/* Big stat */
.stat { display:flex; flex-direction:column; gap:4px; padding:14px; background:#fff; border:1px solid #EFE8D5; border-radius:14px; }
.stat .num { font-family:'Poppins', 'Nunito', sans-serif; font-weight:700; font-size:30px; line-height:1; color:var(--ink); letter-spacing:-0.01em; }
.stat .lbl { font-size:.72rem; font-weight:600; color:var(--ink-mute); text-transform:uppercase; letter-spacing:.06em; }

/* Sheet (bottom modal) */
.sheet-overlay { position:fixed; inset:0; background:rgba(40,47,55,.45); }
.sheet-panel {
  position:absolute; left:0; right:0; bottom:0; background:#fff;
  border-radius:18px 18px 0 0; box-shadow:0 -8px 30px rgba(40,47,55,.18);
  padding-bottom: max(var(--safe-bot), 8px);
  /* dvh shrinks automatically when the iOS keyboard appears */
  max-height: 92dvh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  /* Smooth sheet presentation */
  will-change: transform;
}
/* Drag handle at top of every sheet */
.sheet-panel::before {
  content:''; display:block; width:36px; height:4px;
  background:#D8CFB6; border-radius:999px;
  margin:10px auto 4px;
}
/* Extra breathing room at the bottom of sheet content so last inputs
   don't sit flush against the keyboard when it's open */
.sheet-body { padding-bottom: env(keyboard-inset-height, 0px); }

/* Lapsed-customers action chips/toggles are styled inline (style-only hooks),
   so give them a visible keyboard focus ring like the rest of the app. */
.lw-chip:focus-visible, .js-day-btn:focus-visible, .js-done:focus-visible,
.js-unassigned:focus-visible { outline: 2px solid var(--coral); outline-offset: 2px; }

/* Modal */
.modal-overlay { position:fixed; inset:0; background:rgba(40,47,55,.55); display:grid; place-items:center; padding:16px; }
.modal-panel { background:#fff; border-radius:16px; max-width: 480px; width:100%; max-height:88vh; overflow:auto; }

/* Toast */
.toast { background:var(--ink); color:#fff; padding:.7rem 1rem; border-radius:12px; box-shadow:0 8px 24px rgba(0,0,0,.18); font-weight:500; pointer-events:auto; max-width:92vw; }
.toast.ok { background:#205C3A; }
.toast.warn { background:#7A4E10; }
.toast.err { background:#9B2A2A; }

/* Helpers */
.hr-soft { height:1px; background:#EFE8D5; }
.divider-label { display:flex; align-items:center; gap:.6rem; color:var(--ink-mute); font-size:.72rem; font-weight:600; text-transform:uppercase; letter-spacing:.08em; }
.divider-label::before, .divider-label::after { content:""; flex:1; height:1px; background:#EFE8D5; }

/* Camera + scanner */
.camera-stage { position:relative; background:#000; aspect-ratio: 3/4; border-radius:14px; overflow:hidden; }
.camera-stage video, .camera-stage canvas { width:100%; height:100%; object-fit: cover; display:block; }
.shutter { width:74px; height:74px; border-radius:999px; background:#fff; border:5px solid var(--coral); }

/* Scrollable lists keep room for bottom nav */
.with-bn { padding-bottom: calc(92px + var(--safe-bot)); }

/* Photo thumb grid */
.thumb-grid { display:grid; grid-template-columns: repeat(3, 1fr); gap:8px; }
.thumb-grid img { aspect-ratio:1; object-fit:cover; border-radius:10px; width:100%; }

/* Display headings */
.display { font-family:'Poppins','Nunito',sans-serif; font-weight:700; letter-spacing:-0.015em; color:var(--ink); }

/* Subtle motion */
@media (prefers-reduced-motion: no-preference) {
  .fade-in { animation: fade .18s ease-out both; }
  @keyframes fade { from { opacity:0; transform: translateY(4px) } to { opacity:1; transform:none } }

  /* Page-level enter - applied by router on every navigation */
  .page-enter { animation: pageIn .2s ease-out both; }
  @keyframes pageIn {
    from { opacity: 0; transform: translateY(7px); }
    to   { opacity: 1; transform: none; }
  }
}

/* Card tap feedback for tappable cards */
a.card, .card[onclick], .task-card {
  -webkit-tap-highlight-color: transparent;
  transition: box-shadow .12s ease, border-color .12s ease, opacity .08s ease;
}
a.card:active, .task-card:active { opacity: .88; }

/* Coral smile underline - small brand flourish under section titles */
.title-row { display:flex; align-items:flex-end; justify-content:space-between; gap:.75rem; }
.smile-mark { display:inline-block; width:24px; height:6px; border-radius:0 0 12px 12px; background:var(--coral); margin-top:2px; }

/* Print friendly POD */
@media print {
  .no-print { display:none !important; }
}

/* ── Desktop / responsive ───────────────────────────────────────────────── */

/* App shell becomes a row on desktop */
.app-shell { display:flex; flex-direction:column; flex:1; min-height:100svh; }
.app-shell-content { display:flex; flex-direction:column; flex:1; min-width:0; }

/* Sidebar.
   Mobile: an off-canvas DRAWER the header hamburger slides in (no more
   rotating to landscape just to reach the nav). On ≥768px the media query
   below reverts it to a static, always-visible sidebar and hides the
   hamburger + scrim. */
.desktop-sidebar {
  display:flex;
  width:min(82vw, 284px); min-width:0;
  background:linear-gradient(180deg, #1C2026 0%, #23282D 100%);
  color:#fff;
  flex-direction:column;
  position:fixed; top:0; left:0; bottom:0;
  padding-top:var(--safe-top); padding-bottom:var(--safe-bot);
  transform:translateX(-100%);
  transition:transform .28s cubic-bezier(.2,.7,.2,1);
  overflow-y:auto; z-index:95;
  box-shadow:0 0 50px rgba(0,0,0,.4);
  border-right:1px solid rgba(255,255,255,.04);
}
.desktop-sidebar.is-open { transform:translateX(0); }

/* Dim scrim behind the open drawer; tap anywhere on it to close. */
.sidebar-scrim {
  position:fixed; inset:0; z-index:90;
  background:rgba(20,24,30,.5);
  opacity:0; pointer-events:none;
  transition:opacity .28s ease;
}
.sidebar-scrim.is-open { opacity:1; pointer-events:auto; }

/* Header hamburger (mobile only - the header itself is hidden ≥768px). */
.js-menu-btn { background:transparent; border:none; cursor:pointer; -webkit-tap-highlight-color:transparent; }
.js-menu-btn:active { transform:scale(.92); }

@media (prefers-reduced-motion: reduce) {
  .desktop-sidebar, .sidebar-scrim { transition:none; }
}
.desktop-sidebar::-webkit-scrollbar { width:6px; }
.desktop-sidebar::-webkit-scrollbar-thumb { background:rgba(255,255,255,.08); border-radius:3px; }
.desktop-sidebar .ds-brand {
  padding:1.1rem 1rem .9rem;
  border-bottom:1px solid rgba(255,255,255,.07);
  display:flex; flex-direction:column; gap:.5rem;
}
.desktop-sidebar .wordmark-img { filter:brightness(0) invert(1); }
.desktop-sidebar .ds-nav { flex:1; padding:.5rem 0 1rem; overflow-y:auto; }

/* ── Group sections ─────────────────────────────────────────────────── */
.desktop-sidebar .ds-group { padding:.4rem 0; }
.desktop-sidebar .ds-group + .ds-group {
  border-top:1px solid rgba(255,255,255,.05);
  margin-top:.3rem;
  padding-top:.6rem;
}
.desktop-sidebar .ds-group-heading {
  padding:.2rem 1.1rem .35rem;
  font-size:.66rem;
  font-weight:700;
  letter-spacing:.1em;
  text-transform:uppercase;
  color:rgba(255,255,255,.32);
}

/* ── Nav items ──────────────────────────────────────────────────────── */
.desktop-sidebar .ds-nav a {
  position:relative;
  display:flex; align-items:center; gap:.7rem;
  padding:.55rem 1rem .55rem .75rem;
  margin:.05rem .5rem;
  border-radius:9px;
  color:rgba(255,255,255,.68);
  font-weight:600; font-size:.84rem;
  text-decoration:none;
  transition:background .15s, color .15s, transform .12s;
}
.desktop-sidebar .ds-nav a:hover {
  background:rgba(255,255,255,.06);
  color:#fff;
}
.desktop-sidebar .ds-nav a:active { transform:scale(.985); }
.desktop-sidebar .ds-nav a.ds-active {
  background:rgba(255,107,107,.13);
  color:#fff;
}
.desktop-sidebar .ds-nav a.ds-active::before {
  content:'';
  position:absolute;
  left:-.5rem; top:.4rem; bottom:.4rem;
  width:3px;
  background:var(--coral);
  border-radius:0 3px 3px 0;
}
.desktop-sidebar .ds-ico {
  width:26px; height:26px; border-radius:7px;
  display:grid; place-items:center;
  background:rgba(255,255,255,.05);
  flex-shrink:0;
  font-size:.95rem;
  transition:background .15s;
}
.desktop-sidebar .ds-nav a.ds-active .ds-ico {
  background:var(--coral);
  box-shadow:0 2px 8px rgba(255,107,107,.35);
}
.desktop-sidebar .ds-label { flex:1; min-width:0; }
.desktop-sidebar .ds-badge {
  background:var(--coral);
  color:#fff;
  border-radius:999px;
  font-size:.65rem;
  font-weight:800;
  min-width:18px; height:18px;
  line-height:1; padding:2px 5px;
  text-align:center;
  flex-shrink:0;
  box-shadow:0 1px 3px rgba(255,107,107,.4);
}
.desktop-sidebar .ds-footer { display:none; }
.desktop-sidebar .ds-device { display:none; }

/* Pinned Me / account link at bottom of sidebar */
.desktop-sidebar .ds-me-link {
  display:flex; align-items:center; gap:.75rem;
  padding:.875rem 1rem;
  border-top:1px solid rgba(255,255,255,.12);
  background:rgba(255,107,107,.08);
  color:rgba(255,255,255,.85);
  font-weight:600; font-size:.875rem;
  transition:background .12s, color .12s;
  text-decoration:none; flex-shrink:0;
}
.desktop-sidebar .ds-me-link:hover { background:rgba(255,107,107,.16); color:#fff; }
.desktop-sidebar .ds-me-link.ds-me-active { background:rgba(255,107,107,.22); color:#fff; }
.desktop-sidebar .ds-me-ico {
  width:34px; height:34px; border-radius:50%;
  background:var(--coral); color:#fff;
  display:grid; place-items:center; flex-shrink:0;
}
.desktop-sidebar .ds-me-info { flex:1; min-width:0; }
.desktop-sidebar .ds-me-name {
  font-weight:700; font-size:.875rem; color:#fff;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.desktop-sidebar .ds-me-role {
  font-size:.7rem; font-weight:600; color:var(--coral);
  text-transform:uppercase; letter-spacing:.06em; margin-top:1px;
}
.desktop-sidebar .ds-me-arrow { color:rgba(255,255,255,.35); font-size:1.1rem; }

/* Fixed footer that sits above mobile bottom-nav but doesn't cover desktop sidebar */
.view-footer,
.view-footer-new {
  position: fixed;
  bottom: calc(86px + var(--safe-bot));   /* clears the floating bottom-nav */
  left: 0; right: 0;
  background: var(--cream); border-top: 1px solid var(--line);
  padding: .75rem 1rem;
  z-index: 60;
}

@media (min-width: 768px) {
  .app-shell { flex-direction:row; }
  /* Revert the mobile drawer back to a static, always-visible sidebar. */
  .desktop-sidebar { display:flex; width:236px; min-width:236px; position:sticky; top:0; bottom:auto; height:100vh; transform:none; transition:none; box-shadow:none; z-index:40; padding-top:0; padding-bottom:0; }
  .sidebar-scrim, .js-menu-btn { display:none !important; }
  .bottom-nav { display:none !important; }
  .with-bn { padding-bottom:1.5rem; }
  /* Sidebar handles navigation - hide the mobile header */
  .app-header { display:none; }
  /* Wider content on desktop */
  .max-w-3xl { max-width:960px; }
  /* Stat grids go wider on desktop */
  .desktop-cols-4 { grid-template-columns: repeat(4,1fr) !important; }
  /* Fixed footers must not cover the sidebar.
     On desktop the mobile bottom-nav is hidden, so the footer can sit
     flush to the viewport bottom rather than 62 px up. Leaving the gap
     caused the Add asset / Save buttons to overlap form content. */
  .view-footer, .view-footer-new {
    left: 236px;
    bottom: 0;
    padding-bottom: 1rem;
    z-index: 20;
  }
}

/* ── Lordwell logo - alive animations ──────────────────────────────────────── */

/* Smile floats gently up and down on idle */
@keyframes smile-float {
  0%, 100% { transform: translateY(0px); }
  50%      { transform: translateY(-5px); }
}
.js-wink-logo .wink-smile {
  animation: smile-float 3.5s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center bottom;
}

/* Wink - eyelid drops */
@keyframes lordwell-wink {
  0%          { transform: scaleY(0); }
  18%, 40%    { transform: scaleY(1); }
  58%, 100%   { transform: scaleY(0); }
}
.lordwell-winking .wink-lid {
  animation: lordwell-wink 0.65s ease-in-out forwards;
}

/* Smile jumps up while winking, then settles back */
@keyframes smile-wink-rise {
  0%          { transform: translateY(0px); }
  25%, 45%    { transform: translateY(-10px); }
  75%, 100%   { transform: translateY(0px); }
}
.lordwell-winking .wink-smile {
  animation: smile-wink-rise 0.65s ease-in-out forwards !important;
}

/* ── Apple UX additions ──────────────────────────────────────────────── */

/* Skeleton shimmer for loading states */
@keyframes shimmer {
  0%   { background-position: -600px 0; }
  100% { background-position: 600px 0; }
}
.skeleton {
  background: linear-gradient(90deg,
    var(--sk-base, #f0ece4) 25%,
    var(--sk-hi,  #e8e2d8) 50%,
    var(--sk-base, #f0ece4) 75%);
  background-size: 600px 100%;
  animation: shimmer 1.4s infinite linear;
  border-radius: 8px;
}
[data-theme="dark"] .skeleton {
  --sk-base: #232931;
  --sk-hi:   #2C333C;
}
.skeleton-row {
  padding: 14px 16px;
  border-bottom: 1px solid var(--line, #EDE9E0);
  display: flex;
  align-items: center;
  gap: 12px;
}
.skeleton-row .sk-avatar { width:40px;height:40px;border-radius:10px;flex-shrink:0 }
.skeleton-row .sk-lines  { flex:1;display:flex;flex-direction:column;gap:7px }
.skeleton-row .sk-line   { height:11px;border-radius:6px }
.skeleton-row .sk-wide   { width:60% }
.skeleton-row .sk-narrow { width:35% }

/* Undo-delete toast fade animations */
@keyframes lw-fade-up {
  from { opacity:0; transform:translateX(-50%) translateY(10px); }
  to   { opacity:1; transform:translateX(-50%) translateY(0); }
}
.lw-undo-toast { animation: lw-fade-up .2s ease both; }

/* Pull-to-refresh spinner */
.ptr-indicator {
  text-align: center;
  padding: 12px 0 4px;
  font-size: .78rem;
  font-weight: 600;
  color: #8a8f99;
  letter-spacing: .02em;
  transition: opacity .15s;
}
@keyframes lw-spin { to { transform: rotate(360deg); } }

/* Wins ticker scroll */
@keyframes wins-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
/* Banner entrance - must NOT use the toast's lw-fade-up (that has a
   translateX(-50%) for centering and would shove the banner off-screen). */
@keyframes wins-pop {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.wins-banner { animation: wins-pop .35s ease both; }
.ptr-spin { display:inline-block; animation: lw-spin .7s linear infinite; }

/* Empty-state card - standardised across list pages.
   Sizes: default (compact, for filtered-out states) and .es-lg (big, for
   truly empty pages). Honours dark mode via CSS variables. */
.empty-state {
  text-align: center;
  padding: 40px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.empty-state.es-lg     { padding: 56px 24px; gap: 14px; }
.empty-state .es-icon  { font-size: 2.5rem; line-height: 1; }
.empty-state.es-lg .es-icon { font-size: 3rem; }
.empty-state .es-title { font-weight: 700; font-size: .95rem; color: var(--ink, #2A2E37); }
.empty-state.es-lg .es-title { font-weight: 800; font-size: 1.1rem; }
.empty-state .es-sub   { font-size: .8rem; color: var(--ink-soft, #8a8f99); max-width: 280px; line-height: 1.5; }
.empty-state.es-lg .es-sub   { font-size: .85rem; max-width: 300px; }
.empty-state .es-cta   { margin-top: 4px; }
.empty-state .es-cta-row { display: flex; gap: 8px; margin-top: 6px; flex-wrap: wrap; justify-content: center; }

/* Customer page - kept as a single column at every width. The earlier
   experiment with a pinned right-side activity panel crushed the form on
   laptops, so we leave the standard mobile-first flow in place across
   breakpoints. The .lw-customer-side wrapper still exists on the page so
   no markup change is needed; it just flows inline like everything else. */

/* ── Operations board (Steve's warehouse screen) ──────────────────────────
   Five stacked lanes, big readable cards, one obvious button per card.
   Tuned for a phone in the warehouse: large tap targets, high contrast. */
.op-lane { }
.op-lane-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: none;
  border-left: 4px solid var(--lane, #485666);
  padding: 6px 10px;
  margin-bottom: 8px;
  cursor: pointer;
  border-radius: 6px;
}
.op-lane-caret   { color: var(--lane, #485666); transition: transform .15s; font-size: .9rem; }
.op-lane-name    { font-weight: 800; font-size: 1.02rem; color: var(--lane, #485666); letter-spacing: .01em; }
.op-lane-count   {
  margin-left: auto;
  background: var(--lane, #485666);
  color: #fff;
  font-weight: 800;
  font-size: .8rem;
  min-width: 24px;
  height: 24px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 7px;
}
.op-lane-body  { display: flex; flex-direction: column; gap: 10px; }
.op-lane-empty { font-size: .82rem; color: var(--ink-soft); padding: 4px 14px 8px; }

.op-card {
  background: var(--surface, #fff);
  border: 1px solid var(--line, #E3E7EC);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: 0 1px 0 rgba(40,47,55,0.04), 0 4px 14px rgba(40,47,55,0.06);
}
.op-card-main  { display: block; text-decoration: none; color: inherit; }
.op-card-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 2px; }
.op-cust       { font-weight: 800; font-size: 1.08rem; color: var(--ink); line-height: 1.2; }
.op-meta       { font-size: .8rem; color: var(--ink-soft); margin-top: 2px; }
.op-detail     { font-size: .9rem; font-weight: 600; margin-top: 6px; }

.op-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}
.op-btn {
  flex: 1;
  min-height: 50px;
  border: none;
  border-radius: 13px;
  color: #fff;
  font-weight: 800;
  font-size: 1rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  white-space: nowrap;
  touch-action: manipulation;
  padding: 0 10px;
}
.op-btn:active   { transform: scale(.98); }
.op-btn:disabled { opacity: .6; }
.op-btn-outline {
  background: var(--surface, #fff);
  color: var(--ink);
  border: 2px solid var(--line, #E3E7EC);
}
[data-theme="dark"] .op-btn-outline { background: var(--surface-3); }

/* ── Big-text / high-contrast accessibility mode ──────────────────────────
   Triggered by `<html class="lw-big">` (set via theme.js based on a
   localStorage toggle). Scales text + tap targets across the app. */
html.lw-big                  { font-size: 18px; }
html.lw-big body             { font-size: 17px; }
html.lw-big .btn,
html.lw-big button.btn       { min-height: 52px; padding: 14px 18px; font-size: 1.05rem; }
html.lw-big .input,
html.lw-big input.input,
html.lw-big .textarea,
html.lw-big textarea.textarea{ font-size: 17px; padding: 14px 14px; min-height: 52px; }
html.lw-big .row             { padding: 16px 12px; }
html.lw-big .pill            { font-size: .9rem; padding: 5px 12px; }
html.lw-big .card            { border-radius: 14px; }
html.lw-big .label,
html.lw-big label.label      { font-size: .92rem; }
html.lw-big .empty-state .es-title { font-size: 1.2rem; }
html.lw-big .empty-state .es-sub   { font-size: 1rem; }

/* ── Gentle new-work pulse ────────────────────────────────────────────────
   Soft glow on a tile to draw attention without being noisy. Added via
   the class `pulse-soft` from a view (e.g. Today's "To print" tile when
   the count is non-zero). */
@keyframes lw-pulse-soft {
  0%   { box-shadow: 0 0 0 0 rgba(29,95,166,.30); }
  70%  { box-shadow: 0 0 0 14px rgba(29,95,166,0); }
  100% { box-shadow: 0 0 0 0 rgba(29,95,166,0); }
}
.pulse-soft { animation: lw-pulse-soft 2.4s ease-out infinite; }
@media (prefers-reduced-motion: reduce) { .pulse-soft { animation: none; } }

/* ═══════════════════════════════════════════════════════════════════════════
   DARK-MODE CONTRAST PATCH - June 2026
   Components built with inline-pastel backgrounds + var(--ink) text become
   light-on-light in dark mode. This block dims the pastels to dark-tinted
   equivalents so the flipped var(--ink) text (now light cream) stays legible
   while keeping the colour cue (red=alert, amber=warn, green=ok etc.).
   ═══════════════════════════════════════════════════════════════════════════ */

/* Red / coral pastels - alert + high-impact event cards + urgent task rows */
[data-theme="dark"] [style*="background:#FEF2F2"],
[data-theme="dark"] [style*="background: #FEF2F2"],
[data-theme="dark"] [style*="background:#FECACA"] {
  background: #3A1F1F !important;
}
/* Amber / orange pastels - medium-impact, query type, warnings */
[data-theme="dark"] [style*="background:#FFFBEB"],
[data-theme="dark"] [style*="background: #FFFBEB"],
[data-theme="dark"] [style*="background:#FFF7ED"],
[data-theme="dark"] [style*="background: #FFF7ED"],
[data-theme="dark"] [style*="background:#FEF3C7"] {
  background: #3A2D1A !important;
}
/* Green pastels - won, ok-margin, success badges */
[data-theme="dark"] [style*="background:#F0FDF4"],
[data-theme="dark"] [style*="background: #F0FDF4"],
[data-theme="dark"] [style*="background:#BBF7D0"] {
  background: #1F3A28 !important;
}
/* Blue pastels - quote type, info pills */
[data-theme="dark"] [style*="background:#EEF2FF"],
[data-theme="dark"] [style*="background: #EEF2FF"],
[data-theme="dark"] [style*="background:#EFF6FF"],
[data-theme="dark"] [style*="background: #EFF6FF"] {
  background: #1F263A !important;
}
/* Violet pastels - note pills */
[data-theme="dark"] [style*="background:#F5F3FF"],
[data-theme="dark"] [style*="background: #F5F3FF"],
[data-theme="dark"] [style*="background:#FDF4FF"],
[data-theme="dark"] [style*="background: #FDF4FF"] {
  background: #2A1F3A !important;
}
/* Cream tones I missed earlier (F8F6F1, FBF8EF) - these are nested chrome */
[data-theme="dark"] [style*="background:#F8F6F1"],
[data-theme="dark"] [style*="background: #F8F6F1"],
[data-theme="dark"] [style*="background:#FBF8EF"],
[data-theme="dark"] [style*="background: #FBF8EF"] {
  background: var(--surface-3, #2A2F36) !important;
}

/* Live Feed - uses a cream-gradient that doesn't match attribute selectors,
   target the class directly. Same for the cockpit-qotd already-dark card
   (no override needed; it's intentionally dark in both themes). */
[data-theme="dark"] .wins-rotate,
[data-theme="dark"] .pipeline-summary,
[data-theme="dark"] .tk-quick {
  background: var(--surface) !important;
  border-color: var(--line) !important;
  color: var(--ink) !important;
}
/* Wins-rotate inner text uses var(--ink, #2A2E37) - the fallback prevents
   the var from flipping. Force the explicit colour back to var(--ink). */
[data-theme="dark"] .wins-rotate [style*="var(--ink"] { color: var(--ink) !important; }

/* "Today" cells, ink pills + any element styled `background:var(--ink)`
   with `color:#fff` - var(--ink) flips to light cream in dark mode and
   the white text becomes invisible. Lock those to a deep ink hex that
   does NOT flip so the contrast is preserved. */
[data-theme="dark"] [style*="background:var(--ink)"]:not(.btn-coral):not(.btn-primary) {
  background: #0F1318 !important;
  color: #fff !important;
}
[data-theme="dark"] [style*="background: var(--ink)"]:not(.btn-coral):not(.btn-primary) {
  background: #0F1318 !important;
  color: #fff !important;
}

/* Tile bg-cream / bg-cream-deep on the cockpit - the inline `background:`
   pattern was already covered above; this catches the Tailwind class form
   on tile inner content too (so cockpit tiles don't show cream-on-cream). */
[data-theme="dark"] .bg-cream-deep { background: var(--surface-3, #2A2F36) !important; }

/* Text colour fallbacks - any inline `color:#2A2E37` / `color:#23282D` that
   slipped through the earlier rule. Keeps deep-ink text legible after
   surfaces flip dark. (Earlier rule already covers most cases.) */
[data-theme="dark"] [style*="color:var(--ink"] { color: var(--ink) !important; }

/* Tiles + cards in the home cockpit use inline `background:#fff` already
   covered, but their inner numbers use class `js-counter` w/ inline colour.
   No additional rule needed - var(--ink) flip handles it.  */

/* Light borders on event cards (#FCA5A5, #FCD34D, #86efac, #93c5fd) stay
   for the colour cue - they look fine against dark-tinted backgrounds. */

/* Quote-card pastel left borders use `border-left:4px solid #COLOUR` -
   these don't need overriding; they're tiny accents. */

/* ── Dark-mode polish for inline-styled light cards + pills ─────────────────
   Many views were built with hard-coded light pastel backgrounds in inline
   style attributes (e.g. background:#FFFBEB, background:linear-gradient(...
   #FFF1F1...)). The CSS-variable flip in [data-theme="dark"] doesn't reach
   those, so they remain bright in dark mode - visible on the suppliers page
   "Live supplier feeds" banner, the orders page status pills, the Sales-log
   budget card, the Worcester College "Get In" pill, etc.

   Rather than chase every view and refactor every inline style, the rules
   below use attribute selectors to override the most common light
   backgrounds when the theme is dark. Tradeoff: any new light card we ship
   later inherits this automatically as long as it uses one of the colours
   here. */

[data-theme="dark"] {
  --pill-ok-bg:     #14331E; --pill-ok-fg:     #6FD3A0;
  --pill-warn-bg:   #3B2A14; --pill-warn-fg:   #E5B570;
  --pill-danger-bg: #3A1C1C; --pill-danger-fg: #F08A8A;
  --pill-info-bg:   #1F2A38; --pill-info-fg:   #9FB4D1;
  --pill-muted-bg:  #2A2620; --pill-muted-fg:  #BDB39A;
  --pill-coral-bg:  #3F1F1F; --pill-coral-fg:  #FF9A9A;
}

[data-theme="dark"] .pill-ok      { background:var(--pill-ok-bg)     !important; color:var(--pill-ok-fg)     !important; }
[data-theme="dark"] .pill-warn    { background:var(--pill-warn-bg)   !important; color:var(--pill-warn-fg)   !important; }
[data-theme="dark"] .pill-danger  { background:var(--pill-danger-bg) !important; color:var(--pill-danger-fg) !important; }
[data-theme="dark"] .pill-info    { background:var(--pill-info-bg)   !important; color:var(--pill-info-fg)   !important; }
[data-theme="dark"] .pill-muted   { background:var(--pill-muted-bg)  !important; color:var(--pill-muted-fg)  !important; }
[data-theme="dark"] .pill-coral   { background:var(--pill-coral-bg)  !important; color:var(--pill-coral-fg)  !important; }

/* Common inline light backgrounds → dark tints. Targets values literally
   present in the codebase (case-insensitive matching by attribute selector
   only matches case-sensitively in browsers, but our inline styles are
   consistent). Each selector covers a class of components: yellow tints
   for warnings / hints, green for "added/listed", indigo for AI panels,
   etc. */

/* Yellow tints (warning / nudge banners - Set all card, Brands AI suggest, etc.) */
[data-theme="dark"] [style*="background:#FFFBEB"],
[data-theme="dark"] [style*="background: #FFFBEB"],
[data-theme="dark"] [style*="background:#FEF3C7"],
[data-theme="dark"] [style*="background:#FFFBE6"] { background:#352C12 !important; color:#E5B570 !important; }
[data-theme="dark"] [style*="border:1px solid #FCD34D"],
[data-theme="dark"] [style*="border: 1px solid #FCD34D"] { border-color:#6B5018 !important; }

/* Green tints (success / listed / selected candidate row) */
[data-theme="dark"] [style*="background:#F0FDF4"],
[data-theme="dark"] [style*="background: #F0FDF4"],
[data-theme="dark"] [style*="background:#DCFCE7"] { background:#0F2B1B !important; color:#86EFAC !important; }
[data-theme="dark"] [style*="border:1px solid #BBF7D0"],
[data-theme="dark"] [style*="border: 1px solid #BBF7D0"],
[data-theme="dark"] [style*="border:1px solid #86EFAC"] { border-color:#2F5A3D !important; }

/* Red tints (danger / overdue / remove buttons) */
[data-theme="dark"] [style*="background:#FEF2F2"],
[data-theme="dark"] [style*="background: #FEF2F2"],
[data-theme="dark"] [style*="background:#FEE2E2"],
[data-theme="dark"] [style*="background:#FFE0E0"] { background:#3A1C1C !important; color:#F08A8A !important; }
[data-theme="dark"] [style*="border:1.5px solid #fecaca"],
[data-theme="dark"] [style*="border:1px solid #FECACA"] { border-color:#6B2F2F !important; }

/* Indigo / violet tints (AI panels, presence banners, Find online cards) */
[data-theme="dark"] [style*="background:#EEF2FF"],
[data-theme="dark"] [style*="background: #EEF2FF"],
[data-theme="dark"] [style*="background:#F5F3FF"] { background:#1B1F38 !important; color:#A5B4FC !important; }
[data-theme="dark"] [style*="border:1.5px solid #C7D2FE"],
[data-theme="dark"] [style*="border:1px solid #C7D2FE"],
[data-theme="dark"] [style*="border:1.5px solid #C4B5FD"] { border-color:#3D3F66 !important; }

/* Blue tints (info badges, discount %, secondary actions) */
[data-theme="dark"] [style*="background:#EFF6FF"],
[data-theme="dark"] [style*="background: #EFF6FF"],
[data-theme="dark"] [style*="background:#F0F9FF"] { background:#162232 !important; color:#9FB4D1 !important; }
[data-theme="dark"] [style*="border:1px solid #93c5fd"],
[data-theme="dark"] [style*="border:1px solid #93C5FD"] { border-color:#2A3F60 !important; }

/* Faint cream / off-white card insets (chip wrap, candidate rows, etc.) */
[data-theme="dark"] [style*="background:#FAFAF8"],
[data-theme="dark"] [style*="background: #FAFAF8"],
[data-theme="dark"] [style*="background:#F5F6F8"],
[data-theme="dark"] [style*="background:#ECEEF1"],
[data-theme="dark"] [style*="background:#EDEFF2"] { background:var(--surface-3) !important; }

/* Light grey neutral cards (sticky bar background, search row) */
[data-theme="dark"] [style*="background:rgba(250,247,240,.97)"] {
  background:rgba(22,26,31,.96) !important;
}

/* Inline white card backgrounds (used by lots of small inline cards) */
[data-theme="dark"] [style*="background:#fff"]:not(button):not(input):not(.btn-coral),
[data-theme="dark"] [style*="background:#FFFFFF"]:not(button):not(input):not(.btn-coral),
[data-theme="dark"] [style*="background: #fff"]:not(button):not(input):not(.btn-coral) {
  background:var(--surface) !important;
}

/* Specific named-colour problem cards. The sales-log budget card uses
   linear-gradient(135deg,#FFF1F1 0%,#FFFBEB 100%) - peach to cream, with
   white text inside that vanishes against the light gradient when CSS-vars
   flip. Force the gradient itself to dark equivalents. */
[data-theme="dark"] [style*="linear-gradient(135deg,#FFF1F1"],
[data-theme="dark"] [style*="linear-gradient(135deg, #FFF1F1"] {
  background:linear-gradient(135deg, #2A1E1E 0%, #2A2418 100%) !important;
}
[data-theme="dark"] [style*="linear-gradient(135deg,#F5F3FF"],
[data-theme="dark"] [style*="linear-gradient(135deg, #F5F3FF"] {
  background:linear-gradient(135deg, #1B1F38 0%, #14171B 70%) !important;
}
[data-theme="dark"] [style*="linear-gradient(135deg,#EEF2FF"] {
  background:linear-gradient(135deg, #1B1F38 0%, #14171B 70%) !important;
}

/* Status-pill-shaped inline boxes (border-radius:999px) that use a
   bg from above will pick up dark colour. Their text-colour stays as
   the original brand colour from inline style - that contrasts nicely
   against the dark tint, so no further override needed. */

/* Worcester College's "Get In" / "Awaiting Stock" badges on order rows
   use inline backgrounds matching the pill colours above - covered. */

/* ── Demo mode ────────────────────────────────────────────────────────────
   Body gets `.lw-demo-mode` while screen-sharing. The selectors below
   blur sensitive content so Max can show the portal's features without
   revealing live customer / supplier / £ data.

   Coverage strategy:
   • Inline-marked spans (.lw-demo-money/name/supplier/qty) handle anything
     a view explicitly tagged - used for customer + supplier name rows.
   • Broad selectors (.cockpit-num, [data-counter], .stat .num) catch the
     big money figures on Home + Sales without the views having to opt in.
   • The blur is heavy (8px) on purpose - at 4-5px shapes are still
     readable. We also disable user-select + pointer-events on blurred
     content so a screenshot or accidental copy can't leak the underlying
     text.

   Reveal-on-hover is intentionally NOT included - the whole point is
   that Max can mouse around freely on a call without un-blurring. */
body.lw-demo-mode .lw-demo-money,
body.lw-demo-mode .lw-demo-name,
body.lw-demo-mode .lw-demo-supplier,
body.lw-demo-mode .lw-demo-qty,
body.lw-demo-mode .cockpit-num,
body.lw-demo-mode [data-counter],
body.lw-demo-mode .stat .num,
body.lw-demo-mode .lw-perday-bar,
body.lw-demo-mode .lw-perday-val {
  filter: blur(8px);
  user-select: none;
  -webkit-user-select: none;
  pointer-events: none;
  transition: filter .15s ease;
}
/* Visual hint that demo is on - a soft red border on every card so it's
   obvious in a screenshot. Not too loud; just enough to read. */
body.lw-demo-mode .card { box-shadow: inset 0 0 0 1px rgba(220,38,38,.18), 0 1px 0 rgba(40,47,55,.04), 0 4px 14px rgba(40,47,55,.06); }

/* ── Client view (present mode) ───────────────────────────────────────────
   Body gets `.lw-hide-margin` when a rep is quoting face-to-face and turns
   their screen to the client. We HIDE (not blur) everything that reveals what
   Lordwell makes on a quote/order - cost, margin %, profit £, the Thomas
   Franks rebate panel, the "This sale" cost/sell/margin override, the
   contract-pricing banner, and the per-line margin chips - while leaving the
   customer's prices, line items and totals fully visible. Toggled from the
   header eye button + the Me page; persisted in localStorage. The quote
   line-edit sheet collapses its cost/margin via _showCost in quotes-detail.js,
   so this CSS only needs to catch the always-visible figures. `.lw-margin` is
   a marker class on the multi-part internal blocks (This-sale panel, the order
   line cost/margin cells + steppers). display:none keeps layout clean. */
body.lw-hide-margin .js-rebate-panel,
body.lw-hide-margin .js-tf-pricing-banner,
body.lw-hide-margin .js-lines-margin-summary,
body.lw-hide-margin .js-sum-margin,
body.lw-hide-margin .js-line-margin,
body.lw-hide-margin .js-hero-margin,
body.lw-hide-margin .js-line-row-margin,
body.lw-hide-margin .lw-margin {
  display: none !important;
}

/* ── Period filter bar (Today / Week / Month / Year) ──────────────────── */
.lw-period-bar .js-period-btn:active { transform: scale(.96); }
@media (prefers-reduced-motion: reduce) { .lw-period-bar .js-period-btn { transition: none; } }

/* ── Sales & Profit per-day bar chart ─────────────────────────────────── */
.lw-perday-row { display: flex; align-items: flex-end; gap: 4px; height: 110px; padding: 0 2px; }
.lw-perday-col { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 3px; }
.lw-perday-bar-wrap { width: 100%; height: 80px; display: flex; align-items: flex-end; gap: 2px; }
.lw-perday-bar      { flex: 1; min-width: 0; border-radius: 3px 3px 0 0; transition: opacity .15s; }
.lw-perday-bar.sell { background: linear-gradient(180deg,#1D5FA6,#0B3E73); }
.lw-perday-bar.prof { background: linear-gradient(180deg,#16a34a,#0e6e34); }
.lw-perday-bar:hover { opacity: .85; }
.lw-perday-lbl { font-size: .58rem; color: var(--ink-soft,#485666); font-weight: 700; line-height: 1; }
@media (max-width: 480px) {
  /* Hide every other day label on phones so the chart stays readable */
  .lw-perday-col:nth-child(even) .lw-perday-lbl { visibility: hidden; }
}



/* ════════════════════════════════════════════════════════════════════
   ✨ Motion + login design system.
   Login = split-screen: a permanent deep-ink brand panel (giant smile
   arcs + warm glow) beside a clean token-driven form panel. Stacks on
   mobile. Hub-wide micro-interactions follow. transform/opacity only;
   entrance motion gated behind prefers-reduced-motion.
   ════════════════════════════════════════════════════════════════════ */

:root { --lw-ease: cubic-bezier(0.16, 1, 0.3, 1); }

/* ── Login layout ──────────────────────────────────────────────────── */
.lw-login {
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr;
}
@media (min-width: 940px) {
  .lw-login { grid-template-rows: none; grid-template-columns: 1.05fr 1fr; }
}

/* ── Brand panel - always deep ink, light or dark theme ────────────── */
.lw-brand {
  position: relative;
  overflow: hidden;
  background: linear-gradient(168deg, #2A323D 0%, #1B2128 55%, #151A20 100%);
  color: #F7F3E8;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(44px, 7vh, 96px) 28px;
}
.lw-brand-inner { position: relative; z-index: 2; max-width: 480px; }

/* Giant concentric smile arcs - the bottom sliver of two huge circles
   reads as the Lordwell smile, drawn architecturally across the panel. */
.lw-arc, .lw-arc::before {
  content: '';
  position: absolute;
  left: 50%;
  border: 2px solid rgba(255, 122, 122, .22);
  border-radius: 50%;
  pointer-events: none;
}
.lw-arc {
  /* A huge circle whose bottom edge sits just above the panel's bottom -
     overflow clips the rest, so only its lowest arc (the smile ⌣) shows. */
  width: 150vmin; height: 150vmin;
  bottom: 9%;
  transform: translateX(-50%);
}
.lw-arc::before {
  width: 124vmin; height: 124vmin;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  border-color: rgba(255, 122, 122, .10);
}

/* Warm coral glow behind the headline - controlled, on a panel designed
   for it (not floating on the page background). */
.lw-brand-glow {
  position: absolute;
  top: 16%; left: 50%;
  width: 64vmin; height: 42vmin;
  transform: translateX(-50%);
  background: radial-gradient(ellipse, rgba(255, 107, 107, .18), transparent 64%);
  filter: blur(28px);
  pointer-events: none;
}

.lw-brand-logo {
  display: block;
  width: clamp(200px, 24vw, 300px);
  height: auto;
  margin: 0 auto 30px;
}
.lw-equation {
  font-family: 'Poppins', 'Nunito', sans-serif;
  font-size: 1.05rem; font-weight: 700; letter-spacing: -.01em;
  color: #C7CFD8;
}
.lw-equation .lw-x, .lw-equation b { color: var(--coral, #F27E3F); }
.lw-equation .lw-eq { opacity: .45; }
.lw-kicker {
  margin-top: 14px;
  font-family: 'Poppins', 'Nunito', sans-serif;
  font-size: .68rem; font-weight: 800;
  letter-spacing: .26em; text-transform: uppercase;
  color: var(--coral, #F27E3F);
}
.lw-mantra {
  margin: 26px auto 0;
  font-family: 'Poppins', 'Nunito', sans-serif;
  font-style: italic; font-weight: 500;
  font-size: .95rem; line-height: 1.55;
  color: #97A0AB;
  max-width: 36ch;
}
/* Compact brand panel when stacked on small screens */
@media (max-width: 939px) {
  .lw-brand { padding: 44px 24px 52px; }
  .lw-mantra { display: none; }
}

/* ── Form panel ────────────────────────────────────────────────────── */
.lw-form {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cream, #F5F6F8);
  padding: clamp(32px, 6vh, 64px) 24px;
}
.lw-form-inner { width: 100%; max-width: 380px; }
.lw-form-title {
  font-family: 'Poppins', 'Nunito', sans-serif;
  font-weight: 800; font-size: 1.65rem; letter-spacing: -.02em;
  color: var(--ink, #2A2E37);
}
.lw-form-title .lw-dot { color: var(--coral, #F27E3F); }
.lw-form-sub { margin: 6px 0 22px; font-size: .9rem; color: var(--ink-soft, #485666); }
.lw-form-help { margin-top: 16px; font-size: .75rem; color: var(--ink-mute, #8A94A6); text-align: center; line-height: 1.5; }
.lw-form .input { background: var(--surface, #fff); }

/* ── Login micro-interactions (always on - feedback, not decoration) ─ */
.lw-enter-btn .lw-arrow { display: inline-block; transition: transform .2s var(--lw-ease); }
.lw-enter-btn:hover .lw-arrow,
.lw-enter-btn:focus-visible .lw-arrow { transform: translateX(4px); }
.lw-spin {
  display: inline-block; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  vertical-align: -2px; margin-right: 6px;
  animation: lw-rotate .7s linear infinite;
}
@keyframes lw-rotate { to { transform: rotate(360deg); } }

/* ── Hub: press + hover feedback ───────────────────────────────────── */
.btn:active { transform: scale(.97); }
@media (hover: hover) {
  .btn-primary { transition: transform .15s var(--lw-ease), box-shadow .15s var(--lw-ease), background .12s, border-color .12s, opacity .12s; }
  .btn-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 18px color-mix(in srgb, var(--coral, #F27E3F) 30%, transparent); }
  .btn-primary:active { transform: scale(.97); box-shadow: none; }
  a.card, .card[onclick], .task-card { transition: transform .18s var(--lw-ease), box-shadow .18s var(--lw-ease), border-color .12s ease, opacity .08s ease; }
  a.card:hover, .card[onclick]:hover, .task-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 2px 0 rgba(40,47,55,.04), 0 10px 26px rgba(40,47,55,.10);
  }
}

/* ── Entrance motion (skipped entirely under reduced-motion) ───────── */
@media (prefers-reduced-motion: no-preference) {

  /* Staggered reveal - each element sets --d (its delay). */
  .lw-rise { animation: lw-rise-in .6s var(--lw-ease) both; animation-delay: var(--d, 0s); }
  @keyframes lw-rise-in {
    from { opacity: 0; transform: translateY(14px) scale(.985); }
    to   { opacity: 1; transform: none; }
  }


  /* The glow breathes - slow, warm, alive. */
  .lw-brand-glow { animation: lw-breathe 9s ease-in-out infinite alternate; }
  @keyframes lw-breathe { from { transform: translateX(-50%) scale(1); opacity: .85; } to { transform: translateX(-50%) scale(1.12); opacity: 1; } }

  /* Wrong-password shake (tight, 320ms, transform-only). */
  .lw-shake { animation: lw-shake .32s cubic-bezier(.36,.07,.19,.97) both; }
  @keyframes lw-shake {
    10%, 90% { transform: translateX(-2px); }
    20%, 80% { transform: translateX(3px); }
    30%, 50%, 70% { transform: translateX(-5px); }
    40%, 60% { transform: translateX(5px); }
  }

  /* Hub: cards cascade in as a page enters (and as lists repaint). */
  .page-enter .card { animation: lw-card-in .34s var(--lw-ease) both; }
  .page-enter .card:nth-child(2) { animation-delay: .03s; }
  .page-enter .card:nth-child(3) { animation-delay: .06s; }
  .page-enter .card:nth-child(4) { animation-delay: .09s; }
  .page-enter .card:nth-child(5) { animation-delay: .12s; }
  .page-enter .card:nth-child(6) { animation-delay: .15s; }
  .page-enter .card:nth-child(n+7) { animation-delay: .18s; }
  @keyframes lw-card-in {
    from { opacity: 0; transform: translateY(10px) scale(.99); }
    to   { opacity: 1; transform: none; }
  }

  /* Hub: sheets slide up with a settled spring; overlay fades. */
  .sheet-panel { animation: lw-sheet-up .38s var(--lw-ease) both; }
  @keyframes lw-sheet-up { from { transform: translateY(48px); opacity: .6; } to { transform: none; opacity: 1; } }
  .sheet-overlay { animation: lw-fade .25s ease-out both; }
  @keyframes lw-fade { from { opacity: 0; } to { opacity: 1; } }

  /* Page transition on the premium curve. */
  .page-enter { animation: pageIn .32s var(--lw-ease) both; }
}

/* Desktop (≥768px, where the fixed sidebar appears): the bottom sheet becomes
   a centred pop-out modal. A full-width slide-up is too heavy on a wide screen;
   mobile keeps the bottom sheet + swipe-to-dismiss. Layout applies regardless
   of motion preference; the pop animation is gated on no-preference below. */
@media (min-width: 768px) {
  .sheet-panel {
    left: 50%; right: auto; top: 50%; bottom: auto;
    transform: translate(-50%, -50%);
    width: min(620px, 94vw);
    max-height: 88vh;
    border-radius: 22px;
    box-shadow: 0 30px 70px -22px rgba(40,47,55,.5), 0 6px 18px -10px rgba(40,47,55,.3);
    padding-bottom: 10px;
  }
  /* The grab handle is a touch affordance - pointless on desktop. */
  .sheet-panel::before { display: none; }
}
@media (min-width: 768px) and (prefers-reduced-motion: no-preference) {
  .sheet-panel { animation: lw-sheet-pop .26s var(--lw-ease) both; }
  @keyframes lw-sheet-pop {
    from { transform: translate(-50%, calc(-50% + 14px)) scale(.97); opacity: 0; }
    to   { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  }
}


/* ═══════════════════════════════════════════════════════════════════════
   ACTION-STACK RHYTHM - added 2 Jul 2026 audit (Max: "spacing on the
   buttons needs serious tweaking"). One global mechanism so views stop
   inventing their own gaps. 8px vertical rhythm between stacked sibling
   buttons; captions hug their button (4px) and breathe before the next
   control (12px). Conservative scope: .card children and .view-footer
   stacks only - grid/flex rows and inline margin-top overrides are
   untouched (inline styles always win over these rules).
   NOTE: the Tailwind-esque runtime space-y-* utilities are injected
   AFTER app.css with higher specificity, so a card that declares
   space-y-3 keeps its 12px - these rules are the fallback for stacks
   with NO mechanism at all. Do NOT add a global `.card + .card` margin:
   cards inside `grid gap-2` containers would double-space.
   ═══════════════════════════════════════════════════════════════════════ */

/* 8px between stacked block buttons (and button↔grid rows) that have no
   other spacing mechanism. Margins collapse with any existing inline
   margin-bottom on the previous sibling, so worst case is still 8px. */
.card > .btn-block + .btn-block,
.card > .btn-block + .grid,
.card > .grid + .btn-block,
.view-footer .btn-block + .btn-block,
.view-footer .btn-block + .grid,
.view-footer .grid + .btn-block,
.view-footer-new .btn-block + .btn-block,
.view-footer-new .btn-block + .grid,
.view-footer-new .grid + .btn-block {
  margin-top: 8px;
}

/* Caption line under a block button: 4px to its button, 12px before the
   next control. Swap ad-hoc inline-styled notes (quote "Send to customer"
   caption, order "Saves the PDF…" caption) to this class over time.
   margin-top needs !important to beat the space-y-* sibling margin-top
   (injected after this sheet); the 12px bottom margin collapses with a
   following space-y margin-top so there is no double gap. */
.btn-caption {
  display: block;
  margin: 4px 2px 12px;
  margin-top: 4px !important;
  font-size: .72rem;
  line-height: 1.45;
  color: var(--ink-soft);
  text-align: center;
}
.btn-caption:last-child { margin-bottom: 0; }

/* ═════════════════════════ LORDWELL KINETIC LAYER (811) ═════════════════════════
   The retail site's motion language brought into the Hub: brand navy + aqua
   tokens, buttons with real physics (lift, press, sheen), drifting aurora
   heroes, and a proper page-enter. Append-only - overrides earlier rules,
   never edits them. Everything is guarded for prefers-reduced-motion. */
:root {
  --navy:      #262E38;   /* brand navy (matches shop.lordwell.co.uk) */
  --navy-2:    #2F3947;
  --aqua:      #4ECDC5;   /* brand aqua accent */
  --aqua-deep: #2FB3AA;
  --aqua-soft: #DFF7F5;
}

/* ── Buttons: lift on hover, spring press, coral sheen ── */
.btn {
  position: relative;
  overflow: hidden;
  transition: transform .16s cubic-bezier(.2,.9,.3,1.3), box-shadow .2s ease,
              background-color .15s ease, border-color .15s ease, color .15s ease;
}
.btn:hover  { transform: translateY(-1px); }
.btn:active { transform: translateY(0) scale(.965); transition-duration: .06s; }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(78,205,197,.5); }
.btn-primary {
  background: linear-gradient(135deg, #FF8383 0%, var(--coral) 45%, var(--coral-deep) 100%);
  border-color: transparent;
  box-shadow: 0 2px 10px rgba(255,107,107,.32), inset 0 1px 0 rgba(255,255,255,.28);
}
.btn-primary:hover { box-shadow: 0 7px 22px rgba(255,107,107,.42), inset 0 1px 0 rgba(255,255,255,.28); }
.btn-primary::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 38%, rgba(255,255,255,.38) 50%, transparent 62%);
  transform: translateX(-130%);
  pointer-events: none;
}
.btn-primary:hover::after { transform: translateX(130%); transition: transform .55s ease; }
/* Aqua variant for web/store-flavoured actions */
.btn-aqua {
  background: linear-gradient(135deg, #63DED6 0%, var(--aqua) 40%, var(--aqua-deep) 100%);
  color: #fff; border-color: transparent; font-weight: 700;
  box-shadow: 0 2px 10px rgba(78,205,197,.35), inset 0 1px 0 rgba(255,255,255,.3);
}
.btn-aqua:hover { box-shadow: 0 7px 22px rgba(78,205,197,.45), inset 0 1px 0 rgba(255,255,255,.3); color: #fff; }

/* ── Interactive cards get a gentle lift ── */
.card { transition: box-shadow .22s ease, transform .22s ease, border-color .22s ease; }
a.card:hover, .cockpit-tile:hover { border-color: rgba(78,205,197,.55); }

/* ── Page enter: rise + settle (router adds .page-enter to every view) ── */
.page-enter { animation: lwPageIn .32s cubic-bezier(.16,.84,.3,1) both; }
@keyframes lwPageIn {
  from { opacity: 0; transform: translateY(10px) scale(.995); }
  to   { opacity: 1; transform: none; }
}
/* Stagger the first cards of a freshly entered page */
.page-enter .card { animation: lwCardIn .34s cubic-bezier(.16,.84,.3,1) both; }
.page-enter .card:nth-child(2) { animation-delay: .04s; }
.page-enter .card:nth-child(3) { animation-delay: .08s; }
.page-enter .card:nth-child(4) { animation-delay: .12s; }
@keyframes lwCardIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* ── Aurora: drifting brand blobs behind any .lw-aurora container ──
   Blobs sit at z-index:-1 inside an isolated stacking context, so NO child
   markup changes are needed - content always paints above them. */
.lw-aurora, .cockpit-hero { isolation: isolate; }
.lw-aurora::before, .lw-aurora::after,
.cockpit-hero::before, .cockpit-hero::after {
  content: '';
  position: absolute; border-radius: 50%; filter: blur(56px);
  z-index: -1; pointer-events: none;
}
.lw-aurora::before, .cockpit-hero::before {
  width: 420px; height: 420px; left: -120px; top: -170px;
  background: radial-gradient(circle, rgba(78,205,197,.4), transparent 70%);
  animation: lwDriftA 16s ease-in-out infinite alternate;
}
.lw-aurora::after, .cockpit-hero::after {
  width: 380px; height: 380px; right: -110px; bottom: -190px;
  background: radial-gradient(circle, rgba(255,107,107,.34), transparent 70%);
  animation: lwDriftB 20s ease-in-out infinite alternate;
}
@keyframes lwDriftA { from { transform: translate(0,0) scale(1); }    to { transform: translate(70px,44px) scale(1.18); } }
@keyframes lwDriftB { from { transform: translate(0,0) scale(1.06); } to { transform: translate(-60px,-40px) scale(.9); } }

/* ── Sidebar: aqua glow on the active rail, springy hover ── */
.desktop-sidebar .ds-nav a { transition: background-color .15s ease, transform .12s ease, color .15s ease; }
.desktop-sidebar .ds-nav a:hover { transform: translateX(2px); }
.desktop-sidebar .ds-nav a.ds-active::before {
  background: linear-gradient(180deg, var(--aqua), var(--coral));
  box-shadow: 0 0 8px rgba(78,205,197,.55);
}

/* ── Bottom nav: active item gets a lifted brand pill ── */
.bottom-nav .bn-item { transition: transform .15s cubic-bezier(.2,.9,.3,1.4), color .15s ease; }
.bottom-nav .bn-item:active { transform: scale(.9); }
.bottom-nav .bn-item[aria-current="page"] { transform: translateY(-2px); }

/* ── Live pulse dot (website status, live badges) ── */
.lw-live-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: var(--aqua); position: relative; }
.lw-live-dot::after {
  content: ''; position: absolute; inset: -4px; border-radius: 50%;
  border: 2px solid rgba(78,205,197,.6); animation: lwPing 1.8s ease-out infinite;
}
@keyframes lwPing { 0% { transform: scale(.6); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } }

/* ── Count-up figures settle without jitter ── */
.lw-num { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum'; }

@media (prefers-reduced-motion: reduce) {
  .page-enter, .page-enter .card, .lw-aurora::before, .lw-aurora::after,
  .cockpit-hero::before, .cockpit-hero::after, .lw-live-dot::after { animation: none !important; }
  .btn, .card, .desktop-sidebar .ds-nav a, .bottom-nav .bn-item { transition: none !important; }
  .btn-primary:hover::after { transition: none !important; transform: translateX(-130%); }
}

/* ── Team-experience motion (wins wall, reply clock, onboarding) ─────────
   Small, reusable keyframes for the celebration surfaces. Gated for
   prefers-reduced-motion at the bottom of the block. */
@keyframes ebPop { from { opacity: 0; transform: translateY(14px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes ebFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@keyframes ebSpinSlow { to { transform: rotate(360deg); } }
@keyframes ebSparkle { 0%, 100% { opacity: 0; transform: scale(.3); } 50% { opacity: 1; transform: scale(1); } }
@keyframes ebRise { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes ebBump { 0% { transform: scale(1); } 35% { transform: scale(1.35); } 100% { transform: scale(1); } }
@keyframes ebGlowPulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
@keyframes ebRingPulse { 0% { transform: scale(.85); opacity: .9; } 100% { transform: scale(1.55); opacity: 0; } }
@keyframes ebFadeIn { from { opacity: 0; } to { opacity: 1; } }
.eb-pop { animation: ebPop .5s cubic-bezier(.16,1,.3,1) both; }
.eb-float { animation: ebFloat 3.2s ease-in-out infinite; }
.eb-spin-slow { animation: ebSpinSlow 16s linear infinite; transform-origin: center; }
.eb-bump { animation: ebBump .35s cubic-bezier(.16,1,.3,1); }
.eb-rise { animation: ebRise .7s cubic-bezier(.16,1,.3,1) both; transform-origin: bottom; }
.eb-fade-in { animation: ebFadeIn .3s ease both; }
@media (prefers-reduced-motion: reduce) {
  .eb-pop, .eb-float, .eb-spin-slow, .eb-bump, .eb-rise, .eb-fade-in { animation: none !important; }
}

/* Sales trend palette (validated light + dark pairs) */
:root { --tr-profit: #E0662A; --tr-cost: #0D9488; }
[data-theme="dark"] { --tr-profit: #F27E3F; --tr-cost: #2DD4BF; }

/* Privacy mode: blur money for screen shares (toggled in the control room) */
body.eb-privacy .cockpit-num,
body.eb-privacy [style*="tabular-nums"] { filter: blur(7px); }
body.eb-privacy::after { content: 'Privacy mode on'; position: fixed; bottom: 14px; left: 50%; transform: translateX(-50%); background: #23282D; color: #fff; font: 800 11px 'Nunito', sans-serif; letter-spacing: .08em; text-transform: uppercase; padding: 7px 16px; border-radius: 999px; z-index: 90; box-shadow: 0 4px 14px rgba(0,0,0,.3); }

/* ══════════════════════════════════════════════════════════════════════════
   Navigation overhaul: fixed top bar + tightened sidebar + bottom nav polish.
   Appended block. Everything below deliberately overrides the older shell
   rules above it (the sticky mobile header, the 768px sidebar breakpoint).
   Desktop is >=900px; 768 to 899 now behaves like mobile (drawer + bottom
   nav) so the top bar owns the chrome at every width.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── The bar itself ──────────────────────────────────────────────────────── */
.app-header.top-bar {
  position: fixed; top: 0; left: 0; right: 0;
  z-index: 80;                              /* over content, under the drawer (95) */
  height: calc(56px + var(--safe-top));
  padding: var(--safe-top) 10px 0;
  display: flex; align-items: stretch;
  background: var(--surface);
  border-bottom: 1px solid var(--line);     /* a hairline, not a heavy shadow */
  box-shadow: none;
}
.tb-inner {
  position: relative;
  width: 100%; max-width: 1400px; margin: 0 auto;
  display: flex; align-items: center; gap: 8px;
}
.tb-left { display: flex; align-items: center; gap: 4px; min-width: 0; }
.tb-brand { display: flex; align-items: center; text-decoration: none; padding: 4px 6px; border-radius: 10px; }
.tb-brand img { height: 24px; width: auto; display: block; }
.tb-logo-dark { display: none; }
[data-theme="dark"] .tb-logo-dark { display: block; }
[data-theme="dark"] .tb-logo-light { display: none; }

/* Round icon buttons (burger, theme, bell) */
.tb-icon-btn {
  position: relative;
  width: 40px; height: 40px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%;
  background: var(--cream-deep); color: var(--ink);
  font-size: 1.05rem; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.tb-icon-btn:hover { background: var(--surface-3); }
.tb-icon-btn:active { transform: scale(.94); }

/* Unread badge. Absolutely positioned over the bell's corner, so showing or
   hiding it never moves a single pixel of layout. */
.tb-badge {
  position: absolute; top: -3px; right: -3px;
  min-width: 18px; height: 18px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--coral); color: #fff;
  border: 2px solid var(--surface);
  border-radius: 999px;
  font-size: .62rem; font-weight: 800; line-height: 1;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.tb-badge[hidden] { display: none; }

/* ── Search (desktop only) ───────────────────────────────────────────────── */
.tb-search {
  position: relative;
  display: none;                            /* shown >=900px below */
  flex: 1; max-width: 560px; margin: 0 auto;
  align-items: center;
}
.tb-search-ico {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  color: var(--ink-mute); display: flex; pointer-events: none;
}
.tb-search-input {
  width: 100%; height: 38px;
  padding: 0 44px 0 38px;
  border: 1.5px solid transparent; border-radius: 999px;
  background: var(--cream-deep); color: var(--ink);
  font-family: 'Nunito', sans-serif; font-size: .9rem; font-weight: 600;
  -webkit-appearance: none; appearance: none;
}
.tb-search-input::placeholder { color: var(--ink-mute); font-weight: 600; }
.tb-search-input::-webkit-search-cancel-button { -webkit-appearance: none; }
.tb-search-input:hover { background: var(--surface-3); }
.tb-search-input:focus { outline: none; border-color: var(--coral); background: var(--surface); }
.tb-search-key {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 5px;
  background: var(--surface);
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: .68rem; font-weight: 700; color: var(--ink-mute);
  pointer-events: none;
}
.tb-search-input:focus ~ .tb-search-key { display: none; }

/* ── Right cluster ───────────────────────────────────────────────────────── */
.tb-right { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.tb-bell-wrap, .tb-avatar-wrap { position: relative; display: flex; }
.tb-avatar-wrap { display: none; }          /* shown >=900px below */
.tb-avatar {
  width: 36px; height: 36px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%;
  background: linear-gradient(135deg, var(--coral) 0%, #F9A825 100%);
  color: #fff; font-family: 'Poppins', 'Nunito', sans-serif;
  font-weight: 700; font-size: .95rem; line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.tb-avatar:active { transform: scale(.94); }

/* ── Popovers (bell tray + account menu) ─────────────────────────────────── */
.tb-pop {
  position: absolute; top: calc(100% + 10px); right: 0;
  width: 360px; max-width: calc(100vw - 16px);
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 12px 40px rgba(20, 24, 30, .16), 0 2px 8px rgba(20, 24, 30, .08);
  overflow: hidden;
  z-index: 99;
}
[data-theme="dark"] .tb-pop { box-shadow: 0 12px 40px rgba(0, 0, 0, .5), 0 2px 8px rgba(0, 0, 0, .35); }

/* Bell tray rows */
.ntf-head {
  padding: 13px 16px 9px;
  font-family: 'Poppins', 'Nunito', sans-serif;
  font-weight: 700; font-size: 1.02rem; color: var(--ink);
}
.ntf-list { max-height: min(62vh, 430px); overflow-y: auto; overscroll-behavior: contain; }
.ntf-row {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 10px 14px;
  text-decoration: none; color: inherit;
}
.ntf-row:hover { background: var(--cream-deep); }
.ntf-row:active { background: var(--surface-3); }
.ntf-ico {
  width: 36px; height: 36px; flex-shrink: 0;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--cream-deep);
  font-size: 1.02rem;
}
.ntf-row[data-tone="danger"] .ntf-ico { background: rgba(180, 35, 24, .13); }
.ntf-row[data-tone="warn"]   .ntf-ico { background: rgba(227, 141, 39, .16); }
.ntf-txt {
  flex: 1; min-width: 0;
  font-size: .84rem; font-weight: 600; line-height: 1.45; color: var(--ink);
  padding-top: 1px;
}
.ntf-time { display: block; margin-top: 2px; font-size: .7rem; font-weight: 700; color: var(--ink-mute); }
.ntf-dot { width: 8px; height: 8px; border-radius: 50%; background: transparent; flex-shrink: 0; margin-top: 6px; }
.ntf-row.is-unread .ntf-dot { background: var(--coral); }
.ntf-row.is-unread .ntf-txt { font-weight: 800; }
.ntf-empty { padding: 34px 20px; text-align: center; font-size: .86rem; font-weight: 600; color: var(--ink-soft); }

/* Account menu */
.tb-pop-menu { width: 248px; padding: 6px; }
.tb-menu-head {
  display: flex; align-items: center; gap: 11px;
  padding: 10px; border-radius: 12px;
  text-decoration: none; color: inherit;
}
.tb-menu-head:hover { background: var(--cream-deep); }
.tb-avatar-lg { width: 42px; height: 42px; font-size: 1.15rem; cursor: default; }
.tb-menu-id { min-width: 0; }
.tb-menu-name {
  display: block; font-weight: 800; font-size: .92rem; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tb-menu-role {
  display: block; margin-top: 1px;
  font-size: .66rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--coral);
}
.tb-menu-sep { height: 1px; background: var(--line); margin: 5px 8px; }
.tb-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 10px; min-height: 44px;
  border: none; border-radius: 12px; background: none;
  font-family: 'Nunito', sans-serif; font-size: .88rem; font-weight: 700;
  color: var(--ink); text-align: left; text-decoration: none; cursor: pointer;
}
.tb-menu-item:hover { background: var(--cream-deep); }
.tb-menu-item:active { background: var(--surface-3); }
.tb-menu-ico {
  width: 30px; height: 30px; flex-shrink: 0;
  display: grid; place-items: center;
  border-radius: 50%; background: var(--cream-deep);
  font-size: .95rem;
}
.js-tb-signout { color: #DC2626; }
.js-tb-signout .tb-menu-ico { color: #DC2626; }

/* ── Layout compensation for the fixed bar ───────────────────────────────── */
.app-shell { padding-top: calc(56px + var(--safe-top)); }
/* Sticky in-page headers (job header on order and quote detail) used to stick
   to the viewport top; they now stop under the bar instead of sliding behind
   it. Scoped to the main pane so sheets and overlays keep their own sticky. */
#app-main [style*="position:sticky"],
#app-main .sticky { top: calc(56px + var(--safe-top)) !important; }

/* ── Mobile bar (<900px): burger left, wordmark centre, bell right ───────── */
@media (max-width: 899.98px) {
  .tb-brand { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); }
}

/* ── 768 to 899: previously desktop, now mobile. Undo the old 768 rules. ── */
@media (min-width: 768px) and (max-width: 899.98px) {
  .app-shell { flex-direction: column; }
  .desktop-sidebar {
    position: fixed; top: 0; bottom: 0; height: auto;
    width: min(82vw, 300px); min-width: 0;
    transform: translateX(-100%);
    box-shadow: 0 0 50px rgba(0, 0, 0, .4);
    z-index: 95;
    padding-top: var(--safe-top); padding-bottom: var(--safe-bot);
  }
  .desktop-sidebar.is-open { transform: translateX(0); }
  .js-menu-btn { display: inline-flex !important; }
  .sidebar-scrim { display: block !important; }
  .bottom-nav { display: flex !important; }
  .with-bn { padding-bottom: calc(92px + var(--safe-bot)); }
  .view-footer, .view-footer-new {
    left: 0; bottom: calc(86px + var(--safe-bot));
    padding-bottom: .75rem; z-index: 60;
  }
}
@media (min-width: 768px) and (max-width: 899.98px) and (prefers-reduced-motion: no-preference) {
  .desktop-sidebar { transition: transform .28s cubic-bezier(.2, .7, .2, 1); }
}

/* ── Desktop (>=900px): search + avatar in the bar, sidebar under it ────── */
@media (min-width: 900px) {
  .app-header.top-bar { display: flex; }    /* beats the old 768 display:none */
  .tb-search { display: flex; }
  .tb-avatar-wrap { display: flex; }
  .js-menu-btn { display: none !important; }
  /* The bar carries the wordmark now; the rail starts with + New.
     !important because the brand link carries an inline display:flex. */
  .desktop-sidebar .ds-brand { display: none !important; }
  .desktop-sidebar {
    top: calc(56px + var(--safe-top));
    height: calc(100vh - 56px - var(--safe-top));
    padding-top: 8px;
  }
}
/* 768 to 899 also needs the bar visible (the old 768 rule hid .app-header). */
@media (min-width: 768px) {
  .app-header.top-bar { display: flex; }
}

/* ── Sidebar tightening: 8px rhythm, quieter headings, orange rail ───────── */
.desktop-sidebar .ds-nav { padding: 8px 0 16px; }
.desktop-sidebar .ds-group { padding: 8px 0; }
.desktop-sidebar .ds-group + .ds-group { margin-top: 0; padding-top: 8px; border-top: 1px solid rgba(255, 255, 255, .05); }
.desktop-sidebar .ds-group-heading {
  padding: 0 16px 8px;
  font-size: .6rem; font-weight: 700;
  letter-spacing: .13em;
  color: rgba(255, 255, 255, .3);
}
.desktop-sidebar .ds-nav a {
  padding: 7px 12px 7px 10px;
  margin: 0 8px; border-radius: 8px;
  font-size: .84rem;
}
.desktop-sidebar .ds-nav a + a { margin-top: 2px; }
/* Hover kept subtle. The rail is charcoal in both themes, so the highlight is
   a soft white wash (a light token here would glare against the dark rail). */
.desktop-sidebar .ds-nav a:hover { background: rgba(255, 255, 255, .07); transform: none; color: #fff; }
.desktop-sidebar .ds-nav a.ds-active {
  background: rgba(242, 126, 63, .16);
  color: #fff; font-weight: 700;
}
.desktop-sidebar .ds-nav a.ds-active::before {
  left: -8px; top: 6px; bottom: 6px;      /* flush to the rail edge */
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--coral);
  animation: none;
}

/* ── Bottom nav polish ───────────────────────────────────────────────────── */
.bottom-nav a, .bottom-nav button.bn-item { min-height: 44px; min-width: 44px; }

/* ── Focus states: every interactive element shows where it is ───────────── */
.top-bar a:focus-visible, .top-bar button:focus-visible, .top-bar input:focus-visible,
.tb-pop a:focus-visible, .tb-pop button:focus-visible,
.desktop-sidebar a:focus-visible, .desktop-sidebar button:focus-visible,
.bottom-nav a:focus-visible, .bottom-nav button:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}
.tb-search-input:focus-visible { outline: none; }  /* has its own ring border */

/* ── Motion, opt-in only ─────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  .tb-icon-btn, .tb-avatar, .tb-brand, .tb-search-input,
  .ntf-row, .tb-menu-item, .tb-menu-head,
  .desktop-sidebar .ds-nav a, .bottom-nav .bn-item {
    transition: background-color .14s ease, color .14s ease,
                border-color .14s ease, transform .12s ease;
  }
  .tb-pop { animation: tb-pop-in .14s ease; }
  @keyframes tb-pop-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
  }
}

/* The closed drawer's 50px shadow bled a grey strip down the left edge of
   every phone screen. The shadow earns its keep only when the drawer is out. */
.desktop-sidebar:not(.is-open) { box-shadow: none; }
