/*
 * Roux — Brand design tokens & base styles
 * ------------------------------------------------------------
 * Single source of truth for the Roux visual system.
 * Human-readable guidelines: docs/brand-guidelines.md
 *
 * Usage:
 *   <link rel="stylesheet" href="/css/brand.css?v=4e9fdc52ac5ac52679727d85525deb1e0ced3e10" />
 * Then use the CSS variables below — do NOT redeclare :root tokens per page.
 * Fonts (load once in <head>):
 *   Cormorant Garamond (display/serif)  +  Inter (UI/sans)
 */

:root {
  /* ── Core palette ── */
  --ink: #1E1E1E;
  --cream: #F6F2E8;
  --copper: #B8734A;
  --copper-hover: #C9845C;
  --sage: #7C8B6B;
  --sage-hover: #8a997a;
  --stone: #A6A69A;

  /* ── Dark UI surfaces ── */
  --bg: #1E1E1E;
  --bg-sidebar: #222222;
  --bg-raised: #272727;
  --bg-input: #2E2E2E;
  --border: #3A3A3A;

  /* ── Semantic / status (status only — never decorative) ── */
  --green: #7AAD6A;
  --amber: #C4A25A;
  --red: #D97B6B;
  --blue: #6A9ABF;

  /* ── Tinted status backgrounds (~12% wash) ── */
  --green-wash: rgba(122,173,106,.12);
  --amber-wash: rgba(196,162,90,.12);
  --red-wash: rgba(217,123,107,.12);
  --copper-wash: rgba(184,115,74,.12);

  /* ── Typography ── */
  --font-display: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --font-ui: 'Inter', system-ui, -apple-system, sans-serif;

  /* ── Radius ── */
  --radius-sm: 5px;
  --radius: 7px;
  --radius-lg: 10px;
  --radius-xl: 12px;

  /* ── App chrome ── */
  --page-header-height: 8.25rem;
  --page-header-primary-action-width: 11rem;
  --empty-state-action-width: 9.5rem;

  /* ── Elevation (soft, low-opacity — surfaces do most of the lifting) ── */
  --shadow: 0 1px 3px rgba(0,0,0,.25);
  --shadow-lg: 0 8px 28px rgba(0,0,0,.35);

  /* ── Actionable controls ──
   * Filled buttons and the avatar use a deep "action green" with cream text.
   * These are theme-STABLE (the same in light and dark) and NOT derived from
   * --copper/--cream, because text on a filled control must always stay light —
   * --cream flips to dark ink in light mode, which would put dark text on the fill.
   * Copper stays the accent for links, active nav and the mark; green is for doing. */
  --btn-bg: #43512F;
  --btn-bg-hover: #526040;
  --btn-fg: #F6F2E8;
}

/* ────────────────────────────────────────────────────────────
 * Theming — dark is the default (the :root tokens above).
 * Light mode is opt-in via <html data-theme="light"> (see web/js/theme.js?v=4e9fdc52ac5ac52679727d85525deb1e0ced3e10).
 *
 * The token *names* never change meaning: --bg is always "page background",
 * --cream is always "primary text", --stone is always "muted text" — only
 * their values flip. Build UI against these variables and both themes work
 * for free. The selector below is (0,2,0) specificity, so it also overrides
 * any per-page :root {} token block that redeclares the dark values.
 * ──────────────────────────────────────────────────────────── */
:root { color-scheme: dark; }

:root[data-theme="light"] {
  color-scheme: light;

  /* ── Core palette (values retuned for a light ground) ── */
  --ink: #1E1E1E;
  --cream: #23201A;        /* primary text — dark ink on light ground */
  --copper: #A25E38;       /* darkened for AA contrast on cream */
  --copper-hover: #8C4F2E;
  --sage: #5E6D4E;
  --sage-hover: #52603F;
  --stone: #6E6656;        /* muted text */

  /* ── Light UI surfaces ── */
  --bg: #FBF8F1;           /* warm off-white */
  --bg-sidebar: #F1EBDD;   /* slightly deeper cream */
  --bg-raised: #FFFFFF;    /* cards lift by getting brighter, not darker */
  --bg-input: #FFFFFF;
  --border: #E5DDCC;

  /* ── Semantic / status (darkened for contrast on light) ── */
  --green: #4E8140;
  --amber: #927126;
  --red: #C1503C;
  --blue: #3E7BA6;

  /* ── Tinted status backgrounds (~12% wash) ── */
  --green-wash: rgba(78,129,64,.12);
  --amber-wash: rgba(146,113,38,.12);
  --red-wash: rgba(193,80,60,.12);
  --copper-wash: rgba(162,94,56,.12);

  /* ── Elevation (warm-grey shadow reads better than black on light) ── */
  --shadow: 0 1px 3px rgba(60,50,35,.12);
  --shadow-lg: 0 8px 28px rgba(60,50,35,.18);
}

/* Smooth the flip between themes without animating layout. */
body { transition: background-color .18s ease, color .18s ease; }
@media (prefers-reduced-motion: reduce) { body { transition: none; } }

/* Author styles must never accidentally override the native hidden contract. */
[hidden] { display: none !important; }

/* Keep signed-in content out of the first paint until its page module and data
   have settled. The sidebar remains visible, so hard loads retain a stable app
   frame; soft navigation keeps showing the previous page via View Transitions. */
html:not([data-app-ready]) aside#sidebar ~ main { visibility: hidden; }

/* ────────────────────────────────────────────────────────────
 * Cross-document view transitions — same-origin navigations crossfade
 * instead of hard-cutting (Chrome/Edge, Safari 18+; unsupported browsers
 * simply load pages normally). The sidebar carries its own name so the
 * browser pairs it across pages and it reads as a persistent shell rather
 * than part of the fade.
 * ──────────────────────────────────────────────────────────── */
@view-transition { navigation: auto; }
aside#sidebar { view-transition-name: app-sidebar; }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* ────────────────────────────────────────────────────────────
 * Form selects — native select chrome ignores vertical padding, so a
 * <select> renders shorter than the <input> beside it. Strip the chrome so
 * selects size exactly like inputs (each page's own padding decides the
 * height) and draw the brand chevron in place of the native arrow.
 * The :not() also lifts specificity above page-level `background:` shorthands
 * so the chevron survives them. Table-module filter controls (.rt-select)
 * manage their own metrics and keep their native arrow.
 * ──────────────────────────────────────────────────────────── */
select:not(.rt-select) {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23A6A69A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .875rem center;
}
:root[data-theme="light"] select:not(.rt-select) {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236E6656' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* ────────────────────────────────────────────────────────────
 * Base helpers — opt-in classes, safe to layer over existing pages
 * ──────────────────────────────────────────────────────────── */

/* Wordmark: elegant serif with the brand letter-spacing */
.roux-wordmark {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: .04em;
}

/* Marquee / page-title serif treatment */
.display {
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: .01em;
  line-height: 1.1;
}

/* Copper small-caps kicker (e.g. "RECIPE INTELLIGENCE") */
.kicker {
  font-family: var(--font-ui);
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: var(--copper);
}

/* Quiet uppercase micro-label (widget/table/form labels) */
.eyebrow {
  font-family: var(--font-ui);
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--stone);
}

/* Shared signed-in page header. Generated by web/js/pageHeader.js?v=4e9fdc52ac5ac52679727d85525deb1e0ced3e10 on every page;
   richer editors provide title and action slots to the same component. */
.page-header:is([data-page-header], [data-page-header-ready]) {
  min-height: var(--page-header-height);
  height: var(--page-header-height);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 1.25rem;
  margin: 0 0 1.25rem;
  padding: .15rem 0 1rem;
  border-bottom: 1px solid var(--border);
  box-sizing: border-box;
  flex: 0 0 auto;
}

/* Declarative headers are upgraded by pageHeader.js. Their final footprint is
   reserved above, but unfinished children stay out of sight so actions cannot
   briefly appear in the wrong grid cell while the module graph downloads. */
.page-header[data-page-header]:not([data-page-header-ready]) > * { visibility: hidden; }

.page-header-copy {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: .36rem;
}

.page-header-breadcrumbs {
  min-height: 1rem;
  display: flex;
  align-items: center;
  gap: .45rem;
  overflow: hidden;
  color: var(--stone);
  font-family: var(--font-ui);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.page-header-crumb {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: inherit;
  text-decoration: none;
}

.page-header-back {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  color: var(--copper);
}

.page-header-back::before {
  content: "←";
  flex: 0 0 auto;
  font-size: .95rem;
  font-weight: 400;
  line-height: 1;
}

.page-header-crumb + .page-header-crumb::before {
  content: "/";
  margin-right: .45rem;
  color: var(--border);
}

a.page-header-crumb:hover { color: var(--cream); }

.page-header-title-row {
  min-width: 0;
  min-height: 2.05rem;
  display: flex;
  align-items: baseline;
  gap: .65rem;
}

.page-header-title {
  min-width: 0;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: 1.85rem;
  font-weight: 500;
  letter-spacing: .01em;
  /* Cormorant's descenders extend beyond a tight line box. Keep enough leading
     for letters such as g, p and y while retaining the single-line ellipsis. */
  line-height: 1.2;
  color: var(--cream);
}

/* Editable record titles keep the same type scale and line box as a regular
   page title, so switching between list and detail pages does not make the
   shared header appear to jump. */
.page-header-title-control {
  font-family: var(--font-display);
  font-size: 1.85rem;
  font-weight: 500;
  letter-spacing: .01em;
  line-height: 1.2;
  color: var(--cream);
}

.page-header-count {
  flex: 0 0 auto;
  color: var(--stone);
  font-family: var(--font-ui);
  font-size: .86rem;
  font-weight: 500;
  white-space: nowrap;
}

.page-header-count:empty { display: none; }

.page-header-description {
  min-height: 2.45rem;
  max-width: 64rem;
  margin: 0;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  color: var(--stone);
  font-family: var(--font-ui);
  font-size: .9rem;
  line-height: 1.36;
}

.page-header-description span { display: block; }

.page-header-actions {
  min-width: max-content;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .55rem;
  flex-wrap: wrap;
}

.page-header-actions:empty { display: none; }

.page-header-actions .btn { white-space: nowrap; }

/* List-page primary actions share a stable footprint. Ghost utility actions
 * (Save, More, View live) keep their compact intrinsic widths. */
.page-header-actions > .btn:not(.btn-ghost):not(.btn-danger):not(.btn-link) {
  width: var(--page-header-primary-action-width);
  justify-content: center;
}

@media (max-width: 760px) {
  .page-header:is([data-page-header], [data-page-header-ready]) {
    height: auto;
    min-height: var(--page-header-height);
    grid-template-columns: 1fr;
    align-items: start;
    gap: .85rem;
    padding-bottom: .9rem;
  }

  .page-header-actions {
    min-width: 0;
    justify-content: flex-start;
  }
}

/* ── Buttons ──
 * Filled/primary buttons use the action-green tokens with cream text in both
 * themes. The `.btn:not(...)` selector below is intentionally higher-specificity
 * than a bare `.btn` so it also restyles pages that declare their own local
 * `.btn { background: var(--copper) }` — one change, every page. Ghost/danger
 * buttons opt out via their modifier class. */
.btn-copper,
.btn:not(.btn-ghost):not(.btn-danger):not(.btn-link) {
  font-family: var(--font-ui);
  font-weight: 500;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bg-hover);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.btn-copper { padding: .7rem 1rem; }
.btn-copper:hover,
.btn:not(.btn-ghost):not(.btn-danger):not(.btn-link):hover { background: var(--btn-bg-hover); border-color: var(--btn-bg-hover); }
.btn-copper:disabled { opacity: .6; cursor: not-allowed; }

.btn-ghost {
  font-family: var(--font-ui);
  font-weight: 500;
  background: transparent;
  color: var(--cream);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s, background .15s, color .15s;
}
.btn-ghost:hover { border-color: var(--stone); background: rgba(128,128,128,.12); color: var(--cream); }
.btn-ghost:disabled { opacity: .55; cursor: not-allowed; }

.btn-outline {
  font-family: var(--font-ui);
  font-weight: 500;
  background: transparent;
  color: var(--cream);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .7rem 1rem;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.btn-outline:hover { border-color: var(--stone); background: rgba(246,242,232,.03); }

/* ── Empty states ──
 * Behaviour and safe DOM construction live in web/js/emptyState.js.?v=4e9fdc52ac5ac52679727d85525deb1e0ced3e10 Pages own
 * only the image, copy and optional actions; layout stays consistent. */
.empty-state-host {
  min-height: clamp(22rem, 58vh, 34rem);
  flex: 1 0 auto;
}

.empty-state {
  width: 100%;
  min-height: inherit;
  display: grid;
  align-content: center;
  justify-items: center;
  padding: 2rem 1.5rem 4rem;
  text-align: center;
}

.empty-state-image {
  display: block;
  width: clamp(14rem, 28vw, 20rem);
  max-width: 72vw;
  aspect-ratio: 4 / 3;
  margin: 0 0 1.1rem;
  object-fit: contain;
}

.empty-state-title {
  margin: 0;
  color: var(--cream);
  font-family: var(--font-display);
  font-size: 1.65rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: .01em;
}

.empty-state-description {
  max-width: 34rem;
  min-height: 2.79rem;
  margin: .55rem 0 0;
  color: var(--stone);
  font-family: var(--font-ui);
  font-size: .9rem;
  line-height: 1.55;
}

.empty-state-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: .6rem;
  margin-top: 1.25rem;
}

.empty-state-action {
  box-sizing: border-box;
  width: var(--empty-state-action-width);
  min-height: 2.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: .6rem 1rem;
  font-size: .875rem;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}

@media (max-width: 760px) {
  .empty-state-host { min-height: 24rem; }
  .empty-state { padding: 1.5rem 1rem 3rem; }
  .empty-state-image { width: min(17rem, 78vw); }
}

/* Compact treatment for older manual tables. New data tables should use
   web/js/table.js?v=4e9fdc52ac5ac52679727d85525deb1e0ced3e10, which carries the same row-height contract internally. */
.table-wrap table { table-layout: fixed; }
.table-wrap tbody tr { height: 52px; max-height: 52px; }
.table-wrap tbody td {
  height: 52px;
  max-height: 52px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}
.table-wrap tbody td.empty {
  height: auto;
  max-height: none;
  white-space: normal;
}
.table-wrap tbody td > * { min-width: 0; max-width: 100%; }
.table-wrap .cell-truncate {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.table-wrap .table-pill-list {
  display: flex;
  align-items: center;
  gap: .3rem;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  flex-wrap: nowrap;
}
.table-wrap .table-pill-list .badge,
.table-wrap .table-pill-list .pill {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 0 1 auto;
}
.table-wrap .table-pill-more { flex: 0 0 auto; cursor: help; }

/* ── Status pills ── */
.pill { display: inline-block; padding: .15rem .55rem; border-radius: 999px; font-size: .7rem; font-weight: 500; font-family: var(--font-ui); }
.pill-green { background: var(--green-wash); color: var(--green); }
.pill-amber { background: var(--amber-wash); color: var(--amber); }
.pill-red   { background: var(--red-wash);   color: var(--red); }
.pill-copper{ background: var(--copper-wash); color: var(--copper); }
.pill-sage  { background: rgba(124,139,107,.14); color: var(--sage); }

/* Tabular numerals for data */
.tnum { font-variant-numeric: tabular-nums; }

/* Masked nav icons let traced artwork inherit active/inactive nav colour. */
.nav-mask-icon {
  display: inline-block;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  background: currentColor;
  mask: var(--nav-icon) center / contain no-repeat;
  -webkit-mask: var(--nav-icon) center / contain no-repeat;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: .125rem;
  padding: .5rem .75rem;
  border-radius: var(--radius);
  color: var(--stone);
  background: transparent;
  font-size: .875rem;
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}

.nav-item:hover { color: var(--cream); background: rgba(128,128,128,.1); }
.nav-item.is-active { color: var(--cream); background: var(--copper-wash); }
.nav-item.is-active .nav-mask-icon { color: var(--copper); }

/* The brand lens is API-backed, but the navigation below it must never move
   when that response arrives. Keep one control-height reserved even for an org
   with no brands, where the slot intentionally remains quiet and empty. */
.brand-switcher-slot {
  min-height: 2.0625rem;
  margin-bottom: 1rem;
}

/* ────────────────────────────────────────────────────────────
 * Record-detail chrome — the shared furniture of a detail page.
 * Behaviour lives in web/js/recordChrome.js?v=4e9fdc52ac5ac52679727d85525deb1e0ced3e10; the page pattern is
 * documented in docs/data-detail-pattern.md.
 *
 * menu.html predates this block and declares its own identical copies
 * locally (its <style> wins by cascade order); fold it in when next touched.
 * ──────────────────────────────────────────────────────────── */

/* Status chip — quiet state next to the record title ("Unsaved changes"). */
.chip { display: inline-flex; align-items: center; gap: .35rem; font-family: var(--font-ui); font-size: .72rem; font-weight: 500; padding: .15rem .55rem; border-radius: 99px; border: 1px solid var(--border); color: var(--stone); white-space: nowrap; }
.chip .dot { width: .5rem; height: .5rem; border-radius: 50%; background: var(--stone); }
.chip.live { color: var(--green); border-color: transparent; background: var(--green-wash); }
.chip.live .dot { background: var(--green); }
.chip.edited { color: var(--amber); border-color: transparent; background: var(--amber-wash); }
.chip.edited .dot { background: var(--amber); }

/* Save feedback. The record stays on screen; the toast is the only confirmation. */
#toast { position: fixed; bottom: 1.2rem; right: 1.2rem; background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: .7rem 1rem; font-family: var(--font-ui); font-size: .87rem; color: var(--cream); box-shadow: var(--shadow-lg); opacity: 0; transform: translateY(8px); transition: opacity .25s ease, transform .25s ease; pointer-events: none; max-width: 26rem; z-index: 300; }
#toast.show { opacity: 1; transform: none; }
#toast.error { border-color: var(--red); }
@media (prefers-reduced-motion: reduce) { #toast { transition: none; } }

/* `⋯` secondary record actions. */
#more-menu { position: fixed; z-index: 200; display: none; min-width: 180px; background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: .25rem; }
#more-menu button { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--cream); font-family: var(--font-ui); font-size: .85rem; padding: .45rem .6rem; border-radius: var(--radius-sm); cursor: pointer; }
#more-menu button:hover { background: rgba(128,128,128,.14); }
#more-menu button.danger:hover { background: var(--red-wash); color: var(--red); }
#more-menu button:disabled { color: var(--stone); cursor: not-allowed; }
#more-menu .split { border-top: 1px solid var(--border); margin: .25rem 0; }

/* Task tabs. Copper marks the active tab (interaction/brand), never a fill. */
.tabs { display: flex; gap: .25rem; align-items: center; border-bottom: 1px solid var(--border); }
.tabs [role="tab"] { display: inline-flex; align-items: center; gap: .4rem; background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; color: var(--stone); font-family: var(--font-ui); font-size: .8125rem; font-weight: 500; padding: .55rem .8rem; cursor: pointer; }
.tabs [role="tab"]:hover { color: var(--cream); }
.tabs [role="tab"][aria-selected="true"] { color: var(--copper); border-bottom-color: var(--copper); }
.tabs [role="tab"]:focus-visible { outline: 2px solid var(--copper); outline-offset: -2px; border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.tab-state { font-size: .6875rem; font-variant-numeric: tabular-nums; color: var(--stone); }
.tab-state.attention { width: .45rem; height: .45rem; border-radius: 50%; background: var(--amber); }
.panel[hidden] { display: none; }
