/* projects/demetra/src/css/search-v3.css
 *
 * Phase 3 Stream F — 5-tab parcel search shell styling.
 *
 * Path note: the Phase 3 plan §F lists this file at `src/styles/search-v3.css`
 * but the project convention is `src/css/*` (matches the cache-buster
 * walker in `build-cache-bust.py`). Keeping the file under `src/css/`
 * means it cache-busts automatically and ships with the rest of the CSS.
 *
 * Design tokens: every colour/spacing/radius comes from the legacy
 * aliases in `tokens.css` (which themselves resolve to `@olympus/design-tokens`).
 * No literal hex codes here — see OLYMPUS_DESIGN_SYSTEM §7.
 *
 * Locale: en-GB.
 * Focus ring: `var(--accent-deep)` for AA contrast vs `--bg-soft`.
 */

/* -----------------------------------------------------------------
 * Wrapper
 * ----------------------------------------------------------------- */
.dm-search-v3 {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.dm-search-v3__pane-wrap {
  /* Pane swap with no layout shift: the wrapper reserves the height of
     the tallest pane (the SheetPlan pane with two fields + suggestion +
     button = roughly 160px). Smaller panes pad to the same height so
     the surrounding sidebar layout doesn't reflow on tab switch. */
  min-height: 160px;
}

/* -----------------------------------------------------------------
 * Tab bar (`role=tablist`)
 *
 * 5 tabs, each ~48 × 32px so the hit area meets WCAG 2.5.5 (≥ 24×24).
 * The tab strip wraps inside the 280px sidebar by design — at ~250px
 * inner width the 5 tabs fit on one row at the design font size.
 * ----------------------------------------------------------------- */
.search-tabs {
  display: flex;
  gap: 2px;
  padding: 2px;
  background: var(--bg-soft);
  border-radius: var(--radius-md);
  border: 1px solid var(--olympus-color-border-subtle, #e5e7eb);
}

.search-tab {
  flex: 1 1 auto;
  min-height: 32px;
  padding: 4px 6px;
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  text-align: center;
}

.search-tab:hover {
  color: var(--ink);
  background: var(--bg);
}

.search-tab.active,
.search-tab[aria-selected="true"] {
  color: #ffffff;
  background: var(--accent-deep);
}

.search-tab:focus-visible {
  outline: 2px solid var(--accent-deep);
  outline-offset: 2px;
}

/* -----------------------------------------------------------------
 * Tab pane
 * ----------------------------------------------------------------- */
.search-tab-pane {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-top: var(--space-1);
}

.search-pane-label {
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

/* UX sweep item 15 — inline spinner shown beside the "Municipality /
 * Village" label while the dependent municipality fetch is in flight.
 * Mirrors the .layer-spinner pattern (teal top-color, 0.8s linear). */
.dm-dls-spinner {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-left: 6px;
  border: 2px solid var(--muted, #6b7280);
  border-top-color: var(--teal, #2a9d8f);
  border-radius: 50%;
  vertical-align: middle;
  animation: dm-dls-spin 0.8s linear infinite;
}
@keyframes dm-dls-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .dm-dls-spinner { animation: none; }
}

.search-pane-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.search-pane-input {
  width: 100%;
  height: 32px;
  padding: 4px 8px;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--olympus-color-border-base, #cbd5e1);
  border-radius: var(--radius-sm);
  box-sizing: border-box;
}

.search-pane-input:focus-visible {
  outline: 2px solid var(--accent-deep);
  outline-offset: 1px;
  border-color: var(--accent-deep);
}

.search-pane-suggestion {
  min-height: 1.2em; /* reserve space so polite updates don't shift layout */
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  font-style: italic;
  color: var(--muted);
}

.search-pane-prompt {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--ink);
  margin: 0;
}

.search-pane-coord {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--ink);
  padding: 4px 6px;
  background: var(--bg-soft);
  border-radius: var(--radius-sm);
}

.search-pane-coord-value {
  font-feature-settings: "tnum" 1;
}

/* Submit / Clear buttons inherit the existing .dm-btn styles in
 * components.css; we just give them a top margin for visual rhythm.
 */
.search-submit,
.search-clear {
  margin-top: var(--space-1);
  align-self: flex-start;
}

.search-busy {
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  color: var(--muted);
  margin: 0;
}

.search-error {
  /* Mirrors dm-search-v2__error styling; kept distinct so V2's old error
   * pane (still mounted via index.html until F.7 deletes it) doesn't
   * inherit V3 layout tweaks. */
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  color: var(--error);
  margin: 0;
}

/* Stream G — chip palette + Advanced editor + toast. Co-located here
 * (rather than the plan's chip-palette.css + toast.css split) because
 * the gz budget headroom after Stream F is < 1.1 KB (ADR 0034) and one
 * appended block compresses better than two new files. Tokens reuse
 * the Demetra palette via tokens.css aliases. */
.dm-search-v3 .sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.dm-search-v3__chip-slot {
  display: flex; flex-direction: column; gap: var(--space-1);
  margin-top: var(--space-2); padding-top: var(--space-2);
  border-top: 1px dashed var(--olympus-color-border-subtle, #e5e7eb);
}
.chip-palette-mode-toggle { align-self: flex-end; font-size: var(--fs-xs); }
.chip-palette { display: flex; flex-direction: column; gap: var(--space-1); }
.chip-palette-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-1);
}
.combinator-toggle {
  font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: 0.04em; padding: 2px 6px;
  color: var(--accent-deep); background: var(--bg-soft);
  border: 1px solid var(--accent-deep); border-radius: var(--radius-sm);
  cursor: pointer;
}
.combinator-toggle:focus-visible,
.chip-editor input:focus-visible, .chip-editor select:focus-visible,
.chip-palette-advanced-textarea:focus-visible {
  outline: 2px solid var(--accent-deep); outline-offset: 1px;
}
.chip-list { display: flex; flex-wrap: wrap; gap: 4px; }
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-sans); font-size: var(--fs-xs); color: var(--ink);
  background: var(--bg-soft); border: 1px solid var(--olympus-color-border-base, #cbd5e1);
  border-radius: 999px; padding: 2px 4px 2px 8px;
}
.chip-label { font-feature-settings: "tnum" 1; }
.chip-remove {
  width: 18px; height: 18px; display: inline-flex; align-items: center;
  justify-content: center; border: 0; background: transparent;
  color: var(--muted); font-size: 14px; line-height: 1; cursor: pointer;
  border-radius: 50%;
}
.chip-remove:hover { color: var(--ink); background: var(--bg); }
.chip-editor {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  padding: var(--space-1); background: var(--bg-soft); border-radius: var(--radius-sm);
}
.chip-editor input, .chip-editor select {
  height: 26px; padding: 2px 6px;
  font-family: var(--font-sans); font-size: var(--fs-xs);
  border: 1px solid var(--olympus-color-border-base, #cbd5e1);
  border-radius: var(--radius-sm);
  background: var(--bg); color: var(--ink); box-sizing: border-box;
}
.chip-editor .field-input, .chip-editor .value-input { flex: 1 1 80px; min-width: 60px; }
.chip-palette-advanced { display: flex; flex-direction: column; gap: 4px; }
.chip-palette-advanced-label {
  font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: 600;
  color: var(--muted); text-transform: uppercase; letter-spacing: 0.02em;
}
.chip-palette-advanced-textarea {
  width: 100%; font-family: var(--font-mono); font-size: var(--fs-xs);
  color: var(--ink); background: var(--bg);
  border: 1px solid var(--olympus-color-border-base, #cbd5e1);
  border-radius: var(--radius-sm); padding: 6px 8px;
  resize: vertical; box-sizing: border-box;
}
.chip-palette-advanced-textarea[aria-invalid="true"] { border-color: var(--error); }
.chip-palette-advanced-error {
  font-family: var(--font-sans); font-size: var(--fs-xs); color: var(--error); margin: 0;
}
/* Toast — transient feedback overlay (lib/toast.js) */
.toast {
  position: fixed; right: 24px; bottom: 24px; z-index: 1000;
  max-width: 360px; padding: 10px 14px;
  font-family: var(--font-sans); font-size: var(--fs-sm); color: var(--ink);
  background: var(--bg); border: 1px solid var(--olympus-color-border-base, #cbd5e1);
  border-left: 3px solid var(--muted); border-radius: var(--radius-sm);
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.12);
}
.toast + .toast { margin-bottom: 8px; bottom: 80px; }
.toast-info    { border-left-color: var(--info); }
.toast-success { border-left-color: var(--ok); }
.toast-warning { border-left-color: var(--warn); }
.toast-error   { border-left-color: var(--error); color: var(--error); }

/* -----------------------------------------------------------------
 * Stream H — type-as-you-search suggestions list
 *
 * Renders below the input when SearchTabAddress / SearchTabRegNo
 * receive a non-empty `suggestions` prop. Each <li> is a clickable +
 * keyboard-focusable option (role=option, tabIndex=0). The list is
 * capped to ~8 visible items via max-height + overflow-auto so a
 * dense match-set doesn't push the Search button below the fold.
 * ----------------------------------------------------------------- */
.search-suggestions {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 224px; /* 8 × 28px row height */
  overflow-y: auto;
  background: var(--bg);
  border: 1px solid var(--olympus-color-border-subtle, #e5e7eb);
  border-radius: var(--radius-sm);
}

.search-suggestion {
  display: block;
  padding: 4px 8px;
  min-height: 28px;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--ink);
  cursor: pointer;
  border-bottom: 1px solid var(--olympus-color-border-subtle, #f1f5f9);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-suggestion:last-child {
  border-bottom: 0;
}

.search-suggestion:hover,
.search-suggestion:focus-visible {
  outline: 2px solid var(--accent-deep);
  outline-offset: -2px;
  background: var(--bg-soft);
}

/* -----------------------------------------------------------------
 * Stream H (H.3) — result-marker layers on the map canvas.
 *
 * The bulk of the rendering is Leaflet-driven (one of three layer
 * factories per zoom band — markers / heatmap / polygons). The CSS
 * here governs the SVG path styling for markers + polygon-swap. The
 * heatmap layer paints to a <canvas> and is not styled here.
 * ----------------------------------------------------------------- */
.dm-result-marker {
  /* Default circle-marker styling. Leaflet sets stroke / fill via
   * options; this rule adds a subtle drop-shadow so dots remain
   * visible against bright tile basemaps. */
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.25));
  transition: r 120ms ease-out, opacity 120ms ease-out;
}

.dm-result-polygon {
  /* z18+ polygon-swap render. The `selected` modifier elevates the
   * fill-opacity so the parcel shape reads against the basemap. */
  pointer-events: auto;
  transition: fill-opacity 120ms ease-out;
}

.dm-result-polygon--selected {
  fill-opacity: 0.45;
  stroke-width: 2.5;
}

/* Respect reduced-motion users — disable the transitions so the
 * marker-to-heatmap-to-polygon swap doesn't animate. */
@media (prefers-reduced-motion: reduce) {
  .dm-result-marker,
  .dm-result-polygon {
    transition: none;
  }
}
