/*
 * form.css — form field component family.
 *
 * Used by the render_field macro (templates/macros/form_field.html)
 * which dispatches across ~14 field types: checkbox, ref-entity
 * select, search-select, plain text/number/email/date/datetime
 * (native <input type=date>/datetime-local — the JS calendar `picker`
 * widget was dropped 2026-07-09), textarea, select, money, file, plus
 * widget-driven combobox / tags (Tom Select) / color / rich_text.
 * Native <input type="color"> covers the colour widget.
 *
 * Pre-CSS-refactor every branch composed its own inline Tailwind
 * class string with conditional Jinja for the error/idle border.
 * Post-refactor, the macro emits semantic classes only and styling
 * lives here. Error state derives from the `aria-invalid="true"`
 * attribute the macro already emits for accessibility — single
 * source of truth, no parallel `.is-error` modifier needed.
 *
 * Wrapped in @layer components.
 */

/* ─────────────────────────── outer wrapper ──────────────────────
 * Vertical flow of label / hint / input / error. Tight gap so
 * forms feel cohesive; .stack base utility would be too generous. */

.dz-form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  width: 100%;
}

/* ─────────────────────────── label ──────────────────────────────
 * Block label above the input. Required-mark is a child span. */

.dz-form-label {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--colour-text);
}

.dz-form-required {
  color: var(--colour-danger);
  margin-inline-start: var(--space-xs);
}

/* ─────────────────────────── hint + error ───────────────────────
 * Both small + muted; error is danger-coloured. The macro emits
 * <p id="hint-{name}"> and <p id="error-{name}"> for aria-describedby
 * referencing. */

.dz-form-hint {
  font-size: var(--text-xs);
  color: var(--colour-text-muted);
  line-height: var(--leading-normal);
}

.dz-form-error {
  font-size: var(--text-xs);
  color: var(--colour-danger);
  margin-block-start: var(--space-xs);
}

/* ─────────────────────────── base input ─────────────────────────
 * The canonical row input — used by text, email, number, date,
 * datetime, select. Single class .dz-form-input handles the lot.
 * Error state derives from `aria-invalid="true"` (selector below);
 * focus state via :focus-visible. */

.dz-form-input {
  width: 100%;
  /* border-box: see base.css form controls — select vs input UA mismatch. */
  box-sizing: border-box;
  /* #930: previously `height: 2rem` (32px) with `padding: 8px 12px`
     left only 16px of vertical content area for a ~22px line-box,
     clipping descenders (g/p/y) on every input + select placeholder.
     Switch to a min-height + explicit line-height + padding-block so
     the line-box always fits. `height: auto` lets future multi-line
     content (group labels in selects, wrapped placeholders) scale. */
  height: auto;
  min-height: 2.5rem;
  line-height: 1.4;
  padding-block: var(--space-sm);
  padding-inline: var(--space-md);
  font-size: var(--text-sm);
  color: var(--colour-text);
  background: var(--colour-surface);
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-sm);
  transition:
    box-shadow var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out);
}

/* WebKit (and some UA styles) ignore min-height on native <select>, so a
 * pre-enhance combobox seed can paint ~23px while the post-enhance text
 * input honors min-height 2.5rem — a visible jump on first click. Pin
 * the used height for selects only; text inputs stay height:auto. */
select.dz-form-input {
  height: 2.5rem;
  /* Flatten UA chrome so padding+height share one border-box model. */
  -webkit-appearance: none;
  appearance: none;
}

.dz-form-input::placeholder {
  color: var(--colour-text-muted);
}

.dz-form-input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--colour-brand);
  border-color: var(--colour-brand);
}

.dz-form-input[aria-invalid="true"] {
  border-color: var(--colour-danger);
}

.dz-form-input[aria-invalid="true"]:focus-visible {
  box-shadow: 0 0 0 1px var(--colour-danger);
}

/* ─────────────────────────── textarea ───────────────────────────
 * Same chrome as .dz-form-input but multi-line. Override height
 * + padding-block; resize handle vertical only. */

.dz-form-textarea {
  height: auto;
  min-height: 6rem;
  padding-block: var(--space-sm);
  resize: vertical;
}

/* ─────────────────────────── checkbox ───────────────────────────
 * Inline row: checkbox + text label. The macro wraps both in
 * <label class="dz-form-checkbox-label"> for click-target convenience. */

.dz-form-checkbox-label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--colour-text);
}

.dz-form-checkbox {
  width: 1rem;
  height: 1rem;
  border-radius: var(--radius-sm);
  accent-color: var(--colour-brand);
}

/* HYPERPART: money */
/* ─────────────────────────── money widget ───────────────────────
 * Three sub-elements:
 *   .dz-form-money-group — flex row container
 *   .dz-form-money-prefix — currency symbol box (pinned currency)
 *   .dz-form-money-select — currency dropdown (unpinned currency)
 * The amount input uses .dz-form-input with a .dz-form-input-trailing
 * modifier to round only the right corners. */

.dz-form-money-group {
  display: flex;
  width: 100%;
}

.dz-form-money-prefix {
  display: inline-flex;
  align-items: center;
  /* #930: align with .dz-form-input height to keep prefix flush. */
  min-height: 2.5rem;
  padding-inline: var(--space-md);
  background: var(--colour-bg);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--colour-text-muted);
  border: 1px solid var(--colour-border);
  border-inline-end: 0;
  border-start-start-radius: var(--radius-sm);
  border-end-start-radius: var(--radius-sm);
}

.dz-form-money-select {
  /* #930: matches updated input height; also gets line-height + padding
     so descenders in the currency option list don't clip. */
  height: auto;
  min-height: 2.5rem;
  line-height: 1.4;
  padding-block: var(--space-sm);
  width: 7rem;
  padding-inline: var(--space-sm);
  background: var(--colour-surface);
  color: var(--colour-text);
  font-size: var(--text-sm);
  border: 1px solid var(--colour-border);
  border-inline-end: 0;
  border-start-start-radius: var(--radius-sm);
  border-end-start-radius: var(--radius-sm);
}

.dz-form-money-select:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--colour-brand);
}

/* Modifier on .dz-form-input that joins it to a leading prefix —
 * rounds only the right corners. Used by the money widget. */
.dz-form-input-trailing {
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

/* ─────────────────────────── file upload ────────────────────────
 * Two states (dragging via Alpine x-show; preview vs dropzone via
 * x-show). Container uses .dz-file-upload (existing class on the
 * x-data root). */

.dz-file-upload-preview {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md);
  margin-block-end: var(--space-sm);
  border-radius: var(--radius-sm);
  background: var(--colour-bg);
}

.dz-file-upload-preview-icon {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  color: var(--colour-success);
}

.dz-file-upload-preview-name {
  font-size: var(--text-sm);
  color: var(--colour-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dz-file-upload-preview-clear {
  width: 1.5rem;
  height: 1.5rem;
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  color: var(--colour-text-muted);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}

.dz-file-upload-preview-clear:hover {
  background: var(--colour-bg);
  color: var(--colour-text);
}

.dz-file-upload-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 8rem;
  border: 2px dashed var(--colour-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition:
    background var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out);
}

.dz-file-upload-zone:hover,
.dz-file-upload-zone.dragging {
  background: var(--colour-bg);
  border-color: var(--colour-brand);
}

.dz-file-upload-zone-icon {
  width: 2rem;
  height: 2rem;
  margin-block-end: var(--space-sm);
  color: var(--colour-text-muted);
  opacity: 0.6;
}

.dz-file-upload-zone-prompt {
  font-size: var(--text-sm);
  color: var(--colour-text-muted);
}

.dz-file-upload-progress {
  width: 100%;
  height: 0.25rem;
  margin-block-start: var(--space-sm);
  border-radius: 2px;
}

/* ─────────────────────────── search-select wrapper ──────────────
 * UX-028 search-select dynamic search; the wrapper is the include
 * `fragments/search_select.html` which has its own internal
 * structure. We don't override that here — only style the label /
 * hint / error around it. The fragment-level CSS would migrate
 * separately when we get to fragments/. */

/* No rules needed — search-select inherits .dz-form-label + hint
 * + error from the surrounding macro structure. */

/* ─────────────────────────── colorpicker (UX-024) ───────────────
 * Native <input type="color"> + hex display sit inline next to each
 * other. #976 dropped the Pickr wrapper; the native input ships ~36 KB
 * lighter and covers every actual usage in the example apps. */

.dz-form-color-group {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.dz-form-color-input {
  /* Strip the user-agent native chrome down to a flat 2rem swatch
   * so the button matches the visual rhythm of the other dz-form-*
   * inputs. Cross-browser quirks: WebKit's swatch renders inside
   * `::-webkit-color-swatch-wrapper`; Firefox renders the swatch
   * directly on the input. Both are squared-off here. */
  block-size: 2rem;
  inline-size: 2rem;
  padding: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--colour-border);
  background: transparent;
  cursor: pointer;
  transition: filter var(--duration-fast) var(--ease-out);
}

.dz-form-color-input:hover {
  filter: brightness(1.05);
}

.dz-form-color-input::-webkit-color-swatch-wrapper {
  padding: 0;
}

.dz-form-color-input::-webkit-color-swatch {
  border: 0;
  border-radius: calc(var(--radius-sm) - 1px);
}

.dz-form-color-input::-moz-color-swatch {
  border: 0;
  border-radius: calc(var(--radius-sm) - 1px);
}

.dz-form-color-hex {
  font-family: var(--font-mono, monospace);
  font-size: var(--text-xs);
  color: var(--colour-text-muted);
}

/* ─────────────────────────── richtext (UX-025) ──────────────────
 * Quill editor wrapper. Border + radius live on the wrapper; Quill
 * internals manage their own toolbar/editor styling. */

.dz-form-richtext {
  border: 1px solid var(--colour-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--colour-bg);
}

.dz-form-richtext[aria-invalid="true"] {
  border-color: var(--colour-danger);
}

/* ─────────────────────────── slider (UX-023) ────────────────────
 * Native <input type="range"> + dzRangeTooltip controller. */

.dz-form-slider-group {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.dz-form-slider {
  inline-size: 100%;
}

.dz-form-slider-value {
  font-family: var(--font-mono, monospace);
  font-size: var(--text-xs);
  color: var(--colour-text);
  min-inline-size: 2rem;
  text-align: end;
}

/* ─────────────────────────── companion regions (#923) ───────────
 * Read-only panels that sit alongside form sections — top, bottom,
 * or below a named section anchor. The panel is a muted card with a
 * tighter typographic hierarchy than the form itself. */

.dz-form-companion {
  margin-block: var(--space-md);
  padding: var(--space-md);
  border-radius: var(--radius-md);
  background: var(--colour-bg);
  border: 1px solid var(--colour-border);
}

.dz-form-companion-eyebrow {
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--colour-text-muted);
  margin-block-end: var(--space-2xs);
}

.dz-form-companion-title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--colour-text);
  margin-block-end: var(--space-sm);
}

/* summary_row — horizontal metric tiles. */
.dz-form-companion-summary-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: var(--space-sm);
}

.dz-form-companion-metric {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding: var(--space-sm);
  border-radius: var(--radius-sm);
  background: var(--colour-surface);
  border: 1px solid var(--colour-border);
}

.dz-form-companion-metric-label {
  font-size: var(--text-xs);
  color: var(--colour-text-muted);
  text-transform: capitalize;
}

.dz-form-companion-metric-value {
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  color: var(--colour-text);
  font-variant-numeric: tabular-nums;
}

.dz-form-companion-metric-expr {
  display: none;  /* runtime-evaluated expression — debug only */
}

/* status_list — vertical title + caption rows. */
.dz-form-companion-status-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.dz-form-companion-entry {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding-inline-start: var(--space-md);
  border-inline-start: 2px solid var(--colour-border);
}

.dz-form-companion-entry--ok {
  border-inline-start-color: var(--colour-success, hsl(145 55% 45%));
}

.dz-form-companion-entry--warn {
  border-inline-start-color: var(--colour-warn, hsl(40 90% 55%));
}

.dz-form-companion-entry--pending {
  border-inline-start-color: var(--colour-text-muted);
  opacity: 0.85;
}

.dz-form-companion-entry-title {
  font-weight: var(--weight-medium);
  color: var(--colour-text);
}

.dz-form-companion-entry-caption {
  font-size: var(--text-sm);
  color: var(--colour-text-muted);
  line-height: 1.4;
}

/* pipeline_steps — left-to-right ordered stage cards. */
.dz-form-companion-pipeline {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: var(--space-sm);
  counter-reset: pipeline-step;
}

.dz-form-companion-stage {
  counter-increment: pipeline-step;
  padding: var(--space-sm);
  border-radius: var(--radius-sm);
  background: var(--colour-surface);
  border: 1px solid var(--colour-border);
  position: relative;
}

.dz-form-companion-stage::before {
  content: counter(pipeline-step);
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--colour-text-muted);
  margin-block-end: var(--space-2xs);
}

.dz-form-companion-stage-label {
  display: block;
  font-weight: var(--weight-medium);
  color: var(--colour-text);
}

.dz-form-companion-stage-caption {
  display: block;
  font-size: var(--text-sm);
  color: var(--colour-text-muted);
  line-height: 1.4;
}

.dz-form-companion-placeholder {
  font-size: var(--text-sm);
  color: var(--colour-text-muted);
  font-style: italic;
}

/* ── Selection controls (HaTchi-MaXchi tranche 1) ───────────────────────
   Designed checkbox/radio/switch on NATIVE inputs — appearance:none +
   tokens; keyboard/AT semantics stay the browser's. */

input.dz-checkbox,
input.dz-radio {
  appearance: none;
  width: 1rem;
  height: 1rem;
  margin: 0;
  border: 1px solid var(--colour-border);
  background: var(--colour-surface);
  cursor: pointer;
  flex-shrink: 0;
  display: inline-grid;
  place-content: center;
  transition: background var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}

input.dz-checkbox { border-radius: var(--radius-sm); }
input.dz-radio { border-radius: var(--radius-full); }

input.dz-checkbox:checked,
input.dz-radio:checked {
  background: var(--colour-brand);
  border-color: var(--colour-brand);
}

input.dz-checkbox:checked::before {
  content: "";
  width: 0.625rem;
  height: 0.625rem;
  background: var(--colour-brand-contrast);
  clip-path: polygon(14% 44%, 0 60%, 40% 100%, 100% 16%, 84% 4%, 38% 71%);
}

input.dz-radio:checked::before {
  content: "";
  width: 0.375rem;
  height: 0.375rem;
  border-radius: var(--radius-full);
  background: var(--colour-brand-contrast);
}

input.dz-switch {
  appearance: none;
  width: 2rem;
  height: 1.125rem;
  margin: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  background: var(--neutral-300);
  cursor: pointer;
  flex-shrink: 0;
  position: relative;
  transition: background var(--duration-base) var(--ease-out);
}

input.dz-switch::before {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 2px;
  translate: 0 -50%;
  width: 0.875rem;
  height: 0.875rem;
  border-radius: var(--radius-full);
  background: white;
  box-shadow: var(--shadow-sm);
  transition: inset-inline-start var(--duration-base) var(--ease-out);
}

input.dz-switch:checked {
  background: var(--colour-brand);
}

input.dz-switch:checked::before {
  inset-inline-start: calc(100% - 0.875rem - 2px);
}

@media (prefers-color-scheme: dark) {
  input.dz-switch { background: var(--neutral-700); }
}

[data-theme="dark"] input.dz-switch { background: var(--neutral-700); }
[data-theme="dark"] input.dz-switch:checked { background: var(--colour-brand); }

@media (prefers-reduced-motion: reduce) {
  input.dz-switch, input.dz-switch::before { transition: none; }
}
