/* Necretine Web UI. Design tokens first; every rule below uses them, so sizes, spacing and colors come from one
   small scale (docs/ui/product_direction.md §38–41). No inline styles (CSP style-src 'self'), no web fonts. */

/* ---------- Tokens ---------- */
:root {
  color-scheme: light dark; /* native controls (check boxes, selects, scroll bars) follow the theme */
  /* Surfaces and lines */
  --bg: #ffffff;              /* page */
  --surface: #ffffff;         /* header, panels, controls */
  --surface-sunken: #f4f5f7;  /* bars, notices, folded panels, hover */
  --border: #e3e6ea;          /* separators */
  --border-control: #8b94a1;  /* control outlines (3:1 against the surface) */

  /* Text */
  --text: #1a1d23;
  --text-secondary: #4a5260;
  --text-muted: #636c7a;

  /* Accent and semantic colors */
  --accent: #2457c5;
  --accent-hover: #1d479f;
  --accent-fg: #ffffff;
  --accent-soft: color-mix(in srgb, var(--accent) 9%, transparent);
  --success: #1f7a45;
  --warning: #9a6200;
  --danger: #b42318;
  --danger-fg: #ffffff;       /* text on a solid danger button */
  --danger-soft: color-mix(in srgb, var(--danger) 9%, transparent);
  --visited: #681da8;         /* viewed listings, like a visited link (D-065) */
  --visited-soft: color-mix(in srgb, var(--visited) 9%, transparent);

  /* Typography: one family, six sizes */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --text-xs: 0.75rem;    /* 12px: badges */
  --text-sm: 0.8125rem;  /* 13px: metadata, labels, hints */
  --text-base: 0.9375rem;/* 15px: body */
  --text-md: 1.0625rem;  /* 17px: section headings, price in cards */
  --text-lg: 1.25rem;    /* 20px: key facts */
  --text-xl: 1.5rem;     /* 24px: page title, price on the listing page */
  --leading: 1.45;
  --leading-tight: 1.25;
  --weight-medium: 500;
  --weight-strong: 600;

  /* Spacing: 4px steps */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;

  /* Shape and controls */
  --radius-sm: 4px;
  --radius: 6px;
  --radius-lg: 10px;
  --control-h: 2.125rem;     /* 34px */
  --control-h-sm: 1.75rem;   /* 28px: row actions */
  --control-h-touch: 2.5rem; /* 40px: buttons on phones */
  --content-w: 1200px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #131518;
    --surface: #181b1f;
    --surface-sunken: #1f2328;
    --border: #2c3138;
    --border-control: #646d79;
    --text: #e6e8eb;
    --text-secondary: #b8bec7;
    --text-muted: #9099a5;
    --accent: #7aa7ff;
    --accent-hover: #a3c2ff;
    --accent-fg: #0f1115;
    --success: #5cc27a;
    --warning: #e0a63a;
    --danger: #f2837b;
    --danger-fg: #0f1115;
    --visited: #c58af9;
  }
}

/* ---------- Base ---------- */
* { box-sizing: border-box; }
body { margin: 0; font: var(--text-base)/var(--leading) var(--font); color: var(--text); background: var(--bg);
  -webkit-font-smoothing: antialiased; }
main { max-width: var(--content-w); margin: 0 auto; padding: var(--space-5) var(--space-4) var(--space-6); }
a { color: var(--accent); text-underline-offset: 0.15em; }
h1 { font-size: var(--text-xl); line-height: var(--leading-tight); font-weight: var(--weight-strong);
  margin: 0 0 var(--space-4); overflow-wrap: anywhere; text-wrap: balance; }
h2 { font-size: var(--text-md); line-height: var(--leading-tight); font-weight: var(--weight-strong);
  margin: var(--space-6) 0 var(--space-3); }
p { margin: 0 0 var(--space-3); }
small { font-size: var(--text-sm); }
code { font-size: 0.9em; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Text roles */
.hint, .muted, .empty, small { color: var(--text-muted); }
.hint { font-size: var(--text-sm); }
.hint, .result, .setbar, .empty { text-wrap: pretty; }
.error, .error-text { color: var(--danger); }
/* Text for screen readers only (e.g. "differs" beside a value the page marks with ≠). */
.sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0; }

/* ---------- Header ---------- */
header { background: var(--surface); border-bottom: 1px solid var(--border); }
nav { display: flex; align-items: center; gap: var(--space-1) var(--space-2); max-width: var(--content-w); margin: 0 auto;
  padding: var(--space-2) var(--space-4); min-height: 3.25rem; }
nav .brand { display: inline-flex; align-items: center; gap: var(--space-2); margin-right: var(--space-4);
  color: var(--text); font-weight: var(--weight-strong); font-size: var(--text-md); text-decoration: none; white-space: nowrap; }
nav .brand-mark { display: inline-grid; place-items: center; width: 1.625rem; height: 1.625rem; border-radius: var(--radius);
  background: var(--accent); color: var(--accent-fg); font-size: var(--text-sm); font-weight: 700; }
/* The mark's letter is decoration: generated content with empty alternative text, so the link reads "Necretine". */
nav .brand-mark::before { content: "N"; content: "N" / ""; }
nav .links { display: flex; align-items: center; gap: var(--space-1); min-width: 0; }
nav .links a { display: inline-flex; align-items: center; min-height: var(--control-h); padding: 0 var(--space-3);
  border-radius: var(--radius); color: var(--text-secondary); font-weight: var(--weight-medium); text-decoration: none;
  white-space: nowrap; }
nav .links a:hover { background: var(--surface-sunken); color: var(--text); }
nav .links a[aria-current="page"] { background: var(--surface-sunken); color: var(--text); }
/* Secondary workflows (Possible duplicates) sit apart from the primary item, quieter, with an optional count. */
nav .links { flex: 1 1 auto; }
nav .links a.secondary { margin-left: auto; font-weight: normal; font-size: var(--text-sm); }
nav .count { margin-left: var(--space-2); padding: 0 var(--space-2); border-radius: 999px; background: var(--surface-sunken);
  color: var(--text-secondary); font-size: var(--text-xs); font-weight: var(--weight-medium); font-variant-numeric: tabular-nums;
  line-height: 1.5; }
nav .links a.secondary[aria-current="page"] .count, nav .links a.secondary:hover .count { background: var(--surface); }
@media (max-width: 700px) {
  /* The links in one scrollable row below the brand (no wrapping into a ragged block); the grid is set with the
     account link below. */
  nav { padding: var(--space-2) var(--space-3) 0; }
  nav .brand { min-height: var(--control-h); }
  nav .links { overflow-x: auto; padding-bottom: var(--space-2); scrollbar-width: none; }
}

/* ---------- Controls ---------- */
input, select, textarea { font: inherit; color: inherit; background: var(--surface); border: 1px solid var(--border-control);
  border-radius: var(--radius); padding: 0 var(--space-2); }
input, select { min-height: var(--control-h); }
input[type="checkbox"] { min-height: 0; accent-color: var(--accent); }

/* Buttons: secondary by default; .primary for the one main action, .quiet for row and contextual actions,
   .danger for destructive ones. Links and labels (a hidden box's toggle) styled as buttons use class "button". */
button, :is(a, label).button { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1);
  min-height: var(--control-h); padding: 0 var(--space-3); border: 1px solid var(--border-control); border-radius: var(--radius);
  background: var(--surface); color: var(--text); font: inherit; font-weight: var(--weight-medium); line-height: var(--leading-tight);
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition-property: background-color, border-color, color, transform; transition-duration: 150ms; transition-timing-function: ease-out; }
button:hover, :is(a, label).button:hover { background: var(--surface-sunken); }
button.primary, :is(a, label).button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
button.primary:hover, :is(a, label).button.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
button.quiet, :is(a, label).button.quiet { background: transparent; border-color: transparent; color: var(--text-secondary); }
button.quiet:hover, :is(a, label).button.quiet:hover { background: var(--surface-sunken); color: var(--text); }
button.danger, :is(a, label).button.danger { background: transparent; border-color: transparent; color: var(--danger); }
button.danger:hover, :is(a, label).button.danger:hover { background: var(--danger-soft); }
/* The one destructive action of a confirmation page. */
button.danger.solid { background: var(--danger); border-color: var(--danger); color: var(--danger-fg); }
button.danger.solid:hover { background: color-mix(in srgb, var(--danger) 85%, var(--text)); border-color: transparent; }
button:active, :is(a, label).button:active { transform: scale(0.97); }
@media (prefers-reduced-motion: reduce) {
  button, :is(a, label).button { transition: none; }
  button:active, :is(a, label).button:active { transform: none; }
}

/* Badges: listing and delivery states, small and outlined. */
.status { display: inline-block; font-size: var(--text-xs); font-weight: var(--weight-medium); line-height: 1.4;
  padding: 0 var(--space-2); border-radius: var(--radius-sm); white-space: nowrap;
  border: 1px solid color-mix(in srgb, currentColor 40%, transparent); background: color-mix(in srgb, currentColor 7%, var(--surface)); }
.status-active, .status-sent { color: var(--success); }
.status-pending { color: var(--warning); }
.status-removed { color: var(--text-muted); }
.status-failed { color: var(--danger); }
.missing { color: var(--text-muted); font-size: var(--text-sm); }

/* ---------- Tables ---------- */
table { border-collapse: collapse; width: 100%; font-size: var(--text-base); }
th, td { text-align: left; padding: var(--space-2) var(--space-2); border-bottom: 1px solid var(--border); vertical-align: top; }
th { color: var(--text-muted); font-size: var(--text-sm); font-weight: var(--weight-medium); white-space: nowrap; }
/* Whole words stay whole (narrow tables scroll, below); only a first column (titles, names) may break anywhere. */
td { overflow-wrap: break-word; }
td:first-child { overflow-wrap: anywhere; }
td.when { overflow-wrap: normal; white-space: nowrap; }
.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
td button { white-space: nowrap; }
/* A table that scrolls sideways on a phone or a tablet takes keyboard focus (tabindex="0"), so it can be scrolled
   with the arrow keys (WCAG 2.1.1, UI checkpoint 10); 900px since the Russian headings (phase 11 step 3). */
@media (max-width: 900px) {
  table { display: block; overflow-x: auto; }
  /* Between the cards and 900px the listing page's headings may wrap ("Area m²" over two lines) and the cells are a
     little closer, so the tables scroll less. */
  table.cards th { white-space: normal; }
  table.cards :is(th, td) { padding-left: calc(var(--space-2) * 0.75); padding-right: calc(var(--space-2) * 0.75); }
}
/* On a phone or an upright tablet a table.cards (the listing page's tables, which invited users read) is one card per
   row: the first cell as the card's head, the others as "label value" lines, the label from the cell's data-label (the
   heading's text), so nothing scrolls sideways (phase 11 step 4e; at 768px the Russian group table was 105px too
   wide). The owner's tables keep scrolling (the owner does not use a phone). */
@media (max-width: 800px) {
  table.cards, table.cards tbody, table.cards tr, table.cards td { display: block; }
  table.cards { overflow: visible; }
  table.cards thead { display: none; }
  table.cards tr { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-2) var(--space-3);
    margin: 0 0 var(--space-2); }
  /* A hanging indent: the label in the first 8rem, a value that wraps stays right of it. */
  table.cards td { border: 0; padding: 2px 0 2px 8rem; text-indent: -8rem; text-align: left; white-space: normal;
    overflow-wrap: break-word; }
  table.cards td > * { text-indent: 0; }
  table.cards td::before { content: attr(data-label); display: inline-block; width: 8rem; text-indent: 0;
    color: var(--text-muted); font-size: var(--text-sm); }
  table.cards td:first-child { padding: 0 0 var(--space-1); text-indent: 0; font-weight: var(--weight-strong); }
  table.cards td:first-child::before { content: none; }
}

/* ---------- Facts ---------- */
dl.facts { display: grid; grid-template-columns: minmax(8.5rem, max-content) minmax(0, 1fr); gap: var(--space-1) var(--space-4); margin: 0 0 var(--space-4); }
dl.facts dt { color: var(--text-muted); max-width: 13rem; }
dl.facts dd { margin: 0; overflow-wrap: anywhere; }
/* Phones: a fixed label column, so the values keep their width; long labels wrap. */
@media (max-width: 600px) { dl.facts { grid-template-columns: 8.5rem minmax(0, 1fr); } }

/* ---------- Forms ---------- */
form.search { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: end; margin-bottom: var(--space-3); }
form.search label { display: flex; flex-direction: column; gap: var(--space-1); font-size: var(--text-sm); color: var(--text-muted); }
form.search label input, form.search label select { font-size: var(--text-base); color: var(--text); }
form.search .submit { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
form.criteria { display: grid; gap: var(--space-3); max-width: 36rem; }
form.criteria label { display: flex; flex-direction: column; gap: var(--space-1); }
form.criteria label.check { flex-direction: row; align-items: center; gap: var(--space-2); }
form.criteria fieldset { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3); margin: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-2); }
form.criteria fieldset.picker { display: block; }
form.criteria fieldset.picker details { margin: var(--space-1) 0; }
form.criteria legend { padding: 0 var(--space-1); font-weight: var(--weight-medium); }
form.criteria > button { justify-self: start; }
form.inline { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; margin-bottom: var(--space-4); }
label.check, form.search label.check { display: flex; flex-direction: row; align-items: center; gap: var(--space-2);
  color: var(--text); font-size: var(--text-sm); }
.choices { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(12rem, 100%), 1fr)); gap: var(--space-1) var(--space-3); margin: var(--space-1) 0 var(--space-2); }
.choices.floors { grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); }
/* "basement (suteren, polusuteren, nisko prizemlje)" and "ground (…)" are long: each gets a row of its own, so the numbers below stay in line. */
.choices.floors > label:nth-child(-n+2) { grid-column: 1 / -1; }
details summary { cursor: pointer; }
details > details { margin-left: var(--space-2); }

/* Location tree: city → municipality → neighborhood, each with include (✓) and exclude (✕) beside its box. */
.places { margin: var(--space-1) 0 var(--space-2); --row: 24px; --boxes: 4.5rem; --tree-bg: var(--bg); }
.pick-body .places { --tree-bg: var(--surface-sunken); }
/* A city or municipality: its ✓ ✕ in the first column, its name (which opens its list) and the list in the second, so
   each level is indented by one box column. Lists start closed; the server opens those with something checked. */
.node { display: grid; grid-template-columns: var(--boxes) minmax(0, 1fr); align-items: start; margin: 2px 0; }
.node > details > summary, .node > .head { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--space-1);
  min-height: var(--row); font-size: var(--text-sm); list-style: none; }
.node > details > summary::-webkit-details-marker { display: none; }
.node > details > summary::before, .node > .head::before { content: "▸"; width: 1em; color: var(--text-muted); font-size: var(--text-xs); }
.node > details[open] > summary::before { content: "▾"; }
.node > .head::before { visibility: hidden; }
/* An open list keeps its row (boxes and name) on top while it scrolls past, a municipality's under its city's, so it
   can be checked or closed from anywhere; workspace.js then brings the closed name back into view. */
.node > details[open] > summary, .node:has(> details[open]) > .boxes { position: sticky; top: 0; z-index: 1; background: var(--tree-bg); }
.place-muni > details[open] > summary, .place-muni:has(> details[open]) > .boxes { top: var(--row); }
.tally { font-size: var(--text-xs); }
.tally .t-inc { color: var(--accent); }
.tally .t-exc { color: var(--danger); }
.node > details[open] > summary .tally { display: none; }
.node:has(> .boxes label.exc input:checked) > details > summary > .nm,
.node:has(> .boxes label.exc input:checked) > .head > .nm { color: var(--danger); text-decoration: line-through; }
.tree-fold { min-height: var(--row); margin: var(--space-1) 0 var(--space-2); font-size: var(--text-sm); }
.tree-fold[hidden] { display: none; }
.place { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-sm); }
.place label { display: inline-flex; align-items: center; color: var(--text-muted); }
.places .place label { flex: none; flex-direction: row; gap: 2px; font-size: var(--text-xs); }
/* Touch targets (WCAG 2.2 2.5.8, UI checkpoint 10): each ✓ / ✕ box with its mark is at least 24 px, rows do not
   crowd each other; on phones (below) 32 px. */
.places .place { min-height: 24px; }
.places .place label { min-width: 24px; min-height: 24px; }
.place label.exc { color: var(--danger); }

/* ---------- Pager ---------- */
.pager { display: flex; gap: var(--space-4); justify-content: center; align-items: center; margin-top: var(--space-4);
  color: var(--text-muted); font-size: var(--text-sm); }

/* ---------- Duplicates ---------- */
/* "Possible duplicates" (checkpoint 9): the list to check or set aside (D-067) and the order, then one card per
   listing, side by side; a fact the two state differently is tinted and marked ≠, a fact only one states reads
   "not stated" on the other. */
.group-note { font-size: var(--text-sm); color: var(--text-muted); }
.dup-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4); }
.dup-head h1 { margin: 0 0 var(--space-1); }
.dup-head p { margin: 0; max-width: 62ch; color: var(--text-secondary); text-wrap: pretty; }
.dup-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.cmp-legend { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); margin: 0 0 var(--space-3); font-size: var(--text-sm);
  color: var(--text-muted); }
.mk { display: inline-grid; place-items: center; width: 1.25rem; height: 1.25rem; margin-right: var(--space-1); border-radius: var(--radius-sm);
  font-size: var(--text-xs); font-weight: var(--weight-strong); }
.mk-diff { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--warning); }
.g-sample { font-style: italic; }
section.pair { border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-4); margin: 0 0 var(--space-4); }
.why { margin: 0 0 var(--space-3); font-size: var(--text-sm); color: var(--text-secondary); text-wrap: pretty; }
.why strong { color: var(--text); font-weight: var(--weight-strong); }
.why .but { color: var(--warning); font-weight: var(--weight-medium); }
.why .when { color: var(--text-muted); white-space: nowrap; }
.pair-sides { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-4); }
.pair-sides .side { overflow-wrap: anywhere; }
/* Taller lines keep the source link and the title link apart enough to hit each (WCAG 2.5.8, UI checkpoint 10). */
.side-head { margin: 0 0 var(--space-2); line-height: 1.9; }
.side-head .src { font-weight: var(--weight-strong); }
.side-title { font-size: var(--text-sm); color: var(--text-secondary); }
dl.facts dd.d { margin-left: calc(-1 * var(--space-1)); padding: 0 var(--space-1); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--warning) 9%, transparent); font-weight: var(--weight-strong); }
dl.facts dd.d::after { content: " ≠"; content: " ≠" / ""; color: var(--warning); }
dl.facts dd.g { color: var(--text-muted); font-style: italic; }
form.decide { display: flex; gap: var(--space-2); flex-wrap: wrap; margin: var(--space-1) 0; }
.pair form.decide { margin: var(--space-3) 0 0; }
.aside-head { margin: var(--space-5) 0 var(--space-1); font-size: var(--text-base); }
form.decide button { white-space: nowrap; }
@media (max-width: 700px) {
  .pair-sides { grid-template-columns: minmax(0, 1fr); }
  section.pair { padding: var(--space-3); }
  .pair form.decide button { flex: 1 1 auto; min-height: var(--control-h-touch); }
}

/* ---------- Empty states ---------- */
/* A page or list with nothing to show says why and what to do next (product_direction.md §30); a section of a page
   with nothing to show keeps one quiet line (.empty). */
.empty-state { max-width: 44rem; margin: var(--space-4) 0; padding: var(--space-5); border: 1px dashed var(--border-control);
  border-radius: var(--radius-lg); }
.empty-state h2 { margin: 0 0 var(--space-2); font-size: var(--text-md); }
.empty-state p { margin: 0 0 var(--space-3); color: var(--text-secondary); text-wrap: pretty; }
.empty-state p:last-child { margin-bottom: 0; }
.empty-state .acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
@media (max-width: 600px) {
  .empty-state { padding: var(--space-4); }
}

/* ---------- Notification log ---------- */
.log-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); margin: 0 0 var(--space-3); }
.log-filters .field-inline { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text-muted); font-size: var(--text-sm); }
.log-filters select { color: var(--text); font-size: var(--text-base); }
ul.notes { list-style: none; margin: 0 0 var(--space-3); padding: 0; border-top: 1px solid var(--border); }
li.note { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr) minmax(0, 11rem) minmax(0, 13rem); gap: var(--space-1) var(--space-4);
  align-items: baseline; padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3); border-bottom: 1px solid var(--border); }
li.note .n-when { color: var(--text-muted); font-size: var(--text-sm); white-space: nowrap; }
li.note .n-what { min-width: 0; overflow-wrap: anywhere; }
li.note .n-what .kind { color: var(--text-muted); font-size: var(--text-sm); }
li.note .n-what a { font-weight: var(--weight-medium); }
li.note .n-search { font-size: var(--text-sm); overflow-wrap: anywhere; }
li.note .n-search a { color: var(--text-secondary); }
li.note .n-state { font-size: var(--text-sm); color: var(--text-muted); }
li.note .n-err, li.note .n-retry { grid-column: 2 / -1; font-size: var(--text-sm); overflow-wrap: anywhere; }
li.note .n-err { color: var(--danger); }
li.note .n-retry { color: var(--text-muted); }
@media (max-width: 700px) {
  li.note { grid-template-columns: minmax(0, 1fr) auto; padding-left: var(--space-2); }
  li.note .n-when, li.note .n-err, li.note .n-retry { grid-column: 1 / -1; }
}

/* ---------- Error pages ---------- */
.errpage { max-width: 40rem; margin: var(--space-6) 0; }
.errpage .code { margin: 0 0 var(--space-2); color: var(--text-muted); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.errpage h1 { margin: 0 0 var(--space-2); }
.errpage p { color: var(--text-secondary); }
.errpage .acts { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-4); }

/* ---------- Bars and notices ---------- */
.result { margin: 0 0 var(--space-3); }
/* The filter set the table was opened from (D-052). */
.setbar { background: var(--surface-sunken); border-radius: var(--radius); padding: var(--space-2) var(--space-3); margin: 0 0 var(--space-3); }
/* "Hidden … Unhide" stays in view while the page sits at the row next to the hidden one. */
.notice { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: var(--space-3); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-1) var(--space-3); margin: 0 0 var(--space-3);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--text) 8%, transparent); }
.notice > span { white-space: nowrap; }
.notice a { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notice form.mark { margin: 0; }
/* On a phone the hidden listing's title takes its own line under "Hidden everywhere: … Unhide", whole (phase 11 step
   4e; it was cut with "…"). */
@media (max-width: 600px) {
  .notice { flex-wrap: wrap; row-gap: 0; padding-bottom: var(--space-2); }
  .notice form.mark { margin-left: auto; }
  .notice a { order: 3; flex: 1 0 100%; overflow: visible; white-space: normal; }
}

/* ---------- My searches ---------- */
/* Page head: title and a short orientation on the left, the one primary action on the right. */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4); }
.page-head h1 { margin: 0 0 var(--space-1); }
.page-head p { margin: 0; }

/* Welcome: a calm surface above the rows (dismissible) or, with no Searches, the page's onboarding. */
.welcome { display: flex; align-items: flex-start; gap: var(--space-4); background: var(--surface-sunken); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-4) var(--space-3); margin: 0 0 var(--space-5); }
.welcome > div { flex: 1 1 auto; min-width: 0; }
.welcome h2 { margin: 0 0 var(--space-2); }
.welcome p { max-width: 65ch; color: var(--text-secondary); text-wrap: pretty; }
.welcome form { margin: 0; flex: 0 0 auto; }
.welcome.onboarding { display: block; padding: var(--space-5); }
.welcome.onboarding p:has(> .button) { margin: var(--space-4) 0; }

/* Search rows: a compact list, not cards. The whole row opens the Search (the name's link covers it); the actions
   sit above that link. "12 new" (D-055) is a column in front of .search-main: calm, the accent color, no large badge;
   while any Search has new results every row has it (empty where 0), so the names stay aligned. */
ul.searches { display: grid; gap: var(--space-2); list-style: none; margin: 0; padding: 0; }
li.search { position: relative; display: flex; align-items: center; gap: var(--space-2) var(--space-4);
  padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-lg); scroll-margin-top: var(--space-2); }
li.search:hover { background: var(--surface-sunken); }
li.search:target { background: var(--accent-soft); }
.search-main { flex: 1 1 auto; min-width: 0; }
.new-count { flex: 0 0 auto; min-width: 4.5rem; color: var(--accent); font-size: var(--text-sm); font-weight: var(--weight-strong);
  white-space: nowrap; }
.search-main p { margin: 0; }
.search-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-2); }
a.search-name, span.search-name { color: var(--text); font-size: var(--text-md); font-weight: var(--weight-strong); text-decoration: none;
  overflow-wrap: anywhere; }
a.search-name::after { content: ""; position: absolute; inset: 0; }
a.search-name:hover { text-decoration: underline; }
a.search-name:focus-visible { outline: none; }
a.search-name:focus-visible::after { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--radius); }
.state-active { color: var(--text-muted); font-size: var(--text-sm); }
.state-active::before { content: ""; display: inline-block; width: 0.4rem; height: 0.4rem; margin-right: var(--space-1);
  border-radius: 50%; background: var(--success); vertical-align: 0.1em; }
.search-summary { color: var(--text-secondary); font-size: var(--text-sm); margin-top: var(--space-1); overflow-wrap: anywhere; }
.search-summary .more { color: var(--text-muted); white-space: nowrap; }
.search-actions { position: relative; z-index: 1; display: flex; align-items: center; gap: var(--space-1); flex: 0 0 auto; }
/* An open menu sits above the following rows (each row's actions are their own stacking layer). */
.search-actions:has(details.menu[open]) { z-index: 3; }
.search-actions .button { min-height: var(--control-h-sm); padding: 0 var(--space-2); font-size: var(--text-sm); }

/* Row menu ("⋯"): a disclosure, no JavaScript; its items are quiet, a destructive one would go last, set apart. */
details.menu { position: relative; }
details.menu > summary { display: inline-flex; align-items: center; justify-content: center; min-width: var(--control-h-sm);
  min-height: var(--control-h-sm); border-radius: var(--radius); color: var(--text-secondary); font-weight: var(--weight-strong);
  list-style: none; user-select: none; }
details.menu > summary::-webkit-details-marker { display: none; }
details.menu > summary:hover, details.menu[open] > summary { background: var(--surface-sunken); color: var(--text); }
li.search:hover details.menu > summary:hover, li.search:hover details.menu[open] > summary { background: var(--border); }
.menu-panel { position: absolute; right: 0; top: calc(100% + var(--space-1)); z-index: 2; display: grid; min-width: 11rem;
  padding: var(--space-1); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--text) 12%, transparent); }
.menu-panel form { margin: 0; }
.menu-panel a, .menu-panel button, .menu-panel label { display: flex; width: 100%; justify-content: flex-start; min-height: var(--control-h-sm);
  padding: 0 var(--space-2); border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text);
  font-size: var(--text-sm); font-weight: normal; text-decoration: none; align-items: center; white-space: nowrap; }
.menu-panel a:hover, .menu-panel button:hover, .menu-panel label:hover { background: var(--surface-sunken); }
.menu-panel label, form.rename label.button { cursor: pointer; }
/* The destructive item: last, below a line, in the danger color. */
.menu-panel hr { margin: var(--space-1) calc(-1 * var(--space-1)); border: 0; border-top: 1px solid var(--border); }
.menu-panel a.danger { color: var(--danger); }
.menu-panel a.danger:hover { background: var(--danger-soft); }
@media (max-width: 600px) {
  /* Phones: name and summary take the width, "Edit criteria" moves into the menu, touch-sized "⋯". */
  .page-head .button { flex: 0 0 auto; }
  li.search { align-items: flex-start; padding: var(--space-3); }
  .search-actions .edit { display: none; }
  details.menu > summary { min-width: var(--control-h-touch); min-height: var(--control-h-touch); }
  .menu-panel a, .menu-panel button, .menu-panel label { min-height: var(--control-h-touch); font-size: var(--text-base); }
  .welcome { flex-direction: column; gap: var(--space-2); padding: var(--space-3) var(--space-4); }
  .welcome.onboarding { padding: var(--space-4); }
}

/* Rename in place (UI checkpoint 9, D-068): ✎ beside a Search's name, or "Rename…" in a row's menu, is the label of a
   visually hidden check box; while it is checked the rename form takes the name's place (no JavaScript, and the page
   does not scroll as it would to an anchor). Save posts and returns to the same place; Cancel unchecks the box. */
form.rename { display: none; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; }
:is(.ws-head, li.search):has(.rename-toggle:checked) form.rename { display: flex; }
form.rename input[name="name"] { flex: 1 1 16rem; min-width: 0; max-width: 28rem; font-size: var(--text-lg);
  font-weight: var(--weight-strong); }
li.search form.rename input[name="name"] { font-size: var(--text-md); }
form.rename .error { flex-basis: 100%; margin: 0; }
.ws-head:has(.rename-toggle:checked) .ws-title,
li.search:has(.rename-toggle:checked) :is(.search-title, .search-actions) { display: none; }
li.search:has(.rename-toggle:checked) { background: var(--accent-soft); }
/* The hidden box takes the keyboard focus: show it on its visible label (✎), or on the row. */
.ws-head:has(.rename-toggle:focus-visible) .rename-btn { outline: 2px solid var(--accent); outline-offset: 2px; }
li.search:has(.rename-toggle:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
.ws-title .rename-btn { cursor: pointer; display: inline-flex; align-items: center; justify-content: center; min-width: var(--control-h-sm);
  min-height: var(--control-h-sm); border-radius: var(--radius); color: var(--text-muted); text-decoration: none; }
.ws-title .rename-btn:hover { background: var(--surface-sunken); color: var(--text); }
@media (max-width: 600px) {
  form.rename input[name="name"] { flex-basis: 100%; max-width: none; }
  form.rename button, form.rename .button { flex: 1 1 auto; min-height: var(--control-h-touch); }
  .ws-title .rename-btn { min-width: var(--control-h-touch); min-height: var(--control-h-touch); }
}

/* "Delete search" confirmation (D-054): what is deleted for good, what is kept, the destructive button, Cancel. */
.confirm { max-width: 44rem; }
.confirm h1 { margin: 0 0 var(--space-2); }
.confirm .lead { color: var(--text-secondary); margin: 0 0 var(--space-5); }
.confirm-parts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); margin: 0 0 var(--space-5); }
.confirm-parts section { padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-lg); }
.confirm-parts section.gone { border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); background: var(--danger-soft); }
.confirm-parts h2 { margin: 0 0 var(--space-2); font-size: var(--text-base); }
.confirm-parts ul { margin: 0; padding-left: 1.1rem; display: grid; gap: var(--space-1); }
.confirm-parts li { color: var(--text-secondary); font-size: var(--text-sm); overflow-wrap: anywhere; }
.confirm-parts li strong { color: var(--text); font-weight: var(--weight-medium); }
.confirm-parts .crit { display: block; color: var(--text-muted); }
.confirm-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-4); }
.pause-instead { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin: 0;
  padding-top: var(--space-4); border-top: 1px solid var(--border); color: var(--text-muted); font-size: var(--text-sm); }
.pause-instead button { min-height: var(--control-h-sm); font-size: var(--text-sm); }
@media (max-width: 600px) {
  .confirm-parts { grid-template-columns: minmax(0, 1fr); gap: var(--space-3); }
  .confirm-actions { flex-direction: column; align-items: stretch; }
  .confirm-actions button, .confirm-actions .button { min-height: var(--control-h-touch); }
}

/* ---------- Search Workspace ---------- */
/* /listings?set= (a Search) and /listings (the New search draft): head, criteria (one line folded, a panel open),
   Unsaved changes, toolbar, results (docs/ui/product_direction.md §12–20). No JavaScript: <details> and links. */
.backlink { margin: 0 0 var(--space-2); font-size: var(--text-sm); }
.backlink a { color: var(--text-muted); text-decoration: none; }
.backlink a:hover { color: var(--text-secondary); text-decoration: underline; }
.ws-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-3); }
.ws-head > div:first-child { flex: 1 1 auto; min-width: 0; }
.ws-head h1 { margin: 0; }
.ws-head .hint { margin: var(--space-1) 0 0; }
.ws-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); }
.ws-actions { display: flex; align-items: center; gap: var(--space-1); }
.saved { margin: 0 0 var(--space-3); color: var(--success); font-size: var(--text-sm); }

/* Criteria folded: one line saying what the Search looks for, with "Edit criteria". */
.ws-criteria, details.criteria > summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2);
  margin: 0 0 var(--space-3); padding: var(--space-2) var(--space-3); background: var(--surface-sunken); border-radius: var(--radius);
  font-size: var(--text-sm); color: var(--text-secondary); overflow-wrap: anywhere; }
.ws-criteria .label, details.criteria > summary .label { color: var(--text-muted); }
details.criteria > summary { list-style: none; cursor: pointer; }
details.criteria > summary::-webkit-details-marker { display: none; }
/* "Edit criteria" looks like a secondary button; the whole line opens the panel. */
details.criteria > summary .edit-link { display: inline-flex; align-items: center; margin-left: auto; min-height: var(--control-h-sm);
  padding: 0 var(--space-3); border: 1px solid var(--border-control); border-radius: var(--radius); background: var(--surface);
  color: var(--text); font-weight: var(--weight-medium); white-space: nowrap; }
details.criteria > summary:hover .edit-link { background: var(--bg); }
details.criteria[open] > summary { display: none; }

/* Criteria open: one panel; compact controls in a row, floor and registration always visible. */
.panel { margin: 0 0 var(--space-3); padding: var(--space-3) var(--space-4); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: 0 1px 3px color-mix(in srgb, var(--text) 6%, transparent); }
.panel h2 { margin: 0 0 var(--space-3); font-size: var(--text-base); }
.panel-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-3) var(--space-4); }
.field { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; font-size: var(--text-sm); color: var(--text-muted); }
.field:has(> details[open]) { flex-basis: 100%; }
.range { display: flex; align-items: center; gap: var(--space-1); }
.range input { width: 6.5rem; font-size: var(--text-base); color: var(--text); }
details.pick > summary { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--control-h); padding: 0 var(--space-3);
  border: 1px solid var(--border-control); border-radius: var(--radius); background: var(--surface); color: var(--text);
  font-size: var(--text-base); list-style: none; max-width: min(100%, 40rem); }
details.pick > summary::-webkit-details-marker { display: none; }
details.pick > summary::after { content: "▾"; color: var(--text-muted); font-size: var(--text-xs); }
details.pick[open] > summary::after { content: "▴"; }
details.pick > summary.on { border-color: var(--accent); background: var(--accent-soft); }
.crit-group details.pick > summary { min-height: var(--control-h-sm); font-size: var(--text-sm); }
.pick-body { margin-top: var(--space-2); padding: var(--space-3); border-radius: var(--radius); background: var(--surface-sunken);
  color: var(--text); font-size: var(--text-base); }
.crit-group .opts:has(> details[open]) > details { flex-basis: 100%; }
.pick-body .hint { margin: 0; }
/* A group: its label on the left, its options in one block to the right, so a wrapped line starts under the first
   option, not under the label (user, checkpoint 5). */
.crit-group { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-4); margin-top: var(--space-3);
  padding-top: var(--space-3); border-top: 1px solid var(--border); }
.crit-group > .glabel { flex: 0 0 6.5rem; color: var(--text-muted); font-size: var(--text-sm); font-weight: var(--weight-medium); }
.crit-group > .opts { flex: 1 1 0; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); }
.crit-group label.check { font-size: var(--text-base); }
.panel .error { margin: var(--space-3) 0 0; }
.panel-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-3);
  padding-top: var(--space-3); border-top: 1px solid var(--border); }
.panel-actions .hint { flex: 1 1 18rem; margin: 0 0 0 var(--space-2); }
/* The live count (D-063): while a change is being counted, the button's count is out of date. */
.panel-actions button[aria-busy="true"] { opacity: 0.75; }

/* Location: include / exclude explained once; an excluded place reads as excluded as soon as it is checked. */
.legend { display: grid; gap: var(--space-1); margin: 0 0 var(--space-3); font-size: var(--text-sm); color: var(--text-secondary); }
.legend p { margin: 0; }
.legend b { display: inline-grid; place-items: center; width: 1.25rem; height: 1.25rem; margin-right: var(--space-1);
  border-radius: var(--radius-sm); font-size: var(--text-xs); }
.legend .k-inc { background: var(--accent-soft); color: var(--accent); }
.legend .k-exc { background: var(--danger-soft); color: var(--danger); }
.place:has(label.exc input:checked) .nm { color: var(--danger); text-decoration: line-through; }

/* Unsaved changes (a Search) and "not a search yet" (the draft): the one place to save. */
.unsaved, .draftbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-3);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius); }
.unsaved { border: 1px solid color-mix(in srgb, var(--warning) 45%, transparent); background: color-mix(in srgb, var(--warning) 8%, transparent); }
.unsaved strong { color: var(--warning); white-space: nowrap; }
.draftbar { background: var(--surface-sunken); }
.unsaved p, .draftbar p { flex: 1 1 18rem; margin: 0; font-size: var(--text-sm); color: var(--text-secondary); }
.unsaved .acts { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* Toolbar above the results: the count; sort always visible; view settings in a small menu. */
.toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-4);
  padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.toolbar .result { margin: 0; }
.toolbar .was { color: var(--text-muted); font-size: var(--text-sm); }
.tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.tools .lbl { color: var(--text-muted); font-size: var(--text-sm); }
.seg { display: inline-flex; border: 1px solid var(--border-control); border-radius: var(--radius); overflow: hidden; }
.seg a { display: inline-flex; align-items: center; min-height: var(--control-h-sm); padding: 0 var(--space-3);
  color: var(--text-secondary); font-size: var(--text-sm); text-decoration: none; white-space: nowrap; }
.seg a + a { border-left: 1px solid var(--border); }
.seg a:hover { background: var(--surface-sunken); color: var(--text); }
/* The chosen option (sort and View, user's choice A in step 3b-2): a solid accent fill. */
.seg a[aria-current], .seg a[aria-current]:hover { background: var(--accent); color: var(--accent-fg); font-weight: var(--weight-strong); }
.seg a:focus-visible { outline-offset: -2px; }
.seg a[aria-current]:focus-visible { outline-color: var(--accent-fg); outline-offset: -4px; }
details.view { position: relative; }
details.view > summary { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--control-h-sm);
  padding: 0 var(--space-3); border: 1px solid var(--border-control); border-radius: var(--radius); font-size: var(--text-sm);
  list-style: none; white-space: nowrap; }
details.view > summary::-webkit-details-marker { display: none; }
details.view > summary::after { content: "▾"; color: var(--text-muted); font-size: var(--text-xs); }
details.view[open] > summary { border-color: var(--accent); color: var(--accent); }
.view-panel { position: absolute; right: 0; top: calc(100% + var(--space-1)); z-index: 3; display: grid; gap: var(--space-3);
  width: max-content; max-width: min(24rem, calc(100vw - 2rem)); padding: var(--space-3); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 4px 16px color-mix(in srgb, var(--text) 12%, transparent); }
.view-panel .grp { display: grid; gap: var(--space-1); min-width: 0; color: var(--text-secondary); font-size: var(--text-sm);
  font-weight: var(--weight-medium); }
.view-panel .seg { width: max-content; max-width: 100%; flex-wrap: wrap; }
.view-panel .hint { margin: 0; }

/* The "Create search" step: the name and the criteria in words. */
form.create { display: grid; gap: var(--space-3); max-width: 36rem; }
form.create label { display: flex; flex-direction: column; gap: var(--space-1); }
form.create label.check { flex-direction: row; align-items: center; gap: var(--space-2); }
form.create .ws-criteria { margin: 0; }
form.create details label { margin-top: var(--space-2); }
details.help summary { color: var(--text-muted); font-size: var(--text-sm); }
details.help .hint { margin: var(--space-1) 0 0; }

@media (max-width: 600px) {
  details.criteria > summary .edit-link { margin-left: 0; min-height: var(--control-h-touch); }
  .panel { padding: var(--space-3); }
  .panel-row { display: grid; grid-template-columns: minmax(0, 1fr); }
  .range input { flex: 1 1 0; width: auto; min-width: 0; }
  details.pick > summary { justify-content: space-between; width: 100%; min-height: var(--control-h-touch); }
  .places { --row: 32px; }
  .places .place, .places .place label { min-height: 32px; }
  /* Each level indented by a step, not by a whole box column, so neighborhood names keep the width. */
  .places .node > details > :is(.node, .choices) { margin-left: calc(var(--space-4) - var(--boxes)); }
  /* A check box with a note in brackets: one paragraph that wraps under the label, not two narrow columns. */
  label.check:has(> small) { display: block; }
  label.check:has(> small) > input { margin: 0 var(--space-2) 0 0; vertical-align: -2px; }
  .crit-group > .glabel, .crit-group > .opts { flex-basis: 100%; }
  .panel-actions button, .panel-actions .button { flex: 1 1 100%; min-height: var(--control-h-touch); }
  .panel-actions .hint { margin: 0; }
  .unsaved .acts { width: 100%; }
  .unsaved .acts button, .unsaved .acts .button, .draftbar button { flex: 1 1 auto; min-height: var(--control-h-touch); }
  .tools { width: 100%; justify-content: space-between; }
  .seg { max-width: 100%; overflow-x: auto; }
  .seg a, details.view > summary { min-height: var(--control-h-touch); }
  /* On a phone the View panel opens in the page's flow and pushes the results down instead of lying over the first
     rows, whose links and buttons it would cover (phase 11 step 4e). */
  details.view { flex-basis: 100%; }
  .view-panel { position: static; margin-top: var(--space-2); box-shadow: none; }
}

/* ---------- Listing rows ---------- */
/* One structured row per listing (product_direction.md §19, §21; checkpoint 5): the price leads in its own aligned
   column, then size and floor, place and title, source and time, then quiet actions. Two lines on wide screens, a
   stacked block on narrow ones. The price link stretches over the whole row (::after); the source link and the
   buttons sit above it. */
ul.rows { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--border); }
/* The source and time column fits the longest time line: Russian "замечено 6 дней назад" (italic) is about 2 rem
   longer than English "seen 6 days ago" and touched the ☆ in a 7.5 rem column. */
ul.rows { --when-w: 7.5rem; }
:root:lang(ru) ul.rows { --when-w: 9.75rem; }
li.row { position: relative; display: grid; align-items: baseline;
  grid-template-columns: 7rem minmax(12rem, 18rem) minmax(0, 1fr) var(--when-w) auto;
  grid-template-areas: "price size place src act" "state more title when act";
  column-gap: var(--space-4); row-gap: 2px; padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border); scroll-margin-top: var(--space-2); }
/* Wide screens: the size and floor column is wide enough for the longest floor line with its note and registration
   (about 390 px in Russian), so every row keeps two lines. Narrower, the line wraps and nothing is cut. */
@media (min-width: 1200px) { li.row { grid-template-columns: 7rem 25rem minmax(0, 1fr) var(--when-w) auto; } }
li.row:hover { background: var(--surface-sunken); }
li.row:target, li.row:target:hover { background: var(--accent-soft); }
/* Keep anchored rows and keyboard focus clear of the sticky "Hidden … Unhide" notice. */
html:has(.notice) { scroll-padding-top: 3.25rem; }
.r-price { grid-area: price; color: var(--text); font-size: var(--text-md); font-weight: var(--weight-strong);
  font-variant-numeric: tabular-nums; white-space: nowrap; text-decoration: none; }
.r-price::after { content: ""; position: absolute; inset: 0; }
.r-price:focus-visible { outline: none; }
li.row:has(.r-price:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
.r-price .cur { color: var(--text-secondary); font-size: var(--text-sm); font-weight: normal; }
.r-state { grid-area: state; display: flex; flex-wrap: wrap; gap: var(--space-1); }
/* NEW (D-055): the row's property appeared in this Search since the previous visit. */
.badge-new { display: inline-block; padding: 0 var(--space-1); border-radius: var(--radius-sm); background: var(--accent-soft);
  color: var(--accent); font-size: var(--text-xs); font-weight: var(--weight-strong); line-height: 1.4; }
.toolbar .new-total { color: var(--accent); font-weight: var(--weight-medium); }
.r-size { grid-area: size; font-variant-numeric: tabular-nums; }
.r-more { grid-area: more; }
.r-place { grid-area: place; }
.r-place .hood { color: var(--text-secondary); }
.r-title { grid-area: title; }
.r-src { grid-area: src; white-space: nowrap; }
.r-when { grid-area: when; white-space: nowrap; }
.r-more, .r-title, .r-src, .r-when { font-size: var(--text-sm); }
.r-more, .r-title, .r-when, .r-more .note { color: var(--text-muted); }
.r-place, .r-title { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.r-src, .r-title .group-note { color: var(--text-secondary); }
/* The original listing reads as a link (ideas.md 2): accent and underlined; once followed in this Search, the
   visited-link colour, like a search engine (D-065: recorded by the open route; workspace.js marks a link at the
   click, before the page reloads). */
.r-src a { color: var(--accent); font-size: var(--text-base); font-weight: var(--weight-strong); text-decoration: underline;
  text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
.r-src a:hover { text-decoration-thickness: 2px; }
.r-src a.visited, .pv-others a.visited { color: var(--visited); }
/* A date the source does not state ("seen …") reads differently from a publication date (D-051). */
.r-when.first-seen { font-style: italic; }
.r-act { grid-area: act; align-self: center; }
.r-src a, .r-act { position: relative; z-index: 1; }
/* Unknown values stay in their place, quiet: unknown is not bad (§28). */
.unk { color: var(--text-muted); font-weight: normal; }
.r-price .unk { font-size: var(--text-sm); }
/* Viewed (D-065): opened in this Search, in the colour of a visited link; the last viewed row also gets its bar and
   tint. workspace.js moves both to a row whose original link is followed, before the page reloads. */
li.row.viewed :is(.r-price, .r-price .cur, .r-title) { color: var(--visited); }
li.row.last, li.row.last:hover { background: var(--visited-soft); box-shadow: inset 3px 0 0 var(--visited); }
/* Removed and hidden listings stay readable but step back (§29). */
li.row.removed .r-price { color: var(--text-muted); text-decoration: line-through; text-decoration-thickness: 1px; }
li.row.removed :is(.r-size, .r-place), li.row.hidden :is(.r-price, .r-size, .r-place) { color: var(--text-muted); }
/* Favorite / Hide: quiet, so the facts lead; in a row the star alone (its label names it). */
form.mark { display: flex; gap: var(--space-1); margin: var(--space-1) 0; }
form.mark button { min-height: var(--control-h-sm); padding: 0 var(--space-2); font-size: var(--text-sm);
  background: transparent; border-color: transparent; color: var(--text-secondary); }
form.mark button:hover { background: var(--surface-sunken); color: var(--text); }
form.mark button.star.on { color: var(--warning); }
.r-act form.mark { margin: 0; }
.r-act form.mark button.star { min-width: var(--control-h-sm); font-size: var(--text-base); }
.r-act .mark-label { display: none; }
li.row:hover form.mark button:hover { background: var(--border); }
/* "Hide everywhere" in a ⋯ menu beside Hide (D-072): one click less likely to be pressed by mistake. The open row
   rises above the rows below, whose buttons would otherwise paint over the menu. */
form.mark details.mark-menu > summary { min-height: var(--control-h-sm); color: var(--text-secondary); }
form.mark .menu-panel { min-width: 15rem; max-width: calc(100vw - 2rem); }
form.mark .menu-panel button { flex-direction: column; align-items: flex-start; justify-content: center; height: auto;
  padding-top: var(--space-1); padding-bottom: var(--space-1); color: var(--text); text-align: left; }
.menu-panel .sub { color: var(--text-muted); font-size: var(--text-xs); font-weight: normal; white-space: normal; }
li.row:has(details.menu[open]) { z-index: 3; }
/* Hidden everywhere: the same short badge in the danger tint (the price column is narrow); the row's "Unhide
   everywhere" names the kind in words. Hidden rows share one width for their buttons, so their columns line up. */
.status.status-everywhere { background: var(--danger-soft); color: var(--danger); }
li.row.hidden .r-act form.mark { min-width: 11rem; justify-content: flex-end; }
/* Listing Preview (checkpoint 8): under its row, two columns, one close button at the end of the reading line. */
li.preview { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: var(--space-4) var(--space-6);
  margin: 0 0 var(--space-2); padding: var(--space-4) var(--space-5); border: 1px solid var(--border); border-top: 0;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg); background: var(--surface-sunken); }
.pv-back { display: none; }
.pv-head { grid-column: 1 / -1; margin: 0; font-weight: var(--weight-strong); }
.pv-col { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.pv-col p { margin: 0; }
.pv-facts { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: var(--space-1) var(--space-3); margin: 0; font-size: var(--text-sm); }
.pv-facts dt { color: var(--text-muted); }
.pv-facts dd { margin: 0; overflow-wrap: anywhere; }
.pv-facts .note, .pv-note { color: var(--text-muted); }
.pv-note { font-size: var(--text-sm); }
li.preview h3 { margin: 0 0 var(--space-1); font-size: var(--text-xs); font-weight: var(--weight-strong); text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-muted); }
.pv-others { list-style: none; margin: 0; padding: 0; font-size: var(--text-sm); }
.pv-others li { display: flex; justify-content: space-between; gap: var(--space-3); padding: var(--space-1) 0; border-top: 1px solid var(--border); }
.pv-bottom { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4);
  padding-top: var(--space-3); border-top: 1px solid var(--border); }
a.pv-close { display: inline-flex; align-items: center; gap: var(--space-2); min-height: 2.75rem; padding: 0 var(--space-4);
  border: 2px solid var(--accent); border-radius: var(--radius); background: var(--surface); color: var(--accent);
  font-weight: var(--weight-strong); text-decoration: none; white-space: nowrap; }
a.pv-close:hover { background: var(--accent); color: var(--accent-fg); }
.pv-tip { font-size: var(--text-sm); color: var(--text-muted); }
@media (max-width: 860px) {
  li.preview { grid-template-columns: minmax(0, 1fr); padding: var(--space-3); }
}
/* Phones: the preview takes the screen; the rest of the page steps aside until it is closed. */
@media (max-width: 600px) {
  main:has(li.preview) :is(.backlink, .ws-head, .page-head, form.workspace, .notice, .toolbar, .pager),
  ul.rows:has(li.preview) > li.row:not(.open) { display: none; }
  .pv-back { display: inline-block; grid-column: 1 / -1; }
  .pv-tip { display: none; }
}
@media (max-width: 860px) {
  li.row { grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "price price act" "state state act" "size size size" "more more more" "place place place"
      "title title title" "src when when";
    column-gap: var(--space-2); padding: var(--space-3) var(--space-1) var(--space-3) var(--space-2); }
  .r-price { font-size: var(--text-lg); }
  .r-act { align-self: start; }
  .r-title { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .r-when::before { content: "· "; font-style: normal; }
  /* Touch targets of the row buttons: at least 40 px. */
  .r-act form.mark button { min-height: var(--control-h-touch); min-width: 2.75rem; }
  form.search { display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: row dense; gap: var(--space-2) var(--space-3); align-items: end; }
  form.search label.check, form.search .submit { grid-column: 1 / -1; }
  form.search label:not(.check) input, form.search label select { width: 100%; }
}

/* ---------- Listing page ---------- */
/* The facts that decide relevance first, then the original listing. */
.keyfacts { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-5); margin: 0 0 var(--space-1); font-size: var(--text-lg); }
.keyfacts .price { font-size: var(--text-xl); font-weight: var(--weight-strong); }
.placeline { margin: 0 0 var(--space-4); color: var(--text-secondary); }
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-5); }
.actions form.mark { margin: 0; }
/* Beside the main "Open on …" button the mark buttons are ordinary secondary buttons. */
.actions form.mark button { min-height: var(--control-h); padding: 0 var(--space-3); font-size: inherit;
  background: var(--surface); border-color: var(--border-control); color: var(--text); }
.actions form.mark button:hover { background: var(--surface-sunken); }
p.actions .hint { flex: 1 1 16rem; margin: 0; }

/* ---------- Login, one-time link, account (phase 10 step 4) ---------- */
.auth { max-width: 26rem; margin: var(--space-6) auto; }
.auth h2 { margin-top: var(--space-6); }
form.auth-form { display: grid; gap: var(--space-3); }
form.auth-form label { display: flex; flex-direction: column; gap: var(--space-1); }
form.auth-form .error, form.auth-form .field-hint { margin: calc(-1 * var(--space-2)) 0 0; }
form.auth-form .actions { margin: var(--space-1) 0 0; }
/* The language switcher (D-099): radio buttons in one wrapping row of their own, no fieldset frame (the generic
   .choices grid's 12rem columns left the third language alone on a second row in the narrow account column). */
form.auth-form fieldset.choices { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5); border: 0;
  padding: 0; margin: 0; }
form.auth-form label.check { flex-direction: row; align-items: center; }
.auth .actions button { min-width: 8rem; }
.ok-text { color: var(--success); }
.auth > .hint { margin-top: var(--space-4); }
/* The account link: the initial and the name, at the end of the header (on phones on the brand's row). */
nav a.account { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--control-h);
  padding: 0 var(--space-3); border-radius: var(--radius); color: var(--text-secondary); font-size: var(--text-sm);
  text-decoration: none; white-space: nowrap; }
nav a.account:hover, nav a.account[aria-current="page"] { background: var(--surface-sunken); color: var(--text); }
nav .avatar { display: inline-grid; place-items: center; width: 1.375rem; height: 1.375rem; border-radius: 999px;
  background: var(--surface-sunken); color: var(--text-secondary); font-size: var(--text-xs); font-weight: var(--weight-strong);
  text-transform: uppercase; }
/* The initial is decoration (generated content with empty alternative text): the link reads as the name. */
nav .avatar::before { content: attr(data-initial); content: attr(data-initial) / ""; }
nav a.account:hover .avatar, nav a.account[aria-current="page"] .avatar { background: var(--surface); }
/* The language switcher: short codes before the account link; the current one plain, the others quiet buttons. */
nav .lang-switch { display: inline-flex; align-items: center; gap: var(--space-1); }
nav .lang-switch .current, nav .lang-switch button { min-height: var(--control-h); padding: 0 var(--space-2);
  font-size: var(--text-sm); text-transform: uppercase; }
nav .lang-switch .current { display: inline-flex; align-items: center; color: var(--text); font-weight: var(--weight-strong); }
/* The code is decoration (generated content with empty alternative text): each reads as its language's name. */
nav .lang-switch [data-code]::before { content: attr(data-code); content: attr(data-code) / ""; }
/* On phones two rows (UI check 2026-10-17, choice 2B): the brand and the account link, then the links with the
   language switcher at the end of their row. Without a switcher (an owner's page, one language offered) the links
   take the whole row. */
@media (max-width: 700px) {
  nav { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
  nav .brand { grid-area: 1 / 1; justify-self: start; }
  nav a.account { grid-area: 1 / 2; }
  nav .links { grid-area: 2 / 1; }
  nav .lang-switch { grid-area: 2 / 2; padding-bottom: var(--space-2); }
  nav:not(:has(.lang-switch)) .links { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .auth { margin-top: var(--space-4); }
  .auth .actions button { width: 100%; min-height: var(--control-h-touch); }
}

/* ---------- The owner's pages: People and the security log (phase 10 step 5) ---------- */
.page-head .acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.page-head .acts form { margin: 0; }
td.row-acts { white-space: nowrap; text-align: right; }
td.person { overflow-wrap: normal; white-space: nowrap; }
td.link-what { overflow-wrap: normal; min-width: 9rem; }
td.row-acts form { display: inline; margin: 0; }
/* A link just made: shown once, in a field the owner selects and copies. */
.new-link { max-width: 44rem; margin: var(--space-4) 0 var(--space-5); padding: var(--space-4); border: 1px solid var(--border-control);
  border-radius: var(--radius); background: var(--surface-sunken); }
.new-link h2, .new-link h3 { margin: 0 0 var(--space-2); font-size: var(--text-md); }
.new-link p { margin: 0 0 var(--space-3); text-wrap: pretty; }
.new-link .hint { margin: var(--space-2) 0 0; }
label.link-copy { display: flex; flex-direction: column; gap: var(--space-1); color: var(--text-muted); font-size: var(--text-sm); }
label.link-copy input { width: 100%; color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--text-sm); }
table.seclog td.details { font-size: var(--text-sm); overflow-wrap: anywhere; }
table.seclog td.ip { font-size: var(--text-sm); white-space: nowrap; font-variant-numeric: tabular-nums; }
table.seclog td.ua { max-width: 18rem; color: var(--text-muted); font-size: var(--text-sm); overflow-wrap: anywhere; }
