/* Styles for OUR OWN admin widgets only (action rows, element trees, prompt-example panels,
   the PFL filter/modal UI built by pfl_inline.js, task_poll banners) plus a few deliberate
   overrides of unfold chrome (density, the docked filter rail). Everything else about the admin
   look is unfold's. Loaded globally via UNFOLD["STYLES"] (project/unfold.py). */

:root {
    /* Reference unfold's own palette variables so these stay the theme's exact values instead
       of drifting from hand-copied hexes; the fallback keeps them working if a name changes. */
    --icc-border: var(--color-base-200, #e5e7eb);   /* hairlines everywhere */
    --icc-muted: var(--color-base-500, #6a7282);    /* secondary text/icons */
    --icc-soft: var(--color-base-50, #f9fafb);      /* soft panel backgrounds */
    --icc-surface: #fff;                            /* card / rail / modal backgrounds */
    --icc-danger: #dc2626;
}

/* ===== General link rule ================================================== */
/* Link styling by CONTEXT, never per-case. QUIET is the default (surrounding text color,
   underline on hover). GREEN (no underline) is the exception, for exactly three cases - and
   NEVER inside a table (`:not(table *)`), because a link in a table must never be green:
     1. a link that IS a field's value - `.readonly > a` (a key:value fieldset row: PFL, Parent,
        the File link, ...);
     2. unfold's native readonly FK fields (`.text-link`);
     3. `➜` arrow links (`.arrow-link`) - the ONE kind that stays green even inside a table.
   Everything else is quiet: segments/subelements/other table cells, element-tree leaves,
   validation messages, task toasts. Scope: `#content-main` (not sidebar/breadcrumb chrome) +
   `body.change-form` (not changelists) + message lists; buttons/JS action controls excluded. */
:is(body.change-form #content-main, ul.messagelist) a:not(.button):not([class*="admin-"]) {
    color: inherit;
}
/* Underline-on-hover (the "this is a link" affordance) is confined to the few surfaces where
   clicking is the point: messages + form warnings/errors, and the Element tree + Segment table.
   Links everywhere else stay text-colored but flat (no hover underline). Green links/arrows never
   underline anyway (their rule sets text-decoration:none). */
:is(ul.messagelist, ul.errorlist, .errornote, .element-tree-output, .segment-tree) a:hover {
    text-decoration: underline;
}
/* `hover:underline` isn't in unfold's compiled Tailwind build; provide it so a quiet link can opt
   into the hover affordance by class (e.g. the resolved links inside the task-arguments JSON). */
.hover\:underline:hover {
    text-decoration: underline;
}
/* GREEN exceptions (`!important` cleanly overrides the quiet default - deliberate, not a
   specificity accident). Arrows green anywhere; field-value + native-FK links green ONLY outside
   a table. */
a.arrow-link,
body.change-form #content-main .readonly > a:not(table *):not(.button):not([class*="admin-"]),
body.change-form #content-main a.text-link:not(table *) {
    color: var(--color-primary-600) !important;
    text-decoration: none !important;
}

/* ===== Action button row (Product / PFL change pages) ===================== */

.action-button-row,
.action-button-row .force-toggle {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.action-button-row .force-toggle {
    gap: 4px;
    margin-left: 6px;
    font-size: 0.8125rem;
    color: var(--icc-muted);
}

/* Our action buttons + plain `.button` links, styled to match unfold's primary buttons. */
.action-button-row .button,
a.button {
    display: inline-flex;
    align-items: center;
    background: var(--color-primary-600, oklch(59.6% .145 163.225));
    border-radius: 6px;
    color: #fff;
    cursor: pointer;
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1;
    padding: 8px 12px;
    text-decoration: none;
}
.action-button-row .button:hover,
a.button:hover {
    background: var(--color-primary-700, oklch(50.8% .118 165.612));
    color: #fff;
}
/* Focus ring on theme: recolor ONLY (keep the browser/unfold thickness + offset). Covers both the
   native outline (outline-color) and unfold's Tailwind ring (--tw-ring-color). */
.action-button-row .button:focus,
.action-button-row .button:focus-visible,
a.button:focus,
a.button:focus-visible {
    outline-color: var(--color-primary-600, #059669);
    --tw-ring-color: var(--color-primary-600, #059669);
}
/* Disabled action (rendered as a <span>, no href): greyed, inert - e.g. the add actions once the
   word is already in the vocabulary. Overrides the :hover rule too (still a .button). */
.action-button-row .button--disabled,
.action-button-row .button--disabled:hover {
    background: var(--color-base-200, #e5e7eb);
    color: var(--color-base-500, #6b7280);
    cursor: default;  /* inert, but no "block" (not-allowed) cursor on hover */
}

/* ===== task_poll.js injected banners ====================================== */
/* Unfold renders Django messages with its own markup; these style the list task_poll.js
   creates client-side for "Queued…" updates so it reads as a proper alert. */

ul.messagelist {
    list-style: none;
    margin: 0 0 16px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
ul.messagelist li {
    border-radius: 6px;
    padding: 10px 14px;
    font-size: 0.8125rem;
    background: #eff6ff;
    border: 1px solid #bfdbfe;
    color: #1e40af;
}
ul.messagelist li.success { background: #ecfdf5; border-color: #a7f3d0; color: #065f46; }
ul.messagelist li.warning { background: #fffbeb; border-color: #fde68a; color: #92400e; }
ul.messagelist li.error   { background: #fef2f2; border-color: #fecaca; color: #991b1b; }

/* ===== Density + alignment: compact, top-left everywhere ================== */
/* Unfold reserves 62.5px min-height, generous padding, and vertical centering per cell; our
   data pages are read-heavy tables - tighten rows and pin every cell to the top left. */

table.formset td[class*="field-"] {
    min-height: 0 !important;
    padding-top: 6px !important;
    padding-bottom: 6px !important;
    vertical-align: top !important;
    text-align: left !important;
}
table.formset td[class*="field-"] > div {
    align-items: flex-start !important;  /* the cell's inner flex also centered */
}
/* `td` AND `th`: Django renders the first list column as a row-header <th>, which keeps
   unfold's align-middle and drops its text to the row's vertical center on tall (expandable) rows. */
#result_list td,
#result_list th {
    vertical-align: top !important;
    text-align: left !important;
}

/* ===== Column sizing: two rules, every changelist ========================== */
/* Rule 1: every column hugs its content. (`width: 1%` clamps an auto-layout column to its
   minimum content width and bars it from receiving slack; `nowrap` keeps values one line.)
   The expandable section's [colspan] cell is excluded - nowrap would cascade into it.
   Rule 2: the main TEXT column(s) - one short field-name list - take ALL the leftover width
   and wrap. Every table names at least one, so tables still fill their full width and the
   slack always lands in the column meant to hold long text.
   Headers carry no per-column class; the column resolves to its widest cell, so styling the
   td is enough. Adding a long-text column to a list_display? Add its `field-<name>` here. */

/* Direct children only (`> tbody > tr >`) so the nested tables inside expandable [colspan]
   section rows keep their own layout. `:is(td, th)` because Django renders each row's FIRST
   data cell as a row-header <th>. */
#result_list > tbody > tr > :is(td, th):not([colspan]) {
    width: 1%;
    white-space: nowrap;
}

#result_list > tbody > tr > :is(td, th).field-value,
#result_list > tbody > tr > :is(td, th).field-name,
#result_list > tbody > tr > :is(td, th).field-email,
#result_list > tbody > tr > :is(td, th).field-__str__,
#result_list > tbody > tr > :is(td, th).field-display_name,
#result_list > tbody > tr > :is(td, th).field-product,
#result_list > tbody > tr > :is(td, th).field-meaning,
#result_list > tbody > tr > :is(td, th).field-phrases_display,
#result_list > tbody > tr > :is(td, th).field-task,
#result_list > tbody > tr > :is(td, th).field-task_name,
#result_list > tbody > tr > :is(td, th).field-observed,
#result_list > tbody > tr > :is(td, th).field-error,
#result_list > tbody > tr > :is(td, th).field-sent_display,
#result_list > tbody > tr > :is(td, th).field-received_display,
#result_list > tbody > tr > :is(td, th).field-segment_summary {
    width: auto;
    white-space: normal;
}

/* Same policy inside the expandable section's OWN table: every column tight except the value
   column, which takes the slack and wraps. Section cells carry no field-name class, so the
   value column is targeted by position - it's always the last column of the section. */
#result_list td[colspan] table :is(td, th) {
    width: 1%;
    white-space: nowrap;
}
#result_list td[colspan] table :is(td, th):last-child {
    width: auto;
    white-space: normal;
}

/* ===== Changelist section rows (expandable) =============================== */

.section-steps {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 12px;
}
.section-steps__step {
    flex: 1 1 14rem;
    min-width: 0;
}
.section-steps__step--wide {
    flex-basis: 100%;
}
.section-steps__label {
    font-weight: 600;
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--icc-muted);
    margin-bottom: 2px;
}
.section-steps__text {
    font-size: 0.8125rem;
    overflow-wrap: anywhere;
}

/* The expanded section is a colspan cell; inline-size containment zeroes its INTRINSIC width
   contribution (so expanding never shifts the other columns) while it still renders at the
   cell's full width. */
#result_list td[colspan] > div {
    contain: inline-size;
}

/* ===== Element tree previews (PFL tabs, inline rules cells) ================ */

.element-tree-output {
    white-space: pre-wrap;
    background: var(--icc-soft);
    border: 1px solid var(--icc-border);
    border-radius: 6px;
    padding: 12px;
    font-size: 0.8125rem;
    line-height: 1.6;
}
/* Faint per-level vertical guide in the tree view. Each indent level is its own 2-space span; the
   inset box-shadow paints a hairline on its left edge WITHOUT taking layout width, so the monospace
   columns stay aligned and the per-level lines read as continuous guides down the tree. */
.element-tree-output .tree-guide {
    box-shadow: inset 1px 0 0 color-mix(in srgb, var(--icc-muted) 30%, transparent);
}

/* Monospace text block for stored diagnostics (PFLStepFailure error/traceback): preserve the
   newlines + indentation so a traceback reads like a terminal, not one collapsed run-on line. */
.code-block {
    white-space: pre-wrap;
    overflow-wrap: anywhere;   /* long paths/URLs wrap instead of overflowing the card */
    margin: 0;
    background: var(--icc-soft);
    border: 1px solid var(--icc-border);
    border-radius: 6px;
    padding: 12px;
    font-size: 0.75rem;
    line-height: 1.5;
}

/* PFL-failure inline (DBTaskResult page): the Error preview sits in unfold's max-w-2xl readonly
   box, so a one-line message wraps and looks badly cut while the column has room to spare. Drop the
   cap so it uses the column's full width. Full message + traceback are on the linked failure page. */
#pfl_step_failures-group td.field-error_short div.readonly {
    max-width: none;
}

/* "Unbalanced parentheses" / render-failure badges. */
.parens-warning {
    color: #d63638;
    font-weight: bold;
}

/* Editable step textareas inside inline tables: fill the cell, grow with content. `display: block`
   drops the inline-block baseline gap - as an inline element the textarea reserves descender space
   below it, making its row taller than the read-only text rows beside it. */
.inline-textarea {
    display: block;
    width: 100%;
    box-sizing: border-box;
    field-sizing: content;
    resize: none;              /* autogrow.js owns the height; a manual handle only fights it (and let
                                  the box be dragged down to a sliver) */
    overflow: hidden;
    overflow-wrap: anywhere;
}
/* USER step affordance (PFL pipeline rows AND the product page's PFL inline): hovering the
   (idle) cell tints it to show it's editable; clicking drops straight into edit mode - highlight
   clears (`:focus-within`) and there's no focus ring, just a caret. Disabled textareas (the
   nutrition User column - edited via the matrix) are read-only, so no hover invitation. Purely
   visual: background/outline don't affect layout, so row heights are unchanged. */
td:has(.inline-textarea:not(:disabled)):hover:not(:focus-within) {
    background: var(--color-base-100);
}
.inline-textarea:focus {
    outline: none;
}
/* A disabled step textarea (the nutrition User column - edited via the matrix, not here) reads as
   plain text: no input chrome, same colour as the read-only step columns beside it. */
.inline-textarea:disabled {
    border: none;
    background: transparent;
    color: inherit;
    cursor: default;
}

/* ===== PFL pipeline (steps as ROWS on the PFL page) ====================== */
/* One row per step: label in a narrow left column, the value filling the rest. */

.pfl-pipeline {
    width: 100%;
    /* `separate` (not `collapse`) so row heights stay whole pixels - collapsed borders round each
       row to the device grid, drifting text rows and the textarea row ~0.5px out of sync per line
       on hi-DPI. border-spacing:0 keeps the hairlines flush, so it looks identical. */
    border-collapse: separate;
    border-spacing: 0;
}
.pfl-pipeline th {
    text-align: left;
    vertical-align: top;
    font-weight: 600;
    font-size: 0.8125rem;
    width: 6rem;               /* fixed label column; the value column takes the slack. min-width
                                  floors it - auto table-layout treats a bare `width` as a hint and
                                  shrinks the column back to its (short) label content otherwise. */
    min-width: 6rem;
    white-space: nowrap;
    padding: 8px 16px 8px 0;
    border-bottom: 1px solid var(--icc-border);
}
.pfl-pipeline td {
    vertical-align: top;
    padding: 8px 0;
    border-bottom: 1px solid var(--icc-border);
    font-size: 0.8125rem;
    line-height: 20px;         /* same line-height the textarea inherits, so a step's row height is
                                  padding + (lines x 20) whether it's read-only text or the editable
                                  USER textarea - every extra line adds the same 20px, rows stay in sync */
    overflow-wrap: anywhere;   /* long unbroken step text must wrap, not overflow */
}

/* Drop unfold's 224px label gutter for our full-bleed fields: the pipeline, the nutrition matrix,
   and the element-tree tabs (their tab title already names them - the "Element Tree (Tree)" field
   label just repeats it). */
.form-row:has(.pfl-pipeline) div[class*="lg:w-56"],
.form-row:has(.nutrition-matrix) div[class*="lg:w-56"],
.form-row:has(.element-tree-output) div[class*="lg:w-56"] {
    display: none;  /* the whole 224px label column, not just the label text */
}
div.readonly:has(.pfl-pipeline),
div.readonly:has(.nutrition-matrix),
div.readonly:has(.element-tree-output),  /* element-tree tabs - fill the card, don't cap at 2xl */
div.readonly:has(.code-block),           /* error/traceback + LLM prompt/reply blocks - fill width */
div.readonly:has(.llm-convo),            /* LLM few-shot conversation */
div.readonly:has(.llm-rounds),           /* LLM validator-rounds table */
div.readonly:has(.segment-tree) {  /* Translation segments table - fill the row (keeps its label) */
    max-width: none !important;
}

/* ===== Translation segments table (read-only inspector) ================== */
/* Themed with unfold's palette tokens (like .nutrition-matrix) so borders/header/hover match
   every other card and adapt to dark mode - no hand-picked hex, no #result_list machinery. */
.segment-tree {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}
.segment-tree th,
.segment-tree td {
    padding: 4px 10px;
    text-align: left;
    vertical-align: top;
}
.segment-tree th {
    font-weight: 600;
    color: var(--icc-muted);
    border-bottom: 1px solid var(--icc-border);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.segment-tree td {
    border-top: 1px solid var(--icc-border);
}
.segment-tree tr:hover td {
    background: var(--icc-soft);
}
/* `kind` is a fixed vocabulary - keep it one line and clamped to its content so the width goes
   to the four variable columns. `.dim` are the secondary columns (synonyms, trace). */
.segment-tree .col-kind {
    white-space: nowrap;
    width: 1%;
}
.segment-tree .dim {
    color: var(--icc-muted);
}

/* Untranslated-segment flags: a colour square keyed to the sub-kind, shown as a left gutter in the
   segment tree and inline in the Coverage line (which doubles as the legend). Translated rows carry
   a transparent square so their text stays aligned with the flagged rows. */
.seg-flag {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 6px;
    border-radius: 2px;
    vertical-align: middle;
}
/* The COLOUR is set inline from formatter.KIND_TINT (admin/translation.py `_flag_swatch`), so a
   swatch and the tint behind that kind's text are the same hue + saturation by construction and
   differ only in lightness. Only geometry lives here. */
.seg-flag--none { background: transparent; }      /* fine as-is - reserve the gutter, no colour */

/* Coverage breakdown: one item per kind, each its own inline-flex so the swatch stays glued to ITS
   label and the gap between items is real spacing (not &nbsp; runs, which read as ragged). */
.coverage-breakdown {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 18px;
    margin-top: 4px;
}
.coverage-breakdown__item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}
.coverage-breakdown .seg-flag {
    margin-right: 0;  /* the flex gap owns the spacing here */
}
/* The transparent placeholder exists to align the TREE's gutter; in this flex row it is just a
   ragged 10px hole before the unflagged kinds. */
.coverage-breakdown .seg-flag--none {
    display: none;
}

/* ===== LLM call diagnostics (the prompt/reply/validator inspector) ======== */
/* Few-shot conversation: each turn a labelled block, colour-keyed by side (blue = our messages,
   green = the model). The role label distinguishes the injected examples from the real request. */
.llm-convo {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.llm-msg {
    border-left: 3px solid var(--icc-border);
    padding-left: 10px;
}
.llm-msg--user { border-left-color: #2563eb; }                       /* our side */
.llm-msg--assistant { border-left-color: var(--color-primary-600); } /* the model */
.llm-msg__role {
    margin-bottom: 4px;
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--icc-muted);
}
/* Status pill in the overview: OK green, error red. */
.llm-status { font-weight: 600; }
.llm-status--ok { color: var(--color-primary-600); }
.llm-status--warn { color: #d97706; }   /* call OK but the answer never passed validation */
.llm-status--err { color: var(--icc-danger); }
.llm-status--muted { color: var(--icc-muted); }   /* no validator ran - green tick, grey label */

/* Validator loop as a table: candidate + the local verdict fed back (VALID green, else red). */
.llm-rounds {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}
.llm-rounds th,
.llm-rounds td {
    padding: 6px 10px;
    text-align: left;
    vertical-align: top;
    border-top: 1px solid var(--icc-border);
}
.llm-rounds th {
    border-top: none;
    border-bottom: 1px solid var(--icc-border);
    color: var(--icc-muted);
    text-transform: uppercase;
    font-size: 0.6875rem;
    letter-spacing: 0.03em;
}
.llm-rounds td:first-child {
    width: 1%;
    white-space: nowrap;
    color: var(--icc-muted);
}
/* Column policy: # / phase / verdict hug their content; candidate (3) takes the leftover width.
   Header cells drive the sizing (no colspans in the header row, so nth-child = the real column
   there); verdict cells get nowrap via .llm-verdict below. */
.llm-rounds tr:first-child th {
    width: 1%;
    white-space: nowrap;
}
.llm-rounds tr:first-child th:nth-child(3) {
    width: auto;
}
.llm-verdict {
    white-space: nowrap;
}
.llm-cand {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: 12px;
}
.llm-verdict--valid { color: var(--color-primary-600); font-weight: 600; }
.llm-verdict--invalid { color: var(--icc-danger); }
.llm-verdict--none { color: var(--icc-muted); }
/* In-round self-check sub-rows sit under their round, dimmed and slightly inset. */
.llm-rounds .llm-subrow td { color: var(--icc-muted); }
.llm-rounds .llm-subrow .llm-cand { padding-left: 12px; }

/* The Flow strip (in the overview, under Run summary): one lane per round, pill nodes chained
   with arrows - ORIGINAL block names, one rule for every call type - ending in the gate verdict;
   dim bridges between lanes say how the loop continued. */
.llm-flow {
    display: flex;
    flex-direction: column;
    margin-top: 4px;
}
.llm-flow__lane {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 8px 0;
}
.llm-flow__meta {
    flex: none;
    min-width: 9rem;
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--icc-muted);
    line-height: 1.6;
}
.llm-flow__nodes {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    row-gap: 8px;
}
.llm-flow__arrow {
    padding: 0 6px;
    color: var(--icc-muted);
}
.llm-flow__node {
    padding: 5px 14px;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}
.llm-flow__node--think { background: #ede9fe; color: #6d28d9; }        /* thinking */
.llm-flow__node--ok { background: #d1fae5; color: #047857; }           /* tool_use that passed */
.llm-flow__node--fail { background: #fee2e2; color: #b91c1c; }         /* tool_use that failed */
.llm-flow__node--text { background: var(--icc-soft); color: var(--icc-muted); border: 1px solid var(--icc-border); }
.llm-flow__node--redacted { background: #111827; color: #fff; }        /* redacted_thinking */
.llm-flow__node--trunc { background: #fef3c7; color: #b45309; }        /* round died unanswered */
/* Terminal gate nodes: solid fill - the round's verdict is the loudest thing in the lane. */
.llm-flow__node--gate-ok { background: var(--color-primary-600); color: #fff; }
.llm-flow__node--gate-fail { background: var(--icc-danger); color: #fff; }
.llm-flow__bridge {
    padding: 2px 0 2px calc(9rem + 16px);
    font-size: 0.6875rem;
    color: var(--icc-muted);
}
.llm-phase {
    margin-left: 4px;
    font-size: 0.625rem;
    text-transform: uppercase;
    color: var(--icc-muted);
}

/* ===== Nutrition matrix (nutrient rows × step columns, label-style) ======= */

.nutrition-matrix {
    border-collapse: collapse;
    min-width: 40rem;
    font-size: 0.8125rem;
}
.nutrition-matrix th,
.nutrition-matrix td {
    border: 1px solid var(--icc-border);
    padding: 6px 12px;
    text-align: left;
    vertical-align: top;
}
.nutrition-matrix th {
    background: var(--icc-soft);
    font-weight: 600;
}

/* ===== Nutrition declaration: per-step tables, user editable in place ====== */
/* NutritionRowInline (custom template nutrition_declaration.html): every step renders the same
   .nutrition-decl__grid table so the pipeline reads as ONE aligned stack. Fixed layout + the SAME
   four plain-percentage columns everywhere (calc() column widths are silently dropped by table
   layout - measured, not theory): the editable table's 4th column holds the row ✕; read tables
   render it as a borderless ghost, so their grid visually ends at Portion yet every data column
   lines up pixel-for-pixel with the editable one. */

.nutrition-decl__grid {
    table-layout: fixed;
    width: 100%;
    min-width: 0;
}
.nutrition-decl__grid th:nth-child(1) { width: 40%; }
.nutrition-decl__grid th:nth-child(2) { width: 33%; }
.nutrition-decl__grid th:nth-child(3) { width: 24%; }
.nutrition-decl__grid th:nth-child(4) { width: 3%; }
.nutrition-decl__grid td.nutrition-decl__ghost-col,
.nutrition-decl__grid th.nutrition-decl__ghost-col {
    border: none;
    background: transparent;
    padding: 0;
}

.nutrition-decl__caption {
    font-weight: 600;
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--icc-muted);
    margin-bottom: 4px;
}
/* The cell inputs: chromeless, filling the WHOLE cell - the input carries the cell's padding
   (6px 12px, same as the read tables' td) so the text lands exactly where read-table text does.
   The editable affordance is the pfl-pipeline pattern: hovering the (idle) cell tints the entire
   rectangle; clicking drops straight into edit mode - tint clears, no focus ring, just a caret. */
.nutrition-decl__grid td:has(.nutrition-decl__input) {
    padding: 0;
}
.nutrition-decl__grid .nutrition-decl__input {
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    border: none;
    background: transparent;
    padding: 6px 12px;
    font: inherit;
    color: inherit;
}
.nutrition-decl__grid td:has(.nutrition-decl__input):hover:not(:focus-within) {
    background: var(--color-base-100);
}
.nutrition-decl__grid .nutrition-decl__input:focus {
    outline: none;
}
/* Per-row remove control. Selector carries the table class: the bare .nutrition-decl__rm-col
   (0,1,0) LOSES to `.nutrition-matrix td` (0,1,1) - its left-align/padding/top-align would win
   and shove the ✕ off-center. Padding dies so the ✕ centers over the full 2rem cell. */
.nutrition-decl__grid td.nutrition-decl__rm-col,
.nutrition-decl__grid th.nutrition-decl__rm-col {
    white-space: nowrap;
    text-align: center;
    vertical-align: middle;
    padding: 0;
}
.nutrition-decl__rm,
.nutrition-decl__clear {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--icc-muted);
    font-size: 0.875rem;
    line-height: 1;
    padding: 0 4px;
}
.nutrition-decl__rm:hover,
.nutrition-decl__clear:hover {
    color: var(--icc-danger);
}
/* The integrated add control: the table's own last row - a quiet full-width "+ Add row" that
   reads as part of the grid (saving is the page-level Save; there are no other buttons). */
.nutrition-decl__add-row td {
    padding: 0;
}
.nutrition-decl__add {
    display: block;
    width: 100%;
    border: none;
    background: none;
    cursor: pointer;
    color: var(--icc-muted);
    font: inherit;
    font-size: 0.8125rem;
    text-align: left;
    padding: 6px 12px;
}
.nutrition-decl__add:hover {
    background: var(--color-base-100);
    color: var(--color-primary-600, oklch(59.6% .145 163.225));
}

/* ===== Compact inline tables ================================================ */
/* The phrase-forms inline (#forms-group) and the Components inline (#components-group) share one
   look - no lines between rows, 3px top/bottom padding (6px on the first/last row). The input
   boxes already delineate the grid, so unfold's inter-row borders come off. */
:is(#forms-group, #components-group) td.field-order {
    width: 1%;
}
:is(#forms-group, #components-group) td.field-order input {
    width: 5rem;
    min-width: 0;
}
/* Every cell (field cells AND the delete cell) carries unfold's min-h-[62.5px] + py-3 + its own
   border-b/border-t. A row is as tall as its tallest cell, so ALL of them must be reset - covering
   only the field- cells left the delete cell dragging the row back to 62px and drawing stray lines.
   `:not([colspan])` skips unfold's full-width template/spacer cell (colspan=100) - collapsing it
   turned its padding box into a 6px full-width bar between rows. */
:is(#forms-group, #components-group) td:not([colspan]) {
    min-height: 0 !important;
    height: auto !important;
    padding-top: 3px !important;
    padding-bottom: 3px !important;
    border-top: none !important;
    border-bottom: none !important;
    vertical-align: middle !important;  /* global density rule top-aligns inline cells; center here */
}
/* Breathing room at the ends: double the padding above the first row and below the last. Each
   form-row is its own tbody; `.last` marks the last real row (unfold's own marker), `empty-form`
   is the hidden clone template. */
:is(#forms-group, #components-group) tbody.form-group:first-of-type td:not([colspan]) {
    padding-top: 6px !important;
}
:is(#forms-group, #components-group) tbody.last td:not([colspan]) {
    padding-bottom: 6px !important;
}
/* The full-width spacer/template cell: no height contribution, no visible band. */
:is(#forms-group, #components-group) td[colspan] {
    padding: 0 !important;
    border: none !important;
}
:is(#forms-group, #components-group) td[class*="field-"] > div {
    align-items: center !important;  /* the outer flex wrapper too, not just the table cell */
    margin: 0 !important;
}

/* ===== LLM-review lookup dropdown (lookup_dropdown.js) ====================== */
/* The menu is appended to <body> and positioned by the script. */

/* Match unfold's select2 (admin-autocomplete) dropdown exactly: 4px padding around the option
   list, subtle 1px shadow, 6px radius. */
.review-lookup__menu {
    position: absolute;
    z-index: 60;
    max-height: 260px;
    overflow-y: auto;
    padding: 4px;
    background: var(--icc-surface);
    border: 1px solid var(--icc-border);
    border-radius: 6px;
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
/* An option = a select2 result row: 14px text, 8px padding, its own rounded rect, muted-slate
   text (--color-font-default-light). */
.review-lookup__option {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 8px;
    margin-bottom: 2px;
    border-radius: 6px;
    font-size: 0.875rem;
    color: var(--color-font-default-light, #4b5563);
    white-space: nowrap;
    cursor: pointer;
}
.review-lookup__option:last-child {
    margin-bottom: 0;
}
/* select2 auto-highlights one row (the first, then whatever the mouse/keys land on) in base-100
   grey - lookup_dropdown.js moves this class, mirroring that behaviour. */
.review-lookup__option--active {
    background: var(--color-base-100, #f3f4f6);
}

/* ===== Prompt admin: "Available variables" + "Examples" panels ============ */

/* Languages checkbox list (PromptForm.selected_languages): lay the options out in columns
   across the row instead of one per line. `selected_languages` exists only on the Prompt
   form, so the id keeps this page-local. 12rem tracks = the .pfl-filter-group__items precedent. */
.field-selected_languages #id_selected_languages {
    display: grid;
    grid-template-columns: repeat(auto-fill, 7rem);  /* language names are short - snug columns */
    gap: 6px 12px;
    width: 100%;  /* the widget root otherwise shrinks to one track and auto-fill sees no room */
}
.field-selected_languages #id_selected_languages label {
    display: inline-flex;  /* checkbox never separates from its label */
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    margin: 0;
    cursor: pointer;
}

.prompt-var--used {
    color: #188038;
    font-weight: bold;
}

/* ===== LLM-match review (buttons + status on the match page, intermediate action forms) ===== */

/* The Add Form / Add dispreferred intermediate pages: a small centered form card. */
.review-action {
    max-width: 36rem;
}
.review-action__row {
    margin-bottom: 12px;
}
.review-action__row label {
    display: block;
    font-weight: 600;
    font-size: 0.875rem;
    margin-bottom: 4px;
}
.review-action__row :is(input[type="text"], select) {
    width: 100%;
    height: 38px;
    box-sizing: border-box;
    padding: 0 10px;
    border: 1px solid var(--icc-border);
    border-radius: 6px;
    background: var(--icc-surface);
    font-size: 0.875rem;
    color: var(--color-font-default-light, #4b5563);
}
.review-action__row :is(input[type="text"], select):focus {
    /* theme-green focus, matching unfold's own fields - not the browser's default ring */
    outline: 2px solid var(--color-primary-600);
    outline-offset: -2px;
}
/* Native select chrome off; unfold-style chevron pinned 10px from the right, centered.
   `.review-action` prefix out-specifies the shared :is(input, select) row rule above - its
   `background` shorthand would otherwise wipe the chevron image and its padding would win. */
.review-action .review-action__row select {
    appearance: none;
    padding-right: 32px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236a7282' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
}
.review-action__help {
    margin-top: 3px;
    font-size: 0.75rem;
    color: var(--icc-muted);
}
.review-action__buttons {
    margin-top: 16px;
}
.review-action__cancel {
    margin-left: 10px;
    align-self: center;
    /* A grey PILL matching the disabled buttons (same base-200 box). Both box and text are theme
       vars so they flip together and stay contrasting in light/dark - a fixed color on the box's
       fixed surface was the whole invisibility problem. */
    padding: 8px 12px;
    border-radius: 6px;
    background: var(--color-base-200, #e5e7eb);
    color: var(--color-base-500, #6b7280) !important;
    font-size: 0.8125rem;
    text-decoration: none;
}
.review-action__cancel:hover {
    background: var(--color-base-300, #d1d5db);
}
.review-action .errorlist {
    color: var(--icc-danger);
    font-size: 0.8125rem;
    list-style: none;
    padding: 0;
    margin: 4px 0 0;
}

.prompt-examples__lang {
    margin: 12px 0 6px;
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--icc-muted);
}

/* The examples panel is a readonly field, so unfold caps it at max-w-2xl (42rem); widen it to
   max-w-4xl (56rem) so it lines up with the template textareas above, which use that width. */
div.readonly:has(.prompt-examples) {
    max-width: 56rem !important;
}

/* One card per example: a clickable `wrong → correct` row (opens the edit popup). */
.prompt-examples {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0 0 6px;
}
.prompt-example {
    display: grid;
    grid-template-columns: 1fr 1rem 1fr;
    align-items: start;
    gap: 10px;
    padding: 7px 12px;
    border: 1px solid var(--icc-border);
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    font-size: 0.8125rem;
    line-height: 1.4;
    overflow-wrap: anywhere;
    transition: background 0.1s, border-color 0.1s;
}
.prompt-example:hover {
    background: var(--icc-soft);
    border-color: var(--color-primary-600, oklch(59.6% .145 163.225));
}
.prompt-example__wrong {
    color: var(--icc-muted);  /* the "before" */
}
.prompt-example__correct {
    color: var(--color-font-important-light, #1f2937);  /* the "after" */
}
.prompt-example__arrow {
    color: var(--icc-muted);
    text-align: center;
}
.prompt-example--disabled {
    opacity: 0.4;
}

.prompt-examples__group {
    margin-bottom: 16px;
}

.prompt-examples__empty {
    margin: 0 0 6px;
    color: var(--icc-muted);
    font-style: italic;
}

.prompt-examples__add {
    display: inline-block;
    margin-top: 2px;
    font-size: 0.8125rem;
}

/* ===== PFLs inline - filter / column / modal UI (built by pfl_inline.js) == */

/* Flush header section of the PFLs card - no card-in-a-card corner clash. */
.pfl-filter-panel {
    margin: 0;
    padding: 12px;
    background: #f0fdf4;
    border: 0;
    border-bottom: 1px solid #bbf7d0;
    border-radius: 0;
}

.pfl-filter-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid #bbf7d0;
}

.pfl-filter-actions .pfl-button-danger {
    background: var(--icc-danger);
    color: #fff;
}

.pfl-filter-group { margin-bottom: 8px; }
.pfl-filter-group__header { margin-bottom: 4px; }
.pfl-filter-group__title { margin-right: 10px; }

/* A checkbox never separates from its label; fixed grid columns keep the
   checkbox list aligned AND compact. */
.pfl-filter-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
    margin: 0;
    cursor: pointer;
    user-select: none;
}
.pfl-filter-label--all { font-weight: bold; }
.pfl-filter-group__items {
    display: grid;
    grid-template-columns: repeat(auto-fill, 14rem);
    gap: 6px 12px;
    padding-left: 16px;
    margin-top: 4px;
}

.pfl-column-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    margin: 0;
    padding: 8px 12px;
    background: var(--icc-soft);
    border: 0;
    border-bottom: 1px solid var(--icc-border);
    border-radius: 0;
}
.pfl-column-panel__title { margin-right: 10px; }

.pfl-modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
}

.pfl-modal-dialog {
    background: var(--icc-surface);
    padding: 24px;
    border-radius: 8px;
    max-width: 480px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

.pfl-modal-message {
    margin-bottom: 20px;
    font-size: 14px;
    text-align: center;
    white-space: pre-line;  /* confirm messages carry a \n linebreak */
}

/* The affected-phrase link inside the confirm message: reads as part of the sentence, underlines on hover. */
.pfl-modal-message a { color: inherit; text-decoration: none; }
.pfl-modal-message a:hover { text-decoration: underline; }
.pfl-modal-buttons {
    display: flex;
    justify-content: center;
    gap: 10px;
}

/* Hardcoded grey, not a theme var: the dialog bg is always white, so a dark-mode-flipping var would
   turn the Cancel invisible. #6b7280 = base-500's light-mode shade - visible on white either theme. */
.pfl-modal-button { padding: 8px 15px; border-radius: 6px; background: var(--color-base-200, #e5e7eb); color: var(--color-base-500, #6b7280); }
.pfl-modal-button--danger { background: var(--icc-danger); color: #fff; }

/* ===== Persistent filter column: docked rail, collapsible + resizable ===== */
/* Unfold's filter card is a w-80 (320px) slide-over; docked mode (>= 1280px,
   list_filter_sheet=False) turns it into a right sidebar. The Filters button - which unfold
   hides in docked mode - stays visible and acts as the dock's collapse toggle
   (custom_js/filters_toggle.js; state kept in localStorage). The slide-over on smaller screens
   keeps stock width + behavior. */

@media (min-width: 1280px) {
    #changelist-filter .w-80 {
        width: 200px !important;
    }
    .filter-open-button {
        display: flex !important;
    }
    /* Docked, the panel is a right SIDEBAR: position STICKY, not fixed - sticky moves on the
       compositor thread, so during fast scrolls the rail's top edge tracks the header with ZERO
       lag (a JS-updated `top` lags the compositor and flashes over/under the header). In flow it
       sits right under the header; scrolled, it pins to the viewport top - natively. Only the
       HEIGHT is JS-driven (--icc-filters-h = down to the bottom bar, measured by
       filters_toggle.js); its transients hide under the opaque bottom bar, which out-stacks the
       rail. inset:auto wipes the stock inset-0. */
    /* filters_toggle.js reparents the rail into #main (a flex COLUMN, right under the header), so
       the sticky range spans the WHOLE page - the page bottom can never squeeze the rail up (the
       old results-wrapper parent ended just above the bottom bar; scrolling to the very bottom
       clipped the rail's top off-screen). Margins make it flow-neutral in the column: -16px eats
       the header's mb-4, the negative bottom margin (+16 compensation) returns the vertical space
       so the content below doesn't shift. */
    #changelist-filter {
        display: block !important;  /* beat x-show's inline display:none below unfold's 2xl */
        position: sticky !important;
        inset: auto !important;
        top: 0 !important;
        flex: none;
        margin-left: auto !important;  /* right edge of #main = the viewport's right edge */
        width: var(--icc-filters-w, 200px) !important;  /* drag-resizable; 200px default */
        height: var(--icc-filters-h, calc(100vh - 130px)) !important;
        margin-top: -16px !important;
        margin-right: 0 !important;
        margin-bottom: calc(16px - var(--icc-filters-h, calc(100vh - 130px))) !important;
        z-index: 30;
        background: var(--icc-surface);
        border-left: 1px solid var(--icc-border);
        overflow-y: auto;
        overscroll-behavior: contain;  /* rail scroll never chains into the page */
    }
    /* The rail is flow-neutral and hugs the right edge - reserve its width so results never slide
       under it. Same var as the rail width, so drag-resize moves both together; scoped by :has so
       filterless changelists get no phantom gap, and collapse frees the space. */
    html:not(.filters-collapsed) #main:has(> #changelist-filter) .changelist-form-container {
        margin-right: var(--icc-filters-w, 200px);
    }
    /* Belt-and-braces: if any transient overlap with the header still occurs, paint the header
       ABOVE the rail. Its own z-40 is inert while position:static - promote it. */
    div[class*="border-b"]:has(> div > #header-inner) {
        position: relative;
        z-index: 40;
    }
    .filters-resize-handle {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 5px;
        cursor: col-resize;
        z-index: 10;
    }
    html:not(.filters-collapsed) #changelist-filter .w-80 {
        position: static !important;  /* kill unfold's inner sticky - the rail IS the fixed frame */
        flex-direction: column;  /* stock card is a flex ROW; the toggle header needs a stack */
        width: 100% !important;
        padding: 8px 10px;
        /* unfold only strips its sheet-card styling at 2xl - the dock starts at 1280, so
           strip it here: no floating margins, no rounding, no shadow inside the rail */
        margin: 0 !important;
        border: 0 !important;
        border-radius: 0 !important;
        box-shadow: none !important;
        overflow: visible !important;
    }

    /* ONE scroller: the rail itself (overflow-y above). Unfold's card scrolls its filter list
       through an h-full percentage chain into a SimpleBar widget, and rewires that chain at its
       own 2xl breakpoint - fighting it per-width is whack-a-mole (a broken chain collapses the
       list to 0 height and then NOTHING scrolls). Instead, neutralize every inner scroller so
       the content flows at natural height and the rail scrolls it all as one column, with the
       rail's native scrollbar. */
    html:not(.filters-collapsed) #changelist-filter [class*="h-full"],
    html:not(.filters-collapsed) #changelist-filter [data-simplebar],
    html:not(.filters-collapsed) #changelist-filter .simplebar-wrapper,
    html:not(.filters-collapsed) #changelist-filter .simplebar-mask,
    html:not(.filters-collapsed) #changelist-filter .simplebar-offset,
    html:not(.filters-collapsed) #changelist-filter .simplebar-content-wrapper {
        position: static !important;
        height: auto !important;
        overflow: visible !important;
        /* SimpleBar's `.simplebar-wrapper{width:inherit}` collapses to shrink-to-fit once the
           chain is static, narrowing every filter card to its longest label (invisible at the
           200px default width, glaring on a drag-widened rail) - pin the whole chain full-width. */
        width: 100% !important;
        max-width: none !important;
    }

    /* Hide the rail's scrollbar entirely - it still scrolls (overflow-y: auto above), the bar just
       isn't drawn. Covers WebKit, Firefox (scrollbar-width) and old Edge (-ms-overflow-style). */
    html:not(.filters-collapsed) #changelist-filter {
        scrollbar-width: none;
        -ms-overflow-style: none;
    }
    html:not(.filters-collapsed) #changelist-filter::-webkit-scrollbar {
        display: none;
    }
    html:not(.filters-collapsed) #changelist-filter .simplebar-track,
    html:not(.filters-collapsed) #changelist-filter .simplebar-placeholder {
        /* SimpleBar's own scrollbar + its layout spacer (sized to the content it normally
           absolutely-positions) - with the content flowing statically the spacer would DOUBLE
           the column height. The rail's native scrollbar serves. */
        display: none !important;
    }

    /* Unfold strips the filter content's inner padding/chrome only at ITS 2xl - the dock
       starts at 1280, so apply the same strip here. Selectors key on the exact elements
       carrying the 2xl utilities. */
    html:not(.filters-collapsed) #changelist-filter div[class*="2xl:px-0"] {
        padding-left: 0 !important;
        padding-right: 0 !important;
    }
    html:not(.filters-collapsed) #changelist-filter div[class*="2xl:py-0"] {
        padding-top: 0 !important;
        padding-bottom: 0 !important;
    }
    /* The "Clear all filters" footer carries this class. Strip unfold's card background and
       flush its horizontal padding (the `2xl:px-0` rule handles left/right) - but keep top
       margin + padding so the button isn't jammed against the last filter option. */
    html:not(.filters-collapsed) #changelist-filter div[class*="2xl:border-t-0"] {
        background: transparent !important;
        margin-top: 8px;
        padding: 12px 0 0 !important;
    }

    /* Few-option filters (booleans: All│Yes│No) render as a horizontal segmented bar with
       `basis-1/3` cells; at the dock's 200px each cell is too narrow and truncates the counts.
       Stack them vertically like the other filter lists so nothing clips. */
    html:not(.filters-collapsed) #changelist-filter ul:has(> li[class*="basis-1/"]) {
        flex-direction: column;
    }
    html:not(.filters-collapsed) #changelist-filter ul:has(> li[class*="basis-1/"]) > li {
        border-right: 0 !important;
        border-bottom: 1px solid var(--icc-border);
    }
    html:not(.filters-collapsed) #changelist-filter ul:has(> li[class*="basis-1/"]) > li:last-child {
        border-bottom: 0 !important;
    }
    /* Stacked, the segmented links keep their `text-center`; left-align them with the same
       px-3 inset as the normal filter lists so every option lines up under its heading. */
    html:not(.filters-collapsed) #changelist-filter ul:has(> li[class*="basis-1/"]) a {
        text-align: left;
        padding-left: 12px;
        padding-right: 12px;
    }

    /* The toggle lives at the TOP of the rail (filters_toggle.js moves it there in docked
       mode), full-width, like a pane header, pinned while the rail scrolls. */
    .filter-open-button--rail {
        position: sticky;
        top: 0;
        z-index: 5;
        border: 0 !important;
        border-bottom: 1px solid var(--icc-border) !important;
        border-radius: 0 !important;
        box-shadow: none !important;
        background: var(--icc-surface) !important;
        /* When filters are active unfold restyles this as a filled primary button (white text
           on a colored fill); we force the fill back to white, so pin the text dark too or it
           reads white-on-white. */
        color: var(--color-font-important-light, #1f2937) !important;
        /* flex-start + auto-margin arrow: the clear-all icon (filters_toggle.js) sits right after
           the "Filters" text while the collapse arrow stays pinned to the right edge. */
        justify-content: flex-start;
        width: calc(100% + 20px);
        margin: -8px -10px 8px;
        padding: 8px 10px;
    }
    .filter-open-button--rail::after {
        margin-left: auto;
    }
    /* The clear-all icon: shown only when unfold rendered its "Clear all filters" footer (= an
       active filter exists); the link navigates, so no toggle styling. */
    .filters-reset {
        display: inline-flex;
        align-items: center;
        margin-left: 8px;
        color: var(--icc-muted);
    }
    .filters-reset:hover {
        color: var(--icc-danger);
    }
    .filters-reset .material-symbols-outlined {
        font-size: 18px;
    }
    /* Unfold's funnel glyph inside the toggle is noise next to the panel arrow - drop it. */
    .filter-open-button--rail > .material-symbols-outlined {
        display: none;
    }
    /* The button is the dock's collapse toggle up here - say so with a panel arrow that
       flips with the state (material symbol ligatures; the font ships with unfold). */
    .filter-open-button::after {
        content: "right_panel_close";
        font-family: "Material Symbols Outlined";
        font-size: 18px;
        font-weight: normal;
        line-height: 1;
    }
    html.filters-collapsed .filter-open-button::after {
        content: "right_panel_open";
    }

    /* Collapsed: the rail shrinks to a 0-width STICKY strip (not display:none - it stays in flow
       so the reopen arrow, its child, keeps riding the compositor-glued position). The inner card
       hides all content; the rail itself keeps overflow visible so the arrow can hang outside. */
    html.filters-collapsed #changelist-filter,
    html.filters-collapsed #changelist-filter .w-80 {
        width: 0 !important;
        min-width: 0 !important;
        padding: 0 !important;
        border: none !important;
    }
    html.filters-collapsed #changelist-filter .w-80 {
        overflow: hidden !important;
        margin: 0 !important;
    }
    html.filters-collapsed #changelist-filter {
        overflow: visible !important;  /* the arrow hangs at left:-22px - don't clip it */
    }
    /* …and a small arrow tab reopens it: an ABSOLUTE child of the sticky rail, so it always sits
       exactly where the Filters row would be - gliding with the header, zero lag. */
    html.filters-collapsed #filters-edge-handle {
        display: flex;
        position: absolute;
        left: -22px;
        top: 0;  /* flush with the rail's top = exactly where the Filters row starts */
        width: 22px;
        height: 48px;
        align-items: center;
        justify-content: center;
        background: var(--icc-surface);
        border: 1px solid var(--icc-border);
        border-right: 0;
        border-radius: 6px 0 0 6px;
        box-shadow: -1px 1px 3px rgba(0, 0, 0, 0.06);
        color: var(--icc-muted);
        cursor: pointer;
        z-index: 40;
    }

    /* The core content drops its card: results + rail read as ONE white app pane between
       the two sidebars (borders/shadows/rounding off; white pulled up to the header line). */
    .changelist-form-container {
        background: var(--icc-surface);
        margin-top: -16px !important;
        padding-top: 16px !important;
        min-height: calc(100vh - 65px);
    }
    #changelist-form > div,
    #changelist div[class*="lg:border"] {
        border: 0 !important;
        box-shadow: none !important;
        border-radius: 0 !important;
    }
    /* The toolbar's top padding pushed the search bar 12px below the left sidebar's search -
       zero it so both bars sit on the same line, same height. */
    #changelist .changelist-form-container > div > div[class*="lg:border"] {
        padding-top: 0 !important;
    }
    /* The flatten above is for the PAGE chrome - the expandable section rows keep their own
       card borders (they're islands inside the table, not page chrome). */
    #result_list td[colspan] div[class*="lg:border"] {
        border: 1px solid var(--icc-border) !important;
        border-radius: 6px !important;
    }
}

#filters-edge-handle {
    display: none;  /* only exists visually when docked + collapsed (rule above) */
}

/* ===== Sidebar "+" (add new) - injected by sidebar_add_link.js ============= */
/* Right-flush against the nav-row edge, same column as the group ">" chevrons. */

.sidebar-add-link {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    display: flex;
    align-items: center;
    color: #9ca3af;
}
.sidebar-add-link:hover {
    color: var(--color-primary-600, oklch(59.6% .145 163.225));
}
.sidebar-add-link .material-symbols-outlined {
    font-size: 18px;
}

/* ===== Constance config: uniform, left-aligned value inputs ================
   The only changelist with editable cells (no list_editable elsewhere), so the
   scope is safe. Number inputs auto-size to their content and the select hugs
   its option, so they render at different widths; pin them all to one narrow
   width, text flush to the same left edge. */

#changelist-form .data-row td select,
#changelist-form .data-row td input[type="text"],
#changelist-form .data-row td input[type="number"],
#changelist-form .data-row td input[type="url"],
#changelist-form .data-row td textarea {
    width: 8.5rem;
    max-width: 100%;
    box-sizing: border-box;
    padding-left: 0;
}
/* The native <select> adds an intrinsic left text inset the inputs lack, so its
   value hangs right of the numbers. Strip the native chrome (removing both the
   inset AND the built-in arrow) and paint our own chevron so the text aligns. */
#changelist-form .data-row td select {
    appearance: none;
    padding-right: 1.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236a7282' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.25rem center;
}

/* Column widths: the first column (the help text, under the "Name" header) flex-wraps and soaks up
   all the leftover width; every other column hugs its content. Upstream instead caps help at
   max-w-sm and lets the value column sprawl. Scoped by `:has(.reset-link)` - the per-row
   reset-to-default control ONLY the Constance results table has - because #changelist-form (and
   even `.data-row`) wrap every unfold changelist. */
#changelist-form table:has(a.reset-link) {
    width: 100%;
}
#changelist-form table:has(a.reset-link) th,
#changelist-form table:has(a.reset-link) td {
    width: 1%;
    white-space: nowrap;
}
#changelist-form table:has(a.reset-link) tr > :first-child {
    width: auto;
    max-width: none;  /* override Tailwind max-w-sm on the help cell */
    white-space: normal;
}
