/* --- Design tokens (issue #355, direction #354) --------------------------- */
/* One token sheet replacing the hardcoded hexes that had accumulated since
   issue #36 (seventeen greys, two competing "active" blues). Rules:
   - components reference tokens only -- never a raw hex below this block;
   - ONE accent (deep teal), replacing both #2a5db0 and #2563eb;
   - semantic status colours (ok / warn / stop) are never the accent, so
     "selected" can never be misread as "healthy" or vice versa;
   - the warm paper ground generalizes the board's existing #fbf6f0 identity
     (kept as --board-paper for the surfaces that had it);
   - dark theme redefines tokens only, opt-in via [data-theme="dark"] (#373);
   - print keeps its literal white/black (see the @media print block). */
:root {
  color-scheme: light;

  --ground: #faf8f3; /* app background: warm paper */
  --surface: #ffffff; /* cards, panels, the sidebar */
  --chip: #f1ede3; /* muted fills: table heads, quiet panels, badges */
  --board-paper: #fbf6f0; /* the board's warm paper (notes, overlay editor) */

  --ink: #26221b; /* primary text */
  --ink-soft: #5d564a; /* secondary text, quiet labels */
  --line: #e5dfd2; /* borders, rules, grid lines */

  --accent: #1f5f5b; /* the one accent: selection, primary actions, links */
  --accent-soft: #e3efed; /* accent wash: active nav, selected fills */
  --accent-contrast: #ffffff; /* text on solid accent */

  --ok: #2e7d43;
  --ok-soft: #e5f2e8;
  --warn: #9a5a10; /* attention: stale, placeholder, seeded, overlay */
  --warn-soft: #faf0dd;
  --stop: #b3261e; /* blocked / error / food-safety marker */
  --stop-soft: #f9e7e5;

  /* Promo weeks (issue #177) keep a colour deliberately distinct from the
     accent, the overlay warn, and every status colour -- the badge must never
     read as any of them. */
  --promo: #7c3aed;

  --shadow: 0 1px 2px rgba(38, 34, 27, 0.06);
  --shadow-1: 0 1px 2px rgba(38, 34, 27, 0.06);
  --shadow-2: 0 8px 24px rgba(38, 34, 27, 0.07);
  /* Table row hover (issue #361): an ink-based wash, so it tracks the theme
     without ever colliding with a semantic fill like .row-focused. */
  --row-hover: rgba(38, 34, 27, 0.045);

  /* Ink for content ON a run block's pastel fill (labels.ts category/allergen
     swatches) -- the fills do not change with the theme, so neither may the
     text on them; the theme ink is light in dark mode and vanished on them. */
  --on-fill: #26221b;
  --on-fill-soft: rgba(38, 34, 27, 0.72);

  --font-ui: "Source Sans 3", "Source Sans Pro", system-ui, -apple-system, sans-serif;
  --font-display: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif;
  --font-mono: "Source Sans 3", ui-monospace, "SFMono-Regular", Menlo, monospace;

  --text-xs: 0.6875rem;
  --text-sm: 0.8125rem;
  --text-md: 0.9375rem;
  --text-lg: 1.125rem;
  --text-xl: 1.375rem;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2.25rem;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;

  --sidebar: 15.25rem;
  --header-h: 3.6rem;
}

/* Dark tokens (issue #373): opt-in only, via an explicit data-theme attribute
   a future toggle may set -- never inferred from the OS. The planner screen's
   designed identity is the warm-paper light theme above; an OS dark preference
   silently overriding it made the text near-unreadable. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --ground: #1b1916;
  --surface: #242019;
  --chip: #2e2a22;
  --board-paper: #2a2620;

  --ink: #ece7dc;
  --ink-soft: #a89f8f;
  --line: #3a352c;

  --accent: #6fb3ad;
  --accent-soft: #203330;
  --accent-contrast: #1b1916;

  --ok: #7cc28d;
  --ok-soft: #223526;
  --warn: #e0a95e;
  --warn-soft: #392c17;
  --stop: #e2867f;
  --stop-soft: #3d221f;

  --promo: #a78bfa;

  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 10px 28px rgba(0, 0, 0, 0.35);
  --row-hover: rgba(236, 231, 220, 0.06);
}

html {
  hanging-punctuation: first last;
}

body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--text-md);
  line-height: 1.45;
  font-feature-settings: "ss01", "tnum";
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--ground);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --- Shared component treatment (issue #361, direction #354) -------------- */
/* One base layer for headings, form controls, buttons, cards and disclosures,
   replacing the per-view one-offs that had accumulated since #36. Everything
   here is deliberately low-specificity (`:where()` where an element selector
   would otherwise out-rank an existing class rule), so every per-view rule
   below this block still wins unchanged. */

/* Section rhythm: one heading scale. Per-component heading rules (sidebar,
   status cards, publish lead) carry class specificity and still override. */
h1 {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

h2 {
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 1.6rem 0 0.6rem;
}

h3 {
  font-size: 0.95rem;
  font-weight: 600;
  margin: 1.2rem 0 0.4rem;
}

/* Cards never open with a heading's section-gap above it. */
:is(
    .explanation-card,
    .trust-panel,
    .data-health-panel,
    .gate-panel,
    .ingest-slot,
    .status-card,
    .publish-lead,
    .what-if,
    .ingest-report,
    .overlay-editor,
    .replan-review,
    .warning-banner,
    .conflict-banner
  )
  > :first-child {
  margin-top: 0;
}

/* The shared card surface: what .publish-lead and the status-strip cards
   already used, now one rule. Per-card blocks below keep only their own
   padding/margins; .status-card-warn/.status-card-stop still re-tone
   border/background because they come later at equal specificity. */
.explanation-card,
.trust-panel,
.data-health-panel,
.gate-panel,
.ingest-slot,
.status-card,
.publish-lead,
.what-if {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}

/* Form controls: one treatment for every text-like input, select and
   textarea (date fields included). File inputs are excluded -- they are
   visually hidden behind .file-drop-zone. Zero specificity on purpose:
   compact per-view sizes (.add-note-form, .replan-control) still apply. */
:where(
    input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"]),
    select,
    textarea
  ) {
  font: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.65rem;
  box-sizing: border-box;
}

:where(
    input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"]),
    select,
    textarea
  ):focus-visible {
  border-color: var(--accent);
}

:where(input, select, textarea):disabled {
  opacity: 0.55;
}

::placeholder {
  color: var(--ink-soft);
  opacity: 1;
}

/* Buttons: three tiers. Primary = accent fill, applied to the elements that
   already mean "the main action" (form submits, the named primary classes)
   so no view needed renaming; secondary = the outlined default every bare
   <button> gets; quiet = borderless text for tertiary actions. */
:where(button) {
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.95rem;
  cursor: pointer;
  letter-spacing: 0.01em;
}

:where(button:not(:disabled)):hover {
  border-color: var(--accent);
  color: var(--accent);
}

:where(button):disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

button[type="submit"],
.btn-primary,
.run-week-button,
.publish-primary,
.ingest-run-week-cta button,
.readiness-interstitial-actions button:first-child {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
}

:where(
    button[type="submit"],
    .btn-primary,
    .run-week-button,
    .publish-primary,
    .ingest-run-week-cta button,
    .readiness-interstitial-actions button:first-child
  ):not(:disabled):hover {
  border-color: var(--accent);
  color: var(--accent-contrast);
  filter: brightness(1.07);
}

.btn-secondary {
  background: var(--surface);
  border-color: var(--line);
  color: var(--ink);
}

.btn-quiet {
  background: transparent;
  border-color: transparent;
  color: var(--accent);
}

.btn-quiet:not(:disabled):hover {
  background: var(--accent-soft);
  border-color: transparent;
  color: var(--accent);
}

/* Compact buttons inside dense grids (board run blocks, table row actions):
   the base padding above would balloon row heights. */
.run-block-actions button,
.plan-actions button,
.add-note-actions button,
td button {
  font-size: 0.75rem;
  padding: 0.15rem 0.5rem;
}

/* Focus is always visible, always the accent ring (issue #361). Author
   origin beats the UA default even at zero specificity. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Disclosures read as interactive everywhere: What do I need?, Explore a
   what-if, the report sections. Class-level colours still override. */
:where(summary) {
  cursor: pointer;
  font-weight: 600;
  color: var(--accent);
}

/* Guidance + outcome lines shared by every form. These classes predate the
   token sheet and were never styled: hints were indistinguishable from body
   copy, and outcome lines carried no colour at all. */
.hint {
  color: var(--ink-soft);
  font-size: 0.85rem;
  max-width: 65ch;
}

.edit-result {
  color: var(--ok);
  font-size: 0.9rem;
}

/* A blocking gate finding nested inside a saved-outcome line: stop-toned so
   it never inherits .edit-result's success green. */
.gate-blocked {
  color: var(--stop);
}

.edit-rejected {
  color: var(--stop);
  font-size: 0.9rem;
}

.empty {
  color: var(--ink-soft);
  font-style: italic;
}

/* Any transition added by this polish respects reduced-motion by being
   defined only when motion is allowed. */
@media (prefers-reduced-motion: no-preference) {
  a,
  button,
  input,
  select,
  textarea,
  summary,
  .file-drop-zone,
  .mode-link {
    transition:
      background-color 120ms ease,
      border-color 120ms ease,
      color 120ms ease,
      filter 120ms ease,
      box-shadow 120ms ease;
  }
}

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /* Wraps rather than overflows (issue #496): the row is sticky, so on a narrow
     window a second line is cheaper than a horizontal scrollbar -- and the
     identity on the right must stay reachable at every width. */
  flex-wrap: wrap;
  row-gap: var(--space-2);
  position: sticky;
  top: 0;
  z-index: 20;
  margin: -1.25rem -1.75rem 1rem;
  padding: 0.7rem 1.75rem;
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.solve-id {
  font-family: var(--font-mono);
  color: var(--ink-soft);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
}

.run-week {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  padding: 0;
}

/* .run-week-button is primary via the shared button tiers above (#361). */

.run-week-note {
  color: var(--ink-soft);
  font-size: 0.85rem;
}

.run-week-error {
  color: var(--stop);
  font-size: 0.9rem;
}

.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 1.25rem;
}

.tab {
  padding: 0.45rem 0.75rem 0.5rem;
  text-decoration: none;
  color: var(--ink-soft);
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  border-radius: 0;
  font-weight: 500;
}

.tab:hover {
  color: var(--ink);
  border-color: transparent;
}

.tab-active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

.view-intro {
  color: var(--ink-soft);
  max-width: 68ch;
  font-size: var(--text-sm);
  line-height: 1.5;
  margin: 0 0 1.1rem;
}

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem 1rem;
  margin-bottom: 1rem;
  padding: 0.7rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}

.filters label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.filters select,
.filters input[type="search"] {
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--text-sm);
  font-weight: 500;
  min-width: 10rem;
}

.filters label:has(input[type="checkbox"]) {
  flex-direction: row;
  align-items: center;
  gap: 0.4rem;
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink);
  padding-bottom: 0.15rem;
}

/* The one shared table shape (issue #361): every bare <table> in the app --
   Demand, Exceptions, Scenarios, the parameter forms, reports -- reads the
   same. The two bordered grids (.board-grid, .week-grid) add their own
   borders below; .report-section keeps its tighter print-friendly padding. */
table {
  border-collapse: collapse;
  width: 100%;
  margin-bottom: 1.5rem;
}

th,
td {
  text-align: left;
  padding: 0.45rem 0.6rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.9rem;
}

/* Screen-only: the chip header band, digit alignment and row hover never
   reach paper, so print.css and the @media print block below keep printing
   exactly what they printed before #361. */
@media screen {
  thead th {
    background: var(--chip);
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--ink-soft);
  }

  /* Numeric columns line up without per-view column classes: tabular-nums
     is a no-op on non-digit cells. */
  td {
    font-variant-numeric: tabular-nums;
  }

  tbody tr:hover:not(.row-focused) {
    background: var(--row-hover);
  }
}

.row-focused {
  background: var(--warn-soft);
}

.count {
  color: var(--ink-soft);
  font-weight: normal;
  font-size: 0.9rem;
}

.churn-summary {
  display: flex;
  gap: 2rem;
  margin: 0.5rem 0 1.5rem;
}

.churn-summary dt {
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.churn-summary dd {
  margin: 0;
  font-size: 1.4rem;
  font-weight: 600;
}

.explanation-list {
  list-style: none;
  padding: 0;
}

/* Card surface comes from the shared rule above (#361). */
.explanation-card {
  padding: 0.75rem 1rem;
  margin-bottom: 0.75rem;
}

.explanation-card dt {
  font-weight: 600;
  margin-top: 0.5rem;
}

.explanation-card dd {
  margin: 0.15rem 0 0;
}

.caveat {
  color: var(--warn);
}

.resolve-bar {
  margin: 0 0 1.15rem;
  padding: 0.65rem 0.85rem;
  display: flex;
  gap: 1rem 1.5rem;
  align-items: center;
  flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}

.replan-control {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.replan-control label {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.replan-control input {
  width: 10.5rem;
}

.replan-review {
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  margin-bottom: 1.5rem;
}

.warning-banner {
  border: 1px solid var(--warn);
  background: var(--warn-soft);
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
}

/* A seeded/inferred value the planner has not confirmed (#320 review finding 1):
   same amber family as .warning-banner, so "still a guess" reads the same way
   everywhere it appears. */
.seeded-flag {
  background: var(--warn-soft);
  border: 1px solid var(--warn);
  border-radius: 4px;
  padding: 0.1rem 0.35rem;
  font-size: 0.85rem;
  white-space: nowrap;
}

/* Provenance simply not there (issue #363's cpmShared fix): grey, not amber --
   amber says "still our guess"; this says "no claim either way", and the two
   must not read alike. */
.seeded-flag.cpm-unavailable {
  background: var(--chip);
  border-color: var(--line);
  color: var(--ink-soft);
}

.plan-actions {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
}

.pinned-badge {
  background: var(--accent);
  color: var(--accent-contrast);
  border-radius: 4px;
  padding: 0.1rem 0.4rem;
  font-size: 0.75rem;
}

/* Issue #137: an overlaid SKU-week is always announced, never merged into base
   demand -- the warm attention colour, so a what-if never reads as master data
   (and never as the accent). */
.overlay-badge {
  background: var(--warn);
  color: var(--accent-contrast);
  border-radius: 4px;
  padding: 0.1rem 0.4rem;
  font-size: 0.75rem;
}

/* Issue #177: a promo-flagged SKU-week's badge -- independent of and shown
   alongside the overlay badge above, so a distinct colour from it (and from
   the pinned badge's accent) keeps the two from being read as the same thing. */
.promo-badge {
  background: var(--promo);
  color: var(--accent-contrast);
  border-radius: 4px;
  padding: 0.1rem 0.4rem;
  font-size: 0.75rem;
}

.overlay-none {
  color: var(--ink-soft);
  font-size: 0.85rem;
}

.overlay-editor {
  background: var(--board-paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  margin: 0.5rem 0;
}

.overlay-rows {
  margin-bottom: 0.75rem;
}

.conflict-banner {
  border: 1px solid var(--stop);
  background: var(--stop-soft);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  margin-bottom: 1.5rem;
}

.conflict-sentence {
  font-weight: 600;
}

.conflict-notice {
  color: var(--ink-soft);
  font-size: 0.85rem;
}

/* --- Sidebar shell (issue #132; regrouped by #355) ------------------------ */
.app {
  display: flex;
  max-width: none;
  margin: 0;
  padding: 0;
  min-height: 100vh;
  align-items: stretch;
}

.app-sidebar {
  flex: 0 0 var(--sidebar);
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow-y: auto;
  background: var(--surface);
  border-right: 1px solid var(--line);
  color: var(--ink);
  padding: 1.15rem 0.85rem 1.5rem;
  box-sizing: border-box;
  box-shadow: 1px 0 0 color-mix(in srgb, var(--line) 70%, transparent);
}

.app-sidebar::before {
  content: "";
  display: block;
  height: 3px;
  margin: -1.15rem -0.85rem 1rem;
  background: linear-gradient(90deg, var(--accent) 0%, color-mix(in srgb, var(--accent) 30%, var(--warn)) 100%);
}

.app-sidebar h1 {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 500;
  letter-spacing: -0.03em;
  margin: 0 0 1.35rem 0.55rem;
  color: var(--ink);
}

.app-sidebar nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The three workflow groups (issue #355): THIS WEEK / REFERENCE / SETUP. */
.nav-group {
  margin-bottom: 1.35rem;
}

.nav-group-label {
  font-size: 0.66rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: var(--ink-soft);
  margin: 0 0 0.4rem 0.7rem;
}

.mode-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.42rem 0.65rem 0.42rem 0.55rem;
  margin-bottom: 0.12rem;
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: 500;
  border-left: 3px solid transparent;
}

.mode-link:hover {
  background: var(--chip);
  color: var(--ink);
}

.mode-link-active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
  border-left-color: var(--accent);
}

/* The weekly group's step number (issue #355): the order Clare's week runs. */
.nav-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.2rem;
  height: 1.2rem;
  flex: none;
  border-radius: 999px;
  background: var(--chip);
  color: var(--ink-soft);
  font-size: 0.68rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.mode-link-active .nav-step {
  background: var(--accent);
  color: var(--accent-contrast);
}

.mode-link-label {
  flex: 1 1 auto;
  min-width: 0;
}

/* Status dots (issue #355): presentational summaries of signals the shell
   already holds -- warn is "needs attention", stop is "blocked". Never the
   accent, so an active door and an unhappy door stay distinguishable. */
.nav-dot {
  width: 0.45rem;
  height: 0.45rem;
  flex: none;
  border-radius: 50%;
  box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 16%, transparent);
}

.nav-dot-warn {
  background: var(--warn);
}

.nav-dot-stop {
  background: var(--stop);
}

.app-body {
  flex: 1 1 auto;
  min-width: 0;
  padding: 1.25rem 1.75rem 3.5rem;
  max-width: none;
}

/* --- Plan Board panels + block grid -------------------------------------- */
.panel-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem;
  border-bottom: 1px solid var(--line);
  margin: 0 0 1.1rem;
}

.panel-tab {
  padding: 0.5rem 0.85rem 0.55rem;
  text-decoration: none;
  color: var(--ink-soft);
  border-bottom: 2px solid transparent;
  font-size: var(--text-sm);
  font-weight: 500;
}

.panel-tab:hover {
  color: var(--ink);
}

.panel-tab-active {
  border-bottom-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

.allergen-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.85rem;
  list-style: none;
  padding: 0;
  margin: 0.35rem 0 0;
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.allergen-legend li {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.allergen-swatch {
  display: inline-block;
  width: 0.9rem;
  height: 0.9rem;
  border-radius: 3px;
}

/* Issue #177: the CATEGORY legend, mirroring the allergen legend's shape
   exactly -- a swatch matching each run block's background fill. */
.category-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.85rem;
  list-style: none;
  padding: 0;
  margin: 0.25rem 0 1rem;
  font-size: var(--text-sm);
  color: var(--ink-soft);
}

.category-legend li {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.category-swatch {
  display: inline-block;
  width: 0.9rem;
  height: 0.9rem;
  border-radius: 3px;
  border: 1px solid var(--line);
}

.board-scroll {
  overflow-x: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}

.board-scroll table {
  margin-bottom: 0;
}

.board-filters {
  flex-wrap: wrap;
  margin: 0.75rem 0;
}

.board-grid th,
.board-grid td {
  border: 1px solid var(--line);
  padding: 0.35rem;
  vertical-align: top;
  min-width: 120px;
}

.board-grid thead th,
.board-grid tbody th {
  background: var(--chip);
  position: sticky;
  font-size: 0.85rem;
}

.board-grid thead th:first-child,
.board-grid tbody th {
  left: 0;
  z-index: 1;
}

/* An idle line's spanning cell (issue #377): quiet and italic -- a stated
   fact about the plan, not an alert -- so the row reads as honestly empty
   rather than broken. */
.board-cell-idle {
  font-style: italic;
  color: var(--ink-soft);
}

.run-block {
  border-left: 4px solid var(--ink-soft);
  background: var(--surface);
  box-shadow: var(--shadow);
  padding: 0.35rem 0.4rem;
  margin-bottom: 0.35rem;
  border-radius: 3px;
  font-size: 0.82rem;
  /* The inline category fill (PlanBoardView) is a light pastel in BOTH themes,
     so everything inside uses the fixed on-fill ink, links included. */
  color: var(--on-fill);
}

.run-block a {
  color: var(--on-fill);
  text-decoration: underline;
}

.run-block-focused {
  outline: 2px solid var(--accent);
}

.run-block-name {
  font-weight: 600;
}

.run-block-qty,
.run-block-allergen,
.run-block-category {
  color: var(--on-fill-soft);
  font-size: 0.78rem;
}

.run-block-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.3rem;
}

/* A nudged (pin-target) day differing from the solved day: attention amber,
   since the change is staged, not yet solved. */
.day-override {
  color: var(--warn);
  font-size: 0.78rem;
}

/* --- This Week weekly sheet ---------------------------------------------- */
.this-week-controls {
  display: flex;
  gap: 1rem;
  align-items: center;
  margin-bottom: 1rem;
  padding: 0.65rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.week-sheet {
  margin-bottom: 2.25rem;
}

.week-sheet h2 {
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -0.02em;
  margin: 0 0 0.35rem;
}

.week-grid {
  table-layout: fixed;
}

.week-grid th,
.week-grid td {
  border: 1px solid var(--line);
  padding: 0.35rem;
  vertical-align: top;
  font-size: 0.82rem;
}

.week-grid thead th:first-child,
.week-grid tbody th,
.week-product-grid thead th:first-child,
.week-product-grid tbody th,
.demand-grid thead th:first-child,
.demand-grid tbody th {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--chip);
}

.week-product-grid,
.demand-grid {
  border-collapse: collapse;
}

.week-product-grid th,
.week-product-grid td,
.demand-grid th,
.demand-grid td {
  border: 1px solid var(--line);
  padding: 0.4rem 0.5rem;
  vertical-align: top;
  font-size: 0.82rem;
  min-width: 8.5rem;
}

.week-product-grid thead th,
.demand-grid thead th {
  background: var(--chip);
}

.week-sheet-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  color: var(--ink-soft);
  font-size: 0.85rem;
  margin: 0 0 0.6rem;
}

.week-cycle,
.week-cycle-seeded {
  font-weight: 600;
}

.week-cycle-seeded {
  color: var(--warn);
}

.week-days,
.week-bakeries,
.week-regime,
.week-demand,
.week-planned,
.week-empty {
  color: var(--ink-soft);
  font-size: 0.76rem;
}

.week-bakeries {
  display: flex;
  gap: 0.4rem;
}

.week-regime {
  display: block;
  font-weight: 400;
}

.week-short {
  color: var(--stop);
  font-size: 0.78rem;
}

.week-col-focused,
.week-cell-focused {
  outline: 2px solid var(--accent);
}

.demand-actual {
  background: var(--chip);
  color: var(--ink-soft);
}

.week-run {
  margin-bottom: 0.25rem;
}

.week-run-name {
  display: block;
  font-weight: 600;
}

.week-run-qty {
  display: block;
  color: var(--ink-soft);
  font-size: 0.76rem;
}

.staffing-row th,
.staffing-row td {
  background: var(--chip);
  font-weight: 600;
}

/* --- This Week: wash/swab markers (issue #176, split by #262) and notes -- */
.wash-marker,
.swab-marker {
  display: inline-block;
  background: var(--stop);
  color: var(--accent-contrast);
  border-radius: 4px;
  padding: 0.05rem 0.35rem;
  font-size: 0.7rem;
  font-weight: 600;
  vertical-align: middle;
}

.notes-row th,
.notes-row td {
  background: var(--board-paper);
}

.note-latest {
  margin: 0.3rem 0 0;
  font-size: 0.78rem;
}

.note-text {
  color: var(--ink);
}

.note-author {
  color: var(--ink-soft);
  font-style: italic;
}

.note-empty {
  margin: 0.3rem 0 0;
  color: var(--ink-soft);
  font-size: 0.76rem;
}

.note-history {
  margin-top: 0.2rem;
  font-size: 0.76rem;
}

.note-history ul {
  margin: 0.25rem 0 0;
  padding-left: 1rem;
}

.add-note-toggle {
  margin-top: 0.25rem;
  font-size: 0.72rem;
  padding: 0.05rem 0.4rem;
}

.add-note-form {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin-top: 0.3rem;
  font-size: 0.76rem;
}

.add-note-form input,
.add-note-form textarea {
  font-size: 0.76rem;
  padding: 0.2rem;
}

.add-note-form textarea {
  resize: vertical;
  min-height: 2.5rem;
}

.add-note-actions {
  display: flex;
  gap: 0.4rem;
}

.note-rejected {
  color: var(--stop);
  font-size: 0.72rem;
  margin: 0;
}

.notes-unavailable {
  color: var(--stop);
}

/* --- System health (issue #355: Trust + Data Health merged) --------------- */
.system-health-section {
  margin-bottom: 2rem;
}

/* Card surface comes from the shared rule above (#361). */
.trust-panel,
.data-health-panel,
.gate-panel {
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
}

.gate-findings {
  padding-left: 1.2rem;
}

.severity-blocking {
  color: var(--stop);
}

.severity-warning {
  color: var(--warn);
}

.register-level-p0 td:first-child {
  border-left: 3px solid var(--stop);
}

/* Reports (issue #144). The Monday pack is the first of parent #133's five
   printable/exportable reports; these styles are the shared foundation the
   other four reuse. */
.report-toolbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.report-section {
  margin-bottom: 1.5rem;
}

.report-section th,
.report-section td {
  text-align: left;
  padding: 0.25rem 0.75rem 0.25rem 0;
}

/* An explicit "insufficient history / no data recorded" state (ADR 0032
   extended to reports) -- deliberately muted and italic so a reviewer reads it
   as an absence of data, never mistakes it for a real (shrunken) figure. */
.insufficient-data {
  color: var(--ink-soft);
  font-style: italic;
}

/* A report section's own caveat line (placeholder valuations, "cells absent
   are within corridor", trend-unit notes) -- quieter than body text but
   upright, so it reads as a real annotation rather than missing data. */
.report-note {
  color: var(--ink-soft);
  font-size: 0.9rem;
}

/* The insights narrative (parent #133): generated commentary, always visibly
   labelled as such -- never presentable as a planner's own words. */
.narrative-panel {
  border: 1px solid var(--line);
  border-left: 4px solid var(--warn);
  padding: 0.5rem 1rem;
  background: var(--board-paper);
}

.generated-badge {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--warn);
  border: 1px solid var(--warn);
  border-radius: 3px;
  padding: 0.1rem 0.35rem;
  vertical-align: middle;
}

.narrative-panel .citation {
  color: var(--ink-soft);
  font-size: 0.8rem;
}

/* Cover-vs-corridor deviation rows (Service & risk report). */
.cover-below td {
  color: var(--stop);
}

.cover-above td {
  color: var(--warn);
}

/* The repo's first print stylesheet (issue #144): one report per printed
   page, no screen chrome. Kept minimal and generic so every parent-#133 report
   built on `.report`/`.report-section` prints consistently. Literal
   white-on-paper on purpose: print output never follows the screen theme. */
@media print {
  body {
    background: #fff;
  }

  .app {
    max-width: none;
    margin: 0;
    padding: 0;
  }

  /* Hide all interactive screen chrome -- nav tabs, the app header, the
     re-solve bar, and the report's own export button never belong on paper. */
  .tabs,
  .app-header,
  .resolve-bar,
  .report-toolbar {
    display: none;
  }

  /* One report per page; never split a section across a page boundary. */
  .report {
    page-break-after: always;
  }

  .report-section {
    break-inside: avoid;
    page-break-inside: avoid;
  }
}

/* --- File Ingestion (issue #208; card + drop-zone treatment #361) --------- */
/* Card surface comes from the shared rule above (#361). */
.ingest-slot {
  padding: 1rem 1.2rem 1.1rem;
  margin-bottom: 1.25rem;
}

.ingest-slot h2 {
  margin-top: 0;
}

.ingest-slot label {
  display: block;
  margin: 0.5rem 0;
  font-size: 0.85rem;
  font-weight: 600;
}

/* The slot's "What do I need?" disclosure -- a quiet inset panel, its summary
   accent-toned by the shared summary rule above. */
.ingest-help {
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--ground);
  padding: 0.45rem 0.8rem;
  margin: 0.6rem 0 0.9rem;
}

.ingest-help > summary {
  font-size: 0.85rem;
}

.file-drop-field {
  margin: 0.5rem 0 0.75rem;
}

/* The styled drop zone (#361): the dashed target the visually-hidden native
   input sits behind. The -active class is toggled by the component's existing
   drag handlers -- unchanged since #208. */
.file-drop-zone {
  position: relative;
  border: 1.5px dashed var(--ink-soft);
  border-radius: 8px;
  padding: 0.9rem 1rem;
  background: var(--ground);
  font-size: 0.85rem;
}

.file-drop-zone:hover {
  border-color: var(--accent);
}

.file-drop-zone-active {
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* The native input stays in the tree -- focusable and label-associated --
   but visually hidden behind the zone. Never display:none: that would drop
   it from the tab order and the accessibility tree. */
.file-drop-zone input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Keyboard focus on the hidden input lights the zone's ring instead. */
.file-drop-zone:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* label.file-drop-prompt ties .ingest-slot label's specificity and, being
   later, wins -- the prompt must not inherit the field-label bolding. */
label.file-drop-prompt {
  display: block;
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.85rem;
  font-weight: 400;
  cursor: pointer;
}

.file-drop-browse {
  color: var(--accent);
  font-weight: 600;
  text-decoration: underline;
}

/* The chosen filename, shown prominently in the zone itself -- the planner's
   only confirmation the file "took" now the native control is hidden. */
.file-drop-name {
  color: var(--ink);
  font-weight: 600;
  font-size: 0.95rem;
  overflow-wrap: anywhere;
}

/* The slot's date fields, aligned in one compact row (#361). */
.ingest-dates {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  margin: 0.75rem 0;
}

.ingest-dates label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0;
}

.ingest-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

.ingest-report {
  margin-top: 0.75rem;
  padding: 0.6rem 0.75rem;
  background: var(--chip);
  border-radius: 6px;
  font-size: 0.85rem;
}

.ingest-report pre {
  white-space: pre-wrap;
  font-size: 0.78rem;
}

.ingest-run-week-cta {
  margin-top: 0.75rem;
}

/* .ingest-run-week-cta button is primary via the shared button tiers (#361). */

/* --- Plan Board status strip (issue #357, direction #354) ----------------- */
/* Four cards + at most one "do this next" banner, replacing issue #229's
   readiness banner on the board (its Load data door and truthful copy live
   on in the Data card). Card tones are the semantic status tokens only --
   never the accent, so "needs attention" can never read as "selected". */
.status-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11.25rem, 1fr));
  gap: 0.55rem;
  margin-bottom: 0.75rem;
}

/* Card surface comes from the shared rule above (#361). */
.status-card {
  padding: 0.7rem 0.85rem 0.75rem;
  border-left-width: 3px;
}

.status-card h3 {
  margin: 0 0 0.2rem;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.status-card-verdict {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.status-card-detail {
  margin: 0.3rem 0 0;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: 1.35;
}

.status-card-footer {
  margin: 0.45rem 0 0;
  font-size: var(--text-sm);
}

.status-card-ok {
  border-left-color: var(--ok);
}

.status-card-ok .status-card-verdict {
  color: var(--ok);
}

.status-card-warn {
  border-color: var(--warn);
  border-left-color: var(--warn);
  background: var(--warn-soft);
}

.status-card-warn .status-card-verdict {
  color: var(--warn);
}

.status-card-stop {
  border-color: var(--stop);
  border-left-color: var(--stop);
  background: var(--stop-soft);
}

.status-card-stop .status-card-verdict {
  color: var(--stop);
}

.do-next-banner {
  border: 1px solid var(--warn);
  border-left-width: 4px;
  background: var(--warn-soft);
  border-radius: var(--radius);
  padding: 0.7rem 1rem;
  margin: 0 0 1.1rem;
  font-size: var(--text-sm);
  line-height: 1.45;
}

.do-next-stop {
  border-color: var(--stop);
  background: var(--stop-soft);
}

/* --- Exceptions triage (issue #357 quick win c) --------------------------- */
.exception-summary {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.1rem;
  padding: 0;
  margin: 0 0 0.75rem;
  font-size: 0.9rem;
}

/* Cursor + weight + accent come from the shared summary rule above (#361). */
details.exception-section > summary {
  padding: 0.35rem 0;
}

/* --- Data readiness (issue #229) ------------------------------------------ */
.readiness-interstitial {
  border: 1px solid var(--stop);
  background: var(--stop-soft);
  border-radius: 6px;
  padding: 0.75rem 1rem;
  margin-bottom: 1.5rem;
}

.readiness-interstitial-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* The interstitial's buttons take the shared tiers (#361): proceed
   (first-child) is in the primary group above, dismiss is the secondary
   default every bare button gets. */

/* --- Publish lead + what-if fold (issue #359, direction #354) ------------- */

/* Card surface comes from the shared rule above (#361). */
.publish-lead {
  padding: 1rem 1.2rem 1.1rem;
  margin: 0 0 1.1rem;
}

.publish-lead h2 {
  margin: 0 0 0.15rem;
}

.publish-lead-context {
  color: var(--ink-soft);
  font-size: 0.82rem;
  margin: 0 0 0.8rem;
}

.publish-refusal {
  background: var(--stop-soft);
  border: 1px solid var(--stop);
  border-radius: 7px;
  padding: 0.6rem 0.8rem;
  margin: 0 0 0.8rem;
}

.publish-refusal-ack {
  background: var(--warn-soft);
  border-color: var(--warn);
}

.publish-refusal-ack p {
  margin: 0 0 0.4rem;
}

.publish-lead-controls {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
}

/* .publish-primary is primary via the shared button tiers (#361); the
   what-if card surface and its summary's accent affordance come from the
   shared card + summary rules above. */
.what-if {
  padding: 0.6rem 0.9rem;
  margin: 0 0 1.2rem;
}

/* --- Parameters shelves (issue #359) -------------------------------------- */

.parameter-shelf {
  margin-bottom: 0.4rem;
}

.shelf-label {
  font-size: 0.68rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ink-soft);
  margin: 0.8rem 0 0.3rem;
}

.run-order-sections section + section {
  margin-top: 1.4rem;
  border-top: 1px solid var(--line);
  padding-top: 1rem;
}

/* --- Sign-in and the user chip (issue #480) ------------------------------- */
/* Two blocks only. The login screen renders outside the shell, so it has no
   layout to inherit; the chip sits under the nav in the sidebar footer.
   Everything else this feature adds -- the user roster, the account form --
   reuses the existing table and form language on purpose, so User management
   looks like the rest of Setup rather than like a bolt-on. */

.login-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: var(--ground);
}

.login-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.6rem 1.8rem 1.8rem;
  width: min(23rem, 90vw);
}

/* The card has to carry its own field layout (issue #490). The parameter tabs
   use the same bare `<label>Text<input/></label>` markup and read fine, because
   they are wide single rows where inline flow *is* the intended shape. Inside a
   23rem card that same default wrapped "Username [input] Password" onto one line
   with the button beside the password box -- the first screen anyone sees. The
   stacking below is `.filters label`'s, which is what gives the Plan Board its
   HORIZON/PRODUCT/LINE fields; this is the app's field language, not a new one. */
.login-card form {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin-top: 1.2rem;
}

.login-card label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.login-card input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.45rem 0.55rem;
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}

.login-card button[type="submit"] {
  width: 100%;
  padding: 0.5rem;
  margin-top: 0.15rem;
}

/* Both live in the card's flow rather than beside a field, so they need the
   card's own spacing -- `.edit-rejected` assumes a form row above it. */
.login-card p[role="alert"] {
  margin: 0;
  color: var(--stop);
  font-size: var(--text-sm);
}

/* --- Signed-in identity, top right of the header (issue #496) -------------- */
/* This was `.user-chip` in the sidebar footer, styled as quiet small text
   under the nav -- which is how an administrator concluded the site had no
   logout at all. The treatment here is the correction: still quiet in weight
   (nothing may compete with the primary Run action on the left, or with the
   red brand mark in the sidebar), but the sign-out carries a real border so it
   reads as a control rather than a caption. A vertical rule separates the
   identity from the solve id beside it: one is context, the other is a pair of
   things you can do. */
.header-right {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  /* Keeps the group in the corner when the header wraps -- `space-between` puts
     a lone item on a wrapped line at its start, which is the wrong edge. */
  margin-left: auto;
}

.header-identity {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  row-gap: var(--space-1);
  /* Nothing inside breaks mid-phrase ("Your acc / ount"), but the three items
     will stack rather than run off the edge -- at a window narrow enough for
     that the sidebar has already taken most of the width, and a reachable
     sign-out matters more than a single-line header. */
  flex-wrap: wrap;
  white-space: nowrap;
  font-size: var(--text-sm);
}

/* The rule is drawn only when there is actually something on its other side --
   no bundle loaded yet, or a narrow window (below), and it would otherwise hang
   in empty space. */
.solve-id + .header-identity {
  padding-left: var(--space-3);
  border-left: 1px solid var(--line);
}

.header-identity-name {
  font-weight: 600;
  color: var(--ink);
}

.header-identity-link {
  color: var(--ink-soft);
  font-size: var(--text-xs);
}

/* `.btn-quiet` supplies the accent text and the accent-soft hover; the base
   button padding is sized for a primary action and would make this the tallest
   thing in the header row, so it is tightened -- and given back the line border
   `.btn-quiet` drops, which is what stops it reading as a caption again. */
.header-identity-signout {
  padding: 0.28rem 0.6rem;
  font-size: var(--text-sm);
  border-color: var(--line);
}

.header-identity-signout:not(:disabled):hover {
  border-color: var(--accent);
}

/* Narrow windows: the identity is a control and must never be the thing that
   gets squeezed, so the solve id yields instead. Nothing is lost -- System
   health's Provenance panel names the same solve id, and every report header
   repeats it. (The header itself wraps rather than overflowing; see
   `.app-header`.) */
@media (max-width: 56rem) {
  .app-header .solve-id {
    display: none;
  }

  /* Hidden, not removed -- so the separator rule above still matches and has to
     be switched off with it. */
  .app-header .solve-id + .header-identity {
    padding-left: 0;
    border-left: 0;
  }
}

/* --- Placeholder register (issue #493) ------------------------------------ */
/* The register is a parse of docs/DATA_REGISTER.md, so its two prose columns
   carry paragraphs an engineer wrote, not the short values the app's other
   tables hold. Left to the shared table shape they squeeze `#` and Priority to
   nothing and run the prose edge to edge. Fixed widths put the reading columns
   where the eye expects them and keep the row height honest. */
.placeholder-register table {
  table-layout: fixed;
  width: 100%;
}

.placeholder-register th:nth-child(1),
.placeholder-register td:nth-child(1) {
  width: 3rem;
}

/* The item is the sentence a reader starts on, so it gets the width; the
   placeholder beside it is usually a short verdict. Both are sized explicitly
   because `table-layout: fixed` would otherwise split the remaining space
   evenly and leave the long column cramped next to a half-empty one. */
.placeholder-register th:nth-child(2),
.placeholder-register td:nth-child(2) {
  width: 46%;
}

.placeholder-register th:nth-child(3),
.placeholder-register td:nth-child(3) {
  width: auto;
}

.placeholder-register th:nth-child(4),
.placeholder-register td:nth-child(4) {
  width: 8.5rem;
}

.placeholder-register td {
  vertical-align: top;
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.45;
}

/* Identifiers and paths lifted from the document. Quiet, not loud: the register
   is read for its verdicts, and a wall of highlighted code would bury them. */
.placeholder-register code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: 0.88em;
  background: var(--chip);
  border-radius: 3px;
  padding: 0.05em 0.25em;
}

/* --- Brand mark (Kez's Kitchen logo) -------------------------------------- */
/* The customer's own logo, used in their own tool: it identifies whose plan this
   is at a glance, which matters on a screen a planner keeps open all day beside
   half a dozen other tabs. The mark is a red circular badge and the app's accent
   is green, so it is deliberately kept small and given room rather than tinted
   or recoloured -- a brand mark is not ours to restyle. `alt=""` throughout: the
   wordmark beside it already carries the name, so announcing it twice is noise
   to a screen reader. */
.brand {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.brand img {
  flex: 0 0 auto;
  object-fit: contain;
}

/* The login card stacks and centres: the mark leads, the name sits under it, both
   on the card's axis. The fields below stay left-aligned -- centred labels above
   left-aligned inputs read as a mistake, and a form is read down its left edge. */
.brand-stacked {
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  text-align: center;
}

/* The card's own header block: the mark, the name and the one line under them
   share the centre line, and the form starts the left-aligned part of the card. */
.login-card > .hint {
  text-align: center;
  margin-bottom: 0.2rem;
}

/* --- Manual (issue #506) --------------------------------------------------- */
/* The seven-step list reuses the sidebar's own step-badge language (a filled
   circle with the step number) so the manual visually rhymes with the nav it
   is explaining, rather than inventing a second numbering style. */
.help-steps {
  list-style: none;
  margin: 1.2rem 0 1.6rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.3rem;
}

.help-step {
  display: flex;
  gap: 0.9rem;
  align-items: flex-start;
}

.help-step-badge {
  flex: 0 0 auto;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.85rem;
}

.help-step-body h3 {
  margin: 0 0 0.15rem;
  font-size: 1.02rem;
}

.help-step-body p {
  margin: 0.35rem 0;
}

/* Question cards reuse the seeded/unconfirmed amber (`--warn`) that already
   marks a guessed value everywhere else in the app -- these ARE guesses, the
   same kind, just about how the week runs rather than about one product. */
.help-qcard {
  border: 1px solid var(--warn);
  background: var(--warn-soft);
  border-radius: 8px;
  padding: 0.7rem 1rem;
  margin: 0.7rem 0;
}

.help-qcard summary {
  cursor: pointer;
  font-weight: 600;
}

.help-qcard p {
  margin: 0.6rem 0;
}

.help-qoptions {
  list-style: none;
  margin: 0.5rem 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.help-qletter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  font-size: 0.7rem;
  font-weight: 700;
  margin-right: 0.3rem;
}

.help-qwhere {
  font-size: var(--text-xs);
  color: var(--ink-soft);
  border-top: 1px dashed var(--line);
  padding-top: 0.5rem;
  margin-top: 0.5rem !important;
}
/* Print-to-PDF rules for This Week's weekly plan sheet (issue #132), the same
 * browser print-to-PDF doctrine as #133. A4 landscape, one page per week. Type
 * is held at a clipboard-readable minimum; if a zone-week genuinely cannot stay
 * legible on one page, the acceptable fallback is one page per zone -- never
 * shrinking below the sizes set here. */

@media print {
  @page {
    size: A4 landscape;
    margin: 10mm;
  }

  /* Everything outside the printed sheet is chrome -- hide it. */
  .app-header,
  .app-sidebar,
  .panel-tabs,
  .resolve-bar,
  .conflict-banner,
  .status-strip-wrap,
  .filters,
  .no-print {
    display: none !important;
  }

  body,
  .app,
  .app-main,
  main {
    margin: 0;
    padding: 0;
    background: #fff;
    color: #000;
  }

  /* One week per page. */
  .week-sheet {
    page-break-after: always;
    break-after: page;
  }
  .week-sheet:last-of-type {
    page-break-after: auto;
    break-after: auto;
  }

  .week-sheet h2 {
    font-size: 14pt;
    margin: 0 0 4mm 0;
  }

  .week-grid,
  .week-product-grid {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
  }

  .week-product-grid {
    page-break-after: always;
    break-after: page;
  }

  .week-grid th,
  .week-grid td {
    border: 0.5pt solid #000;
    padding: 1.1mm 1.5mm;
    font-size: 8pt; /* clipboard-readable floor -- do not go smaller */
    vertical-align: top;
    word-wrap: break-word;
  }

  .week-run {
    display: block;
    margin-bottom: 1mm;
  }
  .week-run-name {
    display: block;
    font-weight: 600;
  }
  .week-run-qty {
    display: block;
    font-size: 7.5pt;
  }

  .staffing-row th,
  .staffing-row td {
    font-weight: 600;
    background: #f0f0f0;
  }

  /* Wash and swab markers (issue #176, split into two independent markers
   * by #262): bordered badges rather than a background colour, so each
   * reads clearly even on a black-and-white print/PDF where background
   * graphics are often disabled by default. Identical styling -- only the
   * trigger condition differs between the two classes. */
  .wash-marker,
  .swab-marker {
    display: inline-block;
    border: 0.5pt solid #000;
    padding: 0 0.5mm;
    font-weight: 700;
  }

  /* The assumed-cartons-per-mix badge (issue #339): on screen it rides the
   * amber .seeded-flag background, but print output disables background
   * graphics by default -- same bordered-black treatment as the wash/swab
   * markers above, so the "Assumed mix size" claim survives on exactly the
   * printed sheet the planner quoted. */
  .cpm-placeholder {
    display: inline-block;
    background: none;
    border: 0.5pt solid #000;
    border-radius: 0;
    padding: 0 0.5mm;
    font-weight: 700;
  }

  /* Notes row/cells: the same grey-background annotation-row treatment as
   * the staffing row. Only the latest entry ever prints (history/add-note
   * controls are `.no-print` and already hidden above). */
  .notes-row th,
  .notes-row td {
    font-weight: 600;
    background: #f0f0f0;
  }

  .note-latest {
    margin: 0 0 1mm 0;
  }

  .note-author {
    font-style: italic;
  }
}
