/* components.css — reusable UI components in the Scheduler V2 visual system. */

/* ---- Buttons ---- */

.btn-primary,
.btn-secondary,
.btn-danger,
.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  padding: 10px var(--space-6);
  border-radius: var(--radius-button);
  border: 1px solid transparent;
  cursor: pointer;
  transition: filter 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
  white-space: nowrap;
}
.btn-primary:disabled,
.btn-secondary:disabled,
.btn-danger:disabled,
.btn-ghost:disabled { opacity: 0.55; cursor: not-allowed; }

.btn-primary {
  background: linear-gradient(180deg, var(--color-gold-light) 0%, var(--color-gold-dark) 100%);
  color: var(--color-navy-dark);
  box-shadow: var(--shadow-gold-cta);
}
.btn-primary:not(:disabled):hover { filter: brightness(1.05); }

.btn-secondary {
  background: var(--color-white);
  color: var(--color-navy);
  border-color: var(--color-input-border);
  box-shadow: var(--shadow-card);
}
.btn-secondary:not(:disabled):hover { box-shadow: var(--shadow-card-elevated); }

.btn-danger {
  background: linear-gradient(180deg, var(--color-danger-bg-from), var(--color-danger-bg-to));
  color: var(--color-danger-text);
  border-color: var(--color-danger-border);
}
.btn-danger:not(:disabled):hover { filter: brightness(0.98); }

.btn-ghost {
  background: transparent;
  color: var(--color-text-secondary);
  padding: var(--space-2) var(--space-3);
  box-shadow: none;
}
.btn-ghost:not(:disabled):hover { background: rgba(28, 53, 94, 0.05); color: var(--color-navy); }

.btn-sm { padding: 6px var(--space-3); font-size: 13px; }
.btn-icon {
  padding: var(--space-2);
  width: 32px; height: 32px;
  border-radius: var(--radius-button);
}

/* ---- Cards ---- */

.card,
.card-elevated {
  background: var(--color-white);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-card);
  padding: var(--space-6);
}
.card { box-shadow: var(--shadow-card); }
.card-elevated { box-shadow: var(--shadow-card-elevated); }

/* ---- Badges ---- */

.badge-success,
.badge-warning,
.badge-danger,
.badge-neutral {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: 11px;
  font-weight: 500;
  padding: 2px var(--space-3);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge-success {
  background: linear-gradient(180deg, var(--color-success-bg-from), var(--color-success-bg-to));
  color: var(--color-success-text);
  border-color: var(--color-success-border);
}
.badge-warning {
  background: linear-gradient(180deg, var(--color-warning-bg-from), var(--color-warning-bg-to));
  color: var(--color-warning-text);
  border-color: var(--color-warning-border);
}
.badge-danger {
  background: linear-gradient(180deg, var(--color-danger-bg-from), var(--color-danger-bg-to));
  color: var(--color-danger-text);
  border-color: var(--color-danger-border);
}
.badge-neutral {
  background: var(--color-table-header-bg);
  color: var(--color-text-secondary);
  border-color: var(--color-card-border);
}

.status-dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: var(--radius-pill);
  flex: none;
}
.status-dot-success { background: var(--color-success-text); }
.status-dot-warning { background: var(--color-warning-text); }
.status-dot-danger { background: var(--color-danger-text); }
.status-dot-neutral { background: var(--color-text-tertiary); }

/* ---- Inputs ---- */

.input,
.select,
textarea.input {
  width: 100%;
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--color-text-primary);
  background: var(--color-white);
  border: 1px solid var(--color-input-border);
  border-radius: var(--radius-button);
  padding: var(--space-2) var(--space-3);
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.input::placeholder { color: var(--color-text-tertiary); }
.input:focus,
.select:focus,
textarea.input:focus {
  outline: none;
  border-color: var(--color-gold);
  box-shadow: 0 0 0 2px rgba(203, 154, 51, 0.2);
}
textarea.input { min-height: 72px; resize: vertical; }

.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field > label { font-size: 12px; font-weight: 600; color: var(--color-text-secondary); }
.field-hint { font-size: 12px; color: var(--color-text-tertiary); }

.checkbox-row {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 14px;
  cursor: pointer;
}
.checkbox-row input { width: 16px; height: 16px; accent-color: var(--color-gold-dark); }

/* Order Guide "saving" note: its own full-width line under the header, always
   in the layout at a FIXED one-line height whether it holds text or not, so a
   save starting or finishing can move neither the header (the Order complete
   box) nor the entry table under a click in progress, at any width (gate PD2,
   fix round 2 U2). Long text ellipsizes instead of wrapping; the box keeps its
   full width, so the note is visible even at phone width. */
.order-save-pending {
  display: block;
  box-sizing: border-box;
  width: 100%;
  height: 20px;
  line-height: 20px;
  margin: 0 0 var(--space-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 13px;
}

/* Purchasing "Sources" disclosure under each order-guide summary row and each
   Reports row. Native details/summary: Tab reaches it, Enter/Space toggles it.
   Text uses text-secondary (5.5:1 on white); the focus outline uses gold-dark
   (3.3:1, above the 3:1 bar for focus indicators). Warnings never sit inside it. */
.purchase-sources { margin-top: 4px; font-weight: 400; }
.purchase-sources > summary {
  cursor: pointer;
  width: fit-content;
  font-size: 12px;
  color: var(--color-text-secondary);
  border-radius: 4px;
}
.purchase-sources > summary:focus-visible {
  outline: 2px solid var(--color-gold-dark);
  outline-offset: 2px;
}
/* A collapsible section (08-audit §8.12 Section 2; 09 A12), the same native
   details/summary pattern as .purchase-sources above: Tab reaches the summary,
   Enter/Space toggles it. Navy summary text (12.21:1 on white); the gold-dark
   focus ring is 3.30:1, above the 3:1 bar for focus indicators. On a .card the
   card keeps its own padding and border. */
.disclosure { border-bottom: 1px solid var(--color-table-row-border); padding: 4px 0; }
.card.disclosure { border-bottom: 1px solid var(--color-card-border); padding: var(--space-4) var(--space-5); }
.disclosure > summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--color-navy);
  padding: 6px 0;
  width: fit-content;
  border-radius: 4px;
}
.disclosure > summary:focus-visible {
  outline: 2px solid var(--color-gold-dark);
  outline-offset: 2px;
}

/* Inline guidance boxes (09 A12; R93). Existing tokens only:
   .callout        navy text on the table-header tint #fafbfd (11.79:1);
   .callout-warn   warning text #92400e on the warning gradient (6.52:1 → 5.86:1);
   .callout-danger danger text #991b1b on the danger gradient (7.13:1 → 6.09:1).
   Text inside a callout always takes the callout's own colour: .field-hint,
   .text-secondary and .muted fall under 4.5:1 on the warning and danger
   gradients (tests/unit/cogswell/contrastAA.test.ts measures every pair). */
.callout,
.callout-warn,
.callout-danger {
  border-radius: var(--radius-button);
  padding: var(--space-3) var(--space-4);
  margin: var(--space-3) 0;
  border: 1px solid var(--color-card-border);
  font-size: 14px;
}
.callout {
  background: var(--color-table-header-bg);
  color: var(--color-text-primary);
  border-left: 3px solid var(--color-gold);
}
.callout-warn {
  background: linear-gradient(180deg, var(--color-warning-bg-from), var(--color-warning-bg-to));
  color: var(--color-warning-text);
  border-color: var(--color-warning-border);
}
.callout-danger {
  background: linear-gradient(180deg, var(--color-danger-bg-from), var(--color-danger-bg-to));
  color: var(--color-danger-text);
  border-color: var(--color-danger-border);
}
.callout > ul,
.callout-warn > ul,
.callout-danger > ul { margin: var(--space-2) 0 0; padding-left: var(--space-5); }

/* Admin → Import COGS-Well (09 A1.4, A12). Existing tokens only; every pair is
   measured in tests/unit/cogswell/contrastAA.test.ts:
   - tile title and number: navy on white (12.21:1);
   - the scroll box's sticky header: text-secondary on #fafbfd (5.29:1);
   - focus rings: gold-dark on white (3.30:1, above the 3:1 bar for focus indicators).
   A tile at 0 is a plain box, not a button (R101): nothing to open. */
.tabs.wrap { row-gap: var(--space-2); }
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-3);
  margin: var(--space-2) 0 var(--space-4);
}
.stat-tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  text-align: left;
  font: inherit;
  color: var(--color-navy);
  background: var(--color-white);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
}
button.stat-tile:hover { box-shadow: var(--shadow-card-elevated); }
.stat-tile.stat-tile-static { cursor: default; }
.stat-tile:focus-visible,
.scroll-box:focus-visible {
  outline: 2px solid var(--color-gold-dark);
  outline-offset: 2px;
}
.stat-title { font-size: 13px; font-weight: 600; line-height: 1.3; }
.stat-number {
  font-family: var(--font-mono);
  font-size: 24px;
  font-weight: 600;
  line-height: 1.1;
}
.scroll-box {
  max-height: 420px;
  overflow: auto;
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-button);
}
.scroll-box table.data thead th { position: sticky; top: 0; z-index: 1; }
/* The file input and the list filters take the tiles' gold-dark ring (3.30:1 on white; R103).
   .input:focus alone is a 1 px gold border, 2.56:1, under the 3:1 bar for focus indicators; an
   outline also stays visible in forced-colors mode. */
#cogswell-import .input:focus-visible {
  outline: 2px solid var(--color-gold-dark);
  outline-offset: 2px;
  /* No focus halo inside the ring: the ring then has white on both sides (3.30:1), where the halo
     left it at 2.79:1 on its inner edge (R103 amendment 2, t4-2). */
  box-shadow: none;
}
/* A list title the screen scrolls to (a tile, View) stops below the sticky .topbar (WCAG 2.4.11;
   R103). The bar's height from its rules under "Top bar + tabs", measured in Chromium: over 900 px
   one row, 12 + 34.7 (a .tab) + 12 + 1 = 59.5 px. At 900 px and under its padding is 8 px and it
   wraps: 51.5 px on one row, 86.1 px with the user menu (26.6 px) on a second row 8 px down, and
   126.1 px at 320 px, where the tabs take a row of their own under the logo. Each margin is the
   tallest bar of its width band plus var(--space-2). Every focusable control on the screen gets the
   same margin, so a Tab or Shift+Tab never leaves the focused control under the bar (R103
   amendment 2, t4-1). */
#cogswell-import details[data-section] > summary,
#cogswell-import [data-result-slot],
#cogswell-import :is(button, input, select, textarea, summary, a, [tabindex]) { scroll-margin-top: calc(60px + var(--space-2)); }
@media (max-width: 900px) {
  #cogswell-import details[data-section] > summary,
  #cogswell-import [data-result-slot],
  #cogswell-import :is(button, input, select, textarea, summary, a, [tabindex]) { scroll-margin-top: calc(87px + var(--space-2)); }
}
@media (max-width: 480px) {
  #cogswell-import details[data-section] > summary,
  #cogswell-import [data-result-slot],
  #cogswell-import :is(button, input, select, textarea, summary, a, [tabindex]) { scroll-margin-top: calc(127px + var(--space-2)); }
}

/* .badge-retired is a test hook only (09 A13; R93 contradiction 21): the Retired
   tag is span.badge-warning.badge-retired, styled by .badge-warning. */

/* Catalog Audit replacement choices (08-audit §8.12): one native radio per row,
   the whole row is its label. */
.replacement-option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-table-row-border);
  cursor: pointer;
}
.replacement-option input[type="radio"] { margin-top: 4px; accent-color: var(--color-gold-dark); flex: none; }
.replacement-option:focus-within { outline: 2px solid var(--color-gold-dark); outline-offset: 2px; border-radius: 4px; }

.purchase-source-list {
  margin: 4px 0 2px;
  padding-left: 18px;
  font-size: 12px;
  color: var(--color-text-secondary);
}
.purchase-source-list > li { margin: 2px 0; overflow-wrap: anywhere; }
/* Purchasing text shared by screen and paper (purchase_render.js). Warnings are
   ordinary-weight warning text even inside a bold cell; hints under a figure
   ("/lb", "(est)", a case hint) stay ordinary weight. */
.warn-text,
.purchase-warning { color: var(--color-warning-text); }
.purchase-warning,
.hint-normal { font-weight: 400; }
.warn-strong { color: var(--color-warning-text); font-weight: 600; }
table.data.vendor-summary tr.vendor-row th {
  text-align: left;
  font-weight: 400;
  padding: 12px var(--space-3) var(--space-3);
  border-bottom: 1px solid var(--color-table-row-border);
  overflow-wrap: anywhere;
}
table.data.vendor-summary tr.vendor-row td { padding-top: 12px; }
table.data.vendor-summary tr.vendor-row td.num { font-weight: 700; }
.total-amount { margin-left: 8px; }
.total-estimate { margin-left: 6px; }

/* Purchasing rows grow when Sources open: keep every number beside the item
   name instead of floating to the middle of the taller row. */
table.data.vendor-summary tbody td { vertical-align: top; }
/* Long names wrap anywhere, so an unbroken catalog description ("BEEF,GROUND,
   80/20,FINE") cannot widen the table; break-word does nothing in an
   auto-layout table. Headers stay on one line (numbers have no break points
   anyway). On a narrow screen the cells tighten. */
table.data.vendor-summary tbody td:first-child { overflow-wrap: anywhere; min-width: 140px; }
table.data.vendor-summary thead th { white-space: nowrap; }
@media (max-width: 900px) {
  table.data.vendor-summary th,
  table.data.vendor-summary td { padding: var(--space-2) 6px; }
  table.data.vendor-summary tr.vendor-row th { padding: 12px 6px var(--space-2); }
}

/* ---- Tables ---- */

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
table.data thead th {
  text-align: left;
  background: var(--color-table-header-bg);
  color: var(--color-text-secondary);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.02em;
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-card-border);
}
table.data tbody td {
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-table-row-border);
  vertical-align: middle;
}
table.data tbody tr:hover { background: rgba(28, 53, 94, 0.015); }
table.data .num { font-family: var(--font-mono); letter-spacing: -0.01em; text-align: right; }

/* A wide table scrolls sideways inside its card on a narrow screen, instead of
   widening the page or being clipped by the card's rounded corners. */
.table-scroll { overflow-x: auto; }
.table-card { padding: 0; overflow: hidden; }
.table-note { padding: var(--space-4); color: var(--color-text-primary); }
/* The Order Guide entry table: nine columns cannot share a tablet's width, so
   below about 950px it keeps its layout and scrolls sideways inside its card.
   The Item column keeps at least 150px, the inputs have fixed widths and the
   selects size to their options, so Item also takes any room that is left
   (fixed header widths left Item 89px wide on a tablet). */
table.order-entry th:first-child,
table.order-entry td:first-child { min-width: 150px; }
/* As in the summary: an unbroken catalog description wraps instead of widening
   the table on a desktop. */
table.order-entry td:first-child { overflow-wrap: anywhere; }
table.order-entry input.input { width: 70px; }
table.order-entry select.select { width: auto; }
table.order-entry th { white-space: nowrap; }
@media (max-width: 900px) {
  table.data.order-entry th,
  table.data.order-entry td { padding: var(--space-2) 6px; }
}

/* ---- Autocomplete ---- */

.autocomplete { position: relative; }
.autocomplete-menu {
  position: absolute;
  left: 0; right: 0; top: calc(100% + 4px);
  z-index: 40;
  background: var(--color-white);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-button);
  box-shadow: var(--shadow-card-elevated);
  max-height: 240px;
  overflow-y: auto;
}
.autocomplete-item {
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  font-size: 14px;
}
.autocomplete-item:hover,
.autocomplete-item.active { background: rgba(203, 154, 51, 0.12); }
.autocomplete-item .meta { font-size: 12px; color: var(--color-text-tertiary); }
/* Informational row ("+N more — keep typing to narrow"): not selectable. */
.autocomplete-hint {
  padding: var(--space-2) var(--space-3);
  font-size: 12px;
  font-style: italic;
  color: var(--color-text-tertiary);
  cursor: default;
  border-top: 1px solid var(--color-card-border);
}

/* Floating variant: mounted on <body>, positioned via JS. Sits above modals. */
.autocomplete-floating {
  position: fixed;
  left: 0; right: auto; top: 0;
  z-index: 120;
}

/* ---- Top bar + tabs ---- */

.topbar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-6);
  background: var(--color-white);
  border-bottom: 1px solid var(--color-card-border);
  box-shadow: var(--shadow-card);
  position: sticky;
  top: 0;
  z-index: 30;
}
.topbar .brand { display: flex; align-items: center; gap: var(--space-3); }
/* The open-event chip: a BEO-length event name must ellipsize instead of
   pushing Help / user / Sign out off-screen at narrow or zoomed viewports
   (gate pass 2). Full name stays on the title attr. inline-block (not the
   badge's inline-flex) because text-overflow needs a block text container. */
.topbar .badge-neutral {
  display: inline-block;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topbar .brand img { height: 32px; width: auto; }
.topbar .wordmark {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-navy);
}

.tabs { display: flex; gap: var(--space-1); }
.tab {
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-button);
  font-size: 14px;
  font-weight: 600;
  color: var(--color-text-secondary);
  cursor: pointer;
  border: 1px solid transparent;
  background: transparent;
}
.tab:hover { background: rgba(28, 53, 94, 0.05); color: var(--color-navy); }
.tab.active {
  color: var(--color-navy);
  background: rgba(203, 154, 51, 0.14);
  border-color: var(--color-success-border);
}

.page { max-width: 1200px; margin: 0 auto; padding: var(--space-8) var(--space-6); }
.page-header { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); margin-bottom: var(--space-6); }

/* Narrow screens: the top bar wraps instead of pushing Sign out off-screen,
   and the wordmark (the logo already names the app) gives up its room. */
@media (max-width: 900px) {
  .topbar { flex-wrap: wrap; row-gap: var(--space-2); padding: var(--space-2) var(--space-4); }
  .topbar .wordmark { display: none; }
  .topbar .badge-neutral { max-width: 160px; }
  .topbar > .row { flex-wrap: wrap; row-gap: var(--space-1); }
  .page { padding: var(--space-6) var(--space-4); }
}
/* On a phone the open-event chip repeats the page title; it gives up its row. */
@media (max-width: 480px) {
  .topbar .badge-neutral { display: none; }
}

/* ---- Modal ---- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(10, 24, 48, 0.45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: var(--space-12) var(--space-4);
  z-index: 100;
  overflow-y: auto;
}
/* A confirm with no field takes focus on the dialog itself (ui.js openModal). */
.modal:focus { outline: none; }
.modal:focus-visible { outline: 2px solid var(--color-gold-dark); outline-offset: 2px; }
.modal {
  background: var(--color-white);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card-elevated);
  width: 100%;
  max-width: 520px;
  padding: var(--space-8);
}
.modal.modal-wide { max-width: 860px; }
.modal-header { display: flex; align-items: center; margin-bottom: var(--space-5); }
.modal-header h2 { margin: 0; }
.modal-body { display: flex; flex-direction: column; gap: var(--space-4); }
/* The buttons wrap onto a second row on a narrow screen instead of pushing one off it (P6b b5-7:
   at 360 px the D22 dialog's "Switch and archive anyway" pushed the focused Cancel 11 px off). */
.modal-footer { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-3); row-gap: var(--space-2); margin-top: var(--space-6); }
/* A button whose label names an item or a count may wrap within the screen's width rather than widen
   the page (P6b b5-7: the result's "Open Catalog Audit (1 retired item still in use)" at 360 px;
   T15 PD-5: Catalog Audit's "Switch N lines to <long description>"). */
.btn-wrap { white-space: normal; text-align: left; line-height: 1.3; max-width: 100%; }

/* ---- Toast ---- */

.toast-host {
  position: fixed;
  right: var(--space-6);
  bottom: var(--space-6);
  display: flex;
  flex-direction: column;
  z-index: 200;
  /* Sits above modals (z 200 > 100) but must never swallow their clicks: a
     4.5 s error toast over the footer was eating Save/Cancel presses (gate
     pass 2). Nothing in a toast is interactive, so the host is
     click-transparent; restore pointer-events on .toast if that changes. */
  pointer-events: none;
}
/* The stack's two live regions (ui.js, P6b b5-6): polite toasts, then error toasts, each a column;
   a gap only between two lists that both hold toasts, so a lone toast sits where it always did. */
.toast-list { display: flex; flex-direction: column; gap: var(--space-2); }
.toast-list:not(:empty) + .toast-list:not(:empty) { margin-top: var(--space-2); }
.toast {
  min-width: 240px;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-button);
  box-shadow: var(--shadow-card-elevated);
  font-size: 14px;
  font-weight: 500;
  background: var(--color-white);
  border: 1px solid var(--color-card-border);
  color: var(--color-navy);
}
.toast.toast-success { background: linear-gradient(180deg, var(--color-success-bg-from), var(--color-success-bg-to)); color: var(--color-success-text); border-color: var(--color-success-border); }
.toast.toast-error { background: linear-gradient(180deg, var(--color-danger-bg-from), var(--color-danger-bg-to)); color: var(--color-danger-text); border-color: var(--color-danger-border); }

/* ---- Login ---- */

.login-screen {
  min-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
}
.login-card { width: 100%; max-width: 28rem; padding: var(--space-8); }
.login-card .logo { display: block; margin: 0 auto var(--space-6); width: 200px; max-width: 60%; height: auto; }

/* ---- Empty state ---- */

.empty-state {
  text-align: center;
  padding: var(--space-12) var(--space-6);
  color: var(--color-text-tertiary);
}
.empty-state h3 { color: var(--color-text-secondary); }

/* ---- Misc ---- */

.spinner {
  width: 16px; height: 16px;
  border: 2px solid rgba(28, 53, 94, 0.25);
  border-top-color: var(--color-navy);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

.app-loading { display: flex; align-items: center; justify-content: center; gap: var(--space-3); min-height: 60vh; color: var(--color-text-secondary); }

.tree-toggle {
  background: none; border: none; cursor: pointer;
  color: var(--color-text-tertiary); font-size: 12px;
  width: 20px; padding: 0;
}
.drag-handle { cursor: grab; color: var(--color-text-tertiary); user-select: none; }
.dragging { opacity: 0.5; }
.drop-target { box-shadow: inset 0 2px 0 var(--color-gold); }

/* ---- Help & guided tours ---- */

.tour-overlay {
  position: fixed; inset: 0; z-index: 150;
  pointer-events: none; /* read-along: never block the real app */
}
.tour-spotlight {
  position: fixed;
  border-radius: 10px;
  box-shadow: 0 0 0 9999px rgba(10, 24, 48, 0.55);
  transition: top 0.2s ease, left 0.2s ease, width 0.2s ease, height 0.2s ease;
  pointer-events: none;
}
.tour-tip {
  position: fixed; z-index: 151;
  background: var(--color-white);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card-elevated);
  padding: var(--space-4);
  pointer-events: auto;
  max-width: 340px;
}
.tour-tip-head { display: flex; align-items: center; }
.tour-step-count { font-size: 11px; font-weight: 600; letter-spacing: 0.08em; color: var(--color-text-tertiary); }
.tour-x { background: none; border: none; cursor: pointer; color: var(--color-text-tertiary); font-size: 14px; padding: 0; }
.tour-body { font-size: 14px; color: var(--color-text-secondary); line-height: 1.5; }
.tour-tip-foot { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-4); }

.help-tour-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.help-tour-card {
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-button);
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  transition: box-shadow 0.12s ease, border-color 0.12s ease;
  display: flex; flex-direction: column; gap: 2px;
}
.help-tour-card:hover { box-shadow: var(--shadow-card); border-color: var(--color-gold); }
/* Navy, not gold-dark: gold-dark text on white is 3.3:1, under WCAG AA (P3 gate PD11). */
.help-tour-go { color: var(--color-navy); font-size: 13px; font-weight: 600; margin-top: 4px; }

.help-article { border-bottom: 1px solid var(--color-table-row-border); padding: 4px 0; }
.help-article > summary {
  cursor: pointer; font-weight: 600; color: var(--color-navy);
  padding: 6px 0; list-style: none;
}
.help-article > summary::-webkit-details-marker { display: none; }
.help-article > summary::before { content: '▸ '; color: var(--color-text-tertiary); }
.help-article[open] > summary::before { content: '▾ '; }

.help-nudge {
  position: fixed; left: 50%; bottom: var(--space-6); transform: translateX(-50%);
  z-index: 140;
  display: flex; align-items: center; gap: var(--space-3);
  background: var(--color-white);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-card-elevated);
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-5);
  font-size: 14px; color: var(--color-navy);
  max-width: 92vw;
}

@media (max-width: 640px) {
  .help-tour-grid { grid-template-columns: 1fr; }
}
