@layer components {
  /* ---------------------------------------------------------------
   * Choice — a unified block for checkbox and radio.
   * The native input drives state via :checked / :indeterminate /
   * :disabled / :focus-visible. The visible indicator is a sibling
   * span; the input itself is visually hidden but remains in the
   * tab order, focusable, and labelled by the wrapping <label>.
   *
   * WCAG 2.2 AA:
   *   1.4.11 — indicator border ≥3:1 vs canvas (light + dark)
   *   1.4.3  — label text uses --color-ink-dark
   *   2.4.7  — focus-visible ring on indicator
   *   2.5.8  — minimum target 24×24 (full label is clickable;
   *            card variant raises this to 44×44)
   *   1.3.1  — semantics from native input, not ARIA replacement
   * --------------------------------------------------------------- */
  .choice {
    --choice-size: 1.125rem;
    --choice-radius-square: var(--radius-sm);
    --choice-bg: var(--color-canvas);
    /* Idle border meets ≥3:1 vs --color-canvas */
    --choice-border: var(--color-stone-400);
    --choice-border-hover: var(--color-stone-700);
    --choice-fill: var(--color-brand-700);
    --choice-fill-hover: var(--color-brand-800);
    --choice-mark: var(--color-ink-inverted);
    --choice-ring: oklch(0.64 0.16 55 / 0.22);
    --choice-label-fg: var(--color-ink-dark);
    --choice-hint-fg: var(--color-ink-medium);
    --choice-gap: 0.625rem;

    display: inline-flex;
    align-items: flex-start;
    gap: var(--choice-gap);
    font-family: var(--font-sans);
    cursor: pointer;
    /* Padding lifts the per-row hit target to 1.75rem; full row
     * inside a group easily clears WCAG 2.5.8 (24×24). */
    padding-block: 0.25rem;
    line-height: 1.4;

    :where(html[data-theme="dark"]) & {
      --choice-border: var(--color-stone-500);
      --choice-border-hover: var(--color-stone-400);
      --choice-fill: var(--color-brand-500);
      --choice-fill-hover: var(--color-brand-400);
      --choice-mark: var(--color-stone-950);
      --choice-ring: oklch(0.79 0.16 75 / 0.28);
    }

    @media (prefers-color-scheme: dark) {
      :where(html:not([data-theme])) & {
        --choice-border: var(--color-stone-500);
        --choice-border-hover: var(--color-stone-400);
        --choice-fill: var(--color-brand-500);
        --choice-fill-hover: var(--color-brand-400);
        --choice-mark: var(--color-stone-950);
        --choice-ring: oklch(0.79 0.16 75 / 0.28);
      }
    }
  }

  /* The native input — visually hidden, never display:none (would
   * break keyboard + assistive tech). Clicks work via the wrapping
   * <label>, not by position; the input stays in the tab order. */
  .choice__input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    margin: 0;
    padding: 0;
    border: 0;
  }

  /* The visible mark — square for checkbox, circle for radio. */
  .choice__indicator {
    flex: 0 0 auto;
    inline-size: var(--choice-size);
    block-size: var(--choice-size);
    border: 1.5px solid var(--choice-border);
    background: var(--choice-bg);
    color: var(--choice-mark);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Sit on the cap-height of the first label line. */
    margin-block-start: 0.1875rem;
    position: relative;
    transition: border-color 140ms ease,
                background-color 140ms ease,
                box-shadow 140ms ease;

    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }

  /* Shape: checkbox → rounded square, radio → circle. Selected on the
   * input itself so we don't need extra modifiers in markup. */
  .choice__input[type="checkbox"] + .choice__indicator {
    border-radius: var(--choice-radius-square);
  }

  .choice__input[type="radio"] + .choice__indicator {
    border-radius: var(--radius-full);
  }

  @media (any-hover: hover) {
    /* Hover — applies whether the user is over the indicator or the
     * label, because the entire .choice is the hover target. */
    .choice:hover .choice__indicator {
      border-color: var(--choice-border-hover);
    }

    .choice:hover .choice__input:checked + .choice__indicator,
    .choice:hover .choice__input[type="checkbox"]:indeterminate + .choice__indicator {
      background: var(--choice-fill-hover);
      border-color: var(--choice-fill-hover);
    }
  }

  /* Focus — driven by :focus-visible on the input, painted on the
   * indicator. Outline + offset keeps the ring outside the border. */
  .choice__input:focus-visible + .choice__indicator {
    outline: var(--focus-ring-size) solid var(--focus-ring-color);
    outline-offset: var(--focus-ring-offset);
  }

  /* Checked / indeterminate fill.
   * NOTE: unselected HTML5 radio inputs match :indeterminate by default,
   * so the indeterminate half MUST be scoped to type="checkbox" — otherwise
   * every unselected radio renders as a solid fill. */
  .choice__input:checked + .choice__indicator,
  .choice__input[type="checkbox"]:indeterminate + .choice__indicator {
    background: var(--choice-fill);
    border-color: var(--choice-fill);
  }

  /* Checkmark — drawn with two borders. Uses currentColor so it
   * inherits --choice-mark and reads correctly in dark mode. */
  .choice__input[type="checkbox"]:checked + .choice__indicator::after {
    content: "";
    position: absolute;
    inline-size: 0.5em;
    block-size: 0.28em;
    border-inline-start: 2px solid currentColor;
    border-block-end: 2px solid currentColor;
    transform: translate(0, -1px) rotate(-45deg);
  }

  /* Indeterminate bar — a single horizontal stroke. */
  .choice__input[type="checkbox"]:indeterminate + .choice__indicator::after {
    content: "";
    position: absolute;
    inline-size: 0.55em;
    block-size: 2px;
    background: currentColor;
    border-radius: 1px;
  }

  /* Radio dot */
  .choice__input[type="radio"]:checked + .choice__indicator::after {
    content: "";
    inline-size: 0.45em;
    block-size: 0.45em;
    border-radius: var(--radius-full);
    background: currentColor;
  }

  /* ---------------------------------------------------------------
   * Disabled — preserves shape, dims everything, keeps contrast
   * legible (text uses --color-ink-light at ≥3:1 vs canvas).
   * --------------------------------------------------------------- */
  .choice:has(.choice__input:disabled) {
    cursor: not-allowed;
    --choice-label-fg: var(--color-ink-light);
    --choice-hint-fg: var(--color-ink-light);
  }

  .choice__input:disabled + .choice__indicator {
    background: var(--color-ink-lightest);
    border-color: var(--color-ink-light);
    color: var(--color-ink-light);
  }

  .choice__input:disabled:checked + .choice__indicator,
  .choice__input[type="checkbox"]:disabled:indeterminate + .choice__indicator {
    background: var(--color-ink-light);
    border-color: var(--color-ink-light);
    color: var(--color-canvas);
  }

  /* ---------------------------------------------------------------
   * Body — label + optional secondary line (hint, price, etc.)
   * --------------------------------------------------------------- */
  .choice__body {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-inline-size: 0;
  }

  .choice__label {
    color: var(--choice-label-fg);
    font-size: var(--text-base);
    font-weight: 500;
  }

  .choice__hint {
    color: var(--choice-hint-fg);
    font-size: var(--text-x-small);
    line-height: 1.5;
    text-wrap: pretty;
  }

  .choice__badge {
    margin-inline-start: 0.5rem;
    font-family: var(--font-mono);
    font-size: var(--text-x-small);
    color: var(--color-ink-medium);
    background: var(--color-canvas-raised);
    border-radius: var(--radius-sm);
    padding: 0.05rem 0.4rem;
    vertical-align: 0.05em;
  }

  /* ---------------------------------------------------------------
   * Sizes
   * --------------------------------------------------------------- */
  .choice--sm {
    --choice-size: 1rem;
    --choice-gap: 0.5rem;

    & .choice__label {
      font-size: var(--text-small);
    }
  }

  .choice--lg {
    --choice-size: 1.375rem;
    --choice-gap: 0.75rem;

    & .choice__label {
      font-size: var(--text-medium);
    }

    & .choice__indicator {
      margin-block-start: 0.25rem;
    }
  }

  /* ---------------------------------------------------------------
   * Card variant — selectable option box. Used for radio/checkbox
   * choices that need extra context (price, term, description).
   * Whole card is a hit target and lights up when selected.
   * --------------------------------------------------------------- */
  .choice--card {
    align-items: flex-start;
    inline-size: 100%;
    padding: 0.875rem 1rem;
    border: 1px solid var(--color-ink-lightest);
    border-radius: var(--radius-md);
    background: var(--color-canvas);
    /* Card is its own ≥44px target. */
    min-block-size: 2.75rem;
    transition: border-color 140ms ease,
                background-color 140ms ease,
                box-shadow 140ms ease;

    @media (any-hover: hover) {
      &:hover {
        border-color: var(--color-ink-light);
        background: var(--color-canvas-hover);
      }
    }

    &:has(.choice__input:checked) {
      border-color: var(--choice-fill);
      background: var(--color-highlight);
    }

    &:has(.choice__input:focus-visible) {
      box-shadow: 0 0 0 var(--focus-ring-size) var(--choice-ring);
      border-color: var(--choice-fill);
    }

    /* The indicator already shows the focus ring at the per-input
     * level. Inside a card, the card itself is the focus surface,
     * so suppress the inner ring to avoid a doubled outline. */
    & .choice__input:focus-visible + .choice__indicator {
      outline: none;
    }

    &:has(.choice__input:disabled) {
      background: var(--color-canvas-sunken);
      border-color: var(--color-ink-lightest);
      cursor: not-allowed;
    }

    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }

  .choice--card .choice__body {
    flex: 1 1 auto;
  }

  .choice__meta {
    margin-inline-start: auto;
    padding-inline-start: var(--inline-space);
    font-family: var(--font-mono);
    font-size: var(--text-small);
    color: var(--color-ink-medium);
    font-variant-numeric: tabular-nums;
    align-self: center;
    flex: 0 0 auto;
  }

  /* ---------------------------------------------------------------
   * Choice group — fieldset wrapper. Replaces native border/margin
   * defaults; legend provides the accessible group name.
   * --------------------------------------------------------------- */
  .choice-group {
    border: 0;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    min-inline-size: 0;
  }

  .choice-group__legend {
    color: var(--color-ink-dark);
    font-size: var(--text-small);
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: 0.005em;
    padding: 0;
    /* Match .field__label-row baseline rhythm. */
    margin-block-end: 0.125rem;
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
  }

  .choice-group__optional {
    color: var(--color-ink-light);
    font-weight: 400;
    font-size: var(--text-x-small);
  }

  .choice-group__required {
    color: var(--color-negative);
    margin-inline-start: 0.125rem;
  }

  .choice-group__hint {
    font-size: var(--text-x-small);
    color: var(--color-ink-medium);
    margin-block-end: 0.25rem;
    text-wrap: pretty;
  }

  .choice-group__options {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
  }

  .choice-group--inline .choice-group__options {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
  }

  .choice-group--cards .choice-group__options {
    gap: 0.5rem;
  }

  .choice-group__message {
    display: inline-flex;
    align-items: flex-start;
    gap: 0.375rem;
    font-size: var(--text-x-small);
    color: var(--color-negative);
    line-height: 1.4;
    margin-block-start: 0.375rem;

    & svg {
      inline-size: 0.875rem;
      block-size: 0.875rem;
      flex: 0 0 auto;
      margin-block-start: 0.125rem;
      stroke: currentColor;
      fill: none;
      stroke-width: 1.75;
      stroke-linecap: round;
      stroke-linejoin: round;
    }
  }

  /* Error state — re-tints borders and fill of every contained .choice.
   * Fill is overridden so checked indicators and card borders stay danger-
   * colored; without this they revert to --choice-fill (brand). */
  .choice-group--error {
    & .choice {
      --choice-border: var(--color-danger-500);
      --choice-border-hover: var(--color-danger-600);
      --choice-fill: var(--color-danger-500);
      --choice-fill-hover: var(--color-danger-600);
    }

    & .choice--card {
      border-color: var(--color-danger-500);

      @media (any-hover: hover) {
        &:hover {
          border-color: var(--color-danger-600);
        }
      }
    }
  }
}
