/* ============================================================================
   RACI — design tokens and shared components
   ============================================================================
   The visual language established during the Artwork redesign, now applied
   across every module:

     - Solid-glyph monogram SVG icons. Single colour, minimal, no emoji.
     - Pill-shaped buttons.
     - Plain, simple tables — flat borders, no heavy shadows, no gradients.

   Palette is carried forward from the Apps Script app so the migrated system
   looks continuous with what the team uses today, not like a different product.
   ========================================================================= */

:root {
  /* Surfaces */
  --bg: #f4f3ef;
  --surface: #ffffff;
  --surface-2: #f0efe9;
  --border: #e2e0d8;
  --border-strong: #d0cec5;

  /* Text */
  --text: #1e1d1a;
  --text-2: #4a4840;
  --muted: #9a9489;

  /* Accents */
  --accent: #4a4cf0;
  --accent-soft: #eeeeff;
  --green: #18a07a;
  --green-soft: #e8f7f3;
  --amber: #d08c1a;
  --amber-soft: #fdf4e3;
  --red: #d94040;
  --red-soft: #fdeaea;

  /* Brand navy — page header */
  --navy: #1b3a5c;

  /* Geometry. One radius for pills, one for panels. */
  --radius-pill: 999px;
  --radius-panel: 10px;

  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;

  /* ── Motion ───────────────────────────────────────────────────────────────
     Two durations only. More than that and the app stops feeling like one thing. */
  --t-fast: 120ms;
  --t: 200ms;
  --ease: cubic-bezier(.4, 0, .2, 1);
}

/* ══════════════════════════════════════════════════════════════════════════
   DARK THEME
   ══════════════════════════════════════════════════════════════════════════
   Chosen steps, not an inversion. Flipping lightness algorithmically produces
   muddy borders and accent colours that fail contrast on a dark surface, so each
   value here is picked against #1a1917 rather than derived.

   The surfaces stay warm-neutral to match the light palette's character -- a cold
   blue-grey dark theme beside a warm cream light theme reads as two products.

   Accents get LIGHTER in dark mode: #4a4cf0 on near-black is close to unreadable,
   so it steps up to #8b8dff. The soft/tint variants go the other way, becoming
   deep muted versions rather than pale washes.

   Applied by data-theme on <html>, which assets/js/ui.js sets from localStorage.
   With no explicit choice, the OS preference decides.
   ══════════════════════════════════════════════════════════════════════════ */

:root[data-theme="dark"] {
  --bg: #1a1917;
  --surface: #232120;
  --surface-2: #2b2927;
  --border: #37342f;
  --border-strong: #4a4640;

  --text: #f0eee9;
  --text-2: #c4c0b8;
  --muted: #8e8981;

  --accent: #8b8dff;
  --accent-soft: #272749;
  --green: #3fc79c;
  --green-soft: #133329;
  --amber: #e8b04a;
  --amber-soft: #372c14;
  --red: #f07070;
  --red-soft: #3b1f1f;

  --navy: #12293f;
}

/* No stored preference: follow the OS. The :not() guard means an explicit light
   choice still wins on a dark-mode machine. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1a1917;
    --surface: #232120;
    --surface-2: #2b2927;
    --border: #37342f;
    --border-strong: #4a4640;

    --text: #f0eee9;
    --text-2: #c4c0b8;
    --muted: #8e8981;

    --accent: #8b8dff;
    --accent-soft: #272749;
    --green: #3fc79c;
    --green-soft: #133329;
    --amber: #e8b04a;
    --amber-soft: #372c14;
    --red: #f07070;
    --red-soft: #3b1f1f;

    --navy: #12293f;
  }
}

/* Violet is the Artwork section's identity in the sidebar, and the tone for the
   RACI-role tiles on the dashboard. It is a fourth section colour, not a status:
   nothing is good or bad for being violet. */
:root {
  --violet: #7a48c8;
  --violet-soft: #f2ecfd;
  --brand-hbl: #b02a4a;
}
:root[data-theme="dark"] {
  --violet: #b18cf0;
  --violet-soft: #2c2140;
  --brand-hbl: #e86b88;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --violet: #b18cf0;
    --violet-soft: #2c2140;
    --brand-hbl: #e86b88;
  }
}

/* ── Department identity colours (Artwork pipeline) ───────────────────────────
   Six stages that need telling apart at a glance. Carried over in spirit from the
   Apps Script version (Trademark navy, Artwork grey, QA blue, QC pink, FDA teal,
   Sales rose) but re-picked so they survive both themes.

   Used as a left rule and a tinted heading, never a full card fill: a saturated
   block behind body text fails contrast in one theme or the other, and the design
   language calls for flat surfaces. The department NAME is always printed on the
   card, so colour is a fast second channel, never the only one. */
:root {
  --dept-trademark: #3b5f8f;
  --dept-art:       #7b756c;
  --dept-qa:        #2f8fb5;
  --dept-qc:        #b5548a;
  --dept-fda:       #1f9c8a;
  --dept-sales:     #c2557a;
}
:root[data-theme="dark"] {
  --dept-trademark: #6f9cd4;
  --dept-art:       #a8a19a;
  --dept-qa:        #55b9dd;
  --dept-qc:        #e084b6;
  --dept-fda:       #45c4b0;
  --dept-sales:     #ec86a6;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --dept-trademark: #6f9cd4;
    --dept-art:       #a8a19a;
    --dept-qa:        #55b9dd;
    --dept-qc:        #e084b6;
    --dept-fda:       #45c4b0;
    --dept-sales:     #ec86a6;
  }
}

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

/* Colour changes animate so a theme switch reads as one motion rather than a
   flash. Excluded from the reduced-motion block below, since a colour fade is not
   vestibular motion. */
body, .panel, .card, .tile, .dsec, .stage, table th, table td,
.tbl-wrap, .modal, .drawer, .app-header, .nav {
  transition: background-color var(--t) var(--ease), border-color var(--t) var(--ease),
              color var(--t) var(--ease);
}

/* Anyone who has asked the OS to reduce motion gets no movement at all -- only
   instant state changes. This is an accessibility requirement, not a preference. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

html, body { margin: 0; padding: 0; }

body {
  font-family: var(--font);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* ── Layout ────────────────────────────────────────────────────────────────── */

.app-header {
  background: var(--navy);
  color: #fff;
  padding: 14px 26px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.app-header h1 { font-size: 15px; font-weight: 700; margin: 0; letter-spacing: -0.01em; }
.app-header .sub { font-size: 11px; opacity: 0.65; margin-top: 2px; }

.container { max-width: 880px; margin: 0 auto; padding: 24px 16px 64px; }

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-panel);
  padding: 20px;
  margin-bottom: 14px;
}
.panel-title {
  font-size: 13px;
  font-weight: 700;
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ── Icons: solid glyph, single colour, sized by font ──────────────────────── */

.icon {
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  fill: currentColor;
  vertical-align: -0.125em;
}
.icon-lg { width: 1.4em; height: 1.4em; }

/* ── Buttons: pill only ────────────────────────────────────────────────────── */

.btn {
  font-family: var(--font);
  font-size: 12px;
  font-weight: 600;
  padding: 8px 18px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  transition: background 0.14s, border-color 0.14s, color 0.14s;
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover:not(:disabled) { background: #3a3cd8; }

.btn-quiet { background: var(--surface); border-color: var(--border-strong); color: var(--text-2); }
.btn-quiet:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }

/* ── Form fields ───────────────────────────────────────────────────────────── */

.field { margin-bottom: 14px; }
.field label {
  display: block;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: 6px;
}
.field input {
  width: 100%;
  font-family: var(--font);
  font-size: 13px;
  padding: 10px 12px;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  outline: none;
}
.field input:focus { border-color: var(--accent); background: var(--surface); }

/* ── Tables: plain and flat ────────────────────────────────────────────────── */

.table { width: 100%; border-collapse: collapse; font-size: 12px; }
.table th {
  text-align: left;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}
.table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.table tr:last-child td { border-bottom: none; }
.table td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ── Status pills and messages ─────────────────────────────────────────────── */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 11px;
  border-radius: var(--radius-pill);
  border: 1px solid;
}
.pill-ok { background: var(--green-soft); color: var(--green); border-color: rgba(24, 160, 122, 0.25); }
.pill-wait { background: var(--surface-2); color: var(--muted); border-color: var(--border); }
.pill-warn { background: var(--amber-soft); color: var(--amber); border-color: rgba(208, 140, 26, 0.25); }
.pill-err { background: var(--red-soft); color: var(--red); border-color: rgba(217, 64, 64, 0.25); }

.msg {
  font-size: 12px;
  padding: 10px 13px;
  border-radius: 8px;
  border: 1px solid;
  margin-bottom: 12px;
}
.msg-err { background: var(--red-soft); color: var(--red); border-color: rgba(217, 64, 64, 0.25); }
.msg-ok { background: var(--green-soft); color: var(--green); border-color: rgba(24, 160, 122, 0.25); }
.msg-info { background: var(--accent-soft); color: var(--accent); border-color: rgba(74, 76, 240, 0.2); }

.hidden { display: none !important; }
.mono { font-family: var(--mono); font-size: 11px; }
.muted { color: var(--muted); }

/* ══════════════════════════════════════════════════════════════════════════
   CHAT BUBBLES
   ══════════════════════════════════════════════════════════════════════════
   Replaces the flat comment lists. Your own messages sit right with the accent
   fill; everyone else's sit left on a plain surface.

   Alignment alone is not enough to tell whose message is whose -- it fails for
   anyone who cannot perceive the offset, and it collapses on a narrow screen. So
   every bubble also carries its author's name, and only the incoming side shows
   it as a heading. Side, fill and label all say the same thing.
   ══════════════════════════════════════════════════════════════════════════ */

.thread { display: flex; flex-direction: column; gap: 8px; }

.chat-row { display: flex; }
.chat-row.mine { justify-content: flex-end; }

.bubble {
  max-width: min(78%, 460px);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px 12px 12px 3px;   /* tail bottom-left: incoming */
  padding: 8px 11px;
  font-size: 12px;
  line-height: 1.45;
  animation: bubbleIn var(--t) var(--ease) both;
}
.chat-row.mine .bubble {
  background: var(--accent-soft);
  border-color: rgba(74, 76, 240, .22);
  border-radius: 12px 12px 3px 12px;   /* tail bottom-right: outgoing */
}
:root[data-theme="dark"] .chat-row.mine .bubble { border-color: rgba(139, 141, 255, .3); }

.bubble-author {
  font-size: 10px;
  font-weight: 700;
  color: var(--accent);
  margin-bottom: 3px;
}
.bubble-text { white-space: pre-wrap; word-break: break-word; color: var(--text); }
.bubble-time {
  font-size: 9px;
  color: var(--muted);
  margin-top: 4px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* A tag for entries that are not plain chat -- escalations and rejections. */
.bubble-kind {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  margin-bottom: 4px;
}
.bubble-kind.escalation { background: var(--amber-soft); color: var(--amber); }
.bubble-kind.rejection { background: var(--red-soft); color: var(--red); }
.bubble-kind.link { background: var(--accent-soft); color: var(--accent); }

@keyframes bubbleIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

.chat-empty { font-size: 11px; color: var(--muted); padding: 8px 0; }

.chat-compose { display: flex; gap: 8px; align-items: flex-end; margin-top: 12px; }
.chat-compose textarea {
  flex: 1;
  min-height: 40px;
  max-height: 140px;
  resize: vertical;
  font-family: var(--font);
  font-size: 12px;
  padding: 9px 12px;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  outline: none;
}
.chat-compose textarea:focus { border-color: var(--accent); }

/* ══════════════════════════════════════════════════════════════════════════
   MODAL
   ══════════════════════════════════════════════════════════════════════════
   Replaces every native alert / confirm / window.open. Those cannot be styled,
   ignore the theme, and on a confirm the browser may suppress it entirely.
   ══════════════════════════════════════════════════════════════════════════ */

.m-scrim {
  position: fixed; inset: 0; z-index: 900;
  background: rgba(20, 19, 17, .42);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.m-scrim.on { opacity: 1; }

.modal {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-panel);
  width: 100%;
  max-width: 520px;
  max-height: min(80vh, 640px);
  display: flex; flex-direction: column;
  box-shadow: 0 12px 40px rgba(20, 19, 17, .22);
  transform: translateY(10px) scale(.98);
  transition: transform var(--t) var(--ease);
}
.m-scrim.on .modal { transform: none; }
.modal.wide { max-width: 720px; }

.m-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px;
}
.m-title { font-size: 13px; font-weight: 700; flex: 1; }
.m-close {
  background: none; border: none; cursor: pointer; color: var(--muted);
  padding: 3px; display: flex; border-radius: 5px;
}
.m-close:hover { color: var(--text); background: var(--surface-2); }

.m-body { padding: 16px 18px; overflow-y: auto; font-size: 12px; line-height: 1.5; }
.m-foot {
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  display: flex; gap: 8px; justify-content: flex-end;
}

/* ── View transitions and list entrance ─────────────────────────────────────
   Deliberately small. A dashboard people open forty times a day should not make
   them wait for choreography, so this is a short fade with a few pixels of travel
   and nothing staggered per row. */
.fade-in { animation: fadeIn var(--t) var(--ease) both; }
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* Refresh button spins only while a load is in flight. */
.spinning { animation: spin .7s linear infinite; }

/* Held at reduced opacity during a refetch instead of collapsing to a skeleton,
   so nothing jumps. */
.refetching { opacity: .55; transition: opacity var(--t-fast) var(--ease); }

/* ── Spinner ───────────────────────────────────────────────────────────────── */

.spinner {
  display: inline-block;
  width: 11px;
  height: 11px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ══════════════════════════════════════════════════════════════════════════
   SEARCHABLE SELECT  (assets/js/select.js)
   ══════════════════════════════════════════════════════════════════════════
   Replaces the native dropdown everywhere. The real <select> is still in the
   DOM, still holds the value, and is only visually hidden — so if the script
   fails, .ss-native reverts to a working native control.

   The panel animates from 4px above with a fade. It is short (140ms) and it is
   the only motion here: a dropdown someone opens two hundred times a day must
   not make them wait for it.
   ══════════════════════════════════════════════════════════════════════════ */

.ss { position: relative; display: inline-block; width: 100%; }
.ss-native {
  /* Hidden but still focusable-by-code and still submitted. display:none would
     drop it from form semantics; this keeps it real and invisible. */
  position: absolute; opacity: 0; pointer-events: none;
  width: 1px; height: 1px; padding: 0; margin: 0; border: 0;
}

.ss-field {
  width: 100%;
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font); font-size: 12px; text-align: left;
  padding: 7px 10px 7px 12px;
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
  cursor: pointer; min-height: 32px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.ss-field:hover { border-color: var(--accent); }
.ss-field:focus-visible,
.ss.on .ss-field { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.ss-disabled .ss-field { opacity: .5; cursor: not-allowed; }

.ss-value { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.ss-single .ss-value { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ss-ph { color: var(--muted); }
.ss-caret { width: 12px; height: 12px; flex-shrink: 0; color: var(--muted); transition: transform var(--t-fast) var(--ease); }
.ss.on .ss-caret { transform: rotate(180deg); }

/* ── Panel ─────────────────────────────────────────────────────────────────── */
.ss-panel {
  position: absolute; z-index: 500; left: 0; right: 0; top: calc(100% + 5px);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-panel);
  box-shadow: 0 10px 30px rgba(20, 19, 17, .16);
  overflow: hidden;
  opacity: 0; transform: translateY(-4px) scale(.985);
  pointer-events: none;
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.ss.on .ss-panel { opacity: 1; transform: none; pointer-events: auto; }
.ss.up .ss-panel { top: auto; bottom: calc(100% + 5px); transform: translateY(4px) scale(.985); }
.ss.up.on .ss-panel { transform: none; }

.ss-search { padding: 8px; border-bottom: 1px solid var(--border); }
.ss-search input {
  width: 100%;
  font-family: var(--font); font-size: 12px;
  padding: 7px 10px;
  color: var(--text); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 7px; outline: none;
}
.ss-search input:focus { border-color: var(--accent); background: var(--surface); }

.ss-list { max-height: 240px; overflow-y: auto; padding: 5px; }
.ss-opt {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 7px;
  font-size: 12px; color: var(--text-2); cursor: pointer;
}
.ss-opt.hidden { display: none; }
.ss-opt-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Hover and keyboard highlight are the SAME state, so the two never disagree
   about which row Enter will pick. */
.ss-opt:hover, .ss-opt.active { background: var(--surface-2); color: var(--text); }
.ss-opt.active { box-shadow: inset 2px 0 0 var(--accent); }
.ss-opt.sel { color: var(--accent); font-weight: 600; }
.ss-empty { padding: 14px 10px; text-align: center; font-size: 11px; color: var(--muted); }
.ss-empty.hidden { display: none; }

.ss-tick { width: 13px; flex-shrink: 0; font-size: 11px; color: var(--accent); opacity: 0; }
.ss-tick.on { opacity: 1; }

/* ── Chips (multi) ─────────────────────────────────────────────────────────── */
.ss-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 600; line-height: 1.5;
  padding: 1px 4px 1px 9px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid rgba(74, 76, 240, .2);
}
:root[data-theme="dark"] .ss-chip { border-color: rgba(139, 141, 255, .3); }
.ss-chip-x {
  border: none; background: none; cursor: pointer;
  color: inherit; font-size: 13px; line-height: 1;
  padding: 0 2px; border-radius: 50%; opacity: .65;
}
.ss-chip-x:hover { opacity: 1; background: rgba(217, 64, 64, .15); color: var(--red); }

.ss-multi .ss-field { border-radius: 10px; padding: 5px 10px 5px 8px; }

/* ══════════════════════════════════════════════════════════════════════════
   APPLICATION SHELL — sidebar + topbar
   ══════════════════════════════════════════════════════════════════════════
   Replaces the per-page navy header and horizontal tab strip. Every page now
   renders inside the same frame, so navigation is in one place and one shape
   rather than four that drift.

   Built by assets/js/shell.js. The markup is generated, not hand-written per
   page, for the same reason the RPC shim exists: five hand-maintained copies of
   a navigation tree is five chances for them to disagree.

   THE SIDEBAR IS A NAVIGATION SURFACE, NOT A PERMISSION BOUNDARY. Admin-only
   items are hidden from non-admins as a courtesy, exactly as the tab strips did.
   The server refuses them regardless of what the browser chooses to show.
   ══════════════════════════════════════════════════════════════════════════ */

.app { display: flex; min-height: 100vh; align-items: stretch; }

/* ── Sidebar ──────────────────────────────────────────────────────────────── */

.sidebar {
  --sb-w: 226px;
  width: var(--sb-w);
  flex: 0 0 var(--sb-w);
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  transition: width var(--t) var(--ease), flex-basis var(--t) var(--ease);
}
.sidebar.collapsed { --sb-w: 62px; }

.sb-head {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 14px 14px 12px;
}
.sb-brand { flex: 1; min-width: 0; line-height: 1.15; }
.sb-brand .b1 { font-size: 17px; font-weight: 700; color: var(--brand-hbl); letter-spacing: -0.01em; }
.sb-brand .b2 { font-size: 17px; font-weight: 700; color: var(--accent); letter-spacing: -0.01em; }
.sb-brand .b-sub {
  font-size: 8px; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted); margin-top: 3px;
}
.sb-toggle {
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-2); cursor: pointer;
  width: 24px; height: 24px; border-radius: 6px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.sb-toggle:hover { border-color: var(--accent); color: var(--accent); }
.sb-toggle svg { transition: transform var(--t) var(--ease); }
.sidebar.collapsed .sb-toggle svg { transform: rotate(180deg); }

/* ── Signed-in user card ──────────────────────────────────────────────────── */

.sb-user {
  display: flex; align-items: center; gap: 10px;
  margin: 0 10px 12px;
  padding: 10px;
  background: var(--accent-soft);
  border-radius: var(--radius-panel);
  min-width: 0;
}
.sb-av {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; flex-shrink: 0;
}
.sb-who { min-width: 0; }
.sb-name { font-size: 12px; font-weight: 700; color: var(--text); }
.sb-dept {
  font-size: 9px; color: var(--accent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── Sections ─────────────────────────────────────────────────────────────── */

.sb-nav { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 0 10px 10px; }
.sb-sec { margin-bottom: 6px; }

.sb-sec-btn {
  width: 100%;
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font); font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.11em;
  padding: 9px 11px;
  border: none; border-radius: 7px; cursor: pointer;
  background: var(--tone-soft); color: var(--tone);
}
.sb-sec-btn .grow { flex: 1; text-align: left; }
.sb-sec-btn .caret { transition: transform var(--t) var(--ease); opacity: .8; }
.sb-sec-btn[aria-expanded="true"] .caret { transform: rotate(90deg); }

/* Tone is set per section as a custom property, so one rule serves all of them
   and a new section needs no new CSS. */
.sb-sec.tone-indigo { --tone: var(--accent); --tone-soft: var(--accent-soft); }
.sb-sec.tone-green  { --tone: var(--green);  --tone-soft: var(--green-soft); }
.sb-sec.tone-violet { --tone: var(--violet); --tone-soft: var(--violet-soft); }

.sb-items { padding: 4px 0 2px; display: flex; flex-direction: column; gap: 1px; }
.sb-sec[data-open="false"] .sb-items { display: none; }

.sb-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 11px;
  font-size: 12px; color: var(--text-2);
  text-decoration: none; border-radius: 7px;
  border-left: 2px solid transparent;
  white-space: nowrap; overflow: hidden;
}
.sb-item:hover { background: var(--surface-2); color: var(--text); }
.sb-item .icon { color: var(--muted); }
.sb-item.on {
  background: var(--tone-soft); color: var(--tone); font-weight: 600;
  border-left-color: var(--tone);
}
.sb-item.on .icon { color: var(--tone); }

/* ── Footer ───────────────────────────────────────────────────────────────── */

.sb-foot { padding: 10px; border-top: 1px solid var(--border); }
.sb-btn {
  width: 100%;
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font); font-size: 11px; font-weight: 600;
  padding: 9px 11px; margin-bottom: 6px;
  border-radius: 7px; cursor: pointer;
  border: 1px solid transparent;
  white-space: nowrap; overflow: hidden;
}
.sb-btn.train { background: var(--green-soft); color: var(--green); }
.sb-btn.out { background: var(--red-soft); color: var(--red); }
.sb-btn:hover { filter: brightness(0.96); }
.sb-note { font-size: 9px; color: var(--muted); text-align: center; margin-top: 2px; }

/* ── Collapsed rail ───────────────────────────────────────────────────────────
   Labels go, glyphs stay, and every section opens: a rail whose groups can still
   be folded shut would hide its own contents behind two clicks. Each item keeps a
   title attribute, so the name is one hover away. */
.sidebar.collapsed .sb-brand .b2,
.sidebar.collapsed .sb-brand .b-sub,
.sidebar.collapsed .sb-who,
.sidebar.collapsed .sb-item span,
.sidebar.collapsed .sb-btn span,
.sidebar.collapsed .sb-sec-btn .grow,
.sidebar.collapsed .sb-sec-btn .caret,
.sidebar.collapsed .sb-note { display: none; }
.sidebar.collapsed .sb-head { padding: 14px 8px 12px; flex-direction: column; align-items: center; gap: 10px; }
.sidebar.collapsed .sb-brand { flex: none; text-align: center; }
.sidebar.collapsed .sb-user { justify-content: center; padding: 8px; margin: 0 8px 10px; }
.sidebar.collapsed .sb-nav { padding: 0 8px 10px; }
.sidebar.collapsed .sb-sec-btn { justify-content: center; padding: 7px 0; }
.sidebar.collapsed .sb-items { display: flex; }
.sidebar.collapsed .sb-item,
.sidebar.collapsed .sb-btn { justify-content: center; padding: 8px 0; gap: 0; }

/* ── Main column ──────────────────────────────────────────────────────────── */

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 60;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 10px 22px;
  display: flex; align-items: center; gap: 10px;
}
.tb-title { font-size: 15px; font-weight: 700; flex: 1; min-width: 0; }
.tb-right { display: flex; align-items: center; gap: 8px; }

.tb-menu { display: none; background: none; border: none; cursor: pointer; color: var(--text); padding: 4px; }

/* "Live" is a statement about the data source, not a health check: this build
   reads Postgres directly, so what is on screen is what is stored. It is not a
   connection indicator and must never be wired to one without saying so. */
.tb-live {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10px; font-weight: 600; color: var(--green);
}
.tb-live i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--green);
  display: inline-block;
}

.tb-bell { position: relative; }
.tb-bell .dot {
  position: absolute; top: 2px; right: 4px;
  min-width: 14px; height: 14px; padding: 0 3px;
  border-radius: var(--radius-pill);
  background: var(--red); color: #fff;
  font-size: 9px; font-weight: 700; line-height: 14px; text-align: center;
}

.sb-scrim {
  position: fixed; inset: 0; z-index: 70;
  background: rgba(20, 19, 17, .42);
  opacity: 0; pointer-events: none;
  transition: opacity var(--t-fast) var(--ease);
}

@media (max-width: 980px) {
  .sidebar {
    position: fixed; z-index: 80; left: 0; top: 0;
    transform: translateX(-100%);
    transition: transform var(--t) var(--ease);
    box-shadow: 0 0 30px rgba(20, 19, 17, .18);
  }
  .sidebar.open { transform: none; }
  .sidebar.collapsed { --sb-w: 226px; }   /* the rail is a desktop idea */
  .sidebar.collapsed .sb-item span,
  .sidebar.collapsed .sb-btn span,
  .sidebar.collapsed .sb-brand .b2,
  .sidebar.collapsed .sb-brand .b-sub,
  .sidebar.collapsed .sb-who,
  .sidebar.collapsed .sb-sec-btn .grow,
  .sidebar.collapsed .sb-sec-btn .caret,
  .sidebar.collapsed .sb-note { display: revert; }
  .sidebar.collapsed .sb-head { flex-direction: row; padding: 14px 14px 12px; }
  .sidebar.collapsed .sb-item,
  .sidebar.collapsed .sb-btn,
  .sidebar.collapsed .sb-sec-btn { justify-content: flex-start; padding: 7px 11px; gap: 10px; }
  .tb-menu { display: block; }
  .sb-scrim.on { opacity: 1; pointer-events: auto; }
}

/* ══════════════════════════════════════════════════════════════════════════
   DATE PICKER  (assets/js/datepicker.js)
   ══════════════════════════════════════════════════════════════════════════
   The browser's own calendar cannot be styled -- no CSS reaches inside it -- so
   a dark-theme page opened a bright system popup, and weekends could not be
   marked at all. This is that calendar, rebuilt.

   WEEKENDS carry a tinted column and a warmer date colour. That is not
   decoration: the artwork TAT arithmetic skips Sundays, so a deadline landing on
   a weekend behaves differently from one that does not, and it should be visible
   before it is chosen rather than after.
   ══════════════════════════════════════════════════════════════════════════ */

.dp { position: relative; display: block; width: 100%; }
.dp-input { padding-right: 32px !important; }
.dp-open {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  background: none; border: none; cursor: pointer; padding: 4px;
  color: var(--muted); display: flex; border-radius: 5px;
}
.dp-open:hover { color: var(--accent); background: var(--accent-soft); }

.dp-panel {
  position: absolute; z-index: 520; top: calc(100% + 6px); left: 0;
  width: 268px; padding: 10px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-panel);
  box-shadow: 0 12px 34px rgba(20, 19, 17, .18);
  opacity: 0; transform: translateY(-6px) scale(.97);
  transform-origin: top left;
  pointer-events: none;
  transition: opacity var(--t-fast) var(--ease), transform var(--t) var(--ease);
}
.dp.on .dp-panel { opacity: 1; transform: none; pointer-events: auto; }
.dp.up .dp-panel { top: auto; bottom: calc(100% + 6px); transform-origin: bottom left; transform: translateY(6px) scale(.97); }
.dp.up.on .dp-panel { transform: none; }

.dp-head { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.dp-mon { flex: 1; text-align: center; font-size: 12px; font-weight: 700; }
.dp-nav {
  width: 24px; height: 24px; border-radius: 6px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-2); font-size: 15px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.dp-nav:hover { border-color: var(--accent); color: var(--accent); }

.dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dp-dow span {
  text-align: center; font-size: 9px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); padding: 4px 0;
}
.dp-dow span.we { color: var(--amber); }

.dp-day {
  aspect-ratio: 1 / 1;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font); font-size: 11.5px; font-variant-numeric: tabular-nums;
  border: 1px solid transparent; border-radius: 7px;
  background: none; color: var(--text); cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.dp-day:hover { background: var(--surface-2); }
.dp-day.out { color: var(--muted); opacity: .5; }
/* Weekend: tinted cell plus a warmer figure, so it reads in both themes and does
   not rely on the colour alone -- the column heading is tinted to match. */
/* SUNDAY only. The TAT arithmetic skips Sundays and works Saturdays, so marking
   both would say something untrue about how a deadline behaves. */
.dp-day.we { background: var(--amber-soft); color: var(--amber); }
.dp-day.we:hover { background: var(--amber-soft); filter: brightness(.96); }
.dp-day.now { border-color: var(--accent); font-weight: 700; }
.dp-day.cur { box-shadow: 0 0 0 2px var(--accent-soft) inset; }
.dp-day.sel { background: var(--accent) !important; color: #fff !important; font-weight: 700; }

.dp-foot { display: flex; gap: 6px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.dp-mini {
  flex: 1; font-family: var(--font); font-size: 10px; font-weight: 600;
  padding: 5px; border-radius: 6px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-2);
}
.dp-mini:hover { border-color: var(--accent); color: var(--accent); }

/* ── Drawer resize handle ────────────────────────────────────────────────────
   The default width is deliberately narrower than before so the table behind
   stays readable, and this grip lets anyone who disagrees settle it themselves.
   The chosen width is stored, so it is a preference rather than a per-open fiddle.
   A 6px target with a wider hover area: too thin to grab is worse than absent. */
.drawer-grip {
  position: absolute; left: -3px; top: 0; bottom: 0; width: 8px;
  cursor: col-resize; z-index: 5;
  background: transparent;
  transition: background var(--t-fast) var(--ease);
}
.drawer-grip:hover, .drawer-grip.dragging { background: var(--accent); opacity: .35; }
/* No transition while dragging, or the panel lags behind the pointer. */
.drawer.resizing { transition: none !important; }
body.drawer-resizing { user-select: none; cursor: col-resize; }

/* ══════════════════════════════════════════════════════════════════════════
   ARTWORK PIPELINE STRIP
   ══════════════════════════════════════════════════════════════════════════
   Seven nodes on a rail at the top of the artwork panel: the five department
   stages, then Sales. Every request walks all of them in order and nothing
   skips, so "where is this, and what is left" is the panel's first question.

   State is never colour alone. Done carries a tick, correction a warning glyph,
   the current stage is ringed, and every node prints its own name and status
   underneath. Department hue is a second channel on top of that, using the same
   --dept-* tokens the stage cards use, so the strip and the cards agree.

   The rail fills left to right and the nodes settle in sequence on open — the
   direction of travel is the information. Reduced-motion users get the finished
   picture instantly via the global rule near the top of this file.
   ══════════════════════════════════════════════════════════════════════════ */

.pipe {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-panel); padding: 14px 16px 12px; margin-bottom: 12px;
}
.pipe-top { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.pipe-top h3 {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--muted); margin: 0; flex: 1;
}
.pipe-now { font-size: 11px; font-weight: 700; color: var(--accent); }

.pipe-rail {
  position: relative; height: 3px; border-radius: 2px;
  background: var(--border); margin: 0 6px 10px;
}
.pipe-fill {
  height: 100%; border-radius: 2px; background: var(--accent);
  width: 0;
  animation: pipeFill .5s var(--ease) .05s forwards;
}
@keyframes pipeFill { to { width: var(--pipe-fill, 0%); } }

.pipe-nodes { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }

.pipe-node {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  min-width: 0; text-align: center;
  opacity: 0;
  animation: pipeIn .28s var(--ease) forwards;
  animation-delay: calc(60ms * var(--i));
}
@keyframes pipeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }

.pipe-dot {
  width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700;
  border: 2px solid var(--dept, var(--border-strong));
  background: var(--surface); color: var(--dept, var(--muted));
  transition: background var(--t) var(--ease), color var(--t) var(--ease);
}
.pipe-node.d-trademark { --dept: var(--dept-trademark); }
.pipe-node.d-art       { --dept: var(--dept-art); }
.pipe-node.d-qa        { --dept: var(--dept-qa); }
.pipe-node.d-qc        { --dept: var(--dept-qc); }
.pipe-node.d-fda       { --dept: var(--dept-fda); }
.pipe-node.d-sales     { --dept: var(--dept-sales); }

.pipe-node.st-done .pipe-dot { background: var(--dept); color: #fff; border-color: var(--dept); }
.pipe-node.st-wait .pipe-dot { border-color: var(--border-strong); color: var(--muted); }
.pipe-node.st-corr .pipe-dot { border-color: var(--red); color: var(--red); background: var(--red-soft); }
.pipe-node.st-cur  .pipe-dot { box-shadow: 0 0 0 4px var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.pipe-node.late .pipe-dot { border-color: var(--red); }

.pipe-lbl { font-size: 9px; font-weight: 700; color: var(--text-2); line-height: 1.2; }
.pipe-node.st-cur .pipe-lbl { color: var(--accent); }
.pipe-sub {
  font-size: 8px; color: var(--muted); line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}

/* Narrow drawers wrap it to two rows rather than crushing seven columns. */
@media (max-width: 560px) { .pipe-nodes { grid-template-columns: repeat(4, 1fr); row-gap: 10px; } }

/* ── Date picker: month/year jump pane ───────────────────────────────────────
   Paging one month at a time is fine for next week and useless for 2029, so the
   title is a button that swaps the day grid for this. Reaches 2000-2099. */
.dp-mon {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 5px;
  font-family: var(--font); font-size: 12px; font-weight: 700;
  padding: 4px 8px; border-radius: 6px; cursor: pointer;
  background: none; border: 1px solid transparent; color: var(--text);
}
.dp-mon:hover { background: var(--surface-2); border-color: var(--border); }
.dp-nav:disabled { opacity: .3; cursor: not-allowed; }
.dp-nav:disabled:hover { border-color: var(--border); color: var(--text-2); }

.dp-yr { flex: 1; display: flex; justify-content: center; }
.dp-yin {
  width: 78px; text-align: center;
  font-family: var(--font); font-size: 13px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 4px 6px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 6px; outline: none;
}
.dp-yin:focus { border-color: var(--accent); background: var(--surface); }

.dp-months { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; padding: 4px 0; }
.dp-mo {
  font-family: var(--font); font-size: 11px; font-weight: 600;
  padding: 9px 4px; border-radius: 7px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-2);
}
.dp-mo:hover { border-color: var(--accent); color: var(--accent); }
.dp-mo.sel { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Admin entries in the sidebar footer, above Training Documents. Violet, matching
   the Artwork section's tone only in that it is the fourth non-status colour --
   these are neither good nor bad, just restricted. */
.sb-btn.admin { background: var(--violet-soft); color: var(--violet); text-decoration: none; }

/* THE hidden RULE. Do not remove, and do not rely on the browser's own one.

   `hidden` works by a user-agent rule of `display: none`, which ANY author rule
   setting display beats -- and .sb-item, .sb-btn and .btn all set display:flex.
   So every `hidden` admin entry in the sidebar was rendering normally: a non-admin
   has been seeing Management Insights, All Tasks and All Artwork the whole time.

   The line below it used to be `.sb-btn.admin[hidden]`, which patched the two
   footer buttons only and left the nav items broken -- which is why this looked
   fixed and was not. This is the general form; it cannot be defeated by adding a
   display to some new component later. shell.js also REMOVES admin entries from
   the DOM for a non-admin, so the two are independent. */
[hidden] { display: none !important; }
