/* ============================================================================
   CHECKBOX · RADIO — single source of truth.
   Canonical CSS for the custom checkbox + radio controls (.checkbox / .radio
   shell + custom glyph via appearance:none, hover/pressed/focus/disabled, the
   inline .help line). Shared by comp-checkbox-radio.html and any future
   consumer. Import AFTER colors_and_type.css. The whole <label> is the hit
   target; focus ring wraps glyph + text via :has(input:focus-visible) / .is-focus.
   ============================================================================ */

/* ── Checkbox / radio shell ────────────────────────────────────────────
   The whole <label> is the hit-target. We give it inset padding +
   negative margin so the focus ring (a 3 px shadow) wraps the glyph
   *and* the label text with rounded corners, without changing the
   on-screen rhythm of the form. */
.checkbox, .radio {
  display: inline-flex;
  align-items: flex-start;
  /* Labels are click targets; rapid clicks shouldn't text-select the word. */
  -webkit-user-select: none;
  user-select: none;
  gap: 10px;
  font: 400 14px var(--font-sans);
  line-height: 1.4;
  color: var(--color-fg-default);
  cursor: pointer;
  padding: 6px 8px;
  margin: -2px -8px;
  /* Shell radius rides the --radius-control role hook (default 8px) so the
     hover / pressed tint AND the focus ring (box-shadow follows
     border-radius) track a themed radius — sharp themes square the halo,
     pill themes round it fully. */
  border-radius: var(--radius-control, 8px);
  max-width: max-content;
  position: relative;
  /* box-shadow in the base transition so the focus ring blooms; spring
     easing comes from the focus override below. Same recipe as
     comp-inputs / comp-buttons. */
  transition: background-color 100ms linear,
              box-shadow 140ms ease-out;
}
.checkbox:hover:not(.checkbox--disabled),
.radio:hover:not(.radio--disabled),
.checkbox[data-state="hover"]:not(.checkbox--disabled),
.radio[data-state="hover"]:not(.radio--disabled) { background: var(--gov-color-primary-50); }
/* Pressed — deeper well + a stronger glyph border so a click registers.
   `:active` for real pointer; [data-state="pressed"] for the focus playground.
   Routes through --field-pressed-bg (primary-100 light → a neutral translucent
   white in dark) so the press reads as a subtle row tint in BOTH themes from one
   theme-agnostic rule — primary-100 as a raw dark row fill read wrong, which is
   what the old `body[data-theme="dark"] .checkbox:active …` override fixed; that
   override is now gone (the token flips on its own). Same token + reasoning as the
   field/toolbar-select pressed surface (colors_and_type.css @layer tokens). */
.checkbox:active:not(.checkbox--disabled),
.radio:active:not(.radio--disabled),
.checkbox[data-state="pressed"]:not(.checkbox--disabled),
.radio[data-state="pressed"]:not(.radio--disabled) { background: var(--field-pressed-bg); }
/* Focus ring lives on the whole control, rounded to match the shell.
   `:has(input:focus-visible)` for real keyboard nav; `.is-focus`
   modifier for the static spec demo below. */
.checkbox:has(input:focus-visible),
.radio:has(input:focus-visible),
.checkbox.is-focus,
.radio.is-focus {
  box-shadow: var(--shadow-focus, 0 0 0 3px rgba(35,98,162,0.35));
  background: var(--gov-color-primary-50);
  /* Focus-ring bloom — pattern shared with comp-inputs / comp-buttons. */
  transition: background-color 100ms linear,
              box-shadow 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* …and the glyph itself also takes the same 3px semi-transparent
   ring, so users tracking the cursor at the control level see
   *where* focus has landed within the row. Same token as the
   outer shell ring; native :focus-visible for keyboard nav, the
   .is-focus modifier mirrors it for the static demo. */
.checkbox > input:focus-visible,
.radio > input:focus-visible,
.checkbox.is-focus > input,
.radio.is-focus > input {
  box-shadow: var(--shadow-focus, 0 0 0 3px rgba(35,98,162,0.35));
  outline: none;
}
.checkbox--disabled, .radio--disabled {
  color: var(--color-fg-tertiary); cursor: not-allowed;
}

/* ── Error variant — for a REQUIRED selection control left unchecked on submit
   (e.g. a consent checkbox). The red error affordance PERSISTS through hover /
   pressed / focus (mirrors `.field--error`): red label, red glyph border *while
   unchecked*, red row tint (error-50) and a RED focus ring (--shadow-focus-error)
   — the blue hover/focus treatment would mask the invalid state. Cleared the
   moment it becomes valid (checked). Pairs with an adjacent `.field__err` msg.
   No radio is showcased — a single choice can't be "required & empty" — but the
   rules stay parallel for system consistency. */
.checkbox--error, .radio--error { color: var(--gov-color-error-700); }
.checkbox--error > input:not(:checked),
.radio--error > input:not(:checked) { border-color: var(--gov-color-error-500); }
/* Red row tint across hover / pressed / focus (replaces the blue primary-50). */
.checkbox--error:hover:not(.checkbox--disabled),
.radio--error:hover:not(.radio--disabled),
.checkbox--error[data-state="hover"]:not(.checkbox--disabled),
.radio--error[data-state="hover"]:not(.radio--disabled),
.checkbox--error:active:not(.checkbox--disabled),
.radio--error:active:not(.radio--disabled),
.checkbox--error[data-state="pressed"]:not(.checkbox--disabled),
.radio--error[data-state="pressed"]:not(.radio--disabled),
.checkbox--error:has(input:focus-visible),
.radio--error:has(input:focus-visible),
.checkbox--error.is-focus,
.radio--error.is-focus { background: var(--gov-color-error-50); }
/* Red focus ring (instead of the blue --shadow-focus) — on the shell AND glyph. */
.checkbox--error:has(input:focus-visible),
.radio--error:has(input:focus-visible),
.checkbox--error.is-focus,
.radio--error.is-focus,
.checkbox--error:has(input:focus-visible) > input,
.radio--error:has(input:focus-visible) > input,
.checkbox--error.is-focus > input,
.radio--error.is-focus > input { box-shadow: var(--shadow-focus-error); }
/* Red glyph border across hover / pressed while unchecked (overrides the blue
   primary border the base interaction rules apply; focus keeps the resting red). */
.checkbox--error > input:hover:not(:disabled):not(:checked),
.radio--error > input:hover:not(:disabled):not(:checked),
.checkbox--error[data-state="hover"]:not(.checkbox--disabled) > input:not(:checked),
.radio--error[data-state="hover"]:not(.radio--disabled) > input:not(:checked),
.checkbox--error:active:not(.checkbox--disabled) > input:not(:checked),
.radio--error:active:not(.radio--disabled) > input:not(:checked),
.checkbox--error[data-state="pressed"]:not(.checkbox--disabled) > input:not(:checked),
.radio--error[data-state="pressed"]:not(.radio--disabled) > input:not(:checked) { border-color: var(--gov-color-error-500); }

/* ── Custom glyphs (appearance: none) ───────────────────────────────── */
.checkbox > input,
.radio > input {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px;
  /* Align glyph optical center with the first text line's x-height
     center. For 14px text @ line-height 1.4 in Czechia Sans the
     x-center lands ~9 px from the line box top, matching the 18 px
     glyph's vertical center when margin-top is 0. */
  margin: 0;
  flex: none;
  background: transparent;
  border: var(--bw-control, 1.5px) solid var(--color-border-strong);
  border-radius: max(0px, var(--radius-control, 4px) - 1px);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color 100ms linear, border-color 100ms linear, box-shadow 140ms ease-out;
  position: relative;
}
.radio > input { border-radius: 50%; }

.checkbox > input:hover:not(:disabled),
.radio > input:hover:not(:disabled),
.checkbox[data-state="hover"]:not(.checkbox--disabled) > input,
.radio[data-state="hover"]:not(.radio--disabled) > input { border-color: var(--gov-color-primary-500); }
.checkbox:active:not(.checkbox--disabled) > input,
.radio:active:not(.radio--disabled) > input,
.checkbox[data-state="pressed"]:not(.checkbox--disabled) > input,
.radio[data-state="pressed"]:not(.radio--disabled) > input { border-color: var(--gov-color-primary-600); }

/* Checked: filled-square checkbox with white check, filled-dot radio.
   --chk-tick / --rd-dot / --rd-ink parameterize the glyph geometry/ink for
   the W3 tick-animation variants below — defaults resolve byte-identical. */
.checkbox > input:checked {
  --chk-tick: 14px;
  background-color: var(--gov-color-primary-500);
  border-color: var(--gov-color-primary-500);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.5 8l3 3 6-6' stroke='white' stroke-width='2.4' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: var(--chk-tick) var(--chk-tick);
}
.radio > input:checked {
  --rd-ink: var(--gov-color-primary-500);
  border-color: var(--gov-color-primary-500);
  background: radial-gradient(circle, var(--rd-ink) 0 var(--rd-dot, 4px), transparent calc(var(--rd-dot, 4px) + 1px));
  background-repeat: no-repeat;
}

/* Disabled — soft fill, no white well in dark mode. */
.checkbox > input:disabled,
.radio > input:disabled {
  background-color: var(--gov-color-neutral-100);
  border-color: var(--color-border-default);
  cursor: not-allowed;
}
.checkbox > input:checked:disabled {
  background-color: var(--gov-color-neutral-400);
  border-color: var(--gov-color-neutral-400);
}
.radio > input:checked:disabled {
  background: radial-gradient(circle, var(--gov-color-neutral-400) 0 4px, transparent 5px);
  border-color: var(--gov-color-neutral-400);
}

.checkbox > span,
.radio > span { display: block; min-width: 0; }
.checkbox .help, .radio .help {
  display: block;
  font-size: 11.5px;
  color: var(--color-fg-secondary);
  margin-top: 2px;
  font-weight: 400;
}

/* ── W3 opt-in variants: tick / dot entrance animations ───────────────────
   `.checkbox--anim-<v>` / `.radio--anim-<v>` per instance, or
   `body[data-v-check="fade|pop|wipe"]` for every selection control INCLUDING
   sidebar .filter-item checkboxes (theme hook — Theme Lab stamps the attr).
   All pure CSS keyframes on `:checked` — no DOM change, no controller — so
   the global reduced-motion policy collapses them automatically. Registered
   properties make the radio dot's radius/ink interpolable.
   · fade: fill + border fade in; the white tick emerges over the rising fill.
   · pop:  tick / dot scales in from the glyph centre with a small overshoot.
   · wipe: tick uncovered left→right by a shrinking fill-coloured cover layer;
           the radio dot slides in from the left.
   Note: the animation also runs once for already-checked controls when the
   body hook is stamped at load — accepted (it previews the choice). */
@property --rd-dot { syntax: "<length>"; inherits: false; initial-value: 4px; }
@property --rd-ink { syntax: "<color>"; inherits: false; initial-value: transparent; }
/* draw sweep position — rest = 115% so the soft 14%-wide gradient edge sits
   fully past the box (a rest value of 100% would leave a visible fade band). */
@property --chk-draw { syntax: "<percentage>"; inherits: false; initial-value: 115%; }
@keyframes chk-pop {
  0%   { background-size: 0px 0px; }
  62%  { background-size: calc(var(--chk-tick, 14px) * 1.2) calc(var(--chk-tick, 14px) * 1.2); }
  100% { background-size: var(--chk-tick, 14px) var(--chk-tick, 14px); }
}
@keyframes chk-wipe {
  from { background-size: 100% 100%, var(--chk-tick, 14px) var(--chk-tick, 14px); }
  to   { background-size: 0% 100%,   var(--chk-tick, 14px) var(--chk-tick, 14px); }
}
@keyframes chk-fade {
  from { background-color: transparent; border-color: var(--color-border-strong); }
}
@keyframes rd-pop {
  0%   { --rd-dot: 0px; }
  65%  { --rd-dot: 5px; }
  100% { --rd-dot: 4px; }
}
@keyframes rd-slide {
  from { background-position: -12px 0; }
  to   { background-position: 0 0; }
}
@keyframes rd-fade {
  from { --rd-ink: transparent; border-color: var(--color-border-strong); }
}
@keyframes chk-draw {
  from { --chk-draw: 0%; }
  to   { --chk-draw: 115%; }
}
@keyframes rd-draw {
  from { --rd-dot: 0px; }
  to   { --rd-dot: 4px; }
}
:is(body[data-v-check="fade"] .checkbox, .checkbox--anim-fade) > input:checked:not(:disabled),
body[data-v-check="fade"] .filter-item > input:checked:not(:disabled) {
  animation: chk-fade 200ms ease;
}
:is(body[data-v-check="fade"] .radio, .radio--anim-fade) > input:checked:not(:disabled) {
  animation: rd-fade 200ms ease;
}
:is(body[data-v-check="pop"] .checkbox, .checkbox--anim-pop) > input:checked:not(:disabled),
body[data-v-check="pop"] .filter-item > input:checked:not(:disabled) {
  animation: chk-pop 240ms cubic-bezier(0.4, 0, 0.2, 1);
}
:is(body[data-v-check="pop"] .radio, .radio--anim-pop) > input:checked:not(:disabled) {
  animation: rd-pop 260ms cubic-bezier(0.4, 0, 0.2, 1);
}
:is(body[data-v-check="wipe"] .checkbox, .checkbox--anim-wipe) > input:checked:not(:disabled),
body[data-v-check="wipe"] .filter-item > input:checked:not(:disabled) {
  /* two layers: a fill-coloured cover (anchored right, width animated 100%→0)
     over the tick — at rest the cover is 0 wide, so the visual is identical
     to the base checked state. */
  background-image: linear-gradient(var(--gov-color-primary-500), var(--gov-color-primary-500)), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.5 8l3 3 6-6' stroke='white' stroke-width='2.4' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size: 0% 100%, var(--chk-tick, 14px) var(--chk-tick, 14px);
  background-position: right center, center;
  animation: chk-wipe 240ms cubic-bezier(0.4, 0, 0.2, 1);
}
:is(body[data-v-check="wipe"] .radio, .radio--anim-wipe) > input:checked:not(:disabled) {
  animation: rd-slide 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* draw (W4): the tick "inks in" along its stroke direction — a fill-coloured
   cover with a soft diagonal edge sweeps left→right (registered --chk-draw
   drives the gradient stops smoothly). Radio: the dot inks in with a smooth
   grow (no overshoot — that's pop's signature). */
:is(body[data-v-check="draw"] .checkbox, .checkbox--anim-draw) > input:checked:not(:disabled),
body[data-v-check="draw"] .filter-item > input:checked:not(:disabled) {
  background-image: linear-gradient(105deg, transparent calc(var(--chk-draw, 115%) - 14%), var(--gov-color-primary-500) var(--chk-draw, 115%)), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.5 8l3 3 6-6' stroke='white' stroke-width='2.4' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size: 100% 100%, var(--chk-tick, 14px) var(--chk-tick, 14px);
  background-position: center, center;
  animation: chk-draw 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
:is(body[data-v-check="draw"] .radio, .radio--anim-draw) > input:checked:not(:disabled) {
  animation: rd-draw 260ms cubic-bezier(0.16, 1, 0.3, 1);
}
