/* ---------------------------------------------------------
   10. Forms
   --------------------------------------------------------- */

/* Form shell (docs/ui/UI_V3_PLAN.md L1): wrapper for pages whose main content
   is a single form. Caps the card at 832px (two ~400px columns via
   .form-grid) so long forms don't stretch edge-to-edge inside the wider
   --max-w site column. Left-aligned within the container (NOT margin:auto —
   the page stays anchored under the page header, it does not float centered
   on its own). Filter/toolbar rows and data grids are NOT form-shell. */
.form-shell {
  max-width: 52rem;
}

.form-section {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-1);
}

/* Label role (docs/ui/DESIGN_CONTRACT.md §3): .64-.68rem uppercase,
   letter-spacing .07-.09em, weight 650, muted ink. */
.form-row label {
  font-size: 0.66rem;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

.form-row label .required {
  color: var(--color-danger);
  margin-left: var(--sp-1);
  font-weight: 700;
}

.form-row input,
.form-row select,
.form-row textarea {
  width: 100%;
  min-height: 2.5rem;
  padding: var(--sp-2) var(--sp-3);
  font-family: inherit;
  font-size: var(--text-base);
  line-height: 1.4;
  color: var(--color-text);
  background: var(--color-surface);
  /* Inputs (§4): 1px --color-border-strong, radius 3px, flat (no resting
     shadow — only the focus halo below carries a box-shadow). */
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  transition: border-color var(--motion-fast) var(--ease),
    box-shadow var(--motion-fast) var(--ease),
    background-color var(--motion-fast) var(--ease);
  appearance: none;
}

.form-row input::placeholder,
.form-row textarea::placeholder {
  color: var(--color-text-muted);
  opacity: 0.75;
}

.form-row textarea {
  min-height: 4.5rem;
  line-height: 1.5;
}

/* Hover gives the field life before it is focused (skip disabled / focused). */
.form-row input:hover:not(:disabled):not(:focus),
.form-row select:hover:not(:disabled):not(:focus),
.form-row textarea:hover:not(:disabled):not(:focus) {
  border-color: var(--color-text-muted);
}

/* Custom dropdown chevron — appearance:none removes the native arrow. */
.form-row select {
  padding-right: var(--sp-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  background-size: 1rem;
}

/* Focus (§4): accent border + 3px accent-soft halo — the exact formula the
   Forms component spec names, distinct from the generic --shadow-focus glow
   used elsewhere (that one is a translucent ring meant to sit on any
   surface; this is a flat accent-soft fill, which the spec calls for on
   inputs specifically). */
.form-row input:focus,
.form-row select:focus,
.form-row textarea:focus {
  outline: none;
  border-color: var(--accent-fill);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Native validation: flag a field invalid only after the user has interacted. */
.form-row input:user-invalid,
.form-row select:user-invalid,
.form-row textarea:user-invalid {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-danger) 14%, transparent);
}

.form-row input:disabled,
.form-row select:disabled,
.form-row textarea:disabled {
  background: var(--color-bg);
  color: var(--color-text-muted);
  cursor: not-allowed;
}

.date-it-picker {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  max-width: 100%;
}

.form-row .date-it-picker {
  width: 100%;
}

.date-it-picker > input[data-date-it] {
  flex: 1 1 auto;
  min-width: 8.5rem;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.date-it-picker__button {
  flex: 0 0 2.5rem;
  min-height: 2.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-border-strong);
  border-left: 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease),
    box-shadow var(--motion-fast) var(--ease),
    background-color var(--motion-fast) var(--ease);
}

.date-it-picker__button:hover {
  border-color: var(--color-primary);
  background: var(--color-primary-lt);
}

.date-it-picker__button:focus-visible {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--shadow-focus);
}

/* Keep the date text field and calendar trigger as one composed control: the
   focus halo belongs to the pair and the shared internal border never doubles. */
.date-it-picker:focus-within > input[data-date-it],
.date-it-picker:focus-within .date-it-picker__button {
  border-color: var(--accent-fill);
}
.date-it-picker:focus-within > input[data-date-it] {
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.date-it-picker__native {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Checkboxes/radios must NOT inherit the full-width text-input styling above:
   width:100% + appearance:none renders them as an invisible, unclickable box
   (this is what broke the Impostazioni "Abilita OCR" toggle). Restore a real,
   comfortably-sized, clickable native control. */
.form-row input[type="checkbox"],
.form-row input[type="radio"] {
  width: auto;
  min-width: 1.15rem;
  height: 1.15rem;
  min-height: 0;
  padding: 0;
  appearance: auto;
  -webkit-appearance: auto;
  border: 0;
  background: none;
  box-shadow: none;
  cursor: pointer;
  accent-color: var(--color-primary);
}

.form-row .hint {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-text-muted);
}

/* Boolean toggle switch ------------------------------------------------------ */
.switch { display:inline-flex; align-items:center; gap:var(--sp-2); cursor:pointer; user-select:none; }
.switch > input[type="checkbox"] { position:absolute; opacity:0; width:1px; height:1px; }
.switch__track { position:relative; flex:0 0 auto; width:2.5rem; height:1.4rem; border-radius:999px;
  background:var(--color-border); transition:background-color .15s; }
.switch__track::after { content:""; position:absolute; top:50%; left:0.15rem; width:1.1rem; height:1.1rem;
  transform:translateY(-50%); border-radius:50%; background:var(--color-surface); box-shadow:var(--shadow-control-knob); transition:left .15s; }
.switch > input:checked + .switch__track { background:var(--accent-fill); }
.switch > input:checked + .switch__track::after { left:calc(100% - 1.25rem); }
.switch > input:focus-visible + .switch__track { outline:2px solid var(--color-primary); outline-offset:2px; }
.switch > input:disabled + .switch__track { opacity:.5; cursor:not-allowed; }
.switch__text { font-size:var(--text-sm); color:var(--color-text); }

/* Standalone hint paragraph between form fields */
.form-hint {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-top: calc(-1 * var(--sp-2));
  margin-bottom: var(--sp-4);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.form-row .error {
  font-size: var(--text-xs);
  color: var(--color-danger);
}

.form-row--error input,
.form-row--error select,
.form-row--error textarea {
  border-color: var(--color-danger);
}

.checkbox-card {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  cursor: pointer;
}

.checkbox-card input[type="checkbox"] {
  width: auto;
  margin-top: 0.2rem;
  appearance: auto;
  cursor: pointer;
}

.checkbox-card span {
  display: grid;
  gap: var(--sp-1);
}

.checkbox-card small {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* Inline checkbox list item — used for attrezzature on the mansione assignment page */
.checkbox-line {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  cursor: pointer;
  margin-bottom: var(--sp-2);
  font-size: var(--text-sm);
  color: var(--color-text);
  user-select: none;
  /* ensure it stretches to full width for easy tapping on mobile */
  width: 100%;
}

.checkbox-line:hover {
  background: var(--color-primary-lt);
  border-color: var(--color-primary);
}

.checkbox-line:has(input[type="checkbox"]:focus-visible) {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.checkbox-line input[type="checkbox"] {
  /* override any global input sizing so the native checkbox shows at normal size */
  width: auto;
  height: auto;
  flex-shrink: 0;
  appearance: auto;
  cursor: pointer;
  /* comfortable tap target on mobile */
  min-width: 1.1rem;
  min-height: 1.1rem;
  accent-color: var(--color-primary);
}

.form-actions {
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-top: var(--sp-2);
}

/* A repeated-save action is useful on desktop, but three equal controls wrap
   into an accidental-looking orphan button on a phone.  Opt-in only: normal
   short action rows keep their compact horizontal layout. */
@media (max-width: 420px) {
  .form-actions--stack-mobile {
    display: grid;
    grid-template-columns: 1fr;
  }

  .form-actions--stack-mobile .btn {
    justify-content: center;
    width: 100%;
  }
}

/* The real input is still the submitted, keyboard-focusable control.  It
   covers the Italian presentation so the component works without JavaScript
   and does not depend on a browser's localized file-picker chrome. */
.file-picker {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 2.75rem;
  padding: var(--sp-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.file-picker__input {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.file-picker__button {
  flex: 0 0 auto;
  min-height: 2rem;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-sm);
  color: var(--color-primary);
  font-weight: 600;
  line-height: 1;
}

.file-picker__label {
  min-width: 0;
  overflow: hidden;
  color: var(--color-text-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-picker:focus-within {
  border-color: var(--color-primary);
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Responsive field grid — groups related short fields (CAP/Provincia, dates,
   Sesso, etc.) side by side instead of each spanning the full width. Mobile
   first: a single column; from 640px, two columns. Use `.form-row--full` on
   any child that must span both columns (textarea, long address line, the
   CCNL free-text field, the codice-fiscale calculator helper, fieldset-style
   checkbox groups). See docs/ui/DESIGN_CONTRACT.md §7b. */
.form-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-4) var(--sp-5);
}

.form-grid--compact {
  gap: var(--sp-3) var(--sp-4);
}

@media (min-width: 640px) {
  .form-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.form-grid > .form-row--full {
  grid-column: 1 / -1;
}

/* Wizard actions stay in normal document flow.  A `bottom: 0` sticky bar
   looks convenient in an isolated demo, but in a real wizard it is painted
   over the active fields on first load (the fiscal-code calculator and date
   fields were literally hidden below it).  Each JS wizard shows one step at
   a time, so the action row is already close to the active fields; keeping
   it in flow preserves that convenience without masking a control. */
.form-actions--sticky {
  position: static;
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--color-border);
}

/* ---------------------------------------------------------
   11. Combobox — searchable enhancement of select[data-combobox]
   (docs/ui/DESIGN_CONTRACT.md §4; built entirely by static/app.js
   initCombobox(), which wraps a real <select> in this markup). The native
   select stays hidden-but-submitted, so this is pure presentation over a
   text input + floating listbox.
   --------------------------------------------------------- */
.combobox {
  position: relative;
  display: block;
  width: 100%;
}

/* The combobox remains searchable, but it must still read as a choice field
   at a glance. The chevron is drawn in CSS so it inherits the semantic ink
   tokens in both themes instead of falling back to a browser-owned arrow. */
.combobox::after {
  content: "";
  position: absolute;
  z-index: 1;
  top: calc(1.25rem - 0.3rem);
  right: 0.85rem;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid var(--color-text-muted);
  border-bottom: 2px solid var(--color-text-muted);
  pointer-events: none;
  transform: rotate(45deg);
}

.combobox:focus-within::after {
  border-color: var(--accent-ink);
}

/* Inside inline filter toolbars the combobox must size like the
   .filter-select it replaced, not stretch to the full row. */
.filter-bar .combobox,
.filter-bar-controls .combobox,
.list-toolbar .combobox,
.toolbar .combobox {
  display: inline-block;
  /* A business selector needs enough room for a meaningful current label.
     Native selects previously expanded to browser-owned menus at arbitrary
     widths; keep the enhanced field predictable without forcing a full row. */
  width: min(100%, 24rem);
  min-width: 13rem;
  max-width: 100%;
}

/* A toolbar label owns its field width. This avoids a long company/role label
   collapsing to the browser's intrinsic input width once data-combobox swaps
   the native select for the accessible input. */
.toolbar label:has(.combobox) {
  width: min(100%, 24rem);
}

.combobox__native {
  display: none;
}

/* Same visual contract as .form-row input (§4 forms), so a combobox reads
   identically to every other field until the listbox opens. */
.combobox__input {
  width: 100%;
  min-height: 2.5rem;
  padding: var(--sp-2) var(--sp-8) var(--sp-2) var(--sp-3);
  font-family: inherit;
  font-size: var(--text-base);
  line-height: 1.4;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  transition: border-color var(--motion-fast) var(--ease),
    box-shadow var(--motion-fast) var(--ease);
}

.combobox__input:hover:not(:disabled):not(:focus) {
  border-color: var(--color-text-muted);
}

/* Focused input = accent border + accent-soft halo (§4 combobox spec). */
.combobox__input:focus {
  outline: none;
  border-color: var(--accent-fill);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.combobox__input:disabled {
  background: var(--color-bg);
  color: var(--color-text-muted);
  cursor: not-allowed;
}

/* Floating listbox: radius 3px, --shadow-pop (§3/§4 — floating layers only). */
.combobox__listbox {
  position: absolute;
  z-index: 60;
  top: calc(100% + var(--sp-1));
  left: 0;
  right: 0;
  max-height: 28rem;
  overflow-y: auto;
  margin: 0;
  padding: var(--sp-1) 0;
  list-style: none;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-pop);
}

/* Open listboxes are moved to the document body and positioned against the
   viewport by app.js. This lets them clear table overflow and sticky action
   bars instead of being cut after the first few visible choices. */
.combobox__listbox--viewport {
  position: fixed;
  z-index: 1000;
}

.combobox__option {
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--text-sm);
  color: var(--color-text);
  cursor: pointer;
}

/* Highlighted option (keyboard nav or hover) = accent-soft fill (§4). */
.combobox__option.is-active {
  background: var(--accent-soft);
  color: var(--accent-ink);
}

.combobox__option.is-selected {
  font-weight: 650;
}

.combobox__match {
  color: var(--accent-ink);
  font-weight: 650;
}

.combobox__empty {
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  font-style: italic;
}

/* Touch-target floor (contract §0.8, ≥40px): same gating as .btn-sm. */
@media (pointer: coarse) {
  .combobox__option {
    padding-top: var(--sp-3);
    padding-bottom: var(--sp-3);
    min-height: 2.5rem;
  }
}

/* ---------------------------------------------------------
   12. Wizard — multi-step long forms (docs/ui/DESIGN_CONTRACT.md §4)
   ---------------------------------------------------------
   App-wide component: static/app.js initWizard() enhances any
   <form data-wizard> whose direct <fieldset> children are the logical
   steps, generating this exact markup (.wizard-steps > .wizard-step >
   .wizard-step__num + .wizard-step__lbl) from the fieldsets' <legend>
   text. The server-rendered hiring flow (app/anagrafica/assunzione_wizard.py,
   its own round-trip-per-step wizard) reuses the SAME class names for its
   stepper so the app has one stepper language — only the outer page chrome
   (.wizard/.wizard-body/.wizard-nav in personale-ui.css) stays specific to
   that flow. No-JS fallback: without the enhancement all fieldsets stay
   visible and .wizard-steps/.wizard-hint are simply never inserted. */
.wizard-steps {
  display: flex;
  align-items: flex-start;
  gap: 0;
  margin-bottom: var(--sp-2);
  overflow-x: auto;
  scrollbar-width: none;
}

.wizard-steps::-webkit-scrollbar { display: none; }

.wizard-step {
  position: relative;
  flex: 1 1 0;
  min-width: 4.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-1) 0;
  text-align: center;
}

/* Connecting bar (contract §4: "numbered circles joined by 1.5px bars"),
   centred on the boundary with the previous step so it visually links the
   two circles. Muted by default; accent once this step has been reached
   (done or active — i.e. the path already walked). */
.wizard-step:not(:first-child)::before {
  content: "";
  position: absolute;
  top: 0.875rem; /* vertical centre of the 1.75rem circle below */
  left: -50%;
  width: 100%;
  height: 1.5px;
  background: var(--color-border-strong);
}

.wizard-step--done:not(:first-child)::before,
.wizard-step--active:not(:first-child)::before {
  background: var(--accent-fill);
}

.wizard-step__num {
  position: relative;
  z-index: 1; /* sit above the connecting bar */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  flex-shrink: 0;
  border-radius: 50%; /* circles are an explicit shape exception, §3 */
  background: var(--color-surface);
  border: 1.5px solid var(--color-border-strong);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: 1;
  transition: background-color var(--motion-fast) var(--ease),
    border-color var(--motion-fast) var(--ease),
    color var(--motion-fast) var(--ease);
}

/* Current step: accent ring (contract §4), number still shown. */
.wizard-step--active .wizard-step__num {
  border-width: 2px;
  border-color: var(--accent-fill);
  color: var(--accent-ink);
}

/* Done step: filled accent circle with a check (contract §4). The digit is
   hidden (font-size:0) rather than removed, so it stays in the accessible
   name — the checkmark glyph is purely decorative generated content. */
.wizard-step--done .wizard-step__num {
  background: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--on-accent);
  font-size: 0;
}

.wizard-step--done .wizard-step__num::before {
  content: "\2713";
  font-size: 0.85rem;
}

.wizard-step__lbl {
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 1.25;
  color: var(--color-text-muted);
}

.wizard-step--active .wizard-step__lbl {
  color: var(--accent-ink);
  font-weight: 650;
}

.wizard-step--done .wizard-step__lbl {
  color: var(--color-text);
}

/* Completed steps are clickable — go back (never forward past validation). */
.wizard-step--done {
  cursor: pointer;
}

.wizard-step--done:hover .wizard-step__lbl {
  color: var(--accent-ink);
}

.wizard-step--done:focus-visible {
  outline: none;
}

.wizard-step--done:focus-visible .wizard-step__num {
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* initWizard() toggles the Indietro/Continua/Salva buttons via the native
   [hidden] IDL property, but .btn declares its own `display` (buttons.css)
   -- an author-origin rule for the same property always wins over the
   user-agent [hidden] default regardless of selector specificity, so a
   "hidden" wizard button would otherwise stay visible. Restore it. */
.form-actions [hidden] {
  display: none !important;
}

/* "Passo N di M — …" hint line under the stepper. */
.wizard-hint {
  margin: 0 0 var(--sp-4);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* Read-only Riepilogo grid — also reused verbatim by the hiring flow's own
   final step (app/anagrafica/pannello_dipendente.py, assunzione_wizard.py). */
.wizard-summary {
  display: grid;
  gap: var(--sp-2);
}

.wizard-summary__row {
  display: grid;
  grid-template-columns: minmax(9rem, 0.4fr) 1fr;
  gap: var(--sp-3);
  align-items: baseline;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
}

.wizard-summary__row:last-child { border-bottom: none; }

.wizard-summary__row > span:first-child {
  font-size: var(--text-xs);
  font-weight: 650;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

@media (max-width: 639px) {
  .wizard-summary__row {
    grid-template-columns: 1fr;
    gap: var(--sp-1);
  }
}
