/* ============================================================
   global.css — Reset, Typography, Layout, Sidebar, Header
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');

/* ---- Reset ---- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: "Poppins", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
  font-size: 12px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  line-height: 1.5;
}

a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
input, select, textarea { font-family: inherit; }
img { max-width: 100%; display: block; }

/* ---- SVG Icons ---- */
svg.i {
  width: 14px; height: 14px;
  stroke: currentColor; stroke-width: 1.8;
  fill: none; stroke-linecap: round; stroke-linejoin: round;
  flex: 0 0 auto;
}

/* ---- Typography ---- */
h3 { font-weight: 600; font-size: 13px; color: var(--text); }
h4 { font-size: 11px; font-weight: 600; color: var(--label); text-transform: uppercase; letter-spacing: .5px; }

/* ---- Card ---- */
.card {
  background: var(--card);
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
}

/* ---- Link ---- */
.link { font-size: 10.5px; color: var(--primary); font-weight: 500; cursor: pointer; }
.link:hover { text-decoration: underline; }

/* ============================================================
   SIDEBAR
   ============================================================ */
.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--sidebar);
  color: var(--sidebar-fg);
  border-right: 1px solid var(--border);
  padding: 22px 16px 24px;
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0; left: 0; bottom: 0;
  z-index: 50;
  transition: width var(--dur-normal) ease, padding var(--dur-normal) ease;
  /* No overflow:hidden here. The collapse handle deliberately sits at
     right:-25px, outside this box, and clipping it made the handle invisible
     and unclickable — pointer events fell through to the content behind. The
     sidebar has square corners, so nothing needs clipping. */
}

/* Page backdrop: layered gradient blooms in both themes, replacing the flat
   single-colour background. Fixed + z-index -1 so it never intercepts clicks
   and never scrolls independently of the content. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    /* One spreading light, not four corner blobs: a single glow pouring down
       from the top like a lamp, over a base wash.
       The old ramp put --bg-shade back at 100%, which painted a hard dark band
       across the bottom of the viewport on every screen. The darkening now
       only ever appears above the light, and a floor of --bg guarantees the
       whole viewport is covered even where the orb layer does not reach. */
    radial-gradient(62% 48% at 50% -8%, var(--bg-glow) 0%, transparent 72%),
    linear-gradient(180deg, var(--bg-shade) 0%, transparent 38%, transparent 100%),
    var(--bg);
  background-attachment: fixed;
  /* Static base wash — the orb layer above carries the motion, so two
     competing animations do not fight. */
  animation: none;
}
@keyframes bgSpread {
  0%   { transform: translateX(-3%) scale(1.08); filter: hue-rotate(-16deg) saturate(1.18) }
  50%  { transform: translateX(3%) scale(1.15); filter: hue-rotate(16deg) saturate(1.3) }
  100% { transform: translateX(-3%) scale(1.08); filter: hue-rotate(-16deg) saturate(1.18) }
}
@media (prefers-reduced-motion: reduce) {
  body::before { animation: none }
}
.sidebar.collapsed {
  width: var(--sidebar-w-collapsed);
  padding: 22px 10px 24px;
}
.sidebar.collapsed .brand-name,
.sidebar.collapsed .sec-label,
.sidebar.collapsed .nav-text,
.sidebar.collapsed .nav .chev,
.sidebar.collapsed .user .info { display: none; }
.sidebar.collapsed .brand { justify-content: center; padding-left: 0; }
/* Collapsed keeps the real logo — the opener circle that used to replace it
   is removed from the markup. */
.sidebar.collapsed .brand .logo { display: flex; }
  /* The sidebar box is fixed and exactly viewport-tall (top:0/bottom:0), so a
     long nav has nowhere to grow. Left alone it overflowed *out* of the box and
     the lower sections became unreachable. The scroll goes on the nav itself
     rather than the sidebar: overflow on .sidebar would also clip the collapse
     handle, which deliberately sits outside the box at right:-25px. */
  .sidebar > .nav { min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.sidebar.collapsed .nav a { justify-content: center; padding: 10px 0; position: relative; }
.sidebar.collapsed .nav .badge {
  display: flex !important;
  position: absolute; top: 4px; right: 6px;
  min-width: 12px; height: 12px; padding: 0 2px;
  font-size: 7px; border-radius: 6px;
  background: var(--primary); color: #fff;
  align-items: center; justify-content: center;
}
.sidebar.collapsed .user { justify-content: center; padding: 10px 0; }

/* Collapsed: the label is gone, so the icon alone has to identify the section.
   Tinting it with the section's own colour (set per item via data-tone) ties the
   glyph to its meaning, and the active one is filled solid so it stays obvious
   without the text. */
.sidebar.collapsed .nav a .i {
  width: 19px; height: 19px;
  stroke-width: 1.9;
  color: var(--tone-color, var(--sidebar-muted));
}
.sidebar.collapsed .nav a.active .i {
  color: #fff;
  stroke: #fff;
}
.sidebar.collapsed .nav a.active {
  background: var(--tone-color, var(--primary));
  border-radius: 10px;
}
.sidebar.collapsed .nav a:not(.active) { border-radius: 10px; transition: background var(--dur-fast) }
.sidebar.collapsed .nav a:not(.active):hover { background: var(--sidebar-hover) }

/* Sits fully OUTSIDE the sidebar's right edge, flush against it. Only the
   inner edge has a border, so it reads as a tab growing out of the sidebar
   rather than a button floating over it. */
.sidebar-toggle {
  position: absolute;
  right: -25px;
  top: 88px;
  width: 25px; height: 76px;
  border: 1px solid transparent;
  border-radius: 0 11px 11px 0;
  /* Reads as a tab protruding from the sidebar, so it is painted with the
     sidebar's own surface and text colour. Using the main card colour here put
     a white pill on the light main background and made the handle invisible in
     light mode. */
  background: var(--sidebar);
  color: var(--sidebar-muted);
  display: flex; align-items: center; justify-content: center;
  cursor: grab;
  z-index: 60;
  box-shadow: 3px 0 12px rgba(15,17,23,.16);
  touch-action: none;
  transition: color var(--dur-fast), background var(--dur-fast), box-shadow var(--dur-fast);
}
.sidebar-toggle:hover { color: var(--primary); background: var(--sidebar-hover); box-shadow: 3px 0 16px rgba(87,116,183,.34) }
.sidebar-toggle:active { cursor: grabbing; }
.sidebar-toggle svg {
  width: 13px; height: 13px;
  fill: none; stroke: currentColor; stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round;
  pointer-events: none;
}
.sidebar-toggle.dragging {
  color: var(--primary);
  border-color: var(--primary);
  box-shadow: 3px 0 20px rgba(87,116,183,.34);
}
.sidebar.collapsed .sidebar-toggle svg { transform: rotate(180deg) }
.sidebar-toggle.dragging { transition: none }

/* Brand */
.brand {
  display: flex; align-items: center; gap: 9px;
  padding-left: 6px; min-height: 30px;
  /* Breathing room under the logo before the first nav icon. The brand block
     and the nav were butted straight together, so the top icon read as part of
     the logo rather than as the first destination. */
  margin-bottom: 14px;
}
.logo {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--primary);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-size: 15px;
  position: relative; overflow: hidden; flex: 0 0 30px;
}
.logo img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.brand-name { font-weight: 700; font-size: 15px; color: var(--text); white-space: nowrap; }

/* Section labels */
.sec-label {
      /* Group headings, matched to the 4px item gap so a heading never opens a
         hole that is wider than the spacing between icons. */
      margin: 18px 0 4px 8px;
      font-size: 9px; letter-spacing: 1.3px;
      color: var(--muted); text-transform: uppercase;
      font-weight: 500; white-space: nowrap;
    }
.sec-label.second { margin-top: 18px; }
/* The sidebar is three separate <nav> elements - #navMain, [data-group="ops"]
   and [data-group="account"] - so the flex `gap` on .nav does NOT apply between
   them. These margins were the only thing separating the groups, which is why
   the gap only ever showed up in some places: after Communication and after
   Retailers, never inside a group. Matched to the 4px item gap so the column
   of icons is evenly spaced all the way down. */
.nav[data-group] { margin-top: 4px; }
    .nav[data-group="account"] { margin-top: 4px; }

/* Nav links */
.nav { display: flex; flex-direction: column; gap: 4px; }
    .nav a {
      display: flex; align-items: center; gap: 10px;
      /* Even height for every row. Without a floor the links sized themselves
         to their label, so a short name sat in a shorter row than a long one
         and the column of icons looked stepped. */
      min-height: 34px;
      padding: 9px 10px; border-radius: var(--r-sm);
  font-size: 11.5px; font-weight: 500;
  color: var(--label); text-decoration: none;
  cursor: pointer; white-space: nowrap;
  transition: background var(--dur-fast);
}
/* Sidebar sits on the opposite of the theme, so its text/icon ramp comes from
   the --sidebar-* tokens rather than --text/--label/--icon. */
.sidebar .brand-name { color: var(--sidebar-fg); }
.sidebar .sec-label { color: var(--sidebar-muted); }
.sidebar .nav a { color: var(--sidebar-fg); }
.sidebar .nav a .i { color: var(--sidebar-muted); }
.sidebar .nav a:hover { background: var(--sidebar-hover); }
.sidebar .nav a:hover .i { color: var(--sidebar-fg); }
.sidebar .nav a .chev { color: var(--sidebar-muted); }

/* Active section is a solid white bar with dark text — unmistakable at a
   glance, and it reads the same on both themes since the sidebar inverts. */
.sidebar .nav a.active,
.sidebar .nav a.active:hover {
  background: #FFFFFF;
  color: #1B1E27;
}
.sidebar .nav a.active .i,
.sidebar .nav a.active .chev { color: var(--primary); }
.sidebar .nav a.active .badge {
  background: var(--primary) !important;
  color: #fff !important;
}
.nav a .i { color: var(--icon); flex: 0 0 14px; }
.nav a .chev { margin-left: auto; color: #B7BECB; width: 12px; height: 12px; }
.nav a.active .i, .nav a.active .chev { color: var(--primary); }
.nav a .badge {
  margin-left: auto;
  background: var(--primary-soft); color: var(--primary-dark);
  font-size: 9px; font-weight: 600;
  padding: 1px 7px; border-radius: 9px;
}

/* User card */
.user {
  margin-top: auto;
  display: flex; align-items: center; gap: 10px;
  padding: 10px; border-radius: var(--r-md);
  background: var(--elev);
}
.user .av {
  width: 32px; height: 32px; border-radius: 50%;
  background: linear-gradient(135deg, #22C55E, #0E9F6E);
  color: #fff; font-weight: 600; font-size: 11px;
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 32px; overflow: hidden;
}
.user b { display: block; font-size: 11px; color: var(--sidebar-fg); font-weight: 600; }
.user span { display: block; font-size: 9.5px; color: var(--sidebar-muted); }
.sidebar .user { background: var(--sidebar-hover); }

/* ============================================================
   MAIN LAYOUT
   ============================================================ */
.main {
  margin-left: var(--sidebar-w);
  padding: 18px var(--content-gutter) 26px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  transition: margin-left var(--dur-normal) ease;
}
.sidebar.collapsed ~ .main { margin-left: var(--sidebar-w-collapsed); }

/* ---- Content area (router injects here) ---- */
#content { min-height: calc(100vh - 80px); flex: 1; }
  /* Added by ChatFeature for its own route only, and removed in destroy(). The
     chat needs a definite height so the message list scrolls internally instead
     of stretching the whole page; a min-height cannot give it that. */
  /* `flex: 1` on the base rule means flex-basis:0%, and for a column flex item the
     basis wins over `height`, so height alone is ignored and the host still grows
     with its content. flex:none is what makes the height take effect. */
  #content.is-viewport {
    flex: none;
    height: calc(100vh - 80px);
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  #content.is-viewport > * { flex: 1; min-height: 0; }

   /* ---- AI Assistant overlay ----
      A panel that floats above the section you are already on. The host is
      pointer-transparent so the section behind stays usable, and the panel
      opts back in. It is NOT a modal: the sidebar keeps highlighting the
      section you came from, and closing the panel leaves you exactly there. */
   .ai-overlay {
     position: fixed; inset: 0; z-index: 70; pointer-events: none;
   }
   .ai-overlay[hidden] { display: none; }

   .ai-panel {
     position: absolute; right: 22px; bottom: 22px;
     width: 420px; height: 560px;
     display: flex; flex-direction: column;
     background: var(--card);
     border: 1px solid var(--border);
     border-radius: 16px;
     box-shadow: 0 24px 70px -18px rgba(10, 15, 30, .45);
     overflow: hidden; pointer-events: auto;
     /* One shared transition so growing, shrinking and the corner radius all
        move together instead of the panel snapping. */
     transition: width .34s var(--ease), height .34s var(--ease),
                 right .34s var(--ease), bottom .34s var(--ease),
                 border-radius .34s var(--ease);
   }
   /* Expanded takes over the whole content area, not the sidebar: --ai-left is the
      sidebar's right edge, so the panel fills everything to the right of it and
      the sidebar stays readable - you can still see which section you came
      from while the assistant has the screen.

      Sized in % of the overlay rather than vw/vh on purpose. The panel's
      containing block is the overlay, and 100vw/100vh include the scrollbar,
      so a viewport-relative width overshoots and makes the fill jitter as the
      scrollbar appears and disappears. */
   .ai-panel.is-expanded {
     width: calc(100% - var(--ai-left, 0px));
     height: 100%;
     right: 0;
     bottom: 0;
     border-radius: 0;
   }

   .ai-head {
     flex: none; display: flex; align-items: center; gap: 9px;
     padding: 9px 10px 9px 13px;
     border-bottom: 1px solid var(--border);
   }
   .ai-dot {
     width: 7px; height: 7px; border-radius: 50%;
     background: var(--accent); flex: none;
   }
   .ai-title { font-size: 12.5px; font-weight: 700; color: var(--text); }
   .ai-head-actions { margin-left: auto; display: flex; gap: 4px; }

   .ai-hbtn {
     width: 28px; height: 28px; padding: 0; flex: none;
     display: inline-flex; align-items: center; justify-content: center;
     border-radius: 8px; cursor: pointer;
     color: var(--muted); background: transparent;
     border: 1px solid transparent; font: inherit;
     transition: color 160ms var(--ease), background 160ms var(--ease),
                 border-color 160ms var(--ease);
   }
   .ai-hbtn:hover {
     color: var(--text); background: var(--elev);
     border-color: var(--border);
   }
   .ai-hbtn .i { width: 14px; height: 14px; }

   /* The chat view sizes itself off the container it is rendered into, but the
      height rule it relies on is scoped to #content. Give it its own height so
      the composer docks to the bottom of the panel instead of collapsing. */
   .ai-body { flex: 1; min-height: 0; display: flex; }
   .ai-body > * { flex: 1; min-width: 0; height: 100%; }

/* ---- Topbar ---- */
.topbar {
  display: flex; align-items: center; gap: 14px;
}
.greet .h { font-weight: 700; font-size: 16px; color: var(--text); letter-spacing: -.2px; }
.greet .s { font-size: 10.5px; color: var(--muted); margin-top: 1px; }
.top-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }

/* ---- Avatar ---- */
.avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: linear-gradient(135deg, #22C55E, #0E9F6E);
  color: #fff; font-weight: 600; font-size: 12px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow); overflow: hidden; cursor: pointer;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }

/* ---- Search ---- */
.search {
  width: 360px; height: 36px; border-radius: 18px;
  background: var(--card); box-shadow: var(--shadow);
  display: flex; align-items: center; gap: 8px;
  padding: 0 8px 0 14px;
}
.search input {
  flex: 1; border: none; background: none; outline: none;
  font-size: 10.5px; font-family: inherit; color: var(--text); min-width: 0;
}
.search .i { color: var(--icon); }

/* ---- Toolbar ---- */
.toolbar {
  display: flex; align-items: center; gap: 10px;
  margin-top: 14px; justify-content: flex-end;
}

/* ---- Overlay (full-screen panels) ---- */
.overlay { position: fixed; inset: 0; background: rgba(23,32,52,.5); z-index: 200; display: none; align-items: center; justify-content: center; backdrop-filter: blur(2px); }
.overlay.open { display: flex; }

/* ---- Toast ---- */
.toast {
  position: fixed; top: 20px; right: 20px;
  background: #1f2430; color: #fff;
  padding: 12px 20px; border-radius: 10px;
  font-size: 13px; z-index: 300;
  display: none;
  max-width: 350px; box-shadow: 0 4px 16px rgba(0,0,0,.25);
  font-family: Poppins, system-ui, sans-serif;
  overflow: hidden; word-break: break-word;
}
.toast.show { display: block; transform: translateX(0); animation: toastIn .3s var(--ease); }
.toast.success { background: #1e7d32; }
.toast.error { background: #a12b2b; }
@keyframes toastIn { from { transform: translateX(120%); } to { transform: translateX(0); } }

/* ---- Empty state ---- */
.empty { text-align: center; padding: 40px 0; font-size: 12px; color: var(--muted); }
.loading { text-align: center; padding: 20px 0; font-size: 11px; color: var(--muted); }
.empty-rich { padding: 44px 20px; }
.empty-msg { font-size: 13px; color: var(--label); }
.empty-hint { margin-top: 6px; font-size: 11px; color: var(--muted); }

/* ---- Skeletons ---- */
.skel {
  --w: 100%;
  width: var(--w);
  border-radius: var(--r-sm);
  background: linear-gradient(90deg,
    var(--skel-base) 0%, var(--skel-base) 35%,
    var(--skel-tint) 50%, var(--skel-base) 65%, var(--skel-base) 100%);
  background-size: 220% 100%;
  animation: skelShimmer var(--skel-dur) ease-in-out infinite;
}
@keyframes skelShimmer {
  0%   { background-position: 140% 0; }
  100% { background-position: -40% 0; }
}
.skel-text { height: 11px; width: 100%; }
.skel-line { height: 12px; width: 100%; }
.skel-block { height: 100%; width: 100%; border-radius: var(--r-md); }
.skel-cell { height: 13px; width: 60%; }
.skel-circle { height: 34px; width: 34px; border-radius: 50%; }
.skel-title { height: 17px; width: 46%; }
.skel-inline { display: block; }

.skel-rows { display: flex; flex-direction: column; gap: 12px; padding: 4px 0; }
.skel-row { height: 15px; }

/* Skeleton wrappers must span the full width of whatever grid they are dropped
   into. Without this, .skel-cards becomes ONE grid item in a 3-column .grid,
   so it occupies a third of the row and its internal auto-fit then stacks the
   cards vertically in that narrow strip. */
.skel-cards, .skel-rows, .skel-table, .skel-chart {
  grid-column: 1 / -1;
  width: 100%;
}

.skel-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: var(--sp-3); }
.skel-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--card); border: 1px solid var(--border);
}

.skel-table { display: flex; flex-direction: column; gap: 12px; padding: 6px 0; }
.skel-tr { display: flex; align-items: center; gap: var(--sp-4); }
.skel-tr .skel:first-child { flex: 0 0 22%; }

.skel-chart { display: flex; align-items: flex-end; padding: var(--sp-4) 0; }
.skel-chart-bars {
  display: flex; align-items: flex-end; gap: 2.2%;
  width: 100%; height: 100%;
}
.skel-chart-bars i {
  flex: 1; border-radius: 4px 4px 0 0; min-width: 4px;
  background: linear-gradient(90deg, var(--skel-base) 0%, var(--skel-base) 35%,
    var(--skel-tint) 50%, var(--skel-base) 65%, var(--skel-base) 100%);
  background-size: 220% 100%;
  animation: skelShimmer var(--skel-dur) ease-in-out infinite;
}
/* Line-mode placeholder: a trend polyline, so a chart set to Line does not
   flash a row of columns before its real shape appears. */
.skel-chart-bars .skel-trend {
  width: 100%;
  height: 100%;
  color: var(--skel-base);
  overflow: visible;
}
.skel-chart-bars .skel-trend polyline {
  stroke: var(--skel-tint);
  stroke-dasharray: 240;
  animation: skelDash var(--skel-dur) ease-in-out infinite;
}
@keyframes skelDash {
  0% { stroke-dashoffset: 240; }
  100% { stroke-dashoffset: 0; }
}

/* ---- Panel error (replaces stuck placeholders) ---- */.panel-error {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-4); margin: var(--sp-2) 0;
  border: 1px solid var(--danger-soft);
  background: var(--danger-soft);
  border-radius: var(--r-lg);
}
.err-icon {
  flex: 0 0 20px; width: 20px; height: 20px; margin-top: 1px;
  border-radius: 50%; background: var(--danger); color: #fff;
  font-size: 12px; font-weight: 700; line-height: 20px; text-align: center;
}
.err-body { flex: 1 1 auto; min-width: 0; }
.err-msg { font-size: 12px; color: var(--label); line-height: 1.5; }
.err-detail {
  margin-top: 5px; font-size: 11px; color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  word-break: break-word;
}
.err-retry { flex: 0 0 auto; }

/* ---- Toast stack ---- */
.toast-stack {
  position: fixed; top: 18px; right: 18px; z-index: 300;
  display: flex; flex-direction: column; gap: 8px;
  width: min(360px, calc(100vw - 36px));
  pointer-events: none;
}
.toast-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--r-lg);
  background: #1f2430; color: #fff;
  font-size: 12.5px; line-height: 1.45;
  box-shadow: var(--shadow-pop);
  pointer-events: auto;
  opacity: 0; transform: translateX(16px);
  transition: opacity 220ms var(--ease), transform 220ms var(--ease);
}
.toast-item.show { opacity: 1; transform: translateX(0); }
.toast-item.success { background: #1e7d32; }
.toast-item.error   { background: #a12b2b; }
.toast-item.warn    { background: #8a5a08; }
.toast-item.info    { background: #1d4ed8; }
.toast-body { flex: 1 1 auto; min-width: 0; word-break: break-word; }
.toast-action {
  flex: 0 0 auto; background: rgba(255,255,255,.16); color: #fff;
  border: 0; border-radius: var(--r-sm); padding: 5px 9px;
  font: inherit; font-size: 11.5px; font-weight: 600; cursor: pointer;
}
.toast-action:hover { background: rgba(255,255,255,.28); }
.toast-close {
  flex: 0 0 auto; background: none; border: 0; color: rgba(255,255,255,.72);
  font-size: 17px; line-height: 1; padding: 0 2px; cursor: pointer;
}
.toast-close:hover { color: #fff; }

/* ---- Zero / first-run state ----
   One panel that explains the empty screen and the next action, instead of a
   grid of identical "No data" panels. */
.zero-state {
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  padding: 44px 28px;
  border: 1px dashed var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
  grid-column: 1 / -1;
}
.zs-icon {
  width: 46px; height: 46px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--elev); color: var(--muted);
  font-size: 20px; margin-bottom: 14px;
}
.zs-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--text); }
.zs-body-text {
  margin: 8px 0 0; font-size: 12px; line-height: 1.6;
  color: var(--muted); max-width: 46ch;
}
.zs-steps {
  list-style: none; margin: 22px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
  text-align: left;
}
.zs-step {
  display: flex; align-items: flex-start; gap: 9px;
  width: 210px; padding: 11px 13px;
  background: var(--elev); border-radius: var(--r-md);
}
.zs-num {
  flex: 0 0 19px; width: 19px; height: 19px; margin-top: 1px;
  border-radius: 50%; background: var(--primary); color: #fff;
  font-size: 10.5px; font-weight: 700; line-height: 19px; text-align: center;
}
.zs-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.zs-body b { font-size: 11.5px; font-weight: 600; color: var(--text); }
.zs-body span { font-size: 10.5px; line-height: 1.5; color: var(--muted); }
.zs-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 22px; }
.zs-foot { margin-top: 16px; font-size: 10.5px; color: var(--muted); }

/* Inline hint for panels that stay but need explaining. */
.panel-note {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 9px 12px; margin-bottom: 12px;
  border-radius: var(--r-md);
  background: var(--warn-soft); color: var(--warn-text);
  font-size: 11px; line-height: 1.5;
}

/* ---- Offline banner ---- */
[data-connection="offline"] #netBanner {
  display: flex !important;
}
#netBanner {
  display: none;
  align-items: center; justify-content: center; gap: 8px;
  padding: 7px 12px; font-size: 11.5px; font-weight: 500;
  background: var(--warn-soft); color: var(--warn-text);
  border-bottom: 1px solid var(--border);
}

@media (prefers-reduced-motion: reduce) {
  .skel, .skel-chart-bars i { animation: none; background: var(--skel-base); }
  .toast-item { transition: none; opacity: 1; transform: none; }
}

/* ---- View Transition (theme toggle) ---- */
::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 2; animation: theme-reveal 700ms var(--ease) both; }
@keyframes theme-reveal {
  from { clip-path: circle(0px at var(--theme-x) var(--theme-y)); }
  to   { clip-path: circle(var(--theme-radius) at var(--theme-x) var(--theme-y)); }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
  * { scroll-behavior: auto !important; transition-duration: 0.01ms !important; }
}

/* ============================================================
   LANDING PAGE
   ============================================================ */

/* Hide sidebar/topbar on landing */
.sidebar.landing-hidden { display: none; }
.main.landing-mode { margin-left: 0; }
.main.landing-mode .topbar { display: none; }

/* ---- Landing wrapper ---- */
.lp { font-family: 'Poppins', system-ui, sans-serif; color: var(--text); background: var(--bg); min-height: 100vh; overflow-x: hidden; }

/* ---- Nav ---- */
.lp-nav { position: sticky; top: 0; z-index: 100; background: var(--bg); border-bottom: 1px solid var(--border); backdrop-filter: blur(12px); background: color-mix(in srgb, var(--bg) 85%, transparent); }
.lp-nav-inner { max-width: 1200px; margin: 0 auto; padding: 0 24px; height: 60px; display: flex; align-items: center; gap: 24px; }
.lp-brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 16px; color: var(--text); }
.lp-logo { width: 32px; height: 32px; border-radius: 10px; background: #22C55E; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 14px; }
.lp-nav-links { display: flex; gap: 24px; margin-left: auto; }
.lp-nav-links a { font-size: 13px; color: var(--muted); text-decoration: none; font-weight: 500; transition: color .15s; }
.lp-nav-links a:hover { color: var(--text); }

/* ---- Buttons ---- */
.lp-btn { display: inline-flex; align-items: center; gap: 8px; border: none; border-radius: 10px; font-family: inherit; font-weight: 600; cursor: pointer; transition: all .15s; text-decoration: none; }
.lp-btn-primary { background: #22C55E; color: #fff; }
.lp-btn-primary:hover { background: #1ebd54; box-shadow: 0 4px 20px rgba(34,197,94,.3); }
.lp-btn-ghost { background: var(--elev); color: var(--text); border: 1px solid var(--border); }
.lp-btn-ghost:hover { background: var(--border); }
.lp-btn-lg { height: 44px; padding: 0 24px; font-size: 14px; }
.lp-btn-nav { height: 34px; padding: 0 16px; font-size: 12px; background: #22C55E; color: #fff; }

/* ---- Hero ---- */
.lp-hero { text-align: center; padding: 80px 24px 60px; max-width: 800px; margin: 0 auto; }
.lp-hero-badge { display: inline-block; padding: 6px 14px; border-radius: 20px; font-size: 12px; font-weight: 600; color: #22C55E; background: rgba(34,197,94,.1); border: 1px solid rgba(34,197,94,.2); margin-bottom: 24px; }
.lp-hero-title { font-size: clamp(32px, 5vw, 52px); font-weight: 700; line-height: 1.15; color: var(--text); margin-bottom: 20px; letter-spacing: -.5px; }
.lp-gradient { background: linear-gradient(135deg, #22C55E, #3B82F6); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
.lp-hero-sub { font-size: 16px; line-height: 1.7; color: var(--muted); max-width: 560px; margin: 0 auto 32px; }
.lp-hero-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-bottom: 48px; }
.lp-hero-stats { display: flex; gap: 48px; justify-content: center; flex-wrap: wrap; }
.lp-stat-num { font-size: 28px; font-weight: 700; color: var(--text); }
.lp-stat-label { font-size: 12px; color: var(--muted); margin-top: 2px; }

/* ---- Trust logos ---- */
.lp-trust { padding: 40px 24px; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.lp-trust-inner { max-width: 900px; margin: 0 auto; text-align: center; }
.lp-trust-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); font-weight: 600; display: block; margin-bottom: 16px; }
.lp-trust-logos { display: flex; gap: 32px; justify-content: center; align-items: center; flex-wrap: wrap; }
.lp-trust-item { font-size: 16px; font-weight: 700; color: var(--muted); opacity: .6; padding: 8px 16px; border-radius: 8px; background: var(--elev); }

/* ---- Section common ---- */
.lp-section-inner { max-width: 1100px; margin: 0 auto; padding: 0 24px; }
.lp-section-badge { display: inline-block; padding: 5px 12px; border-radius: 16px; font-size: 11px; font-weight: 600; color: #3B82F6; background: rgba(59,130,246,.1); border: 1px solid rgba(59,130,246,.15); margin-bottom: 14px; }
.lp-section-title { font-size: clamp(24px, 3.5vw, 36px); font-weight: 700; color: var(--text); margin-bottom: 12px; }
.lp-section-sub { font-size: 14px; color: var(--muted); max-width: 540px; line-height: 1.6; }

/* ---- Features ---- */
.lp-features { padding: 80px 0; }
.lp-features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 40px; }
.lp-feature-card { background: var(--card); border: 1px solid var(--border); border-radius: 14px; padding: 28px 24px; transition: all .2s; }
.lp-feature-card:hover { border-color: var(--primary); box-shadow: 0 8px 32px rgba(34,197,94,.08); transform: translateY(-2px); }
.lp-feature-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; margin-bottom: 16px; }
.lp-feature-icon svg { width: 20px; height: 20px; }
.lp-icon-green { background: rgba(34,197,94,.12); color: #22C55E; }
.lp-icon-blue { background: rgba(59,130,246,.12); color: #3B82F6; }
.lp-icon-amber { background: rgba(245,165,36,.12); color: #F5A524; }
.lp-icon-purple { background: rgba(139,92,246,.12); color: #8B5CF6; }
.lp-icon-red { background: rgba(239,79,87,.12); color: #EF4F57; }
.lp-icon-teal { background: rgba(6,182,212,.12); color: #06B6D4; }
.lp-feature-card h3 { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 8px; }
.lp-feature-card p { font-size: 13px; line-height: 1.6; color: var(--muted); }

/* ---- How it works ---- */
.lp-how { padding: 80px 0; background: var(--elev); }
.lp-steps { display: flex; align-items: flex-start; gap: 24px; margin-top: 40px; justify-content: center; flex-wrap: wrap; }
.lp-step { text-align: center; flex: 1; min-width: 200px; max-width: 260px; }
.lp-step-num { width: 48px; height: 48px; border-radius: 50%; background: #22C55E; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 700; margin: 0 auto 16px; }
.lp-step h3 { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.lp-step p { font-size: 13px; color: var(--muted); line-height: 1.5; }
.lp-step-arrow { color: var(--muted); margin-top: 16px; flex-shrink: 0; }
.lp-step-arrow svg { width: 20px; height: 20px; }

/* ---- CTA ---- */
.lp-cta { padding: 80px 0; }
.lp-cta-title { font-size: clamp(22px, 3vw, 32px); font-weight: 700; color: var(--text); margin-bottom: 10px; }
.lp-cta-sub { font-size: 14px; color: var(--muted); margin-bottom: 28px; }

/* ---- Footer ---- */
.lp-footer { border-top: 1px solid var(--border); padding: 24px 0; }
.lp-footer-inner { max-width: 1100px; margin: 0 auto; padding: 0 24px; display: flex; align-items: center; justify-content: space-between; }
.lp-footer-brand { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 13px; color: var(--text); }
.lp-footer-copy { font-size: 12px; color: var(--muted); }

/* ---- Responsive ---- */
@media (max-width: 900px) {
  .lp-features-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .lp-features-grid { grid-template-columns: 1fr; }
  .lp-hero { padding: 48px 20px 40px; }
  .lp-hero-stats { gap: 24px; }
  .lp-nav-links { display: none; }
  .lp-footer-inner { flex-direction: column; gap: 8px; text-align: center; }
  .lp-step-arrow { display: none; }
}

/* ============================================================
   Account menu (header avatar)
   ============================================================ */
.acct-menu {
  position: fixed;
  top: 58px; right: 20px;
  width: 246px;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--card);
  box-shadow: var(--shadow-pop);
  padding: 6px;
  z-index: 400;
  animation: acctIn .16s var(--ease);
}
.acct-menu[hidden] { display: none }
@keyframes acctIn {
  from { opacity: 0; transform: translateY(-6px) scale(.98) }
  to   { opacity: 1; transform: none }
}
.acct-head { display: flex; align-items: center; gap: 10px; padding: 9px 10px 11px }
.acct-av {
  width: 34px; height: 34px; flex: 0 0 34px;
  border-radius: 50%; overflow: hidden;
  background: linear-gradient(140deg, var(--accent), var(--accent-2));
  color: #fff; font-weight: 700; font-size: 13px;
  display: flex; align-items: center; justify-content: center;
}
.acct-av img { width: 100%; height: 100%; object-fit: cover }
.acct-id { min-width: 0 }
.acct-id b { display: block; font-size: 12px; color: var(--text); font-weight: 650 }
.acct-id span {
  display: block; font-size: 10.5px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-sep { height: 1px; background: var(--border); margin: 4px 6px }
.acct-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; border: none; border-radius: var(--r-sm);
  background: none; font: inherit; font-size: 12px; color: var(--label);
  cursor: pointer; text-align: left;
}
.acct-item:hover { background: var(--elev) }
.acct-item.danger { color: var(--danger) }
.acct-item.danger:hover { background: var(--danger-soft) }
.acct-ic { width: 16px; height: 16px; flex: 0 0 16px; display: inline-flex }
.acct-ic svg {
  width: 16px; height: 16px;
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
}
.acct-sun { display: block }
.acct-moon { display: none }
[data-theme="dark"] .acct-sun { display: none }
[data-theme="dark"] .acct-moon { display: block }
.acct-label { flex: 1 1 auto }
.acct-state { font-size: 10.5px; color: var(--muted); font-weight: 600 }
.acct-item[aria-checked="true"] .acct-state { color: var(--primary) }

/* Header avatar must read as clickable. */
.topbar .avatar { cursor: pointer; transition: transform var(--dur-fast), box-shadow var(--dur-fast) }
.topbar .avatar:hover { transform: scale(1.05) }
.topbar .avatar:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px }

/* Avatar stack: initials render underneath, the photo covers them on load.
   If the image 404s or is blocked the initials are already there, so the
   circle is never empty and never falls back to the company mark. */
.avatar, .user .av, .acct-av { position: relative }
.av-fallback {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(140deg, var(--accent), var(--accent-2));
  color: #fff; font-weight: 700;
  border-radius: 50%;
}
.av-photo {
  position: relative; z-index: 1;
  width: 100%; height: 100%;
  object-fit: cover; border-radius: 50%;
  display: block;
}

/* Lock the page behind a drawer/modal so the section behind cannot scroll.
   Both html and body are locked: in Chrome the document scrolls on <html>, so
   setting overflow:hidden on <body> alone still leaves the wheel working.
   position:fixed on <body> is what actually stops it on touch devices. */
html.scroll-locked,
body.scroll-locked {
  overflow: hidden !important;
  touch-action: none;
}
body.scroll-locked {
  position: fixed;
  inset: 0;
  width: 100%;
  overflow: hidden !important;
}
/* Grip lines so the handle reads as draggable, not just clickable. */
.sidebar-toggle svg { position: relative; z-index: 1 }

/* ---- Ambient light orbs ----
   Three large blurred colour fields that slowly rotate and drift behind the
   app, so light visibly spreads and turns. Adapted from the fluid-gradient
   reference (orbs + screen blend + rotation) at dashboard pace — ~22s loops,
   not 5s — and without the canvas particle engine, which would cost a
   compositor layer per frame on low-end machines. */
.bg-orbs {
  /* Cover the viewport exactly. The old `inset:-12vw` + explicit 124vw/124vh
     over-spanned, but on very tall viewports the oversized orbs still left the
     bottom edge bare, which read as a black band under the cards. inset:0 with
     a self-clipping container means the base wash always reaches the bottom. */
  position: fixed; inset: 0;
  z-index: 0; pointer-events: none;
  mix-blend-mode: screen;
  overflow: hidden;
}
.orb {
  position: absolute; border-radius: 50%;
  will-change: transform, opacity;
  mix-blend-mode: screen;
  filter: blur(60px) saturate(150%);
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
  animation-direction: alternate;
}
/* Warm brand glow, top-left origin. */
.orb-a {
  width: 52vw; height: 52vw; left: -8vw; top: -14vh;
  background: radial-gradient(circle at center, rgba(87,116,183,.5) 0%, rgba(139,92,246,.28) 46%, transparent 72%);
  animation-name: orb-drift-a; animation-duration: 16.8s;
}
/* Teal-rose spread, right origin. */
.orb-b {
  width: 58vw; height: 58vw; right: -10vw; top: 8vh;
  background: radial-gradient(circle at center, rgba(47,158,143,.42) 0%, rgba(232,121,168,.24) 48%, transparent 74%);
  animation-name: orb-drift-b; animation-duration: 19.6s;
}
/* Deep violet wash, bottom origin. */
.orb-c {
  width: 60vw; height: 60vw; left: 12vw; bottom: -12vh;
  background: radial-gradient(circle at center, rgba(99,102,241,.4) 0%, rgba(47,158,143,.2) 50%, transparent 75%);
  animation-name: orb-drift-c; animation-duration: 18.2s;
}
@keyframes orb-drift-a {
  0%   { transform: translate(0, 0) scale(1) rotate(0deg); opacity: .85; }
  50%  { transform: translate(9vw, 7vh) scale(1.18) rotate(120deg); opacity: 1; }
  100% { transform: translate(-4vw, 12vh) scale(1.06) rotate(240deg); opacity: .9; }
}
@keyframes orb-drift-b {
  0%   { transform: translate(0, 0) scale(1.1) rotate(0deg); opacity: .9; }
  50%  { transform: translate(-10vw, 9vh) scale(.94) rotate(-130deg); opacity: 1; }
  100% { transform: translate(4vw, -6vh) scale(1.14) rotate(-260deg); opacity: .85; }
}
@keyframes orb-drift-c {
  0%   { transform: translate(0, 0) scale(1) rotate(0deg); opacity: .8; }
  50%  { transform: translate(7vw, -8vh) scale(1.22) rotate(150deg); opacity: 1; }
  100% { transform: translate(-6vw, 5vh) scale(1.08) rotate(300deg); opacity: .88; }
}
/* Content sits above the orbs. The sidebar is already fixed with its own
   stacking; only the content column needs lifting. */
.main { position: relative; z-index: 1; }
/* Screens are mostly dark surfaces; screen-blend orbs vanish on white, so in
   light mode they switch to a soft multiply wash instead of disappearing. */
[data-theme="light"] .bg-orbs, :root:not([data-theme="dark"]) .bg-orbs { mix-blend-mode: multiply; opacity: .5; }
@media (prefers-reduced-motion: reduce) {
  .orb { animation: none; }
}