:root {
  --bg: #f5f7f4;
  --surface: #ffffff;
  --ink: #1f2933;
  --muted: #6b7a85;
  --brand: #2f7d4f;
  --brand-2: #195e3a;
  --accent: #3b6fb4;
  --warn: #b04848;
  --chip-bg: #e8efe9;
  --border: #e3e7e3;
  --radius: 14px;
  --shadow: 0 1px 3px rgba(10,30,20,.06), 0 4px 18px rgba(10,30,20,.05);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, sans-serif;
}
* { box-sizing: border-box; }
html, body { margin: 0; background: var(--bg); color: var(--ink); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  /* Match the visual edge of the cards below: `main` is 1180px wide with
   * 18px inner padding, so its card surfaces start at 1144px. Aligning the
   * topbar to the same 1144px width (and dropping the full-bleed bottom
   * border in favour of a rounded `.card`-style box) makes the topbar feel
   * like just another element in the column rather than a banner. */
  max-width: 1144px; margin: 14px auto 0;
  /* Match the content card geometry at every width: centered + capped at
   * 1144px on wide screens, and an 18px gutter on each side once the viewport
   * gets narrow (mirrors `main`'s 18px horizontal padding). `calc(100% - 36px)`
   * also pins an explicit width so the bar doesn't collapse to its content
   * width on the Assistant page, where `body.body-chat` turns it into a flex
   * item (auto side-margins would otherwise shrink it). */
  width: calc(100% - 36px); box-sizing: border-box;
  padding: 14px 22px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 18px; color: var(--brand-2); }
.brand-by { font-weight: 500; opacity: 0.6; font-size: 14px; }
.logo { font-size: 22px; }
.logo-img { width: 28px; height: 28px; border-radius: 6px; object-fit: cover; }
/* Desktop nav: flex row so the inline-flex anchors and the taller
   user-menu pill (avatar 28px + padding) all share the same vertical
   centre line. Without explicit flex on <nav>, the children mix
   inline-block / inline-flex baselines and the user pill drifts up
   relative to the icon labels. */
.topbar nav { display: flex; align-items: center; }
.topbar nav a { margin-left: 18px; color: var(--ink); font-weight: 500;
  display: inline-flex; align-items: center; gap: 6px; }
.topbar nav a:hover { color: var(--brand); }
.navicon { width: 18px; height: 18px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
  vertical-align: -3px; }

/* Intermediate breakpoint: when the labels would push the nav past the
   available width (tablets, narrow desktop windows, HA sidebar-cramped
   ingress views), hide the text and the user-menu name but keep the
   whole bar on one row. Below 560px we additionally wrap the nav onto
   its own line (rule further down). 900px was picked empirically — 7
   icon labels + brand + user pill barely fit at ~900-920px. */
@media (max-width: 900px) {
  .topbar nav > a { margin-left: 12px; }
  .topbar nav > a span { display: none; }
  .navicon { width: 22px; height: 22px; }
  .user-menu__name { display: none; }
}

@media (max-width: 560px) {
  .topbar { padding: 12px 14px; flex-wrap: wrap; row-gap: 8px; }
  /* Drop the nav onto its own full-width row below the brand and spread
     all icons evenly across that single line. Labels are already hidden
     by the 900px rule above. */
  .topbar nav { width: 100%; display: flex; justify-content: space-between; }
  .topbar nav > a { margin-left: 0; flex: 1 1 0; justify-content: center; }
}

main { max-width: 1180px; margin: 22px auto; padding: 0 18px 60px; }

.hero { margin-bottom: 18px; }
.search-wrap { display: flex; gap: 10px; }
.hero .search-wrap { flex-wrap: wrap; align-items: stretch; }
.hero .search-wrap > h2 { flex: 1 0 100%; align-self: center; }
.hero .search-wrap > button {
  flex: 1 1 0; min-width: 0; max-width: 220px;
  padding-top: 14px; padding-bottom: 14px;
  white-space: normal; text-align: center; line-height: 1.2;
}
.search-wrap input { flex: 1; padding: 14px 18px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--surface); font-size: 15px; box-shadow: var(--shadow); }
button { font: inherit; cursor: pointer; padding: 10px 16px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink); }
button:hover { background: #f0f3ef; }
button.primary { background: var(--brand); border-color: var(--brand-2); color: white; }
button.primary:hover { background: var(--brand-2); }
button.danger { background: #fff; color: var(--warn); border-color: #f0caca; }
button.danger:hover { background: #fbeaea; }

.filters { display: flex; gap: 12px; align-items: center; margin: 14px 2px; flex-wrap: wrap; }
.filters select, .filters input {
  padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface);
  font: inherit; line-height: 1.2;
}
.filters button {
  padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface);
  font: inherit; line-height: 1.2; height: auto;
}
.stats { margin-left: auto; color: var(--muted); font-size: 13px; }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px,1fr)); gap: 14px; }
.card-item {
  background: var(--surface); border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow);
  border: 1px solid var(--border); display: flex; flex-direction: column; gap: 6px;
  text-decoration: none; color: var(--ink); transition: transform .08s ease;
}
.card-item:hover { transform: translateY(-1px); text-decoration: none; }
.card-item .sp { font-weight: 600; }
.card-item .sub { color: var(--muted); font-size: 13px; }
.card-item .chips { margin-top: 6px; }
.chip { display: inline-block; background: var(--chip-bg); color: var(--brand-2);
        padding: 3px 9px; border-radius: 999px; font-size: 12px; margin-right: 4px; }
.chip[hidden] { display: none; }
.chip.stage-tissue_culture { background:#e2f0e6; color:#1f5e3a; }
.chip.stage-acclimation { background:#fff0d6; color:#7a4d10; }
.chip.stage-potted { background:#dde9fb; color:#1e457c; }
.chip.stage-mature { background:#e8d7f4; color:#4a1d70; }
.chip.stage-discarded { background:#f1d6d6; color:#7a2222; }
.chip.label { background:#dbe7fb; color:#1b3a78; border:1px solid #b9cef4; }
/* Contamination chips: red for confirmed, orange for suspect. The
   `lot-flag` variant is a softer hint used on samples whose own status
   is still clean but whose parent lot has been flagged. */
.chip.contam-contaminated { background:#fceaea; color:#922020; border:1px solid #f3cccc; font-weight:600; }
.chip.contam-suspect      { background:#fdecd6; color:#8a4a0a; border:1px solid #f1d6b3; }
.chip.lot-flag            { background:#fff7e0; color:#7a4d10; border:1px solid #ecc77e; font-weight:500; }
.chip.lot-flag.contam-contaminated { background:#fff0eb; color:#922020; border-color:#f3cccc; }
.chip.lot-flag.contam-suspect      { background:#fff7e0; color:#8a4a0a; border-color:#ecc77e; }

.card { background: var(--surface); border-radius: var(--radius); padding: 18px;
  box-shadow: var(--shadow); border: 1px solid var(--border); margin-bottom: 18px; }
.card h3 { margin-top: 0; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 800px) { .grid-2 { grid-template-columns: 1fr; } }

.plant-hero { display: flex; justify-content: space-between; align-items: flex-start;
  gap: 22px; background: var(--surface); padding: 22px; border-radius: var(--radius);
  border: 1px solid var(--border); box-shadow: var(--shadow); margin-bottom: 18px; }
.plant-hero > div:nth-of-type(2) { flex: 1 1 auto; margin-right: auto; }
.plant-hero h1 { margin: 0 0 4px 0; }
.plant-hero .muted { color: var(--muted); }
.plant-hero .actions { display: flex; flex-direction: column; gap: 8px; align-items: flex-end; }
.plant-hero-photo { flex: 0 0 140px; }
.plant-hero-photo img { width:140px; height:140px; object-fit:cover; border-radius:10px; border:1px solid var(--border); background:#eef0ec; display:block; }
@media (max-width: 600px) { .plant-hero-photo { flex-basis:96px; } .plant-hero-photo img { width:96px; height:96px; } }

/* On portrait / narrow screens stack hero vertically so the action buttons
   reflow under the photo + plant details instead of overflowing sideways. */
@media (max-width: 600px) {
  .plant-hero { flex-direction: column; align-items: stretch; gap: 14px; }
  .plant-hero .actions { align-items: flex-start; flex-direction: row; flex-wrap: wrap; }
  .plant-hero .action-icons { flex-wrap: wrap; }
}
.action-icons { display:inline-flex; gap:8px; align-items:center; }
.iconbtn { display:inline-flex; align-items:center; justify-content:center;
  width:38px; height:38px; padding:0; border-radius:10px;
  border:1px solid var(--border); background:var(--surface); color:var(--text);
  cursor:pointer; transition:background .15s, color .15s, border-color .15s, transform .05s; }
.iconbtn:hover { background:rgba(140,197,148,0.18); border-color:#8cc594; color:#2c3a2e; }
.iconbtn:active { transform:translateY(1px); }
.iconbtn.primary { background:#8cc594; border-color:#7ab884; color:#1f2a20; }
.iconbtn.primary:hover { background:#9bd1a4; }
.iconbtn.danger { color:#a02818; background:#fdecea; border-color:#c0392b; }
.iconbtn.danger .actionicon { stroke-width:2.4; }
.iconbtn.danger:hover { background:#f9d1cc; border-color:#8a1f12; color:#6e1a10; }
.actionicon { display:block; }
.plant-hero .stage-actions { display: flex; gap: 6px; align-items: center; }

.back { display: inline-block; margin-bottom: 10px; color: var(--muted); }

dialog { border: none; border-radius: 14px; box-shadow: var(--shadow); padding: 22px; max-width: 580px; width: 92%; }
dialog::backdrop { background: rgba(20,30,20,.35); }
dialog h2 { margin-top: 0; }

/* AI photo log dialog */
#dlg-ai-photo { max-width: 760px; }
.ai-photo-grid { display: grid; grid-template-columns: 220px 1fr; gap: 14px; align-items: start; }
.ai-photo-grid .ai-photo-preview {
  background: #eef0ec; border: 1px solid var(--border); border-radius: 10px;
  overflow: hidden; aspect-ratio: 3 / 4; display:flex; align-items:center; justify-content:center;
}
.ai-photo-grid .ai-photo-preview img { width: 100%; height: 100%; object-fit: cover; display:block; }
.ai-photo-grid .ai-photo-text textarea { min-height: 160px; }
.ai-photo-grid .lbl { font-weight: 600; color: var(--ink, inherit); }
#ai-photo-meta { display:block; margin-top:6px; font-size: 12px; }
@media (max-width: 620px) {
  .ai-photo-grid { grid-template-columns: 1fr; }
  .ai-photo-grid .ai-photo-preview { aspect-ratio: 4 / 3; max-height: 240px; }
}
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.grid2 .full { grid-column: 1 / -1; }
.species-field { position: relative; }
.pb-dropdown {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 10;
  background: var(--bg, #fff); color: inherit;
  border: 1px solid #c8d4c8; border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.18);
  max-height: 260px; overflow-y: auto; margin-top: 2px;
}
.pb-item { padding: 8px 10px; cursor: pointer; border-bottom: 1px solid rgba(0,0,0,0.05); font-size: 0.92rem; display:flex; align-items:center; gap:8px; }
.pb-item:last-child { border-bottom: none; }
.pb-item:hover { background: rgba(140,197,148,0.22); }
.pb-item .muted { color: #6b7770; margin-left: 4px; font-size: 0.85rem; }
.pb-item .pb-text { flex:1; min-width:0; }
.pb-thumb { width:36px; height:36px; object-fit:cover; border-radius:4px; flex-shrink:0; background:#eef0ec; }
.species-preview { position:relative; display:flex; align-items:flex-start; gap:8px; margin-top:4px; }
.species-preview img { max-width:140px; max-height:140px; border-radius:6px; border:1px solid #c8d4c8; object-fit:cover; background:#eef0ec; }
.species-preview button { padding:2px 8px; font-size:0.9rem; }
.card-item .thumb { width:100%; height:120px; overflow:hidden; border-radius:6px; margin-bottom:6px; background:#eef0ec; }
.card-item .thumb img { width:100%; height:100%; object-fit:cover; display:block; }
dialog label, .card label { display: flex; flex-direction: column; font-size: 13px; color: var(--muted); gap: 4px; min-width: 0; }
dialog input, dialog select, dialog textarea,
.card input, .card select, .card textarea {
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); font: inherit; background: white;
  width: 100%; min-width: 0; max-width: 100%; box-sizing: border-box;
}
dialog textarea { resize: vertical; }

/* Collapse two-column grids on narrow / portrait screens so inputs
   don't push the dialog wider than the viewport. */
@media (max-width: 560px) {
  .grid2 { grid-template-columns: 1fr; }
  dialog { padding: 16px; width: 96%; }
}
menu { display: flex; gap: 8px; justify-content: flex-end; padding: 0; margin-top: 16px; }

.log-form { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.log-form input, .log-form select { padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); background: white; }
.logs, .children { list-style: none; padding: 0; margin: 0; }
.logs li, .children li {
  padding: 10px 12px; border-bottom: 1px dashed var(--border);
  display: flex; justify-content: space-between; gap: 12px;
}
.logs li { flex-direction: column; gap: 4px; }
.logs li:last-child, .children li:last-child { border-bottom: none; }
.logs .meta { color: var(--muted); font-size: 12px; min-width: 160px; }

.chatbox { background: #fafbf9; border-radius: 10px; padding: 14px; height: 320px;
  overflow-y: auto; border: 1px solid var(--border); margin-bottom: 10px; }
.chatbox.big { height: 480px; }
.chatbox.fill { flex: 1 1 auto; min-height: 0; height: auto; }
.msg { padding: 8px 12px; border-radius: 10px; margin-bottom: 8px; max-width: 88%; white-space: pre-wrap; }
.msg.user { background: var(--brand); color: white; margin-left: auto; }
.msg.assistant { background: white; border: 1px solid var(--border); }
.msg.assistant.markdown { white-space: normal; }
.msg.assistant.markdown p { margin: 0 0 8px; }
.msg.assistant.markdown p:last-child { margin-bottom: 0; }
.msg.assistant.markdown h1,
.msg.assistant.markdown h2,
.msg.assistant.markdown h3,
.msg.assistant.markdown h4,
.msg.assistant.markdown h5,
.msg.assistant.markdown h6 { margin: 8px 0 4px; line-height: 1.25; }
.msg.assistant.markdown h1 { font-size: 1.25em; }
.msg.assistant.markdown h2 { font-size: 1.15em; }
.msg.assistant.markdown h3 { font-size: 1.05em; }
.msg.assistant.markdown ul,
.msg.assistant.markdown ol { margin: 4px 0 8px; padding-left: 22px; }
.msg.assistant.markdown li { margin: 2px 0; }
.msg.assistant.markdown code { background: #f1f3ee; padding: 1px 5px; border-radius: 4px; font-size: 0.92em; }
.msg.assistant.markdown pre { background: #1f2328; color: #e6edf3; padding: 10px 12px; border-radius: 8px;
  overflow-x: auto; margin: 6px 0; font-size: 0.88em; line-height: 1.4; }
.msg.assistant.markdown pre code { background: transparent; color: inherit; padding: 0; border-radius: 0; }
.msg.assistant.markdown blockquote { margin: 6px 0; padding: 4px 10px; border-left: 3px solid var(--border);
  color: var(--muted); background: #fafbf9; border-radius: 4px; }
.msg.assistant.markdown a { color: var(--brand); text-decoration: underline; }
.msg.assistant.markdown hr { border: none; border-top: 1px solid var(--border); margin: 8px 0; }
.msg.assistant.markdown strong { font-weight: 600; }
.msg.system { background: #fff5e1; font-size: 12px; color: #7a4d10; }
.msg.pending { padding: 10px 14px; }
.typing { display: inline-flex; gap: 4px; align-items: center; }
.typing span {
  width: 7px; height: 7px; border-radius: 50%; background: var(--muted, #999);
  display: inline-block; opacity: 0.35;
  animation: typing-bounce 1.2s infinite ease-in-out;
}
.typing span:nth-child(2) { animation-delay: 0.18s; }
.typing span:nth-child(3) { animation-delay: 0.36s; }
@keyframes typing-bounce {
  0%, 60%, 100% { opacity: 0.25; transform: translateY(0); }
  30%           { opacity: 1;    transform: translateY(-3px); }
}
.chat-form { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chat-form input { flex: 1; padding: 10px 14px; border-radius: 999px; border: 1px solid var(--border); background: white; }

/* Full-screen assistant page — turn the body into a flex column so the
 * chat fills whatever vertical space the (now floating-card) topbar leaves
 * over, without us having to hard-code the topbar's height. */
body.body-chat { height: 100dvh; overflow: hidden;
  display: flex; flex-direction: column; }
body.body-chat main { display: flex; flex-direction: column;
  margin: 0 auto; padding: 14px 18px;
  flex: 1 1 auto; min-height: 0; height: auto; }
.chat-page { display: flex; flex-direction: column; gap: 12px;
  flex: 1 1 auto; min-height: 0; height: 100%; margin-bottom: 0; }
.chat-page-head { margin: 0; flex: 0 0 auto; }
.chat-page-head h2 { margin: 0 0 4px 0; }
.chat-page-head p { margin: 0; }

/* 3D lineage graph */
.graph-toolbar { display:flex; justify-content:space-between; align-items:flex-end;
  gap:16px; margin-bottom:10px; flex-wrap:wrap; }
.graph-controls { display:flex; gap:10px; align-items:center; }
.graph-controls select, .graph-controls button { padding:6px 10px; border-radius:8px;
  border:1px solid var(--border); background:var(--surface); }
#graph-3d { width:100%; min-height:500px; border-radius:var(--radius);
  background:
    radial-gradient(ellipse at 30% 25%, #f4f8f1 0%, rgba(244,248,241,0) 55%),
    radial-gradient(ellipse at 75% 80%, #d7e7d8 0%, rgba(215,231,216,0) 60%),
    linear-gradient(160deg, #eaf1e6 0%, #d3e3da 100%);
  box-shadow:var(--shadow); overflow:hidden; border:1px solid #c7d6c8; }
.graph-legend { display:flex; flex-wrap:wrap; gap:10px; margin-top:10px; color:var(--muted); font-size:13px; }
.graph-legend .leg { display:inline-flex; align-items:center; gap:6px; }
.graph-legend i { display:inline-block; width:12px; height:12px; border-radius:3px; }

/* Dashboard plan-limits summary (above the calendar; hidden for unlimited tiers) */
.limits-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; margin-bottom:10px; flex-wrap:wrap; }
.limits-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:12px; }
.limits-item { border:1px solid var(--border); border-radius:10px; padding:10px 12px; background:var(--surface); }
.limits-item__label { font-size:12px; text-transform:uppercase; letter-spacing:.03em; color:var(--muted); font-weight:600; }
.limits-item__val { font-size:14px; color:var(--muted); margin:2px 0 8px; }
.limits-item__val strong { font-size:18px; color:var(--ink); }
.limits-bar { height:6px; border-radius:4px; background:var(--chip-bg); overflow:hidden; }
.limits-bar__fill { height:100%; width:0; background:var(--brand); border-radius:4px; transition:width .25s ease; }
.limits-item.is-near .limits-bar__fill { background:#e0a000; }
.limits-item.is-over .limits-bar__fill { background:var(--warn); }
.limits-item.is-over .limits-item__val strong { color:var(--warn); }

/* Dashboard calendar (below the lineage graph) */
.calendar-card { margin-top: 18px; }
.cal-head { display:flex; justify-content:space-between; align-items:flex-end;
  gap:16px; flex-wrap:wrap; margin-bottom:10px; }
.cal-controls { display:flex; gap:8px; align-items:center; }
.cal-controls button { padding:6px 10px; border-radius:8px; border:1px solid var(--border);
  background:var(--surface); cursor:pointer; }
.cal-controls button:hover { background:#f3f6f1; }
.cal-title { min-width:160px; text-align:center; font-weight:600; color:var(--ink); }
.cal-legend { display:flex; flex-wrap:wrap; gap:12px; color:var(--muted); font-size:12.5px;
  margin-bottom:10px; }
.cal-leg { display:inline-flex; align-items:center; gap:6px; }
.cal-dot { display:inline-block; width:10px; height:10px; border-radius:50%;
  background:var(--muted); }
.cal-dot.kind-establishment    { background:#2e7d32; }
.cal-dot.kind-created          { background:#6e7781; }
.cal-dot.kind-multiplication   { background:#1976d2; }
.cal-dot.kind-move             { background:#00897b; }
.cal-dot.kind-rooting          { background:#6a1b9a; }
.cal-dot.kind-discarded        { background:#c62828; }
.cal-dot.kind-restored         { background:#ef6c00; }
.cal-dot.kind-media-change-due { background:#2e7d32; border:1px dashed #2e7d32;
  box-shadow: inset 0 0 0 2px #fff; }
.cal-weekdays { display:grid; grid-template-columns: repeat(7, minmax(0,1fr));
  gap:4px; color:var(--muted); font-size:12px; font-weight:600;
  text-transform:uppercase; letter-spacing:.04em; padding:0 2px 4px; }
.cal-wd { text-align:center; }
.cal-grid { display:grid; grid-template-columns: repeat(7, minmax(0,1fr));
  gap:4px; }
.cal-day { background:#fafbf9; border:1px solid var(--border); border-radius:10px;
  min-height:96px; padding:6px 6px 4px; display:flex; flex-direction:column;
  gap:4px; cursor:pointer; transition: background .12s ease, border-color .12s ease; }
.cal-day:hover { background:#f0f4ec; }
.cal-day.is-other { background:#f6f7f5; color:var(--muted); opacity:.65; }
.cal-day.is-today { border-color:#8cc594; box-shadow: inset 0 0 0 1px #8cc594; }
.cal-day.is-selected { background:#eaf3e4; border-color:#5fa572; }
.cal-day:focus-visible { outline:2px solid var(--brand); outline-offset:1px; }
.cal-num { font-size:12px; font-weight:600; color:var(--ink); }
.cal-day.is-other .cal-num { color:var(--muted); }
.cal-day.is-today .cal-num { color:var(--brand-2); }
.cal-chips { display:flex; flex-direction:column; gap:2px; min-height:0; overflow:hidden; }
.cal-chip { display:inline-flex; align-items:center; gap:5px; padding:1px 6px;
  border-radius:999px; background:#fff; border:1px solid var(--border);
  font-size:11px; line-height:1.4; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; max-width:100%; }
.cal-chip-label { overflow:hidden; text-overflow:ellipsis; }
.cal-chip.kind-establishment    { background:#eaf6ec; border-color:#cfe6d2; color:#1f5e29; }
.cal-chip.kind-created          { background:#eef0f2; border-color:#d6dadd; color:#4a525a; }
.cal-chip.kind-multiplication   { background:#e7f0fa; border-color:#cfdfee; color:#16538b; }
.cal-chip.kind-move             { background:#e3f3f1; border-color:#bfe2dd; color:#0a5a52; }
.cal-chip.kind-rooting          { background:#f0e6f7; border-color:#dccced; color:#542176; }
.cal-chip.kind-discarded        { background:#fceaea; border-color:#f3cccc; color:#922020; }
.cal-chip.kind-restored         { background:#fbecdb; border-color:#f1d6b3; color:#a4520a; }
.cal-chip.kind-media-change-due { background:#fff; border-style:dashed; color:#2e7d32; }
.cal-chip.is-soon               { background:#fff4e0; border-color:#ecc77e; color:#ef6c00; }
.cal-chip.is-overdue            { background:#fdecec; border-color:#e8a3a3; color:#c62828; font-weight:600; }
.cal-more { font-size:11px; color:var(--muted); padding-left:2px; }
.cal-detail { margin-top:14px; padding:12px 14px; border:1px solid var(--border);
  border-radius:10px; background:#fafbf9; }
.cal-detail-head { margin:0 0 8px; font-size:15px; }
.cal-detail-subhead { margin:10px 0 6px; font-size:12px;
  text-transform:uppercase; letter-spacing:0.04em; color:var(--muted); }
.cal-detail-subhead.is-overdue { color:#c62828; }
.cal-detail-list { list-style:none; margin:0; padding:0; display:flex;
  flex-direction:column; gap:6px; }
.cal-detail-item { display:flex; gap:10px; align-items:flex-start;
  padding:6px 8px; border-radius:8px; background:var(--surface);
  border:1px solid var(--border); }
.cal-detail-item .cal-dot { margin-top:6px; flex:0 0 10px; }
.cal-detail-body { display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
.cal-detail-link { font-weight:600; color:var(--ink); }
.cal-detail-link:hover { color:var(--brand); }
.cal-detail-kind { font-size:12px; color:var(--muted); }
.cal-detail-text { font-size:12.5px; }
.cal-detail-item.is-overdue .cal-detail-kind { color:#c62828; font-weight:600; }
.cal-detail-item.is-soon    .cal-detail-kind { color:#ef6c00; }
.cal-error { padding:10px; }

@media (max-width: 720px) {
  .cal-day { min-height:78px; padding:4px; }
  .cal-chip-label { display:none; }
  .cal-chip { padding:1px 4px; }
}

.jars-fieldset { border:1px solid var(--border); border-radius:8px; padding:10px 12px; margin-top:10px; }
.jars-fieldset legend { padding:0 6px; color:var(--muted); font-size:.9em; }

/* Inline checkbox row inside dialogs (consistent style across forms) */
dialog .inline-check { display:flex; flex-direction:row; align-items:center; gap:8px; margin-top:10px; font-size:14px; color:var(--ink); }
dialog .inline-check input[type="checkbox"] { width:18px; height:18px; min-width:18px; min-height:18px; max-width:18px; max-height:18px; flex:0 0 18px; padding:0; margin:0; border:1px solid var(--border); }

/* Fields auto-filled from a selected lot — hint with light green tint, still editable */
dialog input.from-lot, dialog select.from-lot, dialog textarea.from-lot { background:#e6f6dc; }
dialog input.from-lot:focus, dialog select.from-lot:focus, dialog textarea.from-lot:focus { background:#f1faea; }

.pb-tag { display:inline-block; margin-left:6px; padding:0 6px; font-size:11px; line-height:16px;
  border-radius:8px; background: var(--accent, #2d7d2d); color:#fff; vertical-align: middle; }

/* Settings page */
.settings-form { display: flex; flex-direction: column; gap: 18px; margin-top: 14px; }
.settings-form label.full { display: flex; flex-direction: column; gap: 6px; }
.settings-form .lbl { font-weight: 600; }
.settings-form textarea {
  width: 100%; box-sizing: border-box; padding: 10px 12px;
  font: inherit; line-height: 1.4; border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg, #fff); color: var(--ink, inherit); resize: vertical; min-height: 120px;
}
.settings-form .ghost.small { align-self: flex-start; padding: 4px 10px; font-size: 12px; }
.settings-actions { display: flex; align-items: center; gap: 12px; }

/* Settings: AI backend + Plantbook forms */
.settings-form input[type="text"],
.settings-form input[type="password"],
.settings-form select {
  width: 100%; box-sizing: border-box; padding: 8px 10px;
  font: inherit; line-height: 1.3; border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg, #fff); color: var(--ink, inherit);
}
.settings-form fieldset.ai-group {
  border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px;
  display: flex; flex-direction: column; gap: 12px; margin: 0;
}
.settings-form fieldset.ai-group legend { padding: 0 6px; font-weight: 600; }

/* Chat: extra options row */
.chat-form .chat-opt {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--muted, #666); cursor: pointer;
  margin-left: 4px; white-space: nowrap;
}
.chat-form .chat-opt.full { flex-basis: 100%; margin: 0 2px 2px; }
.chat-form .chat-opt input { width: auto; margin: 0; }

/* Lots page */
.lot-form .grid2 { gap: 10px 16px; }
.lots-list { display: flex; flex-direction: column; gap: 14px; margin-top: 10px; }
.lot-card { border: 1px solid var(--border, #ddd); border-radius: 10px; padding: 12px 14px; background: var(--bg, #fff); }
.lot-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.lot-head h3 { margin: 0; font-size: 16px; }
.lot-date { font-weight: normal; font-size: 12px; }
.lot-actions { display: flex; gap: 6px; align-items: center; }
.lot-actions .small { padding: 4px 10px; font-size: 12px; }
.lot-recipe { margin: 4px 0; font-size: 13px; }
.lot-species-chips { display: flex; flex-wrap: wrap; gap: 5px; margin: 4px 0 6px; }
.species-chip { cursor: pointer; text-decoration: none; background: var(--chip-bg, #eef2ff); color: var(--chip-fg, #3730a3); border-color: transparent; }
.species-chip:hover { filter: brightness(0.95); text-decoration: none; }
.lot-notes { margin: 4px 0; font-size: 80%; font-weight: bold; white-space: pre-wrap; }
.lot-totals { margin: 6px 0; font-size: 13px; }
.lot-totals > summary { cursor: pointer; outline: none; }
.lot-totals-list { margin: 4px 0 0 18px; padding: 0; }
.lot-totals-list li { margin: 2px 0; }
.lot-totals-table { border-collapse: collapse; margin: 6px 0 0; font-size: 13px; width: 100%; }
.lot-totals-table th, .lot-totals-table td { padding: 3px 10px 3px 0; text-align: left; vertical-align: top; }
.lot-totals-table thead th { font-weight: 600; border-bottom: 1px solid #d8d8d2; color: #555; }
.lot-totals-table tbody tr + tr td { border-top: 1px solid #ececea; }
.lot-totals-table .num { text-align: left; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Recipe compare mode */
.rcp-cmp-pick { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--muted, #666); cursor: pointer; white-space: nowrap; }
.rcp-cmp-pick input { cursor: pointer; }
.lot-card.cmp-selected { outline: 2px solid var(--accent, #2e7d32); outline-offset: 1px; }
#btn-compare-recipes.active { background: var(--accent, #2e7d32); color: #fff; border-color: transparent; }
#compare-bar { position: sticky; bottom: 0; z-index: 5; display: flex; align-items: center; gap: 10px; margin: 10px 0 0; padding: 10px 14px; background: var(--card, #fff); border: 1px solid var(--border, #ddd); border-radius: 10px; box-shadow: 0 -2px 10px rgba(0,0,0,.08); }
#compare-bar[hidden] { display: none; }
#compare-bar #cmp-count { font-size: 13px; }
.cmp-table th, .cmp-table td { padding: 5px 14px 5px 0; white-space: nowrap; }
.cmp-table tbody tr.cmp-diff { background: color-mix(in srgb, #f9a825 16%, transparent); }
.cmp-table td.cmp-missing { color: var(--muted, #999); }
#dlg-recipe-compare { min-width: min(640px, 92vw); }
.jars { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.jar-chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 12px; font-size: 12px; border: 1px solid var(--border, #ddd); }
.jar-chip.free { background: rgba(45, 125, 45, .12); border-color: rgba(45, 125, 45, .35); }
.jar-chip.used { background: rgba(0, 0, 0, .05); color: var(--muted, #666); text-decoration: line-through; }
.jar-chip .x { border: 0; background: transparent; cursor: pointer; color: inherit; padding: 0 2px; font-size: 11px; line-height: 1; }
.jar-chip .x:hover { color: #c33; }
button.danger { background: #c33; color: #fff; border: 0; border-radius: 6px; padding: 6px 10px; cursor: pointer; }
button.danger:disabled { background: #d99; cursor: not-allowed; }

/* New-sample jar picker */
.jar-picker-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.jar-picker-row select { padding: 8px 10px; border-radius: 6px; border: 1px solid var(--border, #ddd); }

/* Inventory filter checkbox (e.g. Include discarded) — always touch-friendly */
.filters .chk {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px; border: 1px solid var(--border, #ddd); border-radius: 6px;
  font-size: 14px; cursor: pointer; user-select: none; background: var(--bg, #fff);
}
.filters .chk input[type="checkbox"] {
  width: 18px; height: 18px; min-width: 18px; min-height: 18px;
  max-width: 18px; max-height: 18px;
  margin: 0; padding: 0; border: 0; border-radius: 0;
  box-sizing: border-box; flex: 0 0 18px; cursor: pointer;
}

/* Settings: long checkbox option row */
.settings-form .chat-opt-row {
  display: flex; flex-direction: row !important; align-items: flex-start; gap: 10px;
  padding: 10px 12px; border: 1px solid var(--border, #ddd); border-radius: 8px;
}
.settings-form .chat-opt-row input[type="checkbox"] {
  width: 18px; height: 18px; min-width: 18px; min-height: 18px;
  max-width: 18px; max-height: 18px;
  margin: 3px 0 0; padding: 0; border: 0; border-radius: 0;
  box-sizing: border-box; flex: 0 0 18px; cursor: pointer;
}
.settings-form .chat-opt-row .muted { font-weight: normal; font-size: 12px; }
.settings-form .chat-opt-row--nested { margin-left: 24px; }
.settings-form .chat-opt-row.is-disabled { opacity: 0.55; }
.settings-form .chat-opt-row.is-disabled input[type="checkbox"] { cursor: not-allowed; }

/* ---- Plant timeline ------------------------------------------------- */
.timeline-card { padding: 14px 16px; }
.timeline { position: relative; padding: 14px 8px 8px; overflow-x: auto; }
.timeline-track {
  position: relative;
  display: flex;
  /* Pin every milestone column to the top so the dots line up on the same
     horizontal axis regardless of how much label/relative-time text wraps
     below them. Centering instead would float dots in taller columns
     upward, leaving the track line bisecting the date/label text. */
  align-items: flex-start;
  justify-content: space-between;
  gap: 4px;
  min-height: 56px;
}
.timeline-track::before {
  content: "";
  position: absolute;
  left: 18px; right: 18px;
  /* Pass through the centre of the 34 px dots which sit flush at the top. */
  top: 17px;
  height: 3px;
  background: var(--border, #d0d7de);
  border-radius: 2px;
  z-index: 0;
}
/* Multi-lane variant: parent on row 1, one row per child branching from the
   multiplication node it came from. Columns are shared so a child's first
   node lands exactly under its parent multiplication node. Connecting lines
   are drawn as an SVG overlay (see drawTimelineConnectors) so they stay exact
   as the fluid columns reflow. */
.timeline-grid {
  position: relative;
  display: grid;
  align-items: start;
  gap: 26px 4px;
  min-height: 56px;
  /* Room for the lane UID tag that sits just above each lane's first node. */
  padding-top: 16px;
}
.timeline-grid .timeline-milestone { justify-self: center; }
.tl-overlay {
  position: absolute;
  left: 0; top: 0;
  pointer-events: none;
  overflow: visible;
  z-index: 0;
}
.tl-overlay .tl-seg { stroke: var(--border, #d0d7de); stroke-width: 3; stroke-linecap: round; }
.tl-overlay .tl-seg-child { stroke-width: 2.5; }
.tl-overlay .tl-seg-branch { stroke: #1976d2; stroke-width: 2.5; opacity: .6; }
.tl-overlay path { fill: none; stroke-linejoin: round; }
.timeline-lane-tag {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 3px;
  font-size: 10px;
  line-height: 1;
  white-space: nowrap;
}
.timeline-lane-link {
  color: #1976d2;
  text-decoration: none;
  font-weight: 600;
  white-space: nowrap;
}
.timeline-lane-link:hover { text-decoration: underline; }
/* The lane that represents the sample you're currently viewing: not a link,
 * emphasised so it stands out among parent/sibling/child lanes. */
.timeline-lane-link.is-self {
  color: var(--accent, #2e7d32);
  font-weight: 700;
  cursor: default;
}
/* Soft tint behind every milestone of the current sample's lane. */
.timeline-milestone[data-current="1"] .timeline-label { font-weight: 600; }
/* The lane you're viewing reads as the "solid" branch: filled dots in the
 * milestone's own colour, with the icon knocked out in white. Pending / due
 * markers (media-change-due, is-pending) are intentionally hollow dashed
 * dots, so leave those alone — otherwise the white icon lands on a white
 * fill and disappears. */
.timeline-milestone[data-current="1"]:not(.kind-media-change-due):not(.is-pending) .timeline-dot {
  background: currentColor;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, #2e7d32) 18%, transparent);
}
.timeline-milestone[data-current="1"]:not(.kind-media-change-due):not(.is-pending) .timeline-dot svg { color: #fff; }

.timeline-milestone {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  min-width: 92px;
  max-width: 92px;
  text-align: center;
}
.timeline-dot {
  width: 34px; height: 34px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border: 2px solid var(--accent, #2e7d32);
  color: var(--accent, #2e7d32);
  box-shadow: 0 1px 2px rgba(0,0,0,.08);
  /* Keep the dot from shrinking when long labels make the column tall. */
  flex: 0 0 34px;
}
.timeline-dot svg { width: 18px; height: 18px; }
.timeline-milestone.is-current .timeline-dot {
  outline: 3px solid color-mix(in srgb, var(--accent, #2e7d32) 30%, transparent);
  outline-offset: 1px;
}
.timeline-milestone .timeline-date {
  font-size: 11px;
  color: var(--muted, #6e7781);
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.timeline-milestone .timeline-label {
  font-size: 11px;
  color: var(--fg, #1f2328);
  max-width: 100%;
  line-height: 1.2;
  /* Wrap long single tokens (e.g. species names) instead of overflowing
     and bumping into the neighbouring milestone. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* Color per milestone kind */
.timeline-milestone.kind-establishment .timeline-dot { border-color: #2e7d32; color: #2e7d32; }
.timeline-milestone.kind-created .timeline-dot { border-color: #6e7781; color: #6e7781; }
.timeline-milestone.kind-multiplication .timeline-dot { border-color: #1976d2; color: #1976d2; }
.timeline-milestone.kind-move .timeline-dot { border-color: #00897b; color: #00897b; }
.timeline-milestone.kind-rooting .timeline-dot { border-color: #6a1b9a; color: #6a1b9a; }
.timeline-milestone.kind-discarded .timeline-dot { border-color: #c62828; color: #c62828; background: #fff5f5; }
.timeline-milestone.kind-restored .timeline-dot { border-color: #ef6c00; color: #ef6c00; }
.timeline-milestone.kind-contamination .timeline-dot { border-color: #c62828; color: #c62828; background: #fff5f5; }
.timeline-milestone.kind-media-change-due .timeline-dot {
  border-style: dashed;
  border-color: var(--muted, #6e7781);
  color: var(--muted, #6e7781);
  background: #fff;
  box-shadow: none;
}
.timeline-milestone.kind-media-change-due.is-soon .timeline-dot {
  border-color: #ef6c00;
  color: #ef6c00;
}
.timeline-milestone.kind-media-change-due.is-overdue .timeline-dot {
  border-color: #c62828;
  color: #c62828;
  background: #fff5f5;
}
.timeline-milestone .timeline-rel {
  display: inline-block;
  margin-top: 1px;
  font-size: 10px;
  color: var(--muted, #6e7781);
}
.timeline-milestone.kind-media-change-due.is-soon .timeline-rel { color: #ef6c00; }
.timeline-milestone.kind-media-change-due.is-overdue .timeline-rel { color: #c62828; font-weight: 600; }
.timeline-milestone.is-pending .timeline-dot {
  border-style: dashed;
  border-color: var(--muted, #6e7781);
  color: var(--muted, #6e7781);
  background: #fff;
  box-shadow: none;
}
.timeline-milestone.is-pending .timeline-date,
.timeline-milestone.is-pending .timeline-label { color: var(--muted, #6e7781); }
.timeline-milestone.is-pending .timeline-rel { color: var(--muted, #6e7781); font-style: italic; }
.timeline-empty { padding: 6px 4px; }
@media (max-width: 600px) {
  .timeline-milestone .timeline-label { display: none; }
}

/* ---- Pipeline-plan strip ------------------------------------------- */
/* Rendered ABOVE the dated timeline. Shows the three planner stages
   (establishment → multiplication → rooting) for this sample's species,
   with the recipe assigned to each and a highlight on whichever stage the
   sample is currently in (matched via its lot's recipe id). */
.plan-strip { margin: 0 0 12px; }
.plan-strip-track {
  display: flex; align-items: stretch; gap: 6px; flex-wrap: wrap;
}
.plan-strip-stage {
  flex: 1 1 0;
  min-width: 130px;
  border: 1px solid var(--border, #d0d7de);
  border-radius: 10px;
  padding: 6px 10px;
  background: var(--card-bg, #fff);
  display: flex; flex-direction: column; gap: 2px;
}
.plan-strip-stage.stage-establishment { border-color: color-mix(in srgb, #2e7d32 35%, var(--border, #d0d7de)); }
.plan-strip-stage.stage-multiplication { border-color: color-mix(in srgb, #1976d2 35%, var(--border, #d0d7de)); }
.plan-strip-stage.stage-rooting { border-color: color-mix(in srgb, #6a1b9a 35%, var(--border, #d0d7de)); }
.plan-strip-stage.is-current {
  background: color-mix(in srgb, var(--accent, #2e7d32) 9%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #2e7d32) 30%, transparent);
}
.plan-strip-stage.stage-establishment.is-current { background: color-mix(in srgb, #2e7d32 14%, transparent); box-shadow: 0 0 0 2px color-mix(in srgb, #2e7d32 45%, transparent); }
.plan-strip-stage.stage-multiplication.is-current { background: color-mix(in srgb, #1976d2 14%, transparent); box-shadow: 0 0 0 2px color-mix(in srgb, #1976d2 45%, transparent); }
.plan-strip-stage.stage-rooting.is-current { background: color-mix(in srgb, #6a1b9a 14%, transparent); box-shadow: 0 0 0 2px color-mix(in srgb, #6a1b9a 45%, transparent); }
.plan-strip-stage-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted, #6e7781); font-weight: 600;
}
.plan-strip-stage.is-current .plan-strip-stage-label { color: inherit; }
.plan-strip-now {
  display: inline-block; margin-left: 4px;
  font-size: 10px; letter-spacing: 0; text-transform: none; font-weight: 700;
  padding: 0 6px; border-radius: 8px;
  background: var(--accent, #2e7d32); color: #fff;
}
.plan-strip-stage-recipe { font-size: 13px; line-height: 1.25; }
.plan-strip-stage-recipe a { color: inherit; text-decoration: none; }
.plan-strip-stage-recipe a:hover { text-decoration: underline; }
.plan-strip-arrow {
  align-self: center; color: var(--muted, #6e7781); font-weight: 600;
  padding: 0 2px;
}
.plan-strip-empty { padding: 4px 2px; font-size: 13px; }
@media (max-width: 600px) {
  .plan-strip-arrow { display: none; }
  .plan-strip-stage { flex-basis: 100%; }
}

/* Make the plan-derived chip in the hero visually distinct from the
   lifecycle stage chip next to it (they look similar otherwise). */
.chip.plan-chip { font-weight: 600; }
.chip.plan-chip::before { content: "◆ "; opacity: 0.7; }

/* ---- Planner table -------------------------------------------------- */
.planner-table-wrap { overflow-x: auto; }
.planner-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.planner-table th, .planner-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border, #e1e4e8);
  text-align: left;
  vertical-align: middle;
}
.planner-table thead th {
  font-weight: 600;
  color: var(--muted, #6e7781);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .03em;
  background: var(--card-alt, #fafbfc);
  position: sticky; top: 0; z-index: 1;
}
.planner-table tbody tr:hover { background: color-mix(in srgb, var(--accent, #2e7d32) 6%, transparent); }
.planner-table .col-species { min-width: 180px; }
.planner-table .col-samples { width: 48px; text-align: right; color: var(--muted, #6e7781); }
.planner-table .col-actions { width: 110px; text-align: right; white-space: nowrap; }
.planner-table .col-actions .ai-btn { padding: 3px 8px; font-size: 12px; }
.planner-table .col-actions .ai-btn[disabled] { opacity: .55; cursor: progress; }
.planner-table .col-actions button[data-del-species] {
  padding: 1px 8px;
  font-size: 16px;
  line-height: 1;
  margin-left: 4px;
  color: var(--muted, #6e7781);
}
.planner-table .col-actions button[data-del-species]:hover {
  color: #c62828;
  border-color: #c62828;
}
.planner-table .col-actions button[data-del-species][disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  color: var(--muted, #6e7781);
  border-color: var(--border, #d0d7de);
}
.planner-table .col-actions button[data-del-species][disabled]:hover {
  color: var(--muted, #6e7781);
  border-color: var(--border, #d0d7de);
}
.planner-table select { width: 100%; max-width: 260px; }
@keyframes planner-flash-ok {
  0%   { background: color-mix(in srgb, #2e7d32 28%, transparent); }
  100% { background: transparent; }
}
@keyframes planner-flash-err {
  0%   { background: color-mix(in srgb, #c62828 28%, transparent); }
  100% { background: transparent; }
}
.planner-table tr.flash-ok  > td { animation: planner-flash-ok 1.4s ease-out 1; }
.planner-table tr.flash-err > td { animation: planner-flash-err 1.4s ease-out 1; }
.chip.stage { background: color-mix(in srgb, var(--accent, #2e7d32) 14%, transparent); }
.chip.stage-establishment { background: color-mix(in srgb, #2e7d32 18%, transparent); color: #1b5e20; }
.chip.stage-multiplication { background: color-mix(in srgb, #1976d2 18%, transparent); color: #0d47a1; }
.chip.stage-rooting { background: color-mix(in srgb, #6a1b9a 18%, transparent); color: #4a148c; }

/* ---- AI button lock + rate-limit overlay -------------------------------- */
.ai-btn[disabled], .ai-btn.ai-locked {
  opacity: 0.55;
  cursor: wait;
}

/* Reusable bulk-AI progress bar (planner: determinate; recipes: indeterminate).
   Lives in a small block element next to the bulk button + status line.
   Hidden by default; the JS helper (window.aiProgress) toggles visibility
   and writes label/percentage text into the slots it materialises. */
.ai-progress {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--muted);
}
.ai-progress__label { margin-bottom: 4px; }
.ai-progress__track {
  height: 8px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--accent, #2e7d32) 12%, transparent);
  overflow: hidden;
  position: relative;
}
.ai-progress__bar {
  height: 100%;
  width: 0%;
  background: var(--accent, #2e7d32);
  border-radius: 4px;
  transition: width .25s ease;
}
/* Indeterminate mode: bar takes a fixed slice of the track and slides
   across it on a loop. Used by recipes' single-shot AI audit and any
   other bulk action that can't report exact progress. */
.ai-progress__bar.indet {
  width: 32% !important;
  transition: none;
  animation: ai-progress-indet 1.4s ease-in-out infinite;
  position: relative;
  left: 0;
}
@keyframes ai-progress-indet {
  0%   { left: -32%; }
  100% { left: 100%; }
}
.ai-progress__meta { margin-top: 4px; font-size: 11px; }

.ai-rate-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}
.ai-rate-overlay[hidden] { display: none; }
.ai-rate-card {
  background: var(--card-bg, #fff);
  color: var(--text, #222);
  border-radius: 10px;
  padding: 20px 24px;
  max-width: 380px;
  width: calc(100% - 32px);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
  text-align: center;
}
.ai-rate-card h3 { margin: 0 0 8px; }
.ai-rate-line { margin: 6px 0; font-size: 14px; }
.ai-rate-card strong { font-weight: 600; }

/* ---------- Auth: login page + nav avatar (Phase 26) ---------- */
body.page-login {
  min-height: 100dvh;
  margin: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, #eef3ee 0%, #d9e9df 60%, #c4ddcd 100%);
  padding: 24px;
}
.login-card {
  width: 100%; max-width: 420px;
  background: var(--surface);
  border-radius: 18px;
  box-shadow: 0 20px 60px rgba(10,30,20,.12), 0 4px 12px rgba(10,30,20,.05);
  padding: 36px 30px;
}
.login-card__inner { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.login-card__logo { width: 64px; height: 64px; border-radius: 14px; object-fit: cover; }
.login-card__title { margin: 0; font-size: 22px; color: var(--brand-2); }
.login-card__subtitle { margin: 0 0 10px; color: var(--muted); font-size: 14px; }
.login-card__google {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 12px 22px; border-radius: 10px;
  background: #fff; color: #1f2933; border: 1px solid #dadce0;
  font-weight: 600; font-size: 15px; text-decoration: none;
  box-shadow: 0 1px 2px rgba(0,0,0,.05);
  transition: box-shadow .15s, transform .05s;
}
.login-card__google:hover { box-shadow: 0 2px 6px rgba(0,0,0,.12); }
.login-card__google:active { transform: translateY(1px); }
.login-card__google-icon { width: 20px; height: 20px; flex-shrink: 0; }
.login-card__error {
  background: #fdecea; color: #8a1c1c; border: 1px solid #f5c6c1;
  border-radius: 8px; padding: 10px 12px; font-size: 13px; line-height: 1.4;
  width: 100%; text-align: left;
}
.login-card__note {
  background: #fff8e1; color: #6b5b1a; border: 1px solid #f3e1a7;
  border-radius: 8px; padding: 10px 12px; font-size: 13px; line-height: 1.4;
  width: 100%; text-align: left;
}

/* Nav user avatar + logout */
.user-menu {
  position: relative;
  margin-left: 18px; display: inline-flex; align-items: center;
}
.user-menu__btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: transparent; border: 1px solid transparent;
  border-radius: 999px; padding: 4px 10px 4px 4px;
  cursor: pointer; color: var(--ink); font: inherit;
}
.user-menu__btn:hover { border-color: var(--border); background: var(--chip-bg); }
.user-menu__avatar {
  width: 28px; height: 28px; border-radius: 50%; object-fit: cover;
  background: var(--chip-bg); display: inline-flex; align-items: center; justify-content: center;
  color: var(--brand-2); font-weight: 700; font-size: 13px;
}
.user-menu__name { font-size: 13px; color: var(--ink); max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-menu__panel {
  position: absolute; right: 0; top: calc(100% + 6px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: var(--shadow);
  min-width: 220px; padding: 10px 0;
  display: none; z-index: 20;
}
.user-menu.open .user-menu__panel { display: block; }
.user-menu__email { padding: 4px 14px 8px; font-size: 12px; color: var(--muted); border-bottom: 1px solid var(--border); margin-bottom: 6px; word-break: break-all; }
.user-menu__panel a {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 14px; color: var(--ink); text-decoration: none; font-size: 14px;
}
.user-menu__panel a .navicon { width: 16px; height: 16px; flex: 0 0 16px; }
.user-menu__panel a:hover { background: var(--chip-bg); color: var(--brand-2); }
@media (max-width: 560px) {
  .user-menu { margin-left: 0; order: 99; }
  .user-menu__name { display: none; }
}

/* =================================================================
   Licensing (Phase 27)
   ================================================================= */

/* Top-of-page upgrade banner shown on every page when a cap is hit or near.
   Hidden by default; app.js toggles the [hidden] attribute. */
.upgrade-banner {
  background: linear-gradient(135deg, #fff8e6 0%, #fff1cc 100%);
  border-bottom: 1px solid #f5d57a;
  color: #6c4a04;
  padding: 10px 18px;
  font-size: 14px;
  line-height: 1.45;
  text-align: center;
}
.upgrade-banner--over {
  background: linear-gradient(135deg, #ffe4e4 0%, #ffd2d2 100%);
  border-bottom-color: #f1a3a3;
  color: #8a1a1a;
}
.upgrade-banner strong { font-weight: 700; }

/* Quota-exceeded toasts (one per 402 response) */
.quota-toast-host {
  position: fixed; right: 18px; bottom: 18px;
  display: flex; flex-direction: column; gap: 10px;
  z-index: 9999; pointer-events: none;
}
.quota-toast {
  pointer-events: auto;
  background: var(--surface, #fff);
  border: 1px solid #f1a3a3;
  border-left: 4px solid #c43a3a;
  box-shadow: 0 8px 24px rgba(0,0,0,.15);
  border-radius: 10px;
  padding: 12px 38px 12px 14px;
  width: 320px;
  position: relative;
  animation: quota-toast-in .25s ease-out;
}
@keyframes quota-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.quota-toast__title  { font-weight: 700; color: #8a1a1a; font-size: 14px; margin-bottom: 4px; }
.quota-toast__msg    { font-size: 13px; color: var(--ink, #222); line-height: 1.4; }
.quota-toast__meta   { font-size: 12px; color: var(--muted, #777); margin-top: 6px; }
.quota-toast__close  {
  position: absolute; top: 6px; right: 8px;
  background: transparent; border: 0; cursor: pointer;
  font-size: 20px; line-height: 1; color: var(--muted, #888);
}
.quota-toast__close:hover { color: var(--ink, #222); }

/* Licensing settings card — tier limit table */
.lic-tier-table-wrap { overflow-x: auto; }
.lic-tier-table {
  width: 100%;
  border-collapse: collapse;
}
.lic-tier-table th,
.lic-tier-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
  font-size: 14px;
}
.lic-tier-table thead th {
  background: var(--chip-bg);
  font-weight: 700;
  text-transform: capitalize;
  color: var(--brand-2, var(--ink));
}
.lic-tier-table .lic-cap-col { width: 32%; }
.lic-tier-table tbody th {
  font-weight: 600;
  color: var(--ink);
}
.lic-tier-table tbody th .muted {
  font-weight: 400; font-size: 12px; display: block; margin-top: 2px;
}
.lic-tier-table input[type=number] {
  width: 100%; max-width: 140px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: right;
}
.lic-tier-table input[type=number]::placeholder { color: var(--muted); }

/* Users table */
.lic-users-h { margin-top: 24px; margin-bottom: 4px; }
.lic-users-intro { margin-top: 0; margin-bottom: 8px; }
.lic-reset-row { justify-content: flex-end; }
.lic-users-wrap { overflow-x: auto; }
.lic-users-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 8px;
  font-size: 14px;
}
.lic-users-table th,
.lic-users-table td {
  padding: 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}
.lic-users-table thead th {
  font-weight: 700; color: var(--brand-2, var(--ink));
  background: var(--chip-bg);
}
.lic-users-table .lic-over {
  color: #c43a3a;
  font-weight: 700;
}
.lic-user-cell { display: flex; align-items: center; gap: 10px; }
.lic-user-cell img,
.lic-user-cell .lic-user-initial {
  width: 32px; height: 32px; border-radius: 50%;
  object-fit: cover;
  background: var(--chip-bg);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--brand-2);
  font-weight: 700;
  font-size: 13px;
  flex-shrink: 0;
}
.lic-user-name  { font-weight: 600; }
.lic-user-email { font-size: 12px; }
.lic-admin-badge {
  display: inline-block;
  padding: 1px 6px; margin-left: 4px;
  border-radius: 999px;
  background: var(--brand-bg, #eef);
  color: var(--brand-2, #335);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 700;
  vertical-align: middle;
}
.lic-tier-select {
  padding: 5px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-transform: capitalize;
}
.lic-tier-locked {
  display: inline-block;
  padding: 5px 10px;
  border: 1px dashed var(--border);
  border-radius: 6px;
  background: var(--brand-bg, #eef);
  color: var(--brand-2, #335);
  font: inherit;
  font-weight: 600;
  text-transform: capitalize;
  cursor: not-allowed;
}

/* ============================================================
 * Night theme
 * Toggled by the floating button (bottom-right); the chosen
 * theme is persisted in localStorage and applied to <html> as
 * .theme-dark before first paint (see base.html head script).
 * Most surfaces follow the CSS variables below; a few elements
 * with hardcoded light backgrounds get targeted overrides.
 * ============================================================ */
html.theme-dark {
  --bg: #121815;
  --surface: #1b2320;
  --ink: #e6ece8;
  --muted: #9aa8a1;
  --brand: #4fae74;
  --brand-2: #6cc28f;
  --accent: #7fb0ea;
  --warn: #e08585;
  --chip-bg: #243029;
  --border: #2c3a33;
  /* Aliases used with white fallbacks elsewhere (planner header, plan-strip
     stages, compare bar, lineage dots, modal cards). Defining them here keeps
     those surfaces dark without touching light mode (where they stay unset
     and fall back to the original light literals). */
  --card: #1b2320;
  --card-bg: #1b2320;
  --card-alt: #222d28;
  --text: #e6ece8;
  --fg: #e6ece8;
  --shadow: 0 1px 3px rgba(0,0,0,.45), 0 6px 22px rgba(0,0,0,.4);
  color-scheme: dark;
}
/* Inputs / message bubbles that hardcode white in light mode. */
html.theme-dark input,
html.theme-dark select,
html.theme-dark textarea,
html.theme-dark .log-form input,
html.theme-dark .log-form select,
html.theme-dark .chat-form input,
html.theme-dark .search-wrap input,
html.theme-dark .msg.assistant {
  background: var(--surface);
  color: var(--ink);
}
html.theme-dark button.danger { background: var(--surface); border-color: #5a3636; }
html.theme-dark .msg.system { background: #2a2417; color: #e0c98a; }
html.theme-dark img.logo-img { filter: brightness(.95); }

/* ---- Sections that hardcode light backgrounds (dark-mode fixes) ----
 * Calendar day cells, lineage timeline dots, the plan strip, the planner
 * header and the chat window all baked in white/near-white literals that
 * ignore the theme variables. Re-skin just those surfaces for dark mode. */

/* Chat window */
html.theme-dark .chatbox { background: var(--bg); }
html.theme-dark .msg.assistant.markdown code { background: var(--chip-bg); }
html.theme-dark .msg.assistant.markdown pre { background: var(--bg); }

/* Dashboard calendar */
html.theme-dark .cal-controls button:hover { background: var(--chip-bg); }
html.theme-dark .cal-day { background: var(--surface); }
html.theme-dark .cal-day:hover { background: var(--chip-bg); }
html.theme-dark .cal-day.is-other { background: #161d1a; }
html.theme-dark .cal-day.is-selected {
  background: color-mix(in srgb, var(--brand) 24%, var(--surface));
  border-color: var(--brand);
}
html.theme-dark .cal-chip { background: var(--chip-bg); }
html.theme-dark .cal-chip.kind-media-change-due { background: transparent; }
html.theme-dark .cal-detail { background: var(--surface); }

/* Lineage timeline stage dots + pipeline plan strip */
html.theme-dark .timeline-dot { background: var(--surface); box-shadow: none; }
html.theme-dark .timeline-milestone.kind-media-change-due .timeline-dot,
html.theme-dark .timeline-milestone.is-pending .timeline-dot { background: var(--surface); }
html.theme-dark .timeline-milestone.kind-discarded .timeline-dot,
html.theme-dark .timeline-milestone.kind-contamination .timeline-dot,
html.theme-dark .timeline-milestone.kind-media-change-due.is-overdue .timeline-dot {
  background: color-mix(in srgb, #c62828 22%, var(--surface));
}

/* "Work in progress" banner shown above the dashboard calendar. */
.wip-note {
  margin: 0 0 16px;
  padding: 12px 16px;
  border: 1px solid #f0d8a8;
  border-left: 4px solid #d99a2b;
  border-radius: var(--radius);
  background: #fff7e6;
  color: #7a5410;
  font-size: 14px;
  line-height: 1.45;
}
.wip-note strong { color: #8a5a00; }
html.theme-dark .wip-note {
  border-color: #5a4a22;
  border-left-color: #d99a2b;
  background: #2a2417;
  color: #e0c98a;
}
html.theme-dark .wip-note strong { color: #f0d18a; }


/* Floating night-theme toggle button (bottom-right). */
.theme-toggle {
  position: fixed; right: 18px; bottom: 18px; z-index: 50;
  width: 48px; height: 48px; padding: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border); box-shadow: var(--shadow);
  cursor: pointer; transition: background .2s, color .2s, transform .15s;
}
.theme-toggle:hover { transform: translateY(-2px); color: var(--brand); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-toggle svg {
  width: 22px; height: 22px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.theme-toggle__sun { display: none; }
html.theme-dark .theme-toggle__sun { display: block; }
html.theme-dark .theme-toggle__moon { display: none; }

@media (max-width: 560px) {
  .theme-toggle { right: 14px; bottom: 14px; width: 44px; height: 44px; }
}

/* GDPR cookie consent notice (bottom of the viewport). */
.cookie-banner {
  position: fixed; left: 18px; right: 18px; bottom: 18px; z-index: 60;
  max-width: 720px; margin: 0 auto;
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px;
  padding: 14px 18px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); font-size: 14px; line-height: 1.45;
}
/* The display:flex above would otherwise override the [hidden] attribute
   (same specificity), keeping the banner visible after Accept/Decline. */
.cookie-banner[hidden] { display: none; }
.cookie-banner__text { flex: 1 1 320px; min-width: 0; }
.cookie-banner__more {
  display: inline; padding: 0; margin-left: 4px;
  background: none; border: none; color: var(--accent);
  font: inherit; cursor: pointer; text-decoration: underline;
}
.cookie-banner__details { margin-top: 8px; }
.cookie-banner__details ul { margin: 0; padding-left: 18px; }
.cookie-banner__details li { margin: 2px 0; }
.cookie-banner__actions { flex: 0 0 auto; display: flex; gap: 8px; align-items: center; }
.cookie-banner__decline {
  padding: 10px 18px; border-radius: 8px; cursor: pointer;
  background: transparent; border: 1px solid var(--border); color: var(--ink);
  font-weight: 600;
}
.cookie-banner__decline:hover { background: var(--chip-bg); }
.cookie-banner__decline:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cookie-banner__accept {
  padding: 10px 22px; border-radius: 8px; cursor: pointer;
  background: var(--brand); border: 1px solid var(--brand-2); color: #fff;
  font-weight: 600;
}
.cookie-banner__accept:hover { background: var(--brand-2); }
.cookie-banner__accept:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 560px) {
  .cookie-banner { left: 10px; right: 10px; bottom: 10px; padding: 12px 14px; }
  .cookie-banner__actions { flex: 1 1 100%; }
  .cookie-banner__decline, .cookie-banner__accept { flex: 1 1 0; width: auto; }
}

/* ---- Read-only shared view ---- */
.readonly-banner {
  position: sticky;
  top: 0;
  z-index: 55;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  align-items: center;
  justify-content: center;
  padding: 8px 16px;
  background: var(--brand-2);
  color: #fff;
  font-size: 14px;
  text-align: center;
}
.readonly-banner a {
  color: #fff;
  font-weight: 600;
  text-decoration: underline;
  white-space: nowrap;
}

/* ---- View-only (RBAC) ---- */
/* On areas where the collaborator only has "view", write controls are hidden.
   The `view-only` body class is applied server-side (request.state.view_only)
   so controls never flash in before being removed. */
body.view-only [data-write] { display: none !important; }
.view-only-note {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(120, 120, 130, 0.12);
  color: var(--muted, #667);
  font-size: 13px;
  font-weight: 500;
}
.view-only-note__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #c9a227;
  flex: 0 0 auto;
}

/* ---- Share links (Settings) ---- */
.share-list { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.share-item {
  border: 1px solid var(--border, #d8e0da);
  border-radius: var(--radius, 10px);
  padding: 10px 12px;
  background: var(--surface);
}
.share-item.is-expired { opacity: 0.55; }
.share-item__main { display: flex; gap: 8px; align-items: center; }
.share-item__main .share-url {
  flex: 1 1 auto;
  min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  padding: 6px 8px;
}
.share-item__meta {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  margin-top: 6px;
  flex-wrap: wrap;
}
button.ghost.small {
  padding: 4px 10px;
  font-size: 12px;
  background: transparent;
  border: 1px solid var(--border, #d8e0da);
  border-radius: 8px;
  cursor: pointer;
}
button.ghost.small:hover { background: var(--chip-bg); }

/* ---- Labs: settings card + header switcher ---- */
#labs-body { display: flex; flex-direction: column; gap: 10px; }
.lab-item {
  border: 1px solid var(--border, #d8e0da);
  border-radius: 12px;
  padding: 10px 12px;
}
.lab-item.is-active { border-color: var(--brand-2, #3a7); background: var(--chip-bg); }
.lab-item__main { display: flex; gap: 8px; align-items: center; }
.lab-item__main .lab-name {
  flex: 1 1 auto;
  padding: 6px 8px;
  border: 1px solid var(--border, #d8e0da);
  border-radius: 8px;
  font: inherit;
}
.lab-item__main .lab-name-static { flex: 1 1 auto; font-weight: 600; }
.lab-badge {
  font-size: 11px;
  font-weight: 600;
  color: var(--brand-2, #3a7);
  border: 1px solid var(--brand-2, #3a7);
  border-radius: 999px;
  padding: 2px 8px;
}
.lab-item__meta {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  margin-top: 6px;
  flex-wrap: wrap;
}
.lab-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.lab-collab { margin-top: 10px; border-top: 1px dashed var(--border, #d8e0da); padding-top: 10px; }
.collab-list { display: flex; flex-direction: column; gap: 6px; }
.collab-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 14px;
}
.collab-invite span { font-style: italic; }
.collab-member {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 0;
  border-bottom: 1px dashed var(--border, #e3e9e3);
}
.collab-member:last-child { border-bottom: 0; }
.collab-name { font-weight: 600; }
.collab-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.collab-role-sel { font-size: 13px; padding: 3px 6px; }
.collab-custom-wrap.hidden, .collab-invite-custom-wrap.hidden { display: none; }
.collab-custom {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 6px 12px;
  padding: 8px 10px;
  margin-top: 2px;
  background: var(--surface-2, #f4f7f3);
  border-radius: 8px;
}
.collab-area {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 13px;
}
.collab-area select { font-size: 13px; padding: 2px 5px; }

.user-menu__labs {
  border-bottom: 1px solid var(--border, #d8e0da);
  padding: 6px 0;
  margin: 4px 0;
}
.user-menu__labs-head {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted, #8a948e);
  padding: 4px 12px;
}
.user-menu__lab {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 8px;
  padding: 7px 12px;
  background: transparent;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  color: inherit;
}
.user-menu__lab:hover { background: var(--chip-bg); color: var(--brand-2); }
.user-menu__lab.is-active { font-weight: 600; }
.user-menu__lab-check { color: var(--brand-2, #3a7); }

