/* ──────────────────────────────────────────────────────────────────────────
   ui.css — shared component layer for the neuralduct suite
   ----------------------------------------------------------------------------
   Styles for the cross-app component library in js/core/ui/*. Loaded AFTER
   tokens.css (which defines the --doc-* / --st-* colour families it reads) and
   alongside each app's own stylesheet. Purely additive: every rule is scoped
   under a `.ui-` class so it cannot collide with existing per-app CSS.

   Build order mirrors js/core/ui/. First component: StatusBadge.
   ────────────────────────────────────────────────────────────────────────── */

/* ── StatusBadge ─────────────────────────────────────────────────────────────
   One pill for every lifecycle state across Quoting, Invoicing and Scheduling.
   Colour is driven entirely by a single token per status, resolved from the
   `--_c` custom property set by [data-status]. The tinted background is derived
   from that same token via color-mix, so there is ONE source of truth per
   status (the token) instead of the old fg+bg hardcoded hex pair. color-mix in
   srgb is supported by every browser this app targets. */
.ui-badge {
  --_c: var(--doc-draft);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1, 4px);
  padding: 3px var(--sp-2_5, 10px);   /* matches the legacy .badge metrics */
  border-radius: 999px;
  font-size: var(--text-sm, 12px);
  font-weight: var(--weight-semibold, 600);
  line-height: 1.5;
  white-space: nowrap;
  color: var(--_c);
  background: color-mix(in srgb, var(--_c) 15%, transparent);
}
/* Optional leading dot (e.g. list rows) — inherits the status colour. */
.ui-badge__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--_c);
  flex: 0 0 auto;
}

/* Quote + invoice lifecycle → --doc-* family */
.ui-badge[data-status="draft"]          { --_c: var(--doc-draft); }
.ui-badge[data-status="sent"]           { --_c: var(--doc-sent); }
.ui-badge[data-status="viewed"]         { --_c: var(--doc-viewed); }
.ui-badge[data-status="viewing"]        { --_c: var(--doc-viewing); }
.ui-badge[data-status="accepted"]       { --_c: var(--doc-accepted); }
.ui-badge[data-status="open"]           { --_c: var(--doc-open); }
.ui-badge[data-status="partially_paid"] { --_c: var(--doc-partial); }
.ui-badge[data-status="paid"]           { --_c: var(--doc-paid); }
.ui-badge[data-status="overdue"]        { --_c: var(--doc-overdue); }
.ui-badge[data-status="declined"]       { --_c: var(--doc-declined); }
.ui-badge[data-status="expired"]        { --_c: var(--doc-expired); }
.ui-badge[data-status="void"]           { --_c: var(--doc-void); }

/* Email delivery (feature_email_delivery) — reuses the doc palette: green =
   reached the mailbox, red = bounced, amber = spam-flagged / delayed. */
.ui-badge[data-status="delivered"]        { --_c: var(--doc-paid); }
.ui-badge[data-status="bounced"]          { --_c: var(--doc-overdue); }
.ui-badge[data-status="complained"]       { --_c: var(--doc-expired); }
.ui-badge[data-status="delivery_delayed"] { --_c: var(--doc-expired); }

/* Send channel (db/add-send-channel.sql): "sent_via" is a quiet icon-only chip —
   the lifecycle badge beside it already owns the words, so this one just says
   BY WHAT (mail / message / by hand) and leaves the detail to its tooltip. Its
   negative twin is loud on purpose: a finalized document nothing has gone out
   for is a job half-done, and on a quote it's the only honest signal (finalize
   lands the row in status 'sent' regardless). */
.ui-badge[data-status="sent_via"] { --_c: var(--doc-viewed); padding-inline: var(--sp-2, 8px); }
.ui-badge[data-status="sent_via"] i { font-size: 14px; line-height: 1; }
.ui-badge[data-status="unsent"]   { --_c: var(--doc-expired); }

/* Dispatch job lifecycle → --st-* family (same component, one grammar) */
.ui-badge[data-status="scheduled"]      { --_c: var(--st-scheduled); }
.ui-badge[data-status="en_route"]       { --_c: var(--st-en_route); }
.ui-badge[data-status="in_progress"]    { --_c: var(--st-in_progress); }
.ui-badge[data-status="complete"]       { --_c: var(--st-complete); }
.ui-badge[data-status="no_show"]        { --_c: var(--st-no_show); }
.ui-badge[data-status="cancelled"]      { --_c: var(--st-cancelled); }
.ui-badge[data-status="invoiced"]       { --_c: var(--st-invoiced); }

/* ── AppSwitcher ─────────────────────────────────────────────────────────────
   A compact "waffle" button + dropdown injected next to each app's back arrow
   (js/core/ui/appswitcher.js). The dropdown is SELF-THEMED via local --appsw-*
   vars rather than global tokens, because the three chromes it lives in each
   define their own palette (Books uses --inv-*, the scheduler its own, the hub
   plenum's). Dark surface by default (Books + Dispatch default dark); light
   overrides key off each app's known light-mode hook. The button itself uses
   currentColor so it always matches the bar it sits in. */
.ui-appsw {
  --appsw-surface: #1b1e25;
  --appsw-text:    #f2f4f8;
  --appsw-muted:   #aeb6c4;
  --appsw-border:  #2c313b;
  --appsw-hover:   rgba(255, 255, 255, .07);
  --appsw-accent:  #33b1ff;
  --appsw-shadow:  0 14px 34px -10px rgba(0, 0, 0, .6);
  position: relative;
  display: inline-flex;
  align-items: center;
}
/* Light-mode hook: every app now toggles light via <html data-theme="light">
   (nav unification Phase 4; was data-books-theme / .sched-light). */
:root[data-theme="light"] .ui-appsw {
  --appsw-surface: #ffffff;
  --appsw-text:    #131722;
  --appsw-muted:   #4a5568;
  --appsw-border:  #e4e9f1;
  --appsw-hover:   rgba(19, 23, 34, .06);
  --appsw-accent:  #1493e6;
  --appsw-shadow:  0 14px 34px -10px rgba(28, 26, 22, .22);
}
.ui-appsw__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: var(--r-xs, 8px);
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  opacity: .85;
  transition: background var(--dur-2, 150ms) var(--ease-standard, ease),
              opacity var(--dur-2, 150ms) var(--ease-standard, ease);
}
.ui-appsw__btn:hover,
.ui-appsw__btn[aria-expanded="true"] {
  opacity: 1;
  background: color-mix(in srgb, currentColor 12%, transparent);
}

.ui-appsw__panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: var(--z-dropdown, 100);
  min-width: 200px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-radius: 12px;
  background: var(--appsw-surface);
  border: 1px solid var(--appsw-border);
  box-shadow: var(--appsw-shadow);
  color: var(--appsw-text);
}
.ui-appsw__panel[hidden] { display: none; }

.ui-appsw__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--appsw-text);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
}
.ui-appsw__item i:first-child { font-size: 17px; color: var(--appsw-muted); }
.ui-appsw__item:hover { background: var(--appsw-hover); }
.ui-appsw__item.is-current { color: var(--appsw-accent); }
.ui-appsw__item.is-current i:first-child { color: var(--appsw-accent); }
.ui-appsw__tick { margin-left: auto; font-size: 15px; }

/* ── LifecycleStrip ──────────────────────────────────────────────────────────
   Quote → Job → Invoice breadcrumb (js/core/ui/lifecycle.js). Theme-agnostic:
   chips use currentColor translucency so they read on any editor surface; the
   accent is inherited from the host app (falls back to ice-blue). */
.ui-lc {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 10px 0 4px;
  font-size: 12.5px;
}
.ui-lc__step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  text-decoration: none;
  color: inherit;
  background: color-mix(in srgb, currentColor 8%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
  white-space: nowrap;
}
.ui-lc__step i:first-child { font-size: 14px; opacity: .75; }
.ui-lc__step em { font-style: normal; opacity: .7; font-size: 11px; }
a.ui-lc__step:hover,
button.ui-lc__step.is-action:hover { background: color-mix(in srgb, currentColor 15%, transparent); }
.ui-lc__step.is-todo { opacity: .5; border-style: dashed; }
/* A todo step wired to a linker — clickable, and less faded so it reads as an
   invitation rather than an absent step. */
button.ui-lc__step.is-action {
  cursor: pointer;
  font: inherit;
  opacity: .8;
}
button.ui-lc__step.is-action:hover { opacity: 1; border-style: solid; }
/* Detach control on a linked step — a small muted ✕, clearer on hover. */
button.ui-lc__unlink {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.2em;
  margin-left: -0.15em;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  opacity: .4;
  cursor: pointer;
  font: inherit;
  line-height: 1;
}
button.ui-lc__unlink:hover { opacity: 1; background: color-mix(in srgb, currentColor 18%, transparent); }
button.ui-lc__unlink i { font-size: 0.9em; }
/* The word carries the meaning; keep it small and quiet so it reads as a
   control on the step, not as a second label competing with the doc number. */
button.ui-lc__unlink span { font-size: 0.82em; font-weight: 600; letter-spacing: 0.01em; }
button.ui-lc__unlink { gap: 0.25em; padding: 0.2em 0.5em; opacity: .55; }
.ui-lc__step.is-current {
  color: var(--accent, var(--inv-accent, #1493e6));
  background: color-mix(in srgb, var(--accent, #1493e6) 14%, transparent);
  border-color: color-mix(in srgb, var(--accent, #1493e6) 40%, transparent);
  font-weight: 600;
}
.ui-lc__sep { font-size: 13px; opacity: .4; }
/* Compact (header) variant — no chevrons, so the grouping has to come from the
   spacing alone: an unlink control hugs the step it detaches, and the gap
   BETWEEN chips is wider than the gap inside one. At an even gap, "Job ✕
   Invoice" reads as though the ✕ belonged to the invoice. */
.ui-lc--compact { gap: var(--sp-2); margin: 0; }
.ui-lc--compact .ui-lc__unlink { margin-left: -6px; transition: opacity var(--dur-2, .15s) var(--out, ease); }
/* Detaching is rare, and here it shares a row with the document's own name and
   number — so it waits until you go looking, on hover or keyboard focus. Gated
   on a real pointer: with no hover there is nothing to reveal it, so on touch
   it stays put. It only ever fades, never reflows, so the title can't shift. */
@media (hover: hover) {
  .ui-lc--compact .ui-lc__unlink { opacity: 0; }
  .ui-lc--compact:hover .ui-lc__unlink,
  .ui-lc--compact:focus-within .ui-lc__unlink { opacity: .55; }
  .ui-lc--compact .ui-lc__unlink:hover,
  .ui-lc--compact .ui-lc__unlink:focus-visible { opacity: 1; }
}

/* ── SummaryBar ──────────────────────────────────────────────────────────────
   Segmented, clickable list summary (js/core/ui/summarybar.js). Each segment
   grows proportionally to its weight and carries a status accent on its lower
   edge. Theme-agnostic via currentColor; the accent is set per-segment through
   the inline --seg custom property. */
.ui-sbar {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin: 0 0 4px;
  width: 100%;
  grid-column: 1 / -1;   /* span the full width if dropped into a grid container */
}
.ui-sbar__seg {
  flex: 1 1 128px;       /* equal widths that wrap on narrow screens */
  min-width: 128px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 14px;
  border-radius: 12px;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
  background: color-mix(in srgb, currentColor 6%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 10%, transparent);
  border-bottom: 3px solid var(--seg, currentColor);
  transition: background var(--dur-2, 150ms) var(--ease-standard, ease),
              transform var(--dur-2, 150ms) var(--ease-standard, ease);
}
.ui-sbar__seg:hover {
  background: color-mix(in srgb, currentColor 12%, transparent);
  transform: translateY(-1px);
}
.ui-sbar__seg.is-active {
  background: color-mix(in srgb, var(--seg) 16%, transparent);
  border-color: color-mix(in srgb, var(--seg) 55%, transparent);
}
.ui-sbar__val {
  font-size: 18px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
.ui-sbar__lbl {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .04em;
  opacity: .68;
}

/* ── Locked cross-app entry point (core/access.js) ───────────────────────────
   Applied by NDAccess.decorate() to a link the account may not follow: the
   waffle row for an app that is not on the plan, an apps-menu entry a team
   member has no seat for. Deliberately DISABLED-AND-LABELLED rather than
   hidden — a missing row reads as "this product doesn't exist", which is only
   true for a flag-dark feature (those are removed instead, not locked).

   Self-themed off currentColor rather than global tokens, because this class
   lands inside four different chromes (the appswitcher panel, NDNav's menu,
   the canon rail, the hub topbar waffle) and each defines its own palette. */
.nd-locked {
  opacity: .48;
  cursor: not-allowed;
  position: relative;
}
.nd-locked:hover { opacity: .62; }

/* The padlock sits after the label, in the row's own colour at low emphasis,
   so it reads as a state rather than a decoration. */
.nd-locked::after {
  content: "\ea5f";                    /* ti-lock */
  font-family: "tabler-icons", sans-serif;
  font-size: var(--text-base);
  margin-left: auto;
  padding-left: var(--sp-2);
  opacity: .75;
  flex: none;
}

/* Keyboard users get the same signal a pointer user gets from the cursor. */
.nd-locked:focus-visible { outline: var(--sp-0_5) solid currentColor; outline-offset: var(--sp-0_5); }

@media (prefers-reduced-motion: reduce) {
  .nd-locked { transition: none; }
}

/* ── Live "viewing now" — a customer has the document on screen (core/doc-views.js) ── */
.ui-badge[data-status="viewing"] .ti { animation: nd-viewing-pulse 1.6s ease-in-out infinite; }
.nd-viewing-now { display: flex; align-items: center; gap: var(--sp-2, 8px); margin-top: var(--sp-3, 12px); font-size: var(--fs-xs, 12px); font-weight: 600; color: var(--doc-viewing); }
.nd-viewing-dot { width: 8px; height: 8px; border-radius: 50%; background: currentcolor; animation: nd-viewing-pulse 1.6s ease-in-out infinite; }
@keyframes nd-viewing-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .ui-badge[data-status="viewing"] .ti, .nd-viewing-dot { animation: none; } }
