/* LimeliJourney UI design language — BOLD direction (spec 022, see docs/DESIGN.md).
   "Field-guide, not spreadsheet": deep-forest brand shell, warm-paper content, a vivid
   signal-lime accent, and editorial Bricolage Grotesque headings. Product register:
   bold = stronger hierarchy + committed brand color + decisive type, not theatrics.
   OKLCH throughout; never #000/#fff. Fonts are <link>ed by the page (Bricolage + Inter). */

:root {
  /* Brand shell + canvas */
  --ll-ink:        oklch(0.27 0.045 156);   /* deep-forest sidebar / brand anchor */
  --ll-ink-soft:   oklch(0.33 0.04 156);
  --ll-ink-line:   oklch(0.40 0.035 156 / 0.5);
  --ll-on-ink:     oklch(0.93 0.02 130);    /* text on the forest shell */
  --ll-on-ink-mut: oklch(0.74 0.03 140);

  --ll-bg:        oklch(0.985 0.005 120);   /* warm paper canvas */
  --ll-panel:     oklch(0.998 0.003 120);   /* raised panels / drawer */
  --ll-elevated:  oklch(0.965 0.008 140);   /* hover rows, subtle fills */
  --ll-border:    oklch(0.905 0.008 150);
  --ll-border-strong: oklch(0.84 0.01 150);

  --ll-text:      oklch(0.25 0.02 158);
  --ll-text-soft: oklch(0.42 0.016 158);
  --ll-text-mute: oklch(0.56 0.013 158);

  /* Accent — signal lime (live / active / focus). Used decisively, sparingly. */
  --ll-accent:        oklch(0.78 0.17 138);
  --ll-accent-ink:    oklch(0.30 0.09 145);   /* text on a lime fill */
  --ll-accent-soft:   oklch(0.95 0.06 135);
  --ll-accent-line:   oklch(0.86 0.10 138);
  --ll-focus:         oklch(0.78 0.17 138 / 0.40);

  /* Primary action — deeper green, accessible on white. */
  --ll-green:        oklch(0.52 0.13 152);
  --ll-green-hover:  oklch(0.47 0.13 152);
  --ll-green-press:  oklch(0.43 0.125 152);
  --ll-on-green:     oklch(0.99 0.01 152);

  /* Semantic */
  --ll-success:      oklch(0.58 0.13 150);
  --ll-success-soft: oklch(0.95 0.05 145);
  --ll-warn:         oklch(0.55 0.12 70);
  --ll-warn-soft:    oklch(0.95 0.05 80);
  --ll-danger:       oklch(0.56 0.17 27);
  --ll-danger-soft:  oklch(0.955 0.035 27);

  /* Type */
  --ll-font:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --ll-display: "Bricolage Grotesque", "Inter", system-ui, sans-serif;
  --ll-fs-xs: 0.75rem; --ll-fs-sm: 0.8125rem; --ll-fs-md: 0.875rem; --ll-fs-lg: 1rem;
  --ll-fs-title: clamp(1.9rem, 1.4rem + 1.6vw, 2.4rem);

  --ll-r-sm: 7px; --ll-r-md: 10px; --ll-r-lg: 16px; --ll-r-pill: 100px;
  --ll-shadow-1: 0 1px 2px oklch(0.3 0.04 156 / 0.07), 0 1px 1px oklch(0.3 0.04 156 / 0.04);
  --ll-shadow-2: 0 10px 30px oklch(0.3 0.04 156 / 0.10), 0 3px 8px oklch(0.3 0.04 156 / 0.06);
  --ll-shadow-drawer: -22px 0 60px oklch(0.22 0.04 156 / 0.22);
  --ll-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

.ll-scope { font-family: var(--ll-font); color: var(--ll-text); -webkit-font-smoothing: antialiased; }
/* min-width:0 lets the flex main column shrink below its content's intrinsic
   width. Without it, a wide child (a non-wrapping toolbar or an unclipped
   table) forces the column past the viewport, producing horizontal page
   overflow that pushes the page-header actions off-screen. */
.main-content { background: var(--ll-bg); min-width: 0; }

/* ===== App shell: the deep-forest brand rail =============================== */
.ll-scope .sidebar {
  background: var(--ll-ink);
  border-right: none;
  padding: 0;
}
/* Wordmark (degrades to plain text where ui.css isn't loaded). */
.ll-scope .sidebar-brand,
.ll-scope .navbar-brand.sidebar-brand {
  display: flex !important; align-items: center; gap: 11px;
  padding: 22px 22px 18px; margin: 0; width: 100%; justify-content: flex-start;
  border-bottom: 1px solid var(--ll-ink-line);
}
.ll-scope .sidebar-brand .sidebar-brand-icon { display: none; }
/* Brand mark — inline SVG (the "journey route + leaf"). The leaf node carries a
   faint lime halo so the mark feels lit, not flat, on the deep-forest shell. */
.ll-scope .ll-brandmark {
  width: 28px; height: 28px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 9px;
}
.ll-scope .ll-brandmark svg {
  width: 28px; height: 28px; display: block;
  filter: drop-shadow(0 0 8px oklch(0.78 0.17 138 / 0.18));
}
/* The whole brand lockup nudges up a hair on hover (link affordance). */
.ll-scope .sidebar-brand { transition: opacity .16s var(--ll-ease); }
@media (hover: hover) and (pointer: fine) {
  .ll-scope .sidebar-brand:hover { opacity: 0.92; }
}
.ll-scope .ll-wordmark {
  font-family: var(--ll-display); font-weight: 700; font-size: 1.15rem; letter-spacing: -0.02em;
  color: var(--ll-on-ink); line-height: 1;
}
.ll-scope .ll-wordmark span { color: var(--ll-accent); }

/* ===== ⌘K hint chip (command-palette discovery) ========================== */
/* A quiet, full-width affordance under the brand. Reads as a search field with
   keycaps; clicking opens LLCommand. The Cmd-K *toggle* itself is keyboard-driven
   and intentionally has no open animation (it's hit hundreds of times a day) — only
   the chip, an occasional click target, gets hover/press feedback. */
.ll-scope .ll-kbar {
  display: flex; align-items: center; gap: 9px; width: calc(100% - 24px);
  margin: 14px 12px 2px; padding: 9px 11px;
  font-family: var(--ll-font); font-size: var(--ll-fs-sm); text-align: left;
  color: var(--ll-on-ink-mut);
  background: oklch(0.4 0.04 156 / 0.35);
  border: 1px solid var(--ll-ink-line); border-radius: var(--ll-r-sm);
  cursor: pointer; -webkit-appearance: none; appearance: none;
  transition: background-color .16s var(--ll-ease), border-color .16s var(--ll-ease),
              color .16s var(--ll-ease), transform .12s var(--ll-ease);
}
.ll-scope .ll-kbar > i { font-size: 0.8rem; color: var(--ll-on-ink-mut); }
.ll-scope .ll-kbar-label { flex: 1; min-width: 0; }
.ll-scope .ll-kbar-keys { display: inline-flex; gap: 3px; flex: none; }
.ll-scope .ll-kbar-keys kbd {
  font-family: var(--ll-font); font-size: 0.7rem; font-weight: 600; line-height: 1;
  min-width: 17px; height: 17px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ll-on-ink); background: oklch(0.46 0.04 156 / 0.6);
  border: 1px solid var(--ll-ink-line); border-radius: 5px;
}
.ll-scope .ll-kbar-keys kbd.ll-kbd-wide { font-size: 0.62rem; letter-spacing: 0.01em; }
@media (hover: hover) and (pointer: fine) {
  .ll-scope .ll-kbar:hover {
    background: oklch(0.43 0.045 156 / 0.55); border-color: var(--ll-accent-line);
    color: var(--ll-on-ink);
  }
  .ll-scope .ll-kbar:hover > i { color: var(--ll-accent); }
}
.ll-scope .ll-kbar:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ll-focus); }
.ll-scope .ll-kbar:active { transform: scale(0.985); }

.ll-scope #accordionSidebar { padding: 16px 12px; gap: 2px; }

/* A top banner (support-access / impersonation) reserves space via body
   padding-top, shifting the fixed rail down so its footer (the collapse toggle)
   drops below the viewport. Subtract that offset so the rail always fits. The var
   defaults to 0px, so a normal tenant (no banner) is unchanged at 100vh. */
.ll-scope .sidebar { height: calc(100vh - var(--ll-topbar-offset, 0px)); }

/* ===== Rail overflow: the nav list scrolls, everything else stays put =======
   The rail is `position: fixed; height: 100vh` (styles.css). With enough nav
   items — or the onboarding "Your journey" widget mounted above the list — the
   content exceeds 100vh, and with no scroll region the bottom links (Settings,
   Help, Sign out) fall off the viewport unreachable. Clamp the inner column to
   the rail height and let ONLY the nav list scroll, so the brand, ⌘K search and
   journey widget stay pinned while every link stays reachable.
   Scoped to the EXPANDED rail: in the collapsed `.toggled` mini-rail the subnav
   flyouts pop out horizontally, and an overflow container would clip them (a
   non-`visible` overflow-y forces overflow-x to compute to `auto`). */
/* nowrap: the rail's .container-fluid inherits `flex-wrap: wrap` from Bootstrap's
   `.navbar`, so clamping its height would otherwise wrap the nav list into a second
   column off to the side. Force a single column and let the list scroll instead. */
.ll-scope .sidebar:not(.toggled) > .container-fluid { flex: 1 1 auto; min-height: 0; flex-wrap: nowrap; }
.ll-scope .sidebar:not(.toggled) #accordionSidebar {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: oklch(0.56 0.035 156 / 0.5) transparent;
}
.ll-scope .sidebar:not(.toggled) #accordionSidebar::-webkit-scrollbar { width: 8px; }
.ll-scope .sidebar:not(.toggled) #accordionSidebar::-webkit-scrollbar-track { background: transparent; }
.ll-scope .sidebar:not(.toggled) #accordionSidebar::-webkit-scrollbar-thumb {
  background: oklch(0.52 0.035 156 / 0.5); border-radius: 999px;
  border: 2px solid transparent; background-clip: padding-box;
}
@media (hover: hover) and (pointer: fine) {
  .ll-scope .sidebar:not(.toggled) #accordionSidebar:hover::-webkit-scrollbar-thumb {
    background: oklch(0.6 0.04 156 / 0.62); background-clip: padding-box;
  }
}

/* ---------------------------------------------------------------------------
 * Paint-time role-nav gating (kills the admin-nav flash on affiliate pages).
 * Affiliate pages declare `data-nav="affiliate"` on the <html> tag, so this rule
 * matches at FIRST PAINT — before sidebar.js injects the partial and before the
 * async sidebar-role-filter.js runs. Admin nav items therefore never paint for an
 * affiliate, and `!important` means client-side JS cannot reveal them either.
 *
 * SECURITY NOTE: this is COSMETIC ONLY. It is NOT the access boundary — un-hiding
 * the nav grants nothing. Real enforcement is (1) every admin page's
 * requireRoleFor redirect (auth.js) and (2) `assert_role('tenant_admin',
 * 'tenant_staff')` on every AdminApi Lambda (server-side, an affiliate token 403s).
 * sidebar-role-filter.js still runs as the role-based confirmation + superadmin axis. */
html[data-nav="affiliate"] .admin-only     { display: none !important; }
html[data-nav="affiliate"] .affiliate-only { display: block !important; }

.ll-scope .sidebar .nav-item { margin: 0 !important; }
.ll-scope .sidebar .nav-link {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; margin: 1px 0; border-radius: var(--ll-r-sm);
  color: var(--ll-on-ink-mut); font-size: var(--ll-fs-md); font-weight: 500;
  transition: background-color .15s var(--ll-ease), color .15s var(--ll-ease);
}
.ll-scope .sidebar .nav-link i { width: 18px; text-align: center; font-size: 0.95rem; color: inherit; opacity: 0.9; }
.ll-scope .sidebar .nav-link span { font-size: var(--ll-fs-md); }
.ll-scope .sidebar .nav-link:hover { background: oklch(0.4 0.04 156 / 0.5); color: var(--ll-on-ink); }
.ll-scope .sidebar .nav-link.active {
  background: var(--ll-accent); color: var(--ll-accent-ink); font-weight: 600;
  box-shadow: 0 6px 16px oklch(0.6 0.14 140 / 0.28);
}
.ll-scope .sidebar .nav-link.active i { opacity: 1; }

/* ===== Nav unread badge (AI Insights) ====================================
   A quiet count pill pushed to the row's right edge; lime on the dark rail,
   ink-on-lime when the row itself is the active lime pill (contrast flips).
   Hidden at zero via [hidden]. In the collapsed icon rail the label is gone,
   so the badge shrinks to a corner dot on the icon (position: relative comes
   from the collapsed rail's [data-tip] rule). */
.ll-scope .sidebar .ll-nav-badge {
  margin-left: auto; flex: none;
  min-width: 20px; height: 20px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.7rem; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ll-accent-ink); background: var(--ll-accent);
  border-radius: var(--ll-r-pill);
}
.ll-scope .sidebar .nav-link.active .ll-nav-badge {
  color: var(--ll-accent-soft); background: var(--ll-accent-ink);
}
@media (min-width: 769px) {
  .ll-scope .sidebar.toggled .ll-nav-badge {
    position: absolute; top: 5px; right: 14px;
    width: 9px; height: 9px; min-width: 0; padding: 0;
    font-size: 0; border: 2px solid var(--ll-ink);
  }
}
.ll-scope #sidebarToggle { background: oklch(0.4 0.04 156 / 0.5); color: var(--ll-on-ink-mut); width: 34px; height: 34px; }
/* Collapse toggle: last item in the nav list, set apart from Sign out with top
   spacing + a hairline divider so it reads as a distinct control (not another link). */
.ll-scope .ll-collapse-li { display: flex; justify-content: center; margin-top: 10px;
  padding-top: 16px; border-top: 1px solid oklch(0.9 0.01 150 / 0.12); }
@media (max-width: 768px) { .ll-scope .ll-collapse-li { display: none; } }
.ll-scope #sidebarToggle { transition: background-color .15s var(--ll-ease), color .15s var(--ll-ease), transform .12s var(--ll-ease); }
@media (hover: hover) and (pointer: fine) {
  .ll-scope #sidebarToggle:hover { background: oklch(0.45 0.045 156 / 0.6); color: var(--ll-on-ink); }
}
.ll-scope #sidebarToggle:active { transform: scale(0.94); }
.ll-scope #sidebarToggle .fa-bars { transition: transform .25s var(--ll-ease); }

/* ===== Reports: collapsible parent + nested sub-reports =================== */
/* The parent toggle is a real button: shares the nav-link look, adds a caret
   that rotates as the group opens. Children live in a height-animated group. */
.ll-scope .sidebar .nav-parent-toggle {
  width: 100%; background: none; border: 0; cursor: pointer;
  font-family: inherit; text-align: left; -webkit-appearance: none; appearance: none;
}
.ll-scope .sidebar .nav-parent-caret {
  margin-left: auto; flex: none; font-size: 0.72rem; opacity: 0.7;
  transition: transform .2s var(--ll-ease);
}
.ll-scope .sidebar .nav-parent.is-open .nav-parent-toggle .nav-parent-caret { transform: rotate(90deg); }
/* A parent whose child is the current page reads as lightly active. */
.ll-scope .sidebar .nav-parent-toggle.has-active-child { color: var(--ll-on-ink); }
.ll-scope .sidebar .nav-parent-toggle.has-active-child i:first-child { color: var(--ll-accent); opacity: 1; }

/* Split parents (Affiliates, Settings): the row is a real link to the parent's
   own page plus a small caret button that only toggles the group. Same visual
   vocabulary as the Reports parent; only the hit areas differ. */
.ll-scope .sidebar .nav-parent-row { display: flex; align-items: center; gap: 2px; }
.ll-scope .sidebar .nav-parent-row .nav-parent-link { flex: 1 1 auto; min-width: 0; }
.ll-scope .sidebar .nav-split-toggle {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 30px; height: 36px; margin: 1px 0; padding: 0;
  color: var(--ll-on-ink-mut); border-radius: var(--ll-r-sm);
  transition: background-color .15s var(--ll-ease), color .15s var(--ll-ease),
              transform .12s var(--ll-ease);
}
.ll-scope .sidebar .nav-split-toggle .nav-parent-caret { margin-left: 0; }
@media (hover: hover) and (pointer: fine) {
  .ll-scope .sidebar .nav-split-toggle:hover { background: oklch(0.4 0.04 156 / 0.5); color: var(--ll-on-ink); }
}
.ll-scope .sidebar .nav-split-toggle:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ll-focus); }
.ll-scope .sidebar .nav-split-toggle:active { transform: scale(0.9); }
/* A split-parent link whose child is the current page reads as lightly active
   (mirrors the button-parent treatment above). */
.ll-scope .sidebar .nav-parent-link.has-active-child { color: var(--ll-on-ink); }
.ll-scope .sidebar .nav-parent-link.has-active-child i:first-child { color: var(--ll-accent); opacity: 1; }

/* Children: collapsed by default (grid-rows trick → animates height cleanly
   without touching layout-thrashing `height:auto`). The subnav is a single
   grid cell wrapping one inner <ul>, so the 0fr→1fr track collapses reliably. */
.ll-scope .sidebar .nav-subnav {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .22s var(--ll-ease);
}
.ll-scope .sidebar .nav-parent.is-open > .nav-subnav { grid-template-rows: 1fr; }
.ll-scope .sidebar .nav-subnav-inner {
  overflow: hidden; min-height: 0;
  list-style: none; margin: 0; padding: 0;
}
.ll-scope .sidebar .nav-subnav .nav-item { padding: 2px 0 0; }
/* Sub-links: indented, with a guide rail so the nesting reads at a glance. */
.ll-scope .sidebar .nav-sublink {
  margin-left: 14px; padding-left: 22px; position: relative;
  font-weight: 450; color: var(--ll-on-ink-mut);
}
.ll-scope .sidebar .nav-sublink::before {
  content: ""; position: absolute; left: 8px; top: 50%; width: 6px; height: 1px;
  background: var(--ll-ink-line); transform: translateY(-50%);
}
.ll-scope .sidebar .nav-sublink i { font-size: 0.82rem; }

/* Collapsed-rail flyout clone: hidden by default. It is built in JS (a clone of
   the inline sub-links) for every rail width, but only the collapsed icon-rail
   should surface it — the `.sidebar.toggled` rules below position + reveal it on
   hover/focus. Without this base hide, the clone renders inline in the expanded
   rail, duplicating the real sub-links (Clicks/Conversions shown twice). */
.ll-scope .sidebar .nav-flyout { display: none; }
.ll-scope .sidebar.toggled .nav-flyout { display: block; }

/* When the sub-nav is closed, ensure children aren't keyboard-focusable. JS
   mirrors this with hidden, but guard visually for reduced-motion too. */
@media (prefers-reduced-motion: reduce) {
  .ll-scope .sidebar .nav-subnav { transition: none; }
  .ll-scope .sidebar .nav-parent-caret { transition: none; }
}

/* ===== Page chrome ======================================================== */
.ll-page { padding: 30px 34px 64px; max-width: 1320px; }
/* Collapsing the rail is an explicit request for more room: lift the readable-width
   cap so the page fills the space the collapsed sidebar frees up. Expanded state keeps
   the 1320px cap for comfortable line length. */
body.sidebar-toggled .ll-page { max-width: none; }
.ll-pagehead { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 20px; margin-bottom: 26px; }
.ll-pagehead h1 { font-family: var(--ll-display); font-size: var(--ll-fs-title); font-weight: 650; letter-spacing: -0.025em; margin: 0; line-height: 1.02; color: var(--ll-text); }
.ll-pagehead .ll-sub { color: var(--ll-text-mute); font-size: var(--ll-fs-md); margin-top: 7px; max-width: 60ch; }
.ll-head-actions { display: flex; align-items: center; gap: 10px; }

/* ===== Buttons ============================================================ */
.ll-btn {
  font-family: inherit; font-size: var(--ll-fs-md); font-weight: 550; line-height: 1;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 15px; border-radius: var(--ll-r-sm); border: 1px solid transparent;
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background-color .16s var(--ll-ease), border-color .16s var(--ll-ease), color .16s var(--ll-ease), box-shadow .16s var(--ll-ease), transform .08s var(--ll-ease);
}
.ll-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ll-focus); }
.ll-btn:active { transform: translateY(1px); }
.ll-btn-primary { background: var(--ll-green); color: var(--ll-on-green); box-shadow: var(--ll-shadow-1); }
.ll-btn-primary:hover { background: var(--ll-green-hover); }
.ll-btn-primary:active { background: var(--ll-green-press); }
.ll-btn-primary:disabled { background: var(--ll-elevated); color: var(--ll-text-mute); cursor: not-allowed; box-shadow: none; }
.ll-btn-ghost { background: transparent; color: var(--ll-text-soft); border-color: var(--ll-border-strong); }
.ll-btn-ghost:hover { background: var(--ll-elevated); color: var(--ll-text); }
.ll-btn-subtle { background: transparent; color: var(--ll-text-soft); }
.ll-btn-subtle:hover { background: var(--ll-elevated); color: var(--ll-text); }
.ll-btn-sm { padding: 7px 11px; font-size: var(--ll-fs-sm); }

/* ===== Toolbar / search =================================================== */
.ll-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 16px; }
.ll-search { position: relative; flex: 1; max-width: 380px; }
.ll-search i { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--ll-text-mute); font-size: var(--ll-fs-sm); pointer-events: none; }
.ll-search input { width: 100%; padding: 10px 12px 10px 36px; border: 1px solid var(--ll-border); border-radius: var(--ll-r-sm); background: var(--ll-panel); font: inherit; font-size: var(--ll-fs-md); color: var(--ll-text); }
.ll-search input::placeholder { color: var(--ll-text-mute); }
.ll-search input:focus { outline: none; border-color: var(--ll-accent-line); box-shadow: 0 0 0 3px var(--ll-focus); }
.ll-count { color: var(--ll-text-mute); font-size: var(--ll-fs-sm); font-variant-numeric: tabular-nums; margin-left: auto; }
/* Inline toolbar filter (e.g. Account Manager on Affiliates): a quiet label +
   an ll-select that sits flush on the toolbar row, matching the search height.
   Revealed by JS via display:inline-flex once assignable managers exist. */
.ll-manager-filter { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.ll-filter-label { display: inline-flex; align-items: center; gap: 6px; font-size: var(--ll-fs-sm); color: var(--ll-text-mute); }
.ll-manager-filter .ll-select { width: auto; min-width: 172px; }

/* ===== Data table ========================================================= */
/* overflow-x:auto (not hidden) lets a table wider than the card scroll within
   it instead of clipping the right-most columns. overflow-y stays hidden so
   the rounded corners still clip the header/rows cleanly; the box-shadow sits
   outside the box and is unaffected. Both axes are non-visible, so neither
   computes back to `visible`. -webkit-overflow-scrolling gives momentum on
   touch. */
.ll-tablewrap { background: var(--ll-panel); border: 1px solid var(--ll-border); border-radius: var(--ll-r-lg); box-shadow: var(--ll-shadow-1); overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
.ll-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--ll-fs-md); }
.ll-table thead th {
  position: sticky; top: 0; z-index: 1; text-align: left;
  font-size: var(--ll-fs-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ll-text-mute); background: oklch(0.975 0.006 140);
  padding: 12px 18px; border-bottom: 1px solid var(--ll-border); user-select: none;
}
.ll-table thead th.ll-sortable { cursor: pointer; }
.ll-table thead th.ll-sortable:hover { color: var(--ll-text-soft); }
.ll-table thead th .ll-sort-ind { margin-left: 5px; font-size: 0.6rem; color: var(--ll-accent); }
.ll-table tbody td { padding: 14px 18px; border-bottom: 1px solid var(--ll-border); color: var(--ll-text-soft); vertical-align: middle; }
.ll-table tbody tr:last-child td { border-bottom: none; }
.ll-table tbody tr.ll-row { transition: background-color .12s var(--ll-ease); }
.ll-table tbody tr.ll-row:hover { background: var(--ll-accent-soft); cursor: pointer; }
.ll-table .ll-cell-primary { color: var(--ll-text); font-weight: 600; }
.ll-table .ll-cell-id { color: var(--ll-text-mute); font-variant-numeric: tabular-nums; font-size: var(--ll-fs-sm); font-weight: 400; }
.ll-table a.ll-link { color: var(--ll-green); text-decoration: none; font-weight: 500; }
.ll-table a.ll-link:hover { text-decoration: underline; }

.ll-badge { display: inline-flex; align-items: center; gap: 6px; font-size: var(--ll-fs-xs); font-weight: 600; padding: 3px 10px; border-radius: var(--ll-r-pill); line-height: 1.45; }
.ll-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.ll-badge-success { color: var(--ll-success); background: var(--ll-success-soft); }
.ll-badge-warn { color: var(--ll-warn); background: var(--ll-warn-soft); }
.ll-badge-danger { color: var(--ll-danger); background: var(--ll-danger-soft); }
.ll-badge-neutral { color: var(--ll-text-mute); background: var(--ll-elevated); }

.ll-skel { height: 12px; border-radius: 5px; background: linear-gradient(90deg, var(--ll-elevated) 25%, oklch(0.93 0.008 145) 50%, var(--ll-elevated) 75%); background-size: 200% 100%; animation: ll-shimmer 1.3s linear infinite; }
@keyframes ll-shimmer { to { background-position: -200% 0; } }
.ll-empty { text-align: center; padding: 64px 20px; color: var(--ll-text-mute); }
.ll-empty .ll-empty-icon { width: 52px; height: 52px; margin: 0 auto 16px; display: grid; place-items: center; border-radius: 15px; background: var(--ll-accent-soft); color: var(--ll-accent-ink); font-size: 1.25rem; }
.ll-empty h3 { font-family: var(--ll-display); font-size: 1.15rem; font-weight: 600; color: var(--ll-text); margin: 0 0 6px; }
.ll-empty p { font-size: var(--ll-fs-md); margin: 0 0 18px; max-width: 42ch; margin-inline: auto; }
/* Error variant: same layout as the neutral empty state, danger-tinted icon chip
   so a failed load never reads as "nothing here yet" (and never fabricates rows). */
.ll-empty.is-error .ll-empty-icon { background: var(--ll-danger-soft); color: var(--ll-danger); }

/* ===== Slide-over drawer ================================================== */
.ll-drawer-overlay { position: fixed; inset: 0; z-index: 1080; background: oklch(0.22 0.04 156 / 0); transition: background-color .28s var(--ll-ease); display: flex; justify-content: flex-end; }
.ll-drawer-overlay.ll-open { background: oklch(0.22 0.04 156 / 0.44); }
.ll-drawer { width: min(560px, 100vw); max-width: 100vw; height: 100%; background: var(--ll-panel); box-shadow: var(--ll-shadow-drawer); display: flex; flex-direction: column; transform: translateX(100%); transition: transform .34s var(--ll-ease); will-change: transform; }
.ll-drawer.ll-wide { width: min(720px, 100vw); }
.ll-drawer-overlay.ll-open .ll-drawer { transform: translateX(0); }
.ll-drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 22px 26px 18px; border-bottom: 1px solid var(--ll-border); }
.ll-drawer-head h2 { font-family: var(--ll-display); font-size: 1.3rem; font-weight: 650; letter-spacing: -0.02em; margin: 0; color: var(--ll-text); }
.ll-drawer-head .ll-drawer-sub { font-size: var(--ll-fs-sm); color: var(--ll-text-mute); margin-top: 4px; }
.ll-drawer-close { background: transparent; border: none; color: var(--ll-text-mute); cursor: pointer; padding: 6px; border-radius: var(--ll-r-sm); line-height: 0; font-size: 1.05rem; }
.ll-drawer-close:hover { background: var(--ll-elevated); color: var(--ll-text); }
.ll-drawer-body { flex: 1; overflow-y: auto; padding: 6px 26px 24px; }
.ll-drawer-foot { display: flex; align-items: center; justify-content: flex-end; gap: 10px; padding: 16px 26px; border-top: 1px solid var(--ll-border); background: var(--ll-panel); }
.ll-drawer-foot .ll-foot-left { margin-right: auto; }

/* ===== Collapsible sections + form ======================================= */
.ll-section { border-top: 1px solid var(--ll-border); }
.ll-section:first-child { border-top: none; }
.ll-section-head { width: 100%; display: flex; align-items: center; gap: 10px; padding: 17px 2px; background: none; border: none; cursor: pointer; font: inherit; color: var(--ll-text); }
.ll-section-head .ll-section-title { font-family: var(--ll-display); font-size: 0.95rem; font-weight: 600; }
.ll-section-head .ll-chev { margin-left: auto; color: var(--ll-text-mute); transition: transform .2s var(--ll-ease); font-size: 0.8rem; }
.ll-section.ll-collapsed .ll-chev { transform: rotate(-90deg); }
.ll-section-body { padding-bottom: 18px; display: grid; grid-template-columns: 1fr 1fr; gap: 15px 16px; }
.ll-section.ll-collapsed .ll-section-body { display: none; }
.ll-field { display: flex; flex-direction: column; gap: 6px; }
.ll-field.ll-col-2 { grid-column: 1 / -1; }
.ll-label { font-size: var(--ll-fs-sm); font-weight: 550; color: var(--ll-text-soft); }
.ll-label .ll-req { color: var(--ll-danger); margin-left: 2px; }
.ll-input, .ll-select, .ll-textarea { width: 100%; font: inherit; font-size: var(--ll-fs-md); color: var(--ll-text); padding: 10px 12px; border: 1px solid var(--ll-border); border-radius: var(--ll-r-sm); background: var(--ll-bg); transition: border-color .14s var(--ll-ease), box-shadow .14s var(--ll-ease); }
.ll-textarea { resize: vertical; min-height: 72px; }
.ll-input:focus, .ll-select:focus, .ll-textarea:focus { outline: none; border-color: var(--ll-accent-line); box-shadow: 0 0 0 3px var(--ll-focus); }
.ll-input.ll-invalid, .ll-select.ll-invalid { border-color: var(--ll-danger); box-shadow: 0 0 0 3px var(--ll-danger-soft); }
.ll-field-hint { font-size: var(--ll-fs-xs); color: var(--ll-text-mute); }
.ll-field-err { font-size: var(--ll-fs-xs); color: var(--ll-danger); }
.ll-form-banner { display: none; align-items: center; gap: 9px; padding: 11px 13px; border-radius: var(--ll-r-sm); font-size: var(--ll-fs-sm); margin: 14px 0 4px; }
.ll-form-banner.ll-show { display: flex; }
.ll-form-banner.ll-err { background: var(--ll-danger-soft); color: var(--ll-danger); }

/* ===== Toast ============================================================== */
.ll-toasts { position: fixed; bottom: 24px; right: 24px; z-index: 1100; display: flex; flex-direction: column; gap: 10px; }
.ll-toast { display: flex; align-items: center; gap: 10px; padding: 13px 16px; border-radius: var(--ll-r-md); background: var(--ll-ink); border: 1px solid var(--ll-ink-line); box-shadow: var(--ll-shadow-2); font-size: var(--ll-fs-md); color: var(--ll-on-ink); transform: translateY(8px); opacity: 0; transition: opacity .22s var(--ll-ease), transform .22s var(--ll-ease); }
.ll-toast.ll-in { transform: translateY(0); opacity: 1; }
.ll-toast .ll-toast-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.ll-toast-success .ll-toast-dot { background: var(--ll-accent); }
.ll-toast-error .ll-toast-dot { background: var(--ll-danger); }

/* ===== Legacy surfaces recolored to the new language (where .ll-scope is active) =====
   Remap the old hex variables to the new tokens so the existing modal/forms/tables
   (offer detail modal, advertiser modal, etc.) inherit the palette without per-rule edits. */
.ll-scope {
  --primary-purple: var(--ll-green);
  --primary-purple-light: oklch(0.6 0.13 152);
  --success-green: var(--ll-success);
  --warning-orange: var(--ll-warn);
  --danger-red: var(--ll-danger);
  --gray-50: var(--ll-elevated);
  --gray-100: oklch(0.95 0.008 150);
  --gray-200: var(--ll-border);
  --gray-300: var(--ll-border-strong);
  --gray-400: var(--ll-text-mute);
  --gray-500: var(--ll-text-mute);
  --gray-600: var(--ll-text-soft);
  --gray-700: var(--ll-text-soft);
  --gray-800: var(--ll-text);
  --gray-900: var(--ll-text);
  --white: var(--ll-panel);
}

/* ===== Offer detail modal — modernized to the design language ============= */
.offer-detail-modal .modal-content { border: 1px solid var(--ll-border); border-radius: var(--ll-r-lg); box-shadow: var(--ll-shadow-2); background: var(--ll-panel); overflow: hidden; }
.offer-detail-modal .modal-header { padding: 20px 26px; border-bottom: 1px solid var(--ll-border); background: var(--ll-panel); }
.offer-detail-modal .modal-title { font-family: var(--ll-display); font-weight: 650; letter-spacing: -0.02em; font-size: 1.3rem; color: var(--ll-text); }
.offer-detail-modal .modal-body { padding: 20px 26px; background: var(--ll-panel); }
.offer-detail-modal .modal-footer { border-top: 1px solid var(--ll-border); padding: 14px 26px; background: var(--ll-panel); }
.offer-detail-modal h5, .offer-detail-modal h6 { font-family: var(--ll-display); letter-spacing: -0.01em; }

/* Tab bar: clean underline with an accent indicator */
.offer-detail-modal .nav-tabs { border-bottom: 1px solid var(--ll-border); margin-bottom: 22px; gap: 2px; }
.offer-detail-modal .nav-tabs .nav-link { font-family: var(--ll-font); font-size: var(--ll-fs-md); font-weight: 550; color: var(--ll-text-mute); padding: 11px 14px; border: none; border-bottom: 2px solid transparent; border-radius: 0; transition: color .15s var(--ll-ease), border-color .15s var(--ll-ease); }
.offer-detail-modal .nav-tabs .nav-link:hover { color: var(--ll-text); background: transparent; }
.offer-detail-modal .nav-tabs .nav-link.active { color: var(--ll-green); border-bottom-color: var(--ll-accent); font-weight: 600; background: transparent; }
.offer-detail-modal .om-tab-count { display: inline-block; margin-left: 6px; min-width: 18px; padding: 1px 6px; font-size: 0.7rem; font-weight: 600; border-radius: var(--ll-r-pill); background: var(--ll-accent-soft); color: var(--ll-accent-ink); }

/* Forms inside the modal */
.offer-detail-modal .form-control, .offer-detail-modal .form-select, .offer-detail-modal .om-input { border: 1px solid var(--ll-border); border-radius: var(--ll-r-sm); font-size: var(--ll-fs-md); color: var(--ll-text); background: var(--ll-bg); }
.offer-detail-modal .form-control:focus, .offer-detail-modal .form-select:focus, .offer-detail-modal .om-input:focus { border-color: var(--ll-accent-line); box-shadow: 0 0 0 3px var(--ll-focus); }
.offer-detail-modal .form-label, .offer-detail-modal .om-label { font-size: var(--ll-fs-sm); font-weight: 550; color: var(--ll-text-soft); }

/* Buttons inside the modal — new palette + press feedback (scale 0.98 on :active) */
.offer-detail-modal .btn { border-radius: var(--ll-r-sm); font-weight: 550; transition: background-color .16s var(--ll-ease), border-color .16s var(--ll-ease), color .16s var(--ll-ease), transform .09s var(--ll-ease); }
.offer-detail-modal .btn:active { transform: scale(0.98); }
.offer-detail-modal .btn-primary { background: var(--ll-green); border-color: var(--ll-green); color: var(--ll-on-green); }
.offer-detail-modal .btn-primary:hover { background: var(--ll-green-hover); border-color: var(--ll-green-hover); }
.offer-detail-modal .btn-secondary { background: transparent; border: 1px solid var(--ll-border-strong); color: var(--ll-text-soft); }
.offer-detail-modal .btn-secondary:hover { background: var(--ll-elevated); color: var(--ll-text); }
.offer-detail-modal .btn-outline-primary { color: var(--ll-green); border-color: var(--ll-border-strong); }
.offer-detail-modal .btn-outline-primary:hover { background: var(--ll-accent-soft); color: var(--ll-accent-ink); border-color: var(--ll-accent-line); }

/* om-table eyebrow header to match .ll-table */
.offer-detail-modal .om-table thead th { font-size: var(--ll-fs-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ll-text-mute); }

/* Offer detail header status pill */
.offer-detail-modal .om-title-status { margin-left: 11px; font-family: var(--ll-font); font-size: 0.7rem; font-weight: 600; letter-spacing: 0.02em; padding: 3px 10px; border-radius: var(--ll-r-pill); vertical-align: middle; }
.om-st-success { background: var(--ll-accent); color: var(--ll-accent-ink); }
.om-st-warn { background: var(--ll-warn-soft); color: var(--ll-warn); }
.om-st-danger { background: var(--ll-danger-soft); color: var(--ll-danger); }
.om-st-neutral { background: var(--ll-elevated); color: var(--ll-text-mute); }

/* Overview tab: two-pane summary + details */
.offer-detail-modal .om-overview { display: grid; grid-template-columns: 38% 62%; gap: 0; }
.offer-detail-modal .om-ov-left { padding-right: 22px; border-right: 1px solid var(--ll-border); }
.offer-detail-modal .om-ov-right { padding-left: 24px; }
.offer-detail-modal .om-ov-eyebrow { font-size: var(--ll-fs-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ll-text-mute); margin-bottom: 12px; }
.offer-detail-modal .om-facts { margin: 0; }
.offer-detail-modal .om-facts > div { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--ll-border); }
.offer-detail-modal .om-facts > div:last-child { border-bottom: none; }
.offer-detail-modal .om-facts dt { font-size: var(--ll-fs-sm); color: var(--ll-text-mute); margin: 0; }
.offer-detail-modal .om-facts dd { font-size: var(--ll-fs-md); color: var(--ll-text); margin: 0; text-align: right; }
.offer-detail-modal .om-facts dd.om-fact-strong { color: var(--ll-green); font-weight: 600; }
/* Entity jump-link inside a fact cell (e.g. the Advertiser name → advertiser card).
   Inherits the fact value's type; the affordance is the underline-on-hover + a small
   external-arrow that brightens. Mirrors the campaign card's cc-link vocabulary. */
.offer-detail-modal .om-entity-link { appearance: none; background: none; border: none; padding: 0; font: inherit; font-weight: inherit; color: inherit; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
.offer-detail-modal .om-entity-link i { font-size: 0.7em; color: var(--ll-text-mute); transition: color .14s var(--ll-ease), transform .14s var(--ll-ease); }
.offer-detail-modal .om-entity-link:hover { text-decoration: underline; text-underline-offset: 3px; }
.offer-detail-modal .om-entity-link:hover i { color: var(--ll-green); transform: translate(1px, -1px); }
.offer-detail-modal .om-entity-link:focus-visible { outline: none; border-radius: var(--ll-r-sm); box-shadow: 0 0 0 3px var(--ll-focus); }
.offer-detail-modal .om-mono { font-variant-numeric: tabular-nums; color: var(--ll-text-mute); }
.offer-detail-modal .om-ov-actions { display: flex; gap: 8px; margin-top: 16px; }
.offer-detail-modal .om-ov-actions .ll-btn { flex: 1; justify-content: center; }
/* Last-7-days performance tile (Home summary). Loading + empty states share the calm
   dashed-frame look of the old placeholder; the populated tile is a quiet metric row
   over a daily-clicks bar sparkline (accent = days with traffic). */
.offer-detail-modal .om-perf { min-height: 96px; }
.offer-detail-modal .om-perf-loading,
.offer-detail-modal .om-perf-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; height: 96px; border: 1px dashed var(--ll-border-strong); border-radius: var(--ll-r-md); color: var(--ll-text-mute); font-size: var(--ll-fs-sm); background: var(--ll-bg); text-align: center; padding: 0 12px; }
.offer-detail-modal .om-perf-empty i,
.offer-detail-modal .om-perf-loading i { font-size: 1.1rem; color: var(--ll-accent); opacity: 0.8; }
.offer-detail-modal .om-perf-metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 12px; }
.offer-detail-modal .om-perf-metric { display: flex; flex-direction: column; gap: 2px; }
.offer-detail-modal .om-perf-n { font-family: var(--ll-display); font-size: 1.15rem; font-weight: 650; line-height: 1.05; color: var(--ll-text); font-variant-numeric: tabular-nums; }
.offer-detail-modal .om-perf-l { font-size: var(--ll-fs-xs); letter-spacing: 0.04em; text-transform: uppercase; color: var(--ll-text-mute); }
.offer-detail-modal .om-perf-spark { display: flex; align-items: flex-end; gap: 4px; height: 44px; padding: 6px 2px 0; border-top: 1px solid var(--ll-border); }
.offer-detail-modal .om-perf-bar { flex: 1; min-height: 2px; border-radius: 2px 2px 0 0; background: var(--ll-border-strong); }
.offer-detail-modal .om-perf-bar.is-on { background: var(--ll-accent); }
.offer-detail-modal .om-readfield { margin-bottom: 16px; }
.offer-detail-modal .om-readfield label { display: block; font-size: var(--ll-fs-sm); font-weight: 550; color: var(--ll-text-soft); margin-bottom: 5px; }
.offer-detail-modal .om-readval { font-size: var(--ll-fs-md); color: var(--ll-text); padding: 9px 11px; background: var(--ll-bg); border: 1px solid var(--ll-border); border-radius: var(--ll-r-sm); word-break: break-all; }
.offer-detail-modal .om-readval-url { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--ll-fs-sm); color: var(--ll-text-soft); }
.offer-detail-modal .om-ov-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 4px 0 16px; }
.offer-detail-modal .om-stat { text-align: left; background: var(--ll-bg); border: 1px solid var(--ll-border); border-radius: var(--ll-r-md); padding: 13px 15px; cursor: pointer; transition: border-color .14s var(--ll-ease), background-color .14s var(--ll-ease); }
.offer-detail-modal .om-stat:hover { border-color: var(--ll-accent-line); background: var(--ll-accent-soft); }
.offer-detail-modal .om-stat-n { display: block; font-family: var(--ll-display); font-size: 1.5rem; font-weight: 650; color: var(--ll-text); line-height: 1.1; }
.offer-detail-modal .om-stat-l { display: flex; align-items: center; gap: 5px; font-size: var(--ll-fs-sm); color: var(--ll-text-mute); margin-top: 3px; }
.offer-detail-modal .om-stat-l i { font-size: 0.7em; }
.offer-detail-modal .om-readonly-note { display: flex; align-items: center; gap: 8px; font-size: var(--ll-fs-sm); color: var(--ll-text-mute); padding: 10px 12px; background: var(--ll-elevated); border-radius: var(--ll-r-sm); }
.offer-detail-modal .om-readonly-note i { color: var(--ll-text-soft); }
@media (max-width: 760px) { .offer-detail-modal .om-overview { grid-template-columns: 1fr; } .offer-detail-modal .om-ov-left { border-right: none; border-bottom: 1px solid var(--ll-border); padding-right: 0; padding-bottom: 18px; margin-bottom: 18px; } .offer-detail-modal .om-ov-right { padding-left: 0; } }

@media (max-width: 640px) {
  .ll-page { padding: 20px 16px 48px; }
  .ll-section-body { grid-template-columns: 1fr; }
}
/* ===== Command palette (Cmd-K) ========================================== */
.ll-cmd-overlay { position: fixed; inset: 0; z-index: 1200; display: flex; justify-content: center; align-items: flex-start; padding-top: 14vh; background: oklch(0.22 0.04 156 / 0); transition: background-color .18s var(--ll-ease); pointer-events: none; }
.ll-cmd-overlay.ll-open { background: oklch(0.22 0.04 156 / 0.42); pointer-events: auto; }
.ll-cmd { width: min(620px, 92vw); background: var(--ll-panel); border: 1px solid var(--ll-border); border-radius: var(--ll-r-lg); box-shadow: var(--ll-shadow-2); overflow: hidden; transform: translateY(-8px) scale(0.98); opacity: 0; transition: transform .2s var(--ll-ease), opacity .18s var(--ll-ease); }
.ll-cmd-overlay.ll-open .ll-cmd { transform: translateY(0) scale(1); opacity: 1; }
.ll-cmd-head { display: flex; align-items: center; gap: 11px; padding: 15px 18px; border-bottom: 1px solid var(--ll-border); }
.ll-cmd-head > i { color: var(--ll-text-mute); font-size: var(--ll-fs-md); }
.ll-cmd-input { flex: 1; border: none; outline: none; background: transparent; font: inherit; font-size: 1rem; color: var(--ll-text); }
.ll-cmd-input::placeholder { color: var(--ll-text-mute); }
.ll-cmd-esc { font-family: var(--ll-font); font-size: 0.7rem; color: var(--ll-text-mute); background: var(--ll-elevated); border: 1px solid var(--ll-border); border-radius: 5px; padding: 2px 6px; }
.ll-cmd-list { max-height: 52vh; overflow-y: auto; padding: 8px; }
.ll-cmd-group { font-size: var(--ll-fs-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ll-text-mute); padding: 10px 10px 5px; }
.ll-cmd-item { display: flex; align-items: center; gap: 12px; padding: 10px 11px; border-radius: var(--ll-r-sm); cursor: pointer; color: var(--ll-text-soft); font-size: var(--ll-fs-md); }
.ll-cmd-item > i:first-child { width: 18px; text-align: center; color: var(--ll-text-mute); font-size: 0.95rem; }
.ll-cmd-item > span { flex: 1; min-width: 0; }
.ll-cmd-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
.ll-cmd-sub { color: var(--ll-text-mute); margin-left: 8px; font-size: var(--ll-fs-sm); font-weight: 400; }
.ll-cmd-item.ll-cmd-on .ll-cmd-sub { color: var(--ll-accent-ink); opacity: 0.7; }
.ll-cmd-item .ll-cmd-enter { opacity: 0; font-size: 0.75rem; color: var(--ll-accent-ink); }
.ll-cmd-item.ll-cmd-on { background: var(--ll-accent); color: var(--ll-accent-ink); }
.ll-cmd-item.ll-cmd-on > i:first-child { color: var(--ll-accent-ink); }
.ll-cmd-item.ll-cmd-on .ll-cmd-enter { opacity: 0.8; }
.ll-cmd-empty { padding: 22px; text-align: center; color: var(--ll-text-mute); font-size: var(--ll-fs-md); }

/* ===== Responsive app shell (single source of truth) =====================
   The brand rail is fixed and on-canvas on wide screens. Below 768px it
   becomes a left drawer revealed by an always-reachable top bar, so the nav
   is never stranded off-screen. This section OWNS the shell's responsive
   behavior — it supersedes the legacy styles.css `.sidebar` media rules
   (which slid the rail off-canvas with no way back). */

/* Top bar: injected by sidebar.js, only shown on narrow screens. It keeps the
   wordmark + a hamburger permanently on-screen so the nav is always reachable. */
.ll-topbar {
  display: none;
  position: sticky; top: 0; z-index: 1100;
  align-items: center; gap: 12px;
  height: 56px; padding: 0 14px;
  background: var(--ll-ink); color: var(--ll-on-ink);
  border-bottom: 1px solid var(--ll-ink-line);
}
.ll-topbar .ll-topbar-burger {
  flex: none; width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--ll-ink-line); border-radius: var(--ll-r-sm);
  background: oklch(0.4 0.04 156 / 0.5); color: var(--ll-on-ink);
  font-size: 1rem; cursor: pointer; -webkit-appearance: none; appearance: none;
  transition: background-color .15s var(--ll-ease), transform .12s var(--ll-ease);
}
@media (hover: hover) and (pointer: fine) {
  .ll-topbar .ll-topbar-burger:hover { background: oklch(0.45 0.045 156 / 0.6); }
}
.ll-topbar .ll-topbar-burger:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ll-focus); }
.ll-topbar .ll-topbar-burger:active { transform: scale(0.95); }
.ll-topbar .ll-topbar-mark { display: inline-flex; align-items: center; }
.ll-topbar .ll-wordmark { font-size: 1.05rem; }

/* Scrim behind the open drawer (injected by sidebar.js). */
.ll-scrim {
  position: fixed; inset: 0; z-index: 1040;
  background: oklch(0.22 0.04 156 / 0.42);
  opacity: 0; pointer-events: none;
  transition: opacity .22s var(--ll-ease);
}

@media (max-width: 768px) {
  .ll-scope .ll-topbar { display: flex; }

  /* Off-canvas drawer; revealed by body.sidebar-open. GPU transform only. */
  .ll-scope .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0;
    width: min(280px, 84vw); height: 100vh; z-index: 1050;
    transform: translateX(-100%);
    transition: transform .3s var(--ll-ease);
    will-change: transform;
    box-shadow: var(--ll-shadow-drawer);
    overflow-y: auto; -webkit-overflow-scrolling: touch;
  }
  .ll-scope.sidebar-open .sidebar { transform: translateX(0); }
  .ll-scope.sidebar-open .ll-scrim { opacity: 1; pointer-events: auto; }

  /* Content takes the full width; the top bar provides the brand + nav entry. */
  .ll-scope .main-content { margin-left: 0 !important; }
  /* The in-rail bottom toggle (desktop collapse) is meaningless on mobile. */
  .ll-scope .sidebar #sidebarToggle { display: none; }
  .ll-page { padding: 22px 18px 56px; }
}

/* ===== Collapsed icon-rail (desktop) =====================================
   `body.sidebar-toggled` + `.sidebar.toggled` shrink the rail to an 80px
   icon-only column. This block OWNS that state (supersedes the legacy
   styles.css media rules, which only hid link text and left the wordmark,
   the ⌘K chip and the section label overflowing). Goals: icons centered,
   brand reduced to its mark, the search chip reduced to a button, the
   "Reports" group handled via a divider + hover flyout, and every icon item
   gets a hover/focus tooltip so the nav stays usable without labels. */
@media (min-width: 769px) {
  .ll-scope .sidebar.toggled { transition: width .25s var(--ll-ease); }

  /* Brand: keep the mark, drop the wordmark; center it in the rail. */
  .ll-scope .sidebar.toggled .sidebar-brand,
  .ll-scope .sidebar.toggled .navbar-brand.sidebar-brand {
    justify-content: center; gap: 0; padding: 22px 0 18px;
  }
  .ll-scope .sidebar.toggled .ll-wordmark { display: none; }

  /* ⌘K chip → a centered icon button (label + keycaps hidden). */
  .ll-scope .sidebar.toggled .ll-kbar {
    width: 44px; margin: 14px auto 2px; padding: 0; height: 40px;
    justify-content: center; gap: 0;
  }
  .ll-scope .sidebar.toggled .ll-kbar .ll-kbar-label,
  .ll-scope .sidebar.toggled .ll-kbar .ll-kbar-keys { display: none; }
  .ll-scope .sidebar.toggled .ll-kbar > i { font-size: 0.95rem; }

  /* Onboarding "Your journey" card: the full 250px checklist can't live in the
     80px icon rail (it overruns into the content). Hide it while collapsed — it
     returns when the rail is expanded, matching how the wordmark and nav labels
     drop out of the mini-rail. */
  .ll-scope .sidebar.toggled .ll-onb-widget { display: none; }

  /* Nav list: icons centered, labels hidden, comfortable square hit areas. */
  .ll-scope .sidebar.toggled #accordionSidebar { padding: 16px 14px; }
  .ll-scope .sidebar.toggled .nav-link {
    justify-content: center; gap: 0; padding: 11px 0;
  }
  .ll-scope .sidebar.toggled .nav-link > span { display: none; }
  .ll-scope .sidebar.toggled .nav-link i { width: 24px; font-size: 1.05rem; }

  /* Nav groups: hide the caret (and the whole split-toggle button), neutralize
     the inline children, and lean on the flyout below. The parent icon stays
     as the entry point (button parents toggle the flyout; split parents
     navigate, with the flyout on hover/focus). */
  .ll-scope .sidebar.toggled .nav-parent-caret { display: none; }
  .ll-scope .sidebar.toggled .nav-split-toggle { display: none; }
  .ll-scope .sidebar.toggled .nav-subnav { display: none; }

  /* Divider in place of the bottom toggle's spacing; keeps groups legible. */
  .ll-scope .sidebar.toggled #sidebarToggle { transform: none; }
  .ll-scope .sidebar.toggled #sidebarToggle .fa-bars { transform: rotate(180deg); }

  /* ---- Tooltips for icon-only items -----------------------------------
     A flyout label to the right of each icon, shown on hover/focus. CSS-only
     so it can't get stranded; pointer-events off so it never blocks clicks. */
  .ll-scope .sidebar.toggled [data-tip] { position: relative; }
  .ll-scope .sidebar.toggled [data-tip]::after {
    content: attr(data-tip);
    position: absolute; left: calc(100% + 10px); top: 50%;
    transform: translateY(-50%) translateX(-4px) scale(0.97);
    transform-origin: left center;
    white-space: nowrap; z-index: 1200; pointer-events: none;
    font-family: var(--ll-font); font-size: var(--ll-fs-sm); font-weight: 500; line-height: 1;
    color: var(--ll-on-ink);
    background: oklch(0.22 0.04 156); border: 1px solid var(--ll-ink-line);
    padding: 7px 10px; border-radius: var(--ll-r-sm);
    box-shadow: var(--ll-shadow-2);
    opacity: 0; visibility: hidden;
    transition: opacity .14s var(--ll-ease), transform .14s var(--ll-ease), visibility .14s;
  }
  /* Small connector arrow on the tooltip. */
  .ll-scope .sidebar.toggled [data-tip]::before {
    content: ""; position: absolute; left: calc(100% + 5px); top: 50%;
    transform: translateY(-50%) translateX(-4px); z-index: 1201; pointer-events: none;
    border: 5px solid transparent; border-right-color: oklch(0.22 0.04 156);
    opacity: 0; visibility: hidden;
    transition: opacity .14s var(--ll-ease), transform .14s var(--ll-ease), visibility .14s;
  }
  @media (hover: hover) and (pointer: fine) {
    .ll-scope .sidebar.toggled [data-tip]:hover::after,
    .ll-scope .sidebar.toggled [data-tip]:hover::before {
      opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0) scale(1);
    }
  }
  .ll-scope .sidebar.toggled [data-tip]:focus-visible::after,
  .ll-scope .sidebar.toggled [data-tip]:focus-visible::before {
    opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0) scale(1);
  }
  /* Nav-group parents use the richer flyout (below), not the bare tooltip —
     covers the Reports button parent AND the split-parent links, plus the
     cloned links inside the flyout itself. */
  .ll-scope .sidebar.toggled .nav-parent [data-tip]:hover::after,
  .ll-scope .sidebar.toggled .nav-parent [data-tip]:hover::before,
  .ll-scope .sidebar.toggled .nav-parent [data-tip]:focus-visible::after,
  .ll-scope .sidebar.toggled .nav-parent [data-tip]:focus-visible::before {
    opacity: 0; visibility: hidden;
  }

  /* ---- Reports flyout (collapsed state) -------------------------------
     Hovering/focusing the Reports parent reveals a small panel to the right
     listing the two sub-reports. Origin-aware (scales from the left edge,
     i.e. the trigger), per the popover rule. JS adds .is-flyout-open on
     keyboard activation so it works without a hover. */
  .ll-scope .sidebar.toggled .nav-parent { position: relative; }
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout {
    position: absolute; left: calc(100% + 10px); top: 50%;
    transform: translateY(-50%) translateX(-6px) scale(0.97);
    transform-origin: left center;
    min-width: 184px; z-index: 1200;
    background: oklch(0.24 0.042 156); border: 1px solid var(--ll-ink-line);
    border-radius: var(--ll-r-md); box-shadow: var(--ll-shadow-2);
    padding: 7px; margin: 0; list-style: none;
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity .16s var(--ll-ease), transform .16s var(--ll-ease), visibility .16s;
  }
  /* A header line so the flyout reads as its group (label set by sidebar.js). */
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout::before {
    content: attr(data-group); display: block;
    font-size: var(--ll-fs-xs); font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--ll-on-ink-mut); opacity: 0.75; padding: 4px 10px 6px;
  }
  /* Hover bridge so the cursor can cross the 10px gap without dropping it. */
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout::after {
    content: ""; position: absolute; right: 100%; top: 0; bottom: 0; width: 12px;
  }
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout .nav-link {
    justify-content: flex-start; gap: 11px; padding: 9px 11px;
    margin: 1px 0; border-radius: var(--ll-r-sm);
  }
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout .nav-link > span { display: inline; font-size: var(--ll-fs-md); }
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout .nav-link::before { content: none; }
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout .nav-link i { width: 18px; font-size: 0.9rem; }
  @media (hover: hover) and (pointer: fine) {
    .ll-scope .sidebar.toggled .nav-parent:hover .nav-flyout {
      opacity: 1; visibility: visible; pointer-events: auto;
      transform: translateY(-50%) translateX(0) scale(1);
    }
  }
  /* Keyboard / click-driven open (JS toggles .is-flyout-open) + focus-within. */
  .ll-scope .sidebar.toggled .nav-parent.is-flyout-open .nav-flyout,
  .ll-scope .sidebar.toggled .nav-parent:focus-within .nav-flyout {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: translateY(-50%) translateX(0) scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ll-drawer, .ll-drawer-overlay, .ll-toast, .ll-skel, .ll-btn, .ll-cmd, .ll-cmd-overlay { transition: none; animation: none; }
  .ll-scope .sidebar, .ll-scrim, .ll-topbar .ll-topbar-burger { transition: none; }
  .ll-scope .sidebar.toggled [data-tip]::after, .ll-scope .sidebar.toggled [data-tip]::before,
  .ll-scope .sidebar.toggled .nav-parent .nav-flyout { transition: opacity .14s var(--ll-ease), visibility .14s; transform: translateY(-50%); }
}

/* ============================================================================
   Report-table vocabulary (popovers, saved-view chips, saveview trigger).
   These classes are ALSO injected at runtime by report-table.js (scoped under
   .ll-rt there). The affiliate performance grid reuses the SAME class names for
   visual parity, but that page doesn't load report-table.js — so the styles are
   declared here too (additive; report-table.js's own scoped copy still wins on
   its pages). Keep the two definitions in sync.
   ============================================================================ */

/* Popover: origin-aware (scales from the trigger). */
.ll-rt-colwrap { position: relative; display: inline-flex; }
.ll-rt-pop { position: absolute; top: calc(100% + 6px); right: 0; z-index: 40; width: 248px;
  max-height: min(60vh, 420px); overflow: auto; background: var(--ll-panel);
  border: 1px solid var(--ll-border); border-radius: var(--ll-r-md); box-shadow: var(--ll-shadow-2);
  padding: 8px; transform-origin: top right; transform: scale(.96); opacity: 0;
  pointer-events: none; transition: transform 160ms var(--ll-ease), opacity 160ms var(--ll-ease); }
.ll-rt-pop.ll-rt-pop-open { transform: scale(1); opacity: 1; pointer-events: auto; }
.ll-rt-pop-left { right: auto; left: 0; transform-origin: top left; }
.ll-rt-pop-head { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 8px 8px; font-size: var(--ll-fs-xs); font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ll-text-mute); }
.ll-rt-pop-reset { font: inherit; font-size: var(--ll-fs-xs); text-transform: none; letter-spacing: 0;
  background: none; border: 0; color: var(--ll-green); cursor: pointer; padding: 2px 4px; border-radius: var(--ll-r-sm); }
.ll-rt-pop-reset:hover { text-decoration: underline; }
.ll-rt-opt { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: var(--ll-r-sm);
  font-size: var(--ll-fs-sm); color: var(--ll-text); cursor: pointer; user-select: none; }
.ll-rt-opt:hover { background: var(--ll-accent-soft); }
.ll-rt-opt input { width: 15px; height: 15px; accent-color: var(--ll-green); cursor: pointer; }
.ll-rt-opt.ll-rt-opt-locked { cursor: default; color: var(--ll-text-mute); }
.ll-rt-opt.ll-rt-opt-locked:hover { background: transparent; }

/* Save-view popover: a small named-input form sharing the popover surface. */
.ll-rt-pop.ll-rt-pop-form { width: 264px; padding: 12px; }
.ll-rt-pop-form .ll-rt-pop-head { padding: 0 2px 10px; }
.ll-rt-saveform { display: flex; flex-direction: column; gap: 10px; }
.ll-rt-saveform .ll-input { width: 100%; }
.ll-rt-saveform-row { display: flex; gap: 8px; justify-content: flex-end; }
.ll-rt-saveform-hint { font-size: var(--ll-fs-xs); color: var(--ll-text-mute); line-height: 1.4; }

/* Saved-views bar: a quiet strip; active view reads as a lime pill. */
.ll-rt-views { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.ll-rt-views-lbl { font-size: var(--ll-fs-xs); font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ll-text-mute); margin-right: 2px; }
.ll-rt-chip { display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 6px 0 12px;
  border: 1px solid var(--ll-border); border-radius: var(--ll-r-pill); background: var(--ll-panel);
  color: var(--ll-text-soft); font-size: var(--ll-fs-sm); font-weight: 500; cursor: pointer;
  transition: background-color 150ms var(--ll-ease), border-color 150ms var(--ll-ease), color 150ms var(--ll-ease); }
.ll-rt-chip:hover { background: var(--ll-accent-soft); border-color: var(--ll-accent-line); color: var(--ll-text); }
.ll-rt-chip.ll-rt-chip-active { background: var(--ll-accent); border-color: var(--ll-accent); color: var(--ll-accent-ink); font-weight: 600; }
.ll-rt-chip.ll-rt-chip-active:hover { background: var(--ll-accent); }
.ll-rt-chip-x { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px;
  border-radius: var(--ll-r-pill); border: 0; background: transparent; color: inherit; opacity: .6; cursor: pointer;
  font-size: .7rem; padding: 0; transition: opacity 120ms var(--ll-ease), background-color 120ms var(--ll-ease); }
.ll-rt-chip-x:hover { opacity: 1; background: oklch(0.4 0.04 156 / 0.14); }
.ll-rt-saveview { display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 12px;
  border: 1px dashed var(--ll-border-strong); border-radius: var(--ll-r-pill); background: transparent;
  color: var(--ll-text-mute); font-size: var(--ll-fs-sm); font-weight: 550; cursor: pointer;
  transition: background-color 150ms var(--ll-ease), border-color 150ms var(--ll-ease), color 150ms var(--ll-ease); }
.ll-rt-saveview:hover { border-color: var(--ll-green); color: var(--ll-green); background: var(--ll-success-soft); }
.ll-rt-saveview:active { transform: scale(.98); }

/* ---- Affiliate performance grid: numeric metric columns ---- */
/* Right-aligned tabular numerics; sortable headers with a hover/active caret. */
.ll-aff-grid th.ll-aff-num, .ll-aff-grid td.ll-aff-num {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ll-aff-grid td.ll-aff-num { color: var(--ll-text); }
/* Zeros render muted so active affiliates pop. */
.ll-aff-grid td.ll-aff-zero { color: var(--ll-text-mute); }
/* Revenue + profit are the hero metrics: a touch heavier. */
.ll-aff-grid td.ll-aff-hero { font-weight: 600; }
.ll-aff-grid td.ll-aff-hero.ll-aff-zero { font-weight: 500; }
/* Negative profit reads red (still tabular). */
.ll-aff-grid td.ll-aff-neg { color: var(--ll-danger); }

.ll-aff-grid th.ll-aff-sortable { cursor: pointer; user-select: none; transition: color 140ms var(--ll-ease); }
.ll-aff-grid th.ll-aff-sortable:hover { color: var(--ll-text); }
.ll-aff-th-in { display: inline-flex; align-items: center; gap: 6px; }
.ll-aff-grid th.ll-aff-num .ll-aff-th-in { flex-direction: row-reverse; }
.ll-aff-caret { display: inline-flex; width: 11px; font-size: .62rem; line-height: 1; color: var(--ll-text-mute);
  opacity: 0; transition: opacity 140ms var(--ll-ease), color 140ms var(--ll-ease); }
.ll-aff-grid th.ll-aff-sortable:hover .ll-aff-caret { opacity: .5; }
.ll-aff-grid th.ll-aff-sorted .ll-aff-caret { opacity: 1; color: var(--ll-green); }
.ll-aff-grid th.ll-aff-sorted { color: var(--ll-text); }

/* Subtle loading state while performance metrics fetch (profile list stays put). */
.ll-aff-grid.ll-aff-metrics-loading td.ll-aff-num { opacity: .45; transition: opacity 160ms var(--ll-ease); }

@media (prefers-reduced-motion: reduce) {
  .ll-rt-pop, .ll-rt-chip, .ll-rt-saveview, .ll-aff-caret,
  .ll-aff-grid th.ll-aff-sortable, .ll-aff-grid.ll-aff-metrics-loading td.ll-aff-num { transition: none; }
  .ll-rt-saveview:active { transform: none; }
}
