/*!
 * Zenith Form Style — plugin-agnostic form control styling
 * ---------------------------------------------------------------------------
 * Works with plain HTML, Elementor Forms, and any plugin/theme markup you can
 * point a CSS selector at. Everything lives under the `.zt-form` scope class,
 * which zt-forms.js adds to whatever containers you register.
 *
 * HOW THIS FILE IS ORGANISED
 *   1. Design tokens          <- the ONLY block you normally edit
 *   2. State channel          <- how hover/focus/error/disabled are resolved
 *   3. Layout primitives
 *   4. Text-like controls (input / select / textarea)
 *   5. Per-control styling (select, textarea, check, radio, switch, range,
 *      file, color)
 *   6. Control groups, floating labels, enhanced select widget
 *   7. Buttons, sizes, RTL, plugin adapters
 *
 * SPECIFICITY NOTE
 *   Base rules deliberately carry high specificity (the long :not() chain) so
 *   they beat theme and plugin CSS without !important. State rules do NOT try
 *   to out-specify them; instead they reassign the --zt-c-* "state channel"
 *   variables on the element, which the base rules read. Never set a --zt-c-*
 *   variable inside a base rule.
 */

/* ==========================================================================
   1. DESIGN TOKENS
   ==========================================================================
   Override globally on :root, or per-form on any ancestor / the form itself:
     <form class="zt-form" style="--zt-accent:#c8102e">
   ========================================================================== */

:root {
  /* -- Typography --------------------------------------------------------
     Figma: Ravi FaNum. Label = Medium 14/1.6, control + helper text =
     Small 12/1.6. Ship the font yourself (@font-face) or swap the family. */
  --zt-font-family: var(--e-global-typography-primary-font-family);
  --zt-font-size: 12px;
  --zt-line-height: 1.6;
  --zt-label-font-size: 14px;
  --zt-label-font-weight: 500;
  --zt-help-font-size: 12px;

  /* -- Metrics ---------------------------------------------------------- */
  --zt-control-height: 47px;
  --zt-control-padding-x: 12px;
  --zt-control-padding-y: 12px;
  --zt-radius: 4px;              /* Modern/Radius-4 */
  --zt-border-width: 1px;        /* Stroke-1 */
  --zt-icon-size: 18px;
  --zt-icon-gap: 12px;

  /* -- Rhythm ----------------------------------------------------------- */
  --zt-label-gap: 6px;      /* label -> control            (GapPadding-6)  */
  --zt-help-gap: 6px;       /* control -> notice / help    (GapPadding-6)  */
  --zt-field-gap: 18px;     /* field -> field              (GapPadding-18) */
  --zt-option-gap: 10px;    /* checkbox/radio -> its label (GapPadding-10) */

  /* -- Colour ----------------------------------------------------------- */
  --zt-bg: #ffffff;                 /* Others/White              */
  --zt-bg-hover: var(--zt-bg);
  --zt-bg-focus: var(--zt-bg);
  --zt-bg-disabled: #dde5e1;        /* Alerts & Status/Disabled  */
  --zt-bg-readonly: #f7f9f8;

  --zt-text: #212121;               /* Greyscale/900 · Text/Text */
  --zt-text-disabled: #9e9e9e;      /* Greyscale/500             */
  --zt-placeholder: #9e9e9e;        /* Greyscale/500             */

  --zt-border: #bdbdbd;             /* Greyscale/400             */
  --zt-border-hover: #9e9e9e;       /* Greyscale/500             */
  --zt-border-focus: var(--zt-accent);
  --zt-border-disabled: #dde5e1;

  --zt-accent: #1b1b1b;             /* Primary/700               */
  --zt-accent-hover: #8e242c;
  --zt-accent-soft: #FFF7DB;      /* Transparent/Red           */
  --zt-on-accent: #ffffff;

  --zt-label-color: #212121;
  --zt-help-color: #9e9e9e;
  --zt-required-color: #e53935;

  --zt-error: #e53935;              /* Alerts & Status/Error     */
  --zt-error-bg: #ffffff;
  --zt-success: #52c41a;            /* Alerts & Status/Success   */

  /* -- Focus ring --------------------------------------------------------
     The design marks focus with an accent border and accent placeholder, no
     glow — so the ring is off. Set --zt-ring-width to bring it back. */
  --zt-ring-width: 0px;
  --zt-ring: color-mix(in srgb, var(--zt-accent) 20%, transparent);
  --zt-ring-error: color-mix(in srgb, var(--zt-error) 18%, transparent);

  /* -- Shadow ------------------------------------------------------------
     OFF by default: the design has no shadows. Turn them on with the
     .zt-form--shadow class (or shadow:true in the JS / PHP options) and
     recolour with --zt-shadow-color. The "off" values are transparent
     shadows rather than `none` because they sit in a comma-separated list
     with the focus ring, and `none` is not valid inside such a list. */
  --zt-shadow-color: rgba(16, 24, 40, .08);
  --zt-shadow-color-strong: rgba(16, 24, 40, .16);
  --zt-shadow: 0 0 0 0 transparent;
  --zt-shadow-hover: var(--zt-shadow);
  --zt-shadow-focus: var(--zt-shadow);
  --zt-dropdown-shadow: 0 0 0 0 transparent;
  --zt-thumb-shadow: 0 0 0 0 transparent;

  /* -- Motion ----------------------------------------------------------- */
  --zt-transition: 160ms cubic-bezier(.4, 0, .2, 1);

  /* -- Icons (swap the whole url() to change icon AND its colour) -------- */
  --zt-check-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5 6.2 11.7 13 5'/%3E%3C/svg%3E");
  --zt-indeterminate-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M4 8h8'/%3E%3C/svg%3E");
  --zt-select-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%239e9e9e' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 7.5 5 5 5-5'/%3E%3C/svg%3E");
  --zt-radio-dot: var(--zt-on-accent);
  --zt-search-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%239e9e9e' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='7' cy='7' r='4.6'/%3E%3Cpath d='m10.4 10.4 3.1 3.1'/%3E%3C/svg%3E");

  /* -- Choice controls -------------------------------------------------- */
  /* -- Dropdown panel (Figma: the open "Language level" overlay) --------- */
  --zt-dropdown-gap: 6px;           /* trigger -> panel   */
  --zt-dropdown-padding-block: 10px;
  --zt-dropdown-padding-inline: 20px;
  --zt-dropdown-border: var(--zt-accent);
  --zt-option-height: 31px;
  --zt-option-padding-x: 10px;
  --zt-option-gap-y: 4px;

  /* -- Chips (Figma: Form/Tag) ------------------------------------------ */
  --zt-chip-height: 42px;
  --zt-chip-padding-x: 14px;
  --zt-chip-padding-y: 8px;
  --zt-chip-radius: 6px;              /* Modern/Radius-6            */
  --zt-chip-font-size: var(--zt-label-font-size);
  --zt-chip-gap: 8px;
  --zt-chip-bg: var(--zt-bg);
  --zt-chip-border: #bdbdbd;          /* Greyscale/400              */
  --zt-chip-color: #424242;           /* Text/Greyscale/800         */
  --zt-chip-selected-bg: #dad0e8;     /* Secondary/100              */
  --zt-chip-selected-border: #46317c; /* Secondary/Pressed          */
  --zt-chip-selected-color: #46317c;
  --zt-chip-disabled-bg: #dde5e1;     /* Alerts & Status/Disabled   */
  --zt-chip-disabled-color: #aab3ae;  /* Text Form Disabled 600     */

  /* -- File upload (Figma: Upload Component) ---------------------------- */
  --zt-upload-height: 55px;
  --zt-upload-border-style: dashed;
  --zt-upload-gap: 10px;

  --zt-check-size: 20px;
  --zt-check-radius: 4px;
  --zt-radio-radius: 50%;
  --zt-switch-width: 44px;
  --zt-switch-height: 24px;
  --zt-switch-off: #cbd2dc;

  /* -- Range ------------------------------------------------------------ */
  --zt-range-track-height: 6px;
  --zt-range-track: #e4e7ec;
  --zt-range-thumb-size: 20px;

  /* -- Floating label ----------------------------------------------------
     The floated label sits on top of the control's border, so it needs an
     opaque background to punch a hole in that border. Set this to the
     surface colour BEHIND the control if it differs from the control's own
     background (e.g. a tinted card). */
  --zt-float-label-bg: var(--zt-bg);
  --zt-float-label-padding-x: 6px;

  /* -- Notices ------------------------------------------------------------
     The design's inline alert: full-width tinted panel, 4px radius, filled
     round icon at the inline start. Switch to bare text with
     .zt-form--notice-plain (or noticeStyle:'plain'). */
  --zt-notice-radius: var(--zt-radius);
  --zt-notice-padding: 4px 8px;
  --zt-notice-border-width: 0px;
  --zt-notice-gap: 6px;
  --zt-notice-icon-size: 16px;
  --zt-notice-min-height: 27px;

  --zt-notice-error: #f54336;       /* Others/Red        */
  --zt-notice-error-bg: #ffefed;    /* Background/Red    */
  --zt-notice-success: #52c41a;     /* Success           */
  --zt-notice-success-bg: #f3fceb;  /* Background/Green  */
  --zt-notice-info: #2f80ed;        /* Info              */
  --zt-notice-info-bg: #eef6fb;     /* Background/Blue   */
  --zt-notice-warning: #f5a623;     /* Warning           */
  --zt-notice-warning-bg: #fffceb;  /* Background/Yellow */

  /* -- Buttons ---------------------------------------------------------- */
  --zt-button-bg: var(--zt-accent);
  --zt-button-bg-hover: var(--zt-accent-hover);
  --zt-button-color: var(--zt-on-accent);
  --zt-button-radius: var(--zt-radius);
  --zt-button-padding-x: 28px;
  --zt-button-font-weight: 600;
}

/* Opt in to shadows. Put the class on the form (or any ancestor), or let the
   JS add it via { shadow: true, shadowColor: '...' }. */
.zt-form--shadow,
.zt-shadow {
  --zt-shadow: 0 1px 2px 0 var(--zt-shadow-color);
  --zt-shadow-hover: 0 2px 6px -1px var(--zt-shadow-color);
  --zt-shadow-focus: 0 2px 8px -2px var(--zt-shadow-color);
  --zt-dropdown-shadow: 0 12px 32px -8px var(--zt-shadow-color-strong);
  --zt-thumb-shadow: 0 1px 3px var(--zt-shadow-color-strong);
}

/* Dropdowns and popovers read their own token, so they can carry a shadow
   even when the controls stay flat: add .zt-form--shadow-overlay only. */
.zt-form--shadow-overlay {
  --zt-dropdown-shadow: 0 12px 32px -8px var(--zt-shadow-color-strong);
}

/* Fallback for browsers without color-mix() */
@supports not (color: color-mix(in srgb, red 50%, transparent)) {
  :root {
    --zt-ring: rgba(47, 111, 237, .2);
    --zt-ring-error: rgba(217, 45, 32, .18);
  }
}

/* ==========================================================================
   2. STATE CHANNEL
   ==========================================================================
   Base rules read these. State rules write them. Source order below defines
   precedence on ties: hover < focus < invalid < readonly < disabled.
   ========================================================================== */

.zt-form {
  --zt-c-bg: var(--zt-bg);
  --zt-c-text: var(--zt-text);
  --zt-c-border: var(--zt-border);
  --zt-c-ring: transparent;
  --zt-c-ring-width: 0px;
  --zt-c-cursor: auto;
  /* Padding also travels through the channel (as var() fallbacks, so it stays
     unset by default) — that is how icon/action/stepper gutters widen a
     control without having to out-specify the high-specificity base rule. */
}

/* ==========================================================================
   3. LAYOUT PRIMITIVES
   ==========================================================================
   The controls themselves set box-sizing individually, but the boxes this kit
   builds (dropzone, chips, notices, panels) need it too — without it every
   token height is silently off by its own padding and border. Scoped to our
   own class names so it never fights a theme's layout.
   ========================================================================== */

.zt-form .zt-control,
.zt-form .zt-file,
.zt-form .zt-file-item,
.zt-form .zt-chip,
.zt-form .zt-chips,
.zt-form .zt-chips__list,
.zt-form .zt-notice,
.zt-form .zt-notices,
.zt-form .zt-form-notices,
.zt-form .zt-combo,
.zt-form .zt-combo__list,
.zt-form .zt-combo__option,
.zt-form .zt-field,
.zt-form .zt-row {
  box-sizing: border-box;
}

.zt-form {
  font-family: var(--zt-font-family);
  font-size: var(--zt-font-size);
  line-height: var(--zt-line-height);
  color: var(--zt-text);
}

.zt-form .zt-field,
.zt-form .zt-field-group {
  display: flow-root;
  margin-block-end: var(--zt-field-gap);
  min-inline-size: 0;
}

.zt-form .zt-field:last-child,
.zt-form .zt-field-group:last-child { margin-block-end: 0; }

.zt-form .zt-label,
.zt-form .zt-field > label:not(.zt-option-label):not(.zt-option):not(.zt-file) {
  display: block;
  margin-block-end: var(--zt-label-gap);
  font-size: var(--zt-label-font-size);
  font-weight: var(--zt-label-font-weight);
  line-height: 1.45;
  color: var(--zt-label-color);
}

.zt-form .zt-label--required::after,
.zt-form .zt-label.is-required::after {
  content: "*";
  margin-inline-start: 4px;
  color: var(--zt-required-color);
}

.zt-form .zt-help {
  margin-block-start: var(--zt-help-gap);
  font-size: var(--zt-help-font-size);
  line-height: 1.5;
  color: var(--zt-help-color);
}

.zt-form .zt-error-text {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-block-start: var(--zt-help-gap);
  font-size: var(--zt-help-font-size);
  line-height: 1.5;
  color: var(--zt-error);
}

/* Hidden until the field is actually flagged */
.zt-form .zt-error-text:empty { display: none; }

.zt-form fieldset.zt-fieldset {
  margin: 0 0 var(--zt-field-gap);
  padding: 0;
  border: 0;
  min-inline-size: 0;
}

.zt-form .zt-fieldset > legend,
.zt-form .zt-legend {
  padding: 0;
  margin-block-end: var(--zt-label-gap);
  font-size: var(--zt-label-font-size);
  font-weight: var(--zt-label-font-weight);
  color: var(--zt-label-color);
}

/* Simple row/column helper so multi-column layouts don't need a grid system */
.zt-form .zt-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--zt-field-gap);
}
.zt-form .zt-row > * { flex: 1 1 220px; min-inline-size: 0; }

/* ==========================================================================
   4. TEXT-LIKE CONTROLS — shared base
   ==========================================================================
   The :not() chain is intentional: it excludes non-text inputs AND raises
   specificity high enough to beat theme/plugin rules without !important.
   ========================================================================== */

.zt-form .zt-input,
.zt-form .zt-select,
.zt-form .zt-textarea,
.zt-form select:not([data-zt-skip]),
.zt-form textarea:not([data-zt-skip]),
.zt-form input:not([data-zt-skip]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]):not([type="hidden"]) {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  display: block;
  inline-size: 100%;
  max-inline-size: 100%;
  min-block-size: var(--zt-control-height);
  margin: 0;
  padding-block: var(--zt-c-pad-block, var(--zt-control-padding-y));
  padding-inline:
    var(--zt-c-pad-start, var(--zt-control-padding-x))
    var(--zt-c-pad-end, var(--zt-control-padding-x));
  font-family: inherit;
  font-size: var(--zt-font-size);
  line-height: var(--zt-line-height);
  color: var(--zt-c-text);
  background-color: var(--zt-c-bg);
  background-clip: padding-box;
  border: var(--zt-border-width) solid var(--zt-c-border);
  border-radius: var(--zt-radius);
  box-shadow: var(--zt-c-shadow, var(--zt-shadow)), 0 0 0 var(--zt-c-ring-width) var(--zt-c-ring);
  cursor: var(--zt-c-cursor);
  transition:
    border-color var(--zt-transition),
    background-color var(--zt-transition),
    box-shadow var(--zt-transition),
    color var(--zt-transition);
}

/* --- Placeholder ---------------------------------------------------------
   The design's Active state turns the placeholder accent-coloured while the
   value itself stays dark, so this is on ::placeholder, not on the control. */
.zt-form input::placeholder,
.zt-form textarea::placeholder {
  color: var(--zt-placeholder);
  opacity: 1;
  transition: color var(--zt-transition);
}
.zt-form input:focus::placeholder,
.zt-form textarea:focus::placeholder { color: var(--zt-accent); }
.zt-form [aria-invalid="true"]:focus::placeholder { color: var(--zt-error); }

/* A select showing its empty option is the same "placeholder" idea. */
.zt-form select:focus:has(option[value=""]:checked) { color: var(--zt-accent); }

/* --- Autofill ------------------------------------------------------------ */
.zt-form input:-webkit-autofill,
.zt-form input:-webkit-autofill:hover,
.zt-form input:-webkit-autofill:focus,
.zt-form textarea:-webkit-autofill,
.zt-form select:-webkit-autofill {
  -webkit-text-fill-color: var(--zt-text);
  -webkit-box-shadow: 0 0 0 1000px var(--zt-bg) inset;
  box-shadow: 0 0 0 1000px var(--zt-bg) inset;
  caret-color: var(--zt-text);
  transition: background-color 100000s ease-in-out 0s;
}

/* --- States (write the channel, never the properties) -------------------- */

.zt-form input:hover,
.zt-form select:hover,
.zt-form textarea:hover {
  --zt-c-border: var(--zt-border-hover);
  --zt-c-bg: var(--zt-bg-hover);
  --zt-c-shadow: var(--zt-shadow-hover);
}

.zt-form input:focus,
.zt-form input:focus-visible,
.zt-form select:focus,
.zt-form textarea:focus {
  --zt-c-border: var(--zt-border-focus);
  --zt-c-bg: var(--zt-bg-focus);
  --zt-c-ring: var(--zt-ring);
  --zt-c-ring-width: var(--zt-ring-width);
  --zt-c-shadow: var(--zt-shadow-focus);
  outline: none;
}

/* Success — the design's green-bordered state. Applied while the user is
   still in the field after a valid edit; leaving the field drops back to the
   plain filled look, so this only ever reads as "that worked". */
.zt-form input.is-success,
.zt-form select.is-success,
.zt-form textarea.is-success {
  --zt-c-border: var(--zt-success);
}
.zt-form .zt-combo.is-success .zt-combo__button { --zt-c-border: var(--zt-success); }

/* Error — driven by aria-invalid, our own class, or native :user-invalid.
   Plugin-specific error hooks are mapped in the adapter section. */
.zt-form input[aria-invalid="true"],
.zt-form select[aria-invalid="true"],
.zt-form textarea[aria-invalid="true"],
.zt-form .is-invalid,
.zt-form .zt-invalid input,
.zt-form .zt-invalid select,
.zt-form .zt-invalid textarea {
  --zt-c-border: var(--zt-error);
  --zt-c-bg: var(--zt-error-bg);
  --zt-c-ring: transparent;
  --zt-c-ring-width: 0px;
}

.zt-form input[aria-invalid="true"]:focus,
.zt-form select[aria-invalid="true"]:focus,
.zt-form textarea[aria-invalid="true"]:focus,
.zt-form .is-invalid:focus,
.zt-form .zt-invalid input:focus,
.zt-form .zt-invalid select:focus,
.zt-form .zt-invalid textarea:focus {
  --zt-c-ring: var(--zt-ring-error);
  --zt-c-ring-width: var(--zt-ring-width);
}

.zt-form input:read-only:not([type="checkbox"]):not([type="radio"]),
.zt-form textarea:read-only {
  --zt-c-bg: var(--zt-bg-readonly);
  --zt-c-border: var(--zt-border);
  --zt-c-cursor: default;
}

.zt-form input:disabled,
.zt-form select:disabled,
.zt-form textarea:disabled,
.zt-form fieldset:disabled input,
.zt-form fieldset:disabled select,
.zt-form fieldset:disabled textarea {
  --zt-c-bg: var(--zt-bg-disabled);
  --zt-c-text: var(--zt-text-disabled);
  --zt-c-border: var(--zt-border-disabled);
  --zt-c-ring-width: 0px;
  --zt-c-cursor: not-allowed;
  opacity: 1; /* neutralise UA/theme dimming; the tokens carry the state */
}

/* ==========================================================================
   5. PER-CONTROL STYLING
   ========================================================================== */

/* --- 5.1 Select ---------------------------------------------------------- */

.zt-form select:not([data-zt-skip]),
.zt-form .zt-select {
  --zt-c-pad-end: calc(var(--zt-control-padding-x) + var(--zt-icon-size) + 6px);
  background-image: var(--zt-select-icon);
  background-repeat: no-repeat;
  background-position: right var(--zt-control-padding-x) center;
  background-size: var(--zt-icon-size) var(--zt-icon-size);
  cursor: pointer;
}

/* Logical mirroring for RTL */
[dir="rtl"] .zt-form select:not([data-zt-skip]),
.zt-form[dir="rtl"] select:not([data-zt-skip]),
[dir="rtl"] .zt-form .zt-select {
  background-position: left var(--zt-control-padding-x) center;
}

.zt-form select[multiple],
.zt-form select[size]:not([size="1"]) {
  --zt-c-pad-end: var(--zt-control-padding-x);
  --zt-c-pad-block: 6px;
  background-image: none;
  block-size: auto;
}

.zt-form select[multiple] option,
.zt-form select[size]:not([size="1"]) option {
  padding: 8px var(--zt-control-padding-x);
  border-radius: calc(var(--zt-radius) - 4px);
}

/* Placeholder-ish first option */
.zt-form select:has(option[value=""]:checked) { color: var(--zt-placeholder); }
.zt-form select option { color: var(--zt-text); }

/* --- 5.2 Textarea -------------------------------------------------------- */

.zt-form textarea:not([data-zt-skip]),
.zt-form .zt-textarea {
  min-block-size: calc(var(--zt-control-height) * 2.25);
  resize: vertical;
  overflow: auto;
}

.zt-form .zt-textarea--autogrow,
.zt-form textarea[data-zt-autogrow] {
  resize: none;
  overflow: hidden;
}

/* --- 5.3 Checkbox & radio ------------------------------------------------ */

.zt-form input[type="checkbox"]:not([data-zt-skip]),
.zt-form input[type="radio"]:not([data-zt-skip]) {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  flex: 0 0 auto;
  display: inline-block;
  vertical-align: text-bottom;
  inline-size: var(--zt-check-size);
  block-size: var(--zt-check-size);
  margin: 0;
  padding: 0;
  background-color: var(--zt-c-bg);
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  border: var(--zt-border-width) solid var(--zt-c-border);
  box-shadow: 0 0 0 var(--zt-c-ring-width) var(--zt-c-ring);
  cursor: pointer;
  transition:
    background-color var(--zt-transition),
    border-color var(--zt-transition),
    box-shadow var(--zt-transition);
}

.zt-form input[type="checkbox"]:not([data-zt-skip]) { border-radius: var(--zt-check-radius); }
.zt-form input[type="radio"]:not([data-zt-skip])    { border-radius: var(--zt-radio-radius); }

.zt-form input[type="checkbox"]:hover,
.zt-form input[type="radio"]:hover { --zt-c-border: var(--zt-border-hover); }

.zt-form input[type="checkbox"]:focus-visible,
.zt-form input[type="radio"]:focus-visible {
  --zt-c-ring: var(--zt-ring);
  --zt-c-ring-width: var(--zt-ring-width);
  outline: none;
}

.zt-form input[type="checkbox"]:checked,
.zt-form input[type="checkbox"]:indeterminate,
.zt-form input[type="radio"]:checked {
  --zt-c-bg: var(--zt-accent);
  --zt-c-border: var(--zt-accent);
}

.zt-form input[type="checkbox"]:checked      { background-image: var(--zt-check-icon); background-size: 76%; }
.zt-form input[type="checkbox"]:indeterminate { background-image: var(--zt-indeterminate-icon); background-size: 76%; }

.zt-form input[type="radio"]:checked {
  background-image: radial-gradient(circle at center, var(--zt-radio-dot) 0 42%, transparent 44%);
}

.zt-form input[type="checkbox"]:disabled,
.zt-form input[type="radio"]:disabled {
  --zt-c-bg: var(--zt-bg-disabled);
  --zt-c-border: var(--zt-border-disabled);
  --zt-c-cursor: not-allowed;
  cursor: not-allowed;
}

.zt-form input[type="checkbox"]:disabled:checked,
.zt-form input[type="radio"]:disabled:checked {
  --zt-c-bg: var(--zt-text-disabled);
  --zt-c-border: var(--zt-text-disabled);
}

/* Option rows: <label class="zt-option"><input><span>Text</span></label> */
.zt-form .zt-option,
.zt-form .zt-option-label {
  display: flex;
  align-items: flex-start;
  gap: var(--zt-option-gap);
  margin: 0;
  font-size: var(--zt-font-size);
  font-weight: 400;
  line-height: var(--zt-line-height);
  color: var(--zt-text);
  cursor: pointer;
}

.zt-form .zt-option > input { margin-block-start: calc((var(--zt-font-size) * var(--zt-line-height) - var(--zt-check-size)) / 2); }
.zt-form .zt-option:has(input:disabled) { color: var(--zt-text-disabled); cursor: not-allowed; }

.zt-form .zt-options {
  display: flex;
  flex-direction: column;
  gap: var(--zt-option-gap);
}
.zt-form .zt-options--inline {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--zt-option-gap) calc(var(--zt-option-gap) * 2);
}

/* --- 5.4 Switch — <input type="checkbox" class="zt-switch"> -------------- */

.zt-form input[type="checkbox"].zt-switch {
  inline-size: var(--zt-switch-width);
  block-size: var(--zt-switch-height);
  border-radius: 999px;
  background-color: var(--zt-switch-off);
  border-color: transparent;
  background-image: radial-gradient(circle at center, var(--zt-on-accent) 0 48%, transparent 50%);
  background-size: var(--zt-switch-height) var(--zt-switch-height);
  background-position: left center;
  transition:
    background-color var(--zt-transition),
    background-position var(--zt-transition),
    box-shadow var(--zt-transition);
}

.zt-form input[type="checkbox"].zt-switch:checked {
  background-color: var(--zt-accent);
  background-image: radial-gradient(circle at center, var(--zt-on-accent) 0 48%, transparent 50%);
  background-position: right center;
}

[dir="rtl"] .zt-form input[type="checkbox"].zt-switch          { background-position: right center; }
[dir="rtl"] .zt-form input[type="checkbox"].zt-switch:checked  { background-position: left center; }

/* --- 5.5 Range ----------------------------------------------------------- */

.zt-form input[type="range"]:not([data-zt-skip]) {
  -webkit-appearance: none;
  appearance: none;
  inline-size: 100%;
  block-size: var(--zt-range-thumb-size);
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
}

.zt-form input[type="range"]::-webkit-slider-runnable-track {
  block-size: var(--zt-range-track-height);
  background: var(--zt-range-track);
  border-radius: 999px;
}
.zt-form input[type="range"]::-moz-range-track {
  height: var(--zt-range-track-height);
  background: var(--zt-range-track);
  border-radius: 999px;
}
.zt-form input[type="range"]::-moz-range-progress {
  height: var(--zt-range-track-height);
  background: var(--zt-accent);
  border-radius: 999px;
}

.zt-form input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: var(--zt-range-thumb-size);
  height: var(--zt-range-thumb-size);
  margin-top: calc((var(--zt-range-track-height) - var(--zt-range-thumb-size)) / 2);
  background: var(--zt-accent);
  border: 3px solid var(--zt-on-accent);
  border-radius: 50%;
  box-shadow: var(--zt-thumb-shadow);
  transition: box-shadow var(--zt-transition);
}
.zt-form input[type="range"]::-moz-range-thumb {
  width: var(--zt-range-thumb-size);
  height: var(--zt-range-thumb-size);
  background: var(--zt-accent);
  border: 3px solid var(--zt-on-accent);
  border-radius: 50%;
  box-shadow: var(--zt-thumb-shadow);
}

.zt-form input[type="range"]:focus-visible { outline: none; }
.zt-form input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 var(--zt-ring-width) var(--zt-ring); }
.zt-form input[type="range"]:focus-visible::-moz-range-thumb     { box-shadow: 0 0 0 var(--zt-ring-width) var(--zt-ring); }

/* --- 5.6 File ------------------------------------------------------------ */

.zt-form input[type="file"]:not([data-zt-skip]) {
  box-sizing: border-box;
  inline-size: 100%;
  min-block-size: var(--zt-control-height);
  padding: calc(var(--zt-control-padding-y) - 2px) var(--zt-control-padding-x);
  font-family: inherit;
  font-size: var(--zt-font-size);
  color: var(--zt-c-text);
  background-color: var(--zt-c-bg);
  border: var(--zt-border-width) solid var(--zt-c-border);
  border-radius: var(--zt-radius);
  box-shadow: 0 0 0 var(--zt-c-ring-width) var(--zt-c-ring);
  cursor: pointer;
  transition: border-color var(--zt-transition), box-shadow var(--zt-transition);
}

.zt-form input[type="file"]::file-selector-button {
  margin-inline-end: var(--zt-icon-gap);
  padding: 6px 14px;
  font: inherit;
  font-size: calc(var(--zt-font-size) - 1px);
  font-weight: 500;
  color: var(--zt-accent);
  background: color-mix(in srgb, var(--zt-accent) 10%, transparent);
  border: 0;
  border-radius: calc(var(--zt-radius) - 4px);
  cursor: pointer;
  transition: background-color var(--zt-transition);
}
.zt-form input[type="file"]:hover::file-selector-button {
  background: color-mix(in srgb, var(--zt-accent) 18%, transparent);
}

/* Dropzone, built by the JS enhancer — the design's Upload Component: a
   dashed 55px box with centred prompt text, then the format/size limits
   underneath. */
.zt-form .zt-field > .zt-file,
.zt-form .zt-file {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--zt-icon-gap);
  inline-size: 100%;
  min-block-size: var(--zt-upload-height);
  padding: 8px var(--zt-control-padding-x);
  text-align: center;
  background-color: var(--zt-c-bg);
  border: var(--zt-border-width) var(--zt-upload-border-style) var(--zt-c-border);
  border-radius: var(--zt-radius);
  cursor: pointer;
  transition: border-color var(--zt-transition), background-color var(--zt-transition);
}
.zt-form .zt-file:hover { --zt-c-border: var(--zt-border-hover); }
.zt-form .zt-file.is-dragover {
  --zt-c-border: var(--zt-accent);
  --zt-c-bg: var(--zt-accent-soft);
}
.zt-form .zt-file.is-invalid,
.zt-form .zt-file.has-error { --zt-c-border: var(--zt-error); }
.zt-form .zt-file:has(input:disabled) {
  --zt-c-bg: var(--zt-bg-disabled);
  --zt-c-border: var(--zt-border-disabled);
  cursor: not-allowed;
}

.zt-form .zt-file > input[type="file"] {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: inherit;
}

.zt-form .zt-file__icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--zt-icon-size);
  block-size: var(--zt-icon-size);
  color: var(--zt-help-color);
}
.zt-form .zt-file__icon svg { inline-size: 100%; block-size: 100%; display: block; }

.zt-form .zt-file__name {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--zt-font-size);
  color: var(--zt-placeholder);
}
.zt-form .zt-file.has-file .zt-file__name { color: var(--zt-text); }

/* Allowed formats / maximum size, printed under the box. */
.zt-form .zt-file-meta {
  margin-block-start: var(--zt-upload-gap);
  font-size: var(--zt-help-font-size);
  line-height: 1.6;
  color: var(--zt-help-color);
}
.zt-form .zt-file-meta > span { display: block; }

/* The chosen files, when more than a name is worth showing. */
.zt-form .zt-file-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-block-start: var(--zt-upload-gap);
}
.zt-form .zt-file-list:empty { display: none; }
.zt-form .zt-file-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  font-size: var(--zt-help-font-size);
  color: var(--zt-text);
  background: var(--zt-bg-readonly);
  border: var(--zt-border-width) solid var(--zt-border);
  border-radius: var(--zt-radius);
}
.zt-form .zt-file-item__name { flex: 1 1 auto; min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zt-form .zt-file-item__size { flex: 0 0 auto; color: var(--zt-help-color); font-variant-numeric: tabular-nums; }
.zt-form .zt-file-item__remove {
  flex: 0 0 auto;
  inline-size: 18px;
  block-size: 18px;
  padding: 0;
  color: var(--zt-help-color);
  background: none;
  border: 0;
  border-radius: 4px;
  cursor: pointer;
  line-height: 1;
}
.zt-form .zt-file-item__remove:hover { color: var(--zt-error); }
.zt-form .zt-file-item.is-invalid {
  color: var(--zt-notice-error);
  background: var(--zt-notice-error-bg);
  border-color: transparent;
}

/* --- 5.7 Colour ---------------------------------------------------------- */

.zt-form input[type="color"]:not([data-zt-skip]) {
  inline-size: var(--zt-control-height);
  block-size: var(--zt-control-height);
  padding: 4px;
  background-color: var(--zt-c-bg);
  border: var(--zt-border-width) solid var(--zt-c-border);
  border-radius: var(--zt-radius);
  cursor: pointer;
}
.zt-form input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.zt-form input[type="color"]::-webkit-color-swatch { border: 0; border-radius: calc(var(--zt-radius) - 5px); }
.zt-form input[type="color"]::-moz-color-swatch { border: 0; border-radius: calc(var(--zt-radius) - 5px); }

/* Date/time pickers: keep the native indicator but tint it */
.zt-form input::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: .55;
  transition: opacity var(--zt-transition);
}
.zt-form input:hover::-webkit-calendar-picker-indicator { opacity: 1; }

/* Number: hide spinners when a custom stepper is attached */
.zt-form .zt-control--stepper input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}
.zt-form .zt-control--stepper input[type="number"]::-webkit-outer-spin-button,
.zt-form .zt-control--stepper input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* --- 5.8 Chips (Figma: Form/Tag) ------------------------------------------
   A wrapping row of toggle pills. No checkbox, no tick — selection is carried
   entirely by the pill's own fill and border.
   ------------------------------------------------------------------------ */

.zt-form .zt-chips { display: block; inline-size: 100%; }

/* The real <select> stays in the DOM so the form submits unchanged. */
.zt-form .zt-chips__native {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  border: 0;
  opacity: 0;
  pointer-events: none;
}

.zt-form .zt-chips__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--zt-chip-gap);
}

.zt-form .zt-chip {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: var(--zt-chip-height);
  padding: var(--zt-chip-padding-y) var(--zt-chip-padding-x);
  font-family: inherit;
  font-size: var(--zt-chip-font-size);
  font-weight: 400;
  line-height: var(--zt-line-height);
  color: var(--zt-chip-color);
  background-color: var(--zt-chip-bg);
  border: var(--zt-border-width) solid var(--zt-chip-border);
  border-radius: var(--zt-chip-radius);
  cursor: pointer;
  transition:
    background-color var(--zt-transition),
    border-color var(--zt-transition),
    color var(--zt-transition);
}

.zt-form .zt-chip:hover:not(:disabled) { border-color: var(--zt-chip-selected-border); }

.zt-form .zt-chip:focus-visible {
  outline: 2px solid var(--zt-chip-selected-border);
  outline-offset: 2px;
}

.zt-form .zt-chip.is-selected {
  font-weight: 500;
  color: var(--zt-chip-selected-color);
  background-color: var(--zt-chip-selected-bg);
  border-color: var(--zt-chip-selected-border);
}

.zt-form .zt-chip:disabled {
  color: var(--zt-chip-disabled-color);
  background-color: var(--zt-chip-disabled-bg);
  border-color: transparent;
  cursor: not-allowed;
}

.zt-form .zt-chips.is-invalid .zt-chip:not(.is-selected):not(:disabled) {
  border-color: var(--zt-error);
}

/* ==========================================================================
   6. CONTROL GROUPS, ADDONS, FLOATING LABELS
   ========================================================================== */

/* .zt-control wraps a single control plus icons/buttons */
.zt-form .zt-control {
  position: relative;
  display: block;
  inline-size: 100%;
}

.zt-form .zt-control__icon,
.zt-form .zt-control__action {
  position: absolute;
  inset-block-start: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--zt-icon-size);
  block-size: var(--zt-icon-size);
  color: var(--zt-help-color);
  pointer-events: none;
}
.zt-form .zt-control__icon svg,
.zt-form .zt-control__action svg { inline-size: 100%; block-size: 100%; display: block; }

.zt-form .zt-control__icon--start  { inset-inline-start: var(--zt-control-padding-x); }
.zt-form .zt-control__icon--end,
.zt-form .zt-control__action       { inset-inline-end: var(--zt-control-padding-x); }

.zt-form .zt-control__action {
  padding: 0;
  background: none;
  border: 0;
  border-radius: 4px;
  cursor: pointer;
  pointer-events: auto;
  transition: color var(--zt-transition);
}
.zt-form .zt-control__action:hover { color: var(--zt-text); }
.zt-form .zt-control__action:focus-visible {
  outline: 2px solid var(--zt-accent);
  outline-offset: 2px;
  color: var(--zt-text);
}

.zt-form .zt-control--icon-start > input,
.zt-form .zt-control--icon-start > select,
.zt-form .zt-control--icon-start > textarea {
  --zt-c-pad-start: calc(var(--zt-control-padding-x) + var(--zt-icon-size) + var(--zt-icon-gap));
}
.zt-form .zt-control--icon-end > input,
.zt-form .zt-control--icon-end > textarea,
.zt-form .zt-control--action > input {
  --zt-c-pad-end: calc(var(--zt-control-padding-x) + var(--zt-icon-size) + var(--zt-icon-gap));
}

/* Textarea icons sit at the top, not the middle */
.zt-form .zt-control:has(> textarea) .zt-control__icon,
.zt-form .zt-control:has(> textarea) .zt-control__action {
  inset-block-start: calc(var(--zt-control-padding-y) + 2px);
  transform: none;
}

/* Number stepper */
.zt-form .zt-stepper {
  position: absolute;
  inset-inline-end: 6px;
  inset-block-start: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
}
.zt-form .zt-stepper button {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 26px;
  block-size: 17px;
  padding: 0;
  font: inherit;
  font-size: 10px;
  line-height: 1;
  color: var(--zt-help-color);
  background: none;
  border: 0;
  cursor: pointer;
  transition: color var(--zt-transition);
}
.zt-form .zt-stepper button:hover { color: var(--zt-accent); }
.zt-form .zt-control--stepper > input { --zt-c-pad-end: 40px; }

/* --- Floating labels -----------------------------------------------------
   The label rides on the control's top border, so it needs an opaque
   background to break that border cleanly. --zt-float-label-bg must match the
   surface the control sits on; it defaults to the control's own background.
   ------------------------------------------------------------------------ */

.zt-form .zt-field--float .zt-control { display: block; }

.zt-form .zt-field--float .zt-label {
  position: absolute;
  z-index: 2;
  inset-block-start: calc(var(--zt-control-height) / 2);
  inset-inline-start: calc(var(--zt-control-padding-x) - var(--zt-float-label-padding-x) + var(--zt-border-width));
  margin: 0;
  padding-block: 0;
  padding-inline: var(--zt-float-label-padding-x);
  transform: translateY(-50%);
  font-size: var(--zt-font-size);
  font-weight: 400;
  line-height: 1.2;
  color: var(--zt-placeholder);
  background-color: transparent;
  border-radius: 3px;
  pointer-events: none;
  max-inline-size: calc(100% - var(--zt-control-padding-x) * 2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition:
    inset-block-start var(--zt-transition),
    font-size var(--zt-transition),
    color var(--zt-transition),
    background-color var(--zt-transition);
}

/* Icon-leading fields push the resting label past the icon. */
.zt-form .zt-field--float .zt-control--icon-start > .zt-label {
  inset-inline-start: calc(var(--zt-control-padding-x) + var(--zt-icon-size) + var(--zt-icon-gap) - var(--zt-float-label-padding-x));
}

/* Floated state — opaque background covers the border underneath. */
.zt-form .zt-field--float .zt-control:focus-within > .zt-label,
.zt-form .zt-field--float .zt-control.is-filled > .zt-label,
.zt-form .zt-field--float .zt-control:has(input:not(:placeholder-shown)) > .zt-label,
.zt-form .zt-field--float .zt-control:has(textarea:not(:placeholder-shown)) > .zt-label,
.zt-form .zt-field--float .zt-control:has(select) > .zt-label {
  inset-block-start: 0;
  inset-inline-start: calc(var(--zt-control-padding-x) - var(--zt-float-label-padding-x) + var(--zt-border-width));
  font-size: var(--zt-help-font-size);
  color: var(--zt-label-color);
  background-color: var(--zt-float-label-bg);
}

.zt-form .zt-field--float .zt-control:focus-within > .zt-label { color: var(--zt-accent); }
.zt-form .zt-field--float .zt-control:has([aria-invalid="true"]) > .zt-label { color: var(--zt-error); }
.zt-form .zt-field--float .zt-control:has(:disabled) > .zt-label { color: var(--zt-text-disabled); }

/* Textareas float against the top edge, not the vertical centre. */
.zt-form .zt-field--float .zt-control:has(> textarea) > .zt-label {
  inset-block-start: calc(var(--zt-control-padding-y) + (var(--zt-font-size) * var(--zt-line-height)) / 2);
}
.zt-form .zt-field--float .zt-control:has(> textarea):focus-within > .zt-label,
.zt-form .zt-field--float .zt-control:has(> textarea.is-filled) > .zt-label,
.zt-form .zt-field--float .zt-control:has(> textarea:not(:placeholder-shown)) > .zt-label {
  inset-block-start: 0;
}

/* A placeholder must exist for :placeholder-shown to work, but stay invisible
   until the label has moved out of the way. */
.zt-form .zt-field--float input::placeholder,
.zt-form .zt-field--float textarea::placeholder { color: transparent; }
.zt-form .zt-field--float :focus::placeholder { color: var(--zt-placeholder); }

/* ==========================================================================
   7. ENHANCED SELECT (built by zt-forms.js — opt-in)
   ========================================================================== */

.zt-form .zt-combo {
  position: relative;
  display: block;
  inline-size: 100%;
  max-inline-size: 100%;
}
.zt-form .zt-combo > select { position: absolute; opacity: 0; pointer-events: none; inline-size: 1px; block-size: 1px; }

.zt-form .zt-combo__button {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: var(--zt-icon-gap);
  inline-size: 100%;
  min-block-size: var(--zt-control-height);
  padding: var(--zt-control-padding-y) var(--zt-control-padding-x);
  font: inherit;
  font-size: var(--zt-font-size);
  text-align: start;
  color: var(--zt-c-text);
  background-color: var(--zt-c-bg);
  border: var(--zt-border-width) solid var(--zt-c-border);
  border-radius: var(--zt-radius);
  box-shadow: var(--zt-c-shadow, var(--zt-shadow)), 0 0 0 var(--zt-c-ring-width) var(--zt-c-ring);
  cursor: pointer;
  transition:
    border-color var(--zt-transition),
    box-shadow var(--zt-transition),
    background-color var(--zt-transition);
}
.zt-form .zt-combo__button:hover { --zt-c-border: var(--zt-border-hover); }
.zt-form .zt-combo__button:focus-visible,
.zt-form .zt-combo.is-open .zt-combo__button {
  --zt-c-border: var(--zt-border-focus);
  --zt-c-ring: var(--zt-ring);
  --zt-c-ring-width: var(--zt-ring-width);
  outline: none;
}
.zt-form .zt-combo.is-invalid .zt-combo__button { --zt-c-border: var(--zt-error); --zt-c-bg: var(--zt-error-bg); }
.zt-form .zt-combo.is-disabled .zt-combo__button {
  --zt-c-bg: var(--zt-bg-disabled);
  --zt-c-text: var(--zt-text-disabled);
  --zt-c-border: var(--zt-border-disabled);
  cursor: not-allowed;
}

.zt-form .zt-combo__value { flex: 1 1 auto; min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zt-form .zt-combo__value.is-placeholder { color: var(--zt-placeholder); }
.zt-form .zt-combo.is-open .zt-combo__value.is-placeholder { color: var(--zt-accent); }

.zt-form .zt-combo__arrow {
  flex: 0 0 auto;
  inline-size: var(--zt-icon-size);
  block-size: var(--zt-icon-size);
  background: var(--zt-select-icon) no-repeat center / contain;
  transition: transform var(--zt-transition);
}
.zt-form .zt-combo.is-open .zt-combo__arrow { transform: rotate(180deg); }

.zt-form .zt-combo__list {
  position: absolute;
  z-index: 60;
  inset-inline: 0;
  inset-block-start: calc(100% + var(--zt-dropdown-gap));
  max-block-size: 264px;
  margin: 0;
  padding: var(--zt-dropdown-padding-block) var(--zt-dropdown-padding-inline);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Scroll without a visible bar — the design has none. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  list-style: none;
  background: var(--zt-bg);
  border: var(--zt-border-width) solid var(--zt-dropdown-border);
  border-radius: var(--zt-radius);
  box-shadow: var(--zt-dropdown-shadow);
}
.zt-form .zt-combo__list::-webkit-scrollbar { inline-size: 0; block-size: 0; display: none; }
.zt-form .zt-combo__list[hidden] { display: none; }
.zt-form .zt-combo--up .zt-combo__list { inset-block-start: auto; inset-block-end: calc(100% + var(--zt-dropdown-gap)); }

.zt-form .zt-combo__search {
  position: sticky;
  /* Pull up over the list's top padding and re-add it inside, so the sticky
     box is opaque across the full width and nothing peeks out beneath it. */
  inset-block-start: calc(var(--zt-dropdown-padding-block) * -1);
  z-index: 2;
  margin-block: calc(var(--zt-dropdown-padding-block) * -1) var(--zt-dropdown-padding-block);
  margin-inline: calc(var(--zt-dropdown-padding-inline) * -1);
  padding-block: var(--zt-dropdown-padding-block) 8px;
  padding-inline: var(--zt-dropdown-padding-inline);
  background: var(--zt-bg);
  border-block-end: var(--zt-border-width) solid var(--zt-border);
  border-start-start-radius: inherit;
  border-start-end-radius: inherit;
}

.zt-form .zt-combo__search input {
  box-sizing: border-box;
  inline-size: 100%;
  min-block-size: 36px;
  padding-block: 6px;
  padding-inline: 34px 10px;
  font: inherit;
  font-size: calc(var(--zt-font-size) - 1px);
  color: var(--zt-text);
  background-color: var(--zt-bg);
  background-image: var(--zt-search-icon);
  background-repeat: no-repeat;
  background-position: left 9px center;
  background-size: 16px 16px;
  border: var(--zt-border-width) solid var(--zt-border);
  border-radius: calc(var(--zt-radius) - 3px);
  outline: none;
}
[dir="rtl"] .zt-form .zt-combo__search input {
  padding-inline: 10px 34px;
  background-position: right 9px center;
}
.zt-form .zt-combo__search input:focus { border-color: var(--zt-accent); }
.zt-form .zt-combo__search input::placeholder { color: var(--zt-placeholder); }

.zt-form .zt-combo__option[hidden],
.zt-form .zt-combo__group[hidden] { display: none; }

.zt-form .zt-combo__option {
  display: flex;
  align-items: center;
  gap: 8px;
  min-block-size: var(--zt-option-height);
  margin-block-end: var(--zt-option-gap-y);
  padding-block: 6px;
  padding-inline: var(--zt-option-padding-x);
  border-radius: var(--zt-radius);
  font-size: var(--zt-font-size);
  color: var(--zt-text);
  cursor: pointer;
  transition: background-color 80ms linear, color 80ms linear;
}
.zt-form .zt-combo__option:last-child { margin-block-end: 0; }

/* Selected and keyboard-active rows share one treatment in the design:
   a soft accent wash with accent, semibold text. */
.zt-form .zt-combo__option[aria-selected="true"],
.zt-form .zt-combo__option.is-active,
.zt-form .zt-combo__option:hover {
  background: var(--zt-accent-soft);
  color: var(--zt-accent);
  font-weight: 600;
}
.zt-form .zt-combo__option[aria-disabled="true"] {
  color: var(--zt-text-disabled);
  cursor: not-allowed;
  background: none;
  font-weight: 400;
}
.zt-form .zt-combo__group {
  padding-block: 8px 4px;
  padding-inline: var(--zt-option-padding-x);
  font-size: var(--zt-help-font-size);
  font-weight: 600;
  color: var(--zt-help-color);
}
.zt-form .zt-combo__empty { padding: 12px; color: var(--zt-help-color); text-align: center; }

/* ==========================================================================
   8. BUTTONS
   ========================================================================== */

.zt-form .zt-button,
.zt-form button[type="submit"]:not([data-zt-skip]),
.zt-form input[type="submit"]:not([data-zt-skip]) {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-block-size: var(--zt-control-height);
  padding: var(--zt-control-padding-y) var(--zt-button-padding-x);
  font-family: inherit;
  font-size: var(--zt-font-size);
  font-weight: var(--zt-button-font-weight);
  line-height: var(--zt-line-height);
  text-decoration: none;
  color: var(--zt-button-color);
  background-color: var(--zt-button-bg);
  border: var(--zt-border-width) solid transparent;
  border-radius: var(--zt-button-radius);
  cursor: pointer;
  transition: background-color var(--zt-transition), box-shadow var(--zt-transition), opacity var(--zt-transition);
}

.zt-form .zt-button:hover,
.zt-form button[type="submit"]:hover,
.zt-form input[type="submit"]:hover { background-color: var(--zt-button-bg-hover); }

.zt-form .zt-button:focus-visible,
.zt-form button[type="submit"]:focus-visible,
.zt-form input[type="submit"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 var(--zt-ring-width) var(--zt-ring);
}

.zt-form .zt-button:disabled,
.zt-form button[type="submit"]:disabled,
.zt-form input[type="submit"]:disabled { opacity: .55; cursor: not-allowed; }

.zt-form .zt-button--secondary {
  color: var(--zt-accent);
  background-color: transparent;
  border-color: var(--zt-border);
}
.zt-form .zt-button--secondary:hover {
  background-color: color-mix(in srgb, var(--zt-accent) 8%, transparent);
  border-color: var(--zt-accent);
}
.zt-form .zt-button--block { display: flex; inline-size: 100%; }

/* Busy state toggled by the JS on submit */
.zt-form .zt-button.is-busy { pointer-events: none; opacity: .75; }
.zt-form .zt-button.is-busy::before {
  content: "";
  inline-size: 1em;
  block-size: 1em;
  border: 2px solid currentColor;
  border-block-start-color: transparent;
  border-radius: 50%;
  animation: zt-spin .6s linear infinite;
}
@keyframes zt-spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   9. SIZE MODIFIERS
   ========================================================================== */

.zt-form.zt-form--sm, .zt-form .zt-field--sm, .zt-form .zt-input--sm {
  --zt-control-height: 40px;
  --zt-control-padding-x: 12px;
  --zt-control-padding-y: 8px;
  --zt-font-size: 14px;
  --zt-radius: 8px;
  --zt-check-size: 18px;
  --zt-icon-size: 18px;
}

.zt-form.zt-form--lg, .zt-form .zt-field--lg, .zt-form .zt-input--lg {
  --zt-control-height: 56px;
  --zt-control-padding-x: 20px;
  --zt-control-padding-y: 14px;
  --zt-font-size: 16px;
  --zt-radius: 12px;
  --zt-check-size: 22px;
  --zt-icon-size: 22px;
}

/* ==========================================================================
   10. RTL / LTR
   ==========================================================================
   Almost everything above already uses logical properties, so direction is
   handled automatically. Only background positions and transforms need help;
   those are patched inline next to their rules. This block covers the rest.
   ========================================================================== */

.zt-form { text-align: start; }
.zt-form input,
.zt-form select,
.zt-form textarea { text-align: start; }

/* Latin-only fields (email, url, tel, numbers) inside an RTL form read better
   when the *content* stays LTR while the box keeps RTL alignment. Opt in with
   class="zt-ltr" (the JS adds it automatically for those input types).
   ------------------------------------------------------------------------
   The catch: `direction: ltr` also flips what padding-inline-start means for
   that element, while the icon beside it is positioned against the RTL
   wrapper. Left alone, the icon and its gutter end up on opposite sides. The
   rules below re-map the gutters so they follow the wrapper, not the box. */
.zt-form .zt-ltr { direction: ltr; text-align: start; }
[dir="rtl"] .zt-form .zt-ltr { text-align: right; }

[dir="rtl"] .zt-form .zt-control--icon-start > .zt-ltr {
  --zt-c-pad-start: var(--zt-control-padding-x);
  --zt-c-pad-end: calc(var(--zt-control-padding-x) + var(--zt-icon-size) + var(--zt-icon-gap));
}
[dir="rtl"] .zt-form .zt-control--icon-end > .zt-ltr,
[dir="rtl"] .zt-form .zt-control--action > .zt-ltr {
  --zt-c-pad-end: var(--zt-control-padding-x);
  --zt-c-pad-start: calc(var(--zt-control-padding-x) + var(--zt-icon-size) + var(--zt-icon-gap));
}
[dir="rtl"] .zt-form .zt-control--stepper > .zt-ltr {
  --zt-c-pad-end: var(--zt-control-padding-x);
  --zt-c-pad-start: 40px;
}

/* Same story for the floating label: it is positioned against the wrapper,
   so an LTR box underneath must not drag it to the other side. */
[dir="rtl"] .zt-form .zt-field--float .zt-control > .zt-label { direction: rtl; }

/* ==========================================================================
   11. PLUGIN ADAPTERS
   ==========================================================================
   The JS normaliser adds `.zt-form` to registered containers, so the rules
   above already apply. These blocks only fix layout/overrides that the host
   plugin's own CSS insists on.
   ========================================================================== */

/* --- 11.1 Elementor Forms ------------------------------------------------ */

.zt-form.elementor-form .elementor-field-group { margin-block-end: var(--zt-field-gap); }
.zt-form.elementor-form .elementor-field-group > .elementor-field-label {
  margin-block-end: var(--zt-label-gap);
  padding: 0;
  font-size: var(--zt-label-font-size);
  font-weight: var(--zt-label-font-weight);
  color: var(--zt-label-color);
}
.zt-form.elementor-form .elementor-field-group.elementor-field-required > .elementor-field-label::after {
  content: "*";
  margin-inline-start: 4px;
  color: var(--zt-required-color);
}

/* Elementor sets fixed heights per elementor-size-* — let our tokens win */
.zt-form.elementor-form .elementor-field-textual,
.zt-form.elementor-form .elementor-field-textual.elementor-size-xs,
.zt-form.elementor-form .elementor-field-textual.elementor-size-sm,
.zt-form.elementor-form .elementor-field-textual.elementor-size-md,
.zt-form.elementor-form .elementor-field-textual.elementor-size-lg,
.zt-form.elementor-form .elementor-field-textual.elementor-size-xl {
  min-block-size: var(--zt-control-height);
  padding-block: var(--zt-c-pad-block, var(--zt-control-padding-y));
  padding-inline:
    var(--zt-c-pad-start, var(--zt-control-padding-x))
    var(--zt-c-pad-end, var(--zt-control-padding-x));
  font-size: var(--zt-font-size);
  line-height: var(--zt-line-height);
  border-radius: var(--zt-radius);
}
.zt-form.elementor-form select.elementor-field-textual {
  --zt-c-pad-end: calc(var(--zt-control-padding-x) + var(--zt-icon-size) + 4px);
}

/* Elementor injects its own chevron next to selects — hide it, we draw ours */
.zt-form.elementor-form .elementor-select-wrapper .select-caret-down-wrapper,
.zt-form.elementor-form .elementor-select-wrapper .e-font-icon-svg-container { display: none; }
.zt-form.elementor-form .elementor-select-wrapper { position: relative; }

/* Acceptance / checkbox & radio subgroups */
.zt-form.elementor-form .elementor-field-subgroup {
  display: flex;
  flex-direction: column;
  gap: var(--zt-option-gap);
}
.zt-form.elementor-form .elementor-field-subgroup.elementor-subgroup-inline {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--zt-option-gap) calc(var(--zt-option-gap) * 2);
}
.zt-form.elementor-form .elementor-field-option,
.zt-form.elementor-form .elementor-field-subgroup .elementor-field-option {
  display: flex;
  align-items: flex-start;
  gap: var(--zt-option-gap);
}
.zt-form.elementor-form .elementor-field-option label { margin: 0; font-weight: 400; cursor: pointer; }
.zt-form.elementor-form .elementor-field-option input { margin: 0; }

/* Submit button */
.zt-form.elementor-form .elementor-button[type="submit"] {
  min-block-size: var(--zt-control-height);
  padding-inline: var(--zt-button-padding-x);
  font-size: var(--zt-font-size);
  font-weight: var(--zt-button-font-weight);
  background-color: var(--zt-button-bg);
  color: var(--zt-button-color);
  border-radius: var(--zt-button-radius);
}
.zt-form.elementor-form .elementor-button[type="submit"]:hover { background-color: var(--zt-button-bg-hover); }

/* Elementor's widget style controls emit box-shadow straight onto the field
   (".elementor-element-xxx .elementor-field-textual"), which out-specifies our
   base rule. The design has no shadows, so route Elementor's fields back
   through the shadow tokens at a specificity that wins. */
.zt-form.elementor-form .elementor-field-textual,
.zt-form.elementor-form .elementor-field-textual:focus,
.zt-form.elementor-form .elementor-field-textual:hover,
.zt-form.elementor-form .elementor-select-wrapper select {
  box-shadow: var(--zt-c-shadow, var(--zt-shadow)), 0 0 0 var(--zt-c-ring-width) var(--zt-c-ring);
}
.zt-form.elementor-form .elementor-button[type="submit"] { box-shadow: var(--zt-shadow); }

/* Last resort for a theme that uses !important on its input shadows. */
.zt-form--flat input,
.zt-form--flat select,
.zt-form--flat textarea,
.zt-form--flat button,
.zt-form--flat .zt-combo__button {
  box-shadow: var(--zt-c-shadow, var(--zt-shadow)), 0 0 0 var(--zt-c-ring-width) var(--zt-c-ring) !important;
}

/* Elementor's own error/success messages */
.zt-form.elementor-form .elementor-message {
  margin-block-start: var(--zt-help-gap);
  font-size: var(--zt-help-font-size);
  line-height: 1.5;
}
.zt-form.elementor-form .elementor-message.elementor-message-danger { color: var(--zt-error); }
.zt-form.elementor-form .elementor-message.elementor-message-success { color: var(--zt-success); }

/* Elementor flags invalid fields on the group, not the control */
.zt-form.elementor-form .elementor-field-group.elementor-error .elementor-field {
  --zt-c-border: var(--zt-error);
  --zt-c-bg: var(--zt-error-bg);
}

/* --- 11.2 Generic adapter hooks ------------------------------------------
   For your own plugins: either add `zt-form` to the container yourself, or
   register the selector with ZTForms.addScope('.my-form'). If your markup
   flags errors with its own class, map it here (or pass `errorClass` in the
   JS options and the normaliser will mirror it onto `.zt-invalid`).
   ------------------------------------------------------------------------ */

.zt-form .zt-invalid > .zt-label,
.zt-form .zt-field.zt-invalid > label { color: var(--zt-error); }

/* ==========================================================================
   11.3 NOTICES
   ==========================================================================
   Per-field messages (validation errors, confirmations, hints) and one
   form-level banner. Four kinds: error, success, info, warning.

     <div class="zt-notices">
       <p class="zt-notice zt-notice--error" role="alert">
         <span class="zt-notice__icon">…</span>
         <span class="zt-notice__text">Enter a valid email.</span>
       </p>
     </div>

   Built for you by ZTForms.notice() / ZTForms.setErrors(). Plain text by
   default; add .zt-form--notice-boxed for filled panels.
   ========================================================================== */

.zt-form .zt-notices {
  display: flex;
  flex-direction: column;
  gap: var(--zt-notice-gap);
  margin-block-start: var(--zt-help-gap);
}
.zt-form .zt-notices:empty { display: none; margin-block-start: 0; }

.zt-form .zt-notice {
  display: flex;
  align-items: center;
  gap: var(--zt-notice-gap);
  min-block-size: var(--zt-notice-min-height);
  margin: 0;
  padding: var(--zt-notice-padding);
  font-size: var(--zt-help-font-size);
  font-weight: 500;
  line-height: 1.6;
  color: var(--zt-notice-color, var(--zt-help-color));
  background-color: var(--zt-notice-bg, transparent);
  border: var(--zt-notice-border-width) solid transparent;
  border-radius: var(--zt-notice-radius);
}

.zt-form .zt-notice__icon {
  flex: 0 0 auto;
  inline-size: var(--zt-notice-icon-size);
  block-size: var(--zt-notice-icon-size);
  color: var(--zt-notice-color, currentColor);
}
.zt-form .zt-notice__icon svg { inline-size: 100%; block-size: 100%; display: block; }
.zt-form .zt-notice__text { flex: 1 1 auto; min-inline-size: 0; }

/* Inline action inside a notice — the autosave banner's "discard". */
.zt-form .zt-notice__action {
  flex: 0 0 auto;
  padding: 4px 10px;
  font: inherit;
  font-size: var(--zt-help-font-size);
  font-weight: 500;
  color: inherit;
  background: transparent;
  border: var(--zt-border-width) solid currentColor;
  border-radius: var(--zt-radius);
  cursor: pointer;
  opacity: .8;
  transition: opacity var(--zt-transition);
}
.zt-form .zt-notice__action:hover { opacity: 1; }
.zt-form .zt-notice__action:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

.zt-form .zt-notice--error {
  --zt-notice-color: var(--zt-notice-error);
  --zt-notice-bg: var(--zt-notice-error-bg);
}
.zt-form .zt-notice--success {
  --zt-notice-color: var(--zt-notice-success);
  --zt-notice-bg: var(--zt-notice-success-bg);
}
.zt-form .zt-notice--info {
  --zt-notice-color: var(--zt-notice-info);
  --zt-notice-bg: var(--zt-notice-info-bg);
}
.zt-form .zt-notice--warning {
  --zt-notice-color: var(--zt-notice-warning);
  --zt-notice-bg: var(--zt-notice-warning-bg);
}

/* Bare-text variant: no panel, just the coloured message and its icon. */
.zt-form--notice-plain .zt-notice,
.zt-form .zt-notice--plain {
  --zt-notice-bg: transparent;
  --zt-notice-padding: 0px;
  --zt-notice-min-height: 0px;
  font-weight: 400;
}

/* Form-level banner — always boxed, sits above or below the fields. */
.zt-form .zt-form-notices {
  display: flex;
  flex-direction: column;
  gap: var(--zt-notice-gap);
  margin-block-end: var(--zt-field-gap);
}
.zt-form .zt-form-notices:empty { display: none; margin-block-end: 0; }
/* Form-level banner = the Feedback/Toast component: taller, 10px radius,
   14px medium text, 1px border in the status colour. */
.zt-form .zt-form-notices .zt-notice {
  --zt-notice-padding: 10px 14px;
  --zt-notice-radius: 10px;
  --zt-notice-border-width: var(--zt-border-width);
  --zt-notice-icon-size: 18px;
  --zt-notice-min-height: 42px;
  font-size: var(--zt-label-font-size);
  border-color: var(--zt-notice-color);
}

/* Elementor's own messages are re-skinned as notices by the JS; this keeps
   them readable even when the script has not run. */
.zt-form.elementor-form .elementor-message.elementor-message-danger,
.zt-form.elementor-form .elementor-message.elementor-message-success {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

/* ==========================================================================
   12. ACCESSIBILITY & PRINT
   ========================================================================== */

.zt-form .zt-visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .zt-form,
  .zt-form * { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

@media (forced-colors: active) {
  .zt-form input,
  .zt-form select,
  .zt-form textarea,
  .zt-form .zt-combo__button { border-color: ButtonBorder; }
  .zt-form input:focus,
  .zt-form select:focus,
  .zt-form textarea:focus { outline: 2px solid Highlight; outline-offset: 1px; }
}

@media print {
  .zt-form input,
  .zt-form select,
  .zt-form textarea { box-shadow: none; }
  .zt-form .zt-combo__list { display: none; }
}
