/* ============================================================
   <app-radio> / <app-radio-group> — project-owned radio (ADR 0014)

   Native <input type="radio"> with appearance: none, paired with
   a sibling circle span that renders the visual control and the
   selected dot. The input stays the source of truth for focus,
   keyboard activation, selection, form serialization, and a11y;
   the circle span is purely decorative (aria-hidden in markup).

   Visual language matches <app-checkbox> (accent fill + light
   glyph); the shape is a circle with a centre dot. The group
   stacks its options vertically — callers never need layout
   utilities or a Bootstrap .row.

   Lives in @layer components so it sits below @layer brand and
   @layer utilities — host brand overrides and per-element utility
   classes both win cleanly.

   Tokens consumed (semantic only):
     --color-accent       — selected fill
     --color-accent-deep  — focus halo + hover border
     --color-line         — unselected border
     --color-ink          — label text
     --color-ink-mute     — disabled label text
     --color-on-dark      — dot on the accent fill
     --color-surface      — unselected fill
     --color-surface-alt  — disabled fill
     --color-error        — invalid-state border
     --space-2            — label gap
     --space-3            — gap between stacked options
   ============================================================ */
@layer components {

    /* Stacks options vertically with consistent spacing. */
    .app-radio-group {
        display: flex;
        flex-direction: column;
        gap: var(--space-3);
    }

    .app-radio {
        display: inline-flex;
        /* flex-start, not center: role labels are long and wrap, so the circle
           should align to the first line, not the vertical middle of a paragraph. */
        align-items: flex-start;
        gap: var(--space-2);
        cursor: pointer;
        font-size: 0.9375rem;
        line-height: 1.4;
        color: var(--color-ink);
        user-select: none;
    }

    /* Native input — visually hidden but kept focusable and in the tab order.
       Same recipe as .app-checkbox__input. */
    .app-radio__input {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        margin: -1px;
        padding: 0;
        border: 0;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        overflow: hidden;
        white-space: nowrap;
    }

    /* Visible circle. */
    .app-radio__circle {
        inline-size: 1.125rem;
        block-size: 1.125rem;
        flex: 0 0 auto;
        /* nudge down so the circle sits centred on the first line of text */
        margin-block-start: 0.0625rem;
        border: 1.5px solid var(--color-line);
        border-radius: 50%;
        background: var(--color-surface-field);
        display: inline-grid;
        place-items: center;
        transition:
            background-color 120ms ease,
            border-color 120ms ease,
            box-shadow 120ms ease;
    }

    /* Centre dot — hidden until selected. */
    .app-radio__circle::after {
        content: "";
        inline-size: 0.5rem;
        block-size: 0.5rem;
        border-radius: 50%;
        background: var(--color-on-dark);
        opacity: 0;
        transform: scale(0.5);
        transition: opacity 120ms ease, transform 120ms ease;
    }

    /* Selected state — accent fill, light dot. */
    .app-radio__input:checked + .app-radio__circle {
        background-color: var(--color-accent);
        border-color: var(--color-accent);
    }
    .app-radio__input:checked + .app-radio__circle::after {
        opacity: 1;
        transform: scale(1);
    }

    /* Hover (on the label) — only when not disabled. */
    .app-radio:hover .app-radio__input:not(:disabled) + .app-radio__circle {
        border-color: var(--color-accent-deep);
    }

    /* Focus ring — keyboard users only (:focus-visible), applied to the circle. */
    .app-radio__input:focus-visible + .app-radio__circle {
        outline: 2px solid var(--color-accent-deep);
        outline-offset: 2px;
    }

    /* Active (pressing) — slight inset feedback. */
    .app-radio__input:active:not(:disabled) + .app-radio__circle {
        transform: translateY(0.5px);
    }

    /* Disabled state. */
    .app-radio--disabled,
    .app-radio:has(.app-radio__input:disabled) {
        cursor: not-allowed;
        color: var(--color-ink-mute);
    }
    .app-radio__input:disabled + .app-radio__circle {
        background-color: var(--color-surface-alt);
        border-color: var(--color-line);
        opacity: 0.6;
    }

    /* Validation — tint the circle when the input carries the error class/flag
       the FormValidator + app-form pipeline apply. */
    .app-radio__input.input-validation-error + .app-radio__circle,
    .app-radio__input[aria-invalid="true"] + .app-radio__circle {
        border-color: var(--color-error);
    }

    .app-radio__label {
        /* Inherits colour from .app-radio; hook for per-surface spacing/typography. */
    }

    /* A choice with a title and a line of description, drawn as a card that takes the
       group's full width; the whole card is the label, so anywhere on it chooses it. */
    .app-radio--card {
        display: flex;
        gap: var(--space-3);
        padding: var(--space-4) var(--space-5);
        border: 1px solid var(--color-line);
        border-radius: var(--radius-md);
        /* The field fill, not the page surface: the cards sit inside a form section's
           panel, and the page surface is too close to it to stand out. */
        background: var(--color-surface-field);
        transition: border-color 120ms ease, box-shadow 120ms ease, background-color 120ms ease;
    }
    /* Inside a panel the hairline token is rebound pale, which leaves the circle barely
       visible against a white card. */
    .app-radio--card .app-radio__circle {
        border-color: var(--color-ink-mute);
    }
    .app-radio--card:hover {
        border-color: var(--color-accent);
    }
    /* Picked: a 2px edge and a tint, so the choice shows at a glance. The second pixel is
       an inset shadow rather than a thicker border, which would shift the content by 1px. */
    .app-radio--card:has(.app-radio__input:checked) {
        border-color: var(--color-accent);
        box-shadow: inset 0 0 0 1px var(--color-accent);
        background: var(--color-accent-wash);
    }
    /* Keyboard focus is shown on the card, so the circle's own focus ring is dropped
       here rather than drawing two outlines. */
    .app-radio--card:has(.app-radio__input:focus-visible) {
        outline: 2px solid var(--color-accent-deep);
        outline-offset: 2px;
    }
    .app-radio--card .app-radio__input:focus-visible + .app-radio__circle {
        outline: none;
    }
    .app-radio__title {
        display: block;
        font-weight: 600;
        color: var(--color-ink);
    }
    .app-radio__description {
        display: block;
        color: var(--color-ink-soft);
    }
}
