/*
 * mud-radio — Pattern B (atom-interactive, form-associated).
 *
 * The native <input type="radio"> is rendered inside `.control` but visually
 * hidden (opacity 0, sized to the touch target). Its label-via-<label> click
 * forwarding gives us free pointer + keyboard semantics; the painted circle
 * in `.visual` and the centered `.dot` are pure CSS. Focus + checked + error
 * state remap a small set of local custom properties; the structure stays
 * the same.
 */

:host {
  --_size: var(--radio-container-size-md);
  --_dot-size: var(--radio-dot-size-md);
  --_touch-size: var(--radio-touch-target-size-md);
  --_border-width: var(--radio-container-border-width);
  --_radius: var(--radio-container-border-radius);

  --_border-color: var(--radio-border-default);
  --_border-color-hover: var(--radio-border-hover);
  --_bg: var(--radio-background-default);
  --_dot-color: var(--radio-dot-color-default);

  --_label-font-size: var(--radio-label-font-size-md);
  --_label-line-height: var(--radio-label-line-height-md);
  --_supporting-font-size: var(--radio-supporting-text-font-size-md);
  --_supporting-line-height: var(--radio-supporting-text-line-height-md);

  --_transition-duration: var(--radio-container-transition-duration);
  --_transition-easing: var(--radio-container-transition-timing-function);

  display: inline-block;
  font-family: var(--radio-label-font-family);
  color: var(--radio-label-color-default);
}

:host([size='sm']) {
  --_size: var(--radio-container-size-sm);
  --_dot-size: var(--radio-dot-size-sm);
  --_touch-size: var(--radio-touch-target-size-sm);
  --_label-font-size: var(--radio-label-font-size-sm);
  --_label-line-height: var(--radio-label-line-height-sm);
  --_supporting-font-size: var(--radio-supporting-text-font-size-sm);
  --_supporting-line-height: var(--radio-supporting-text-line-height-sm);
}

/* ---------- Layout ---------- */
/*
 * <label> acts as the click target for the entire radio+text composition,
 * so consumers get "click the label to select" for free.
 */
.layout {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--radio-gap-radio-label);
  /*
   * Keeps the layout aligned with the first line of the label rather than
   * the touch-padded radio center — important when supporting text is long.
   */
  min-block-size: var(--_label-line-height);
  cursor: pointer;
}

:host(.is-disabled) .layout,
:host(.is-readonly) .layout {
  cursor: default;
}

/* ---------- Control (visual circle + native input + touch target) ---------- */

.control {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: var(--_size);
  block-size: var(--_size);
  /* Pull the touch ring up so the visual circle aligns with first label line. */
  margin-block: calc((var(--_label-line-height) - var(--_size)) / 2);
}

/*
 * Touch target — a transparent overlay sized to the spec'd touch dimension
 * (40px md / 32px sm) so the hit area is generous on phones without changing
 * the visual footprint. Aligned to the visual circle's center.
 */
.touch-target {
  position: absolute;
  inset: 50% auto auto 50%;
  inline-size: var(--_touch-size);
  block-size: var(--_touch-size);
  transform: translate(-50%, -50%);
  border-radius: var(--_radius);
  pointer-events: none;
}

.visual {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--_size);
  block-size: var(--_size);
  background-color: var(--_bg);
  border: var(--_border-width) solid var(--_border-color);
  border-radius: var(--_radius);
  transition:
    border-color var(--_transition-duration) var(--_transition-easing),
    background-color var(--_transition-duration) var(--_transition-easing),
    box-shadow var(--_transition-duration) var(--_transition-easing);
}

/* The selected dot is painted on top of `.visual` and revealed via opacity. */
.dot {
  inline-size: var(--_dot-size);
  block-size: var(--_dot-size);
  border-radius: var(--_radius);
  background-color: var(--_dot-color);
  opacity: 0;
  transform: scale(0.6);
  transition:
    opacity var(--_transition-duration) var(--_transition-easing),
    transform var(--_transition-duration) var(--_transition-easing);
}

/*
 * Native input is sized to the touch target (not the visual) so pointer
 * activation works anywhere inside the touch zone, and the label still owns
 * the rest of the row. Hidden visually but kept in the a11y tree.
 */
.native {
  position: absolute;
  inset: 50% auto auto 50%;
  inline-size: var(--_touch-size);
  block-size: var(--_touch-size);
  transform: translate(-50%, -50%);
  margin: 0;
  padding: 0;
  opacity: 0;
  cursor: inherit;
  z-index: 1;
}

.native:disabled {
  cursor: not-allowed;
}

/* Suppress native focus ring — we paint our own on `.visual`. */
.native:focus,
.native:focus-visible {
  outline: none;
}

/* ---------- States — checked, hover, focus, invalid, disabled ---------- */

:host(.is-checked) {
  --_border-color: var(--radio-border-checked);
}

:host(.is-checked) .dot {
  opacity: 1;
  transform: scale(1);
}

:host(.is-invalid) {
  --_border-color: var(--radio-border-error);
  --_border-color-hover: var(--radio-border-error);
  --_dot-color: var(--radio-dot-color-error);
}

:host(:not(.is-disabled):not(.is-readonly):not(.is-checked):not(.is-invalid)) .layout:hover .visual {
  border-color: var(--_border-color-hover);
}

/*
 * Focus ring per Figma "Focus Ring/Small" (51:426): a 1px white halo with the
 * blue band ending 3px out. Figma stacks the two spreads, so the outer width
 * is the total — adding the inner one to it would draw the band out to 4px.
 * Two box-shadows, so the radio's own dimensions stay untouched.
 */
:host(.is-focused) .visual {
  box-shadow:
    0 0 0 var(--radio-focus-ring-inner-width) var(--radio-focus-ring-inner-color),
    0 0 0 var(--radio-focus-ring-outer-width) var(--radio-focus-ring-outer-color);
}

:host(.is-disabled) {
  --_border-color: var(--radio-border-disabled);
  --_bg: var(--radio-background-disabled);
  --_dot-color: var(--radio-dot-color-disabled);
  cursor: not-allowed;
}

:host(.is-disabled) .native {
  cursor: not-allowed;
}

/* Read-only stays full-contrast (per the input/checkbox convention) — only the
   cursor and toggle behaviour change. */

/* ---------- Content column (text block + error message) ---------- */

/*
 * Figma "Container" (585:35248): the text block and the error message stack
 * 6px apart. Hidden when it has nothing to show, so an unlabelled radio adds
 * no `.layout` gap after the circle.
 */
.content {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
  gap: var(--radio-error-message-margin-top);
}

:host(:not(.has-label):not(.has-supporting-text):not(.has-error-message)) .content {
  display: none;
}

/* ---------- Text column (label + supporting) ---------- */

.text {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
  gap: var(--radio-supporting-text-margin-top);
  /*
   * Aligns the first line of the label with the visual radio circle.
   * `min-block-size` on `.layout` gives us a hard floor when label is empty.
   */
}

/*
 * Slot-driven visibility: the `.text` block always renders so slot projection
 * happens on first paint, then host classes drive what's actually visible.
 * Mirrors mud-checkbox's `.label:empty` / class-driven pattern.
 */
:host(:not(.has-label):not(.has-supporting-text)) .text {
  display: none;
}

.label-text {
  font-size: var(--_label-font-size);
  line-height: var(--_label-line-height);
  font-weight: var(--radio-label-font-weight);
  color: var(--radio-label-color-default);
  overflow-wrap: anywhere;
}

:host(:not(.has-label)) .label-text {
  display: none;
}

.supporting-text {
  font-size: var(--_supporting-font-size);
  line-height: var(--_supporting-line-height);
  font-weight: var(--radio-supporting-text-font-weight);
  color: var(--radio-supporting-text-color-default);
  overflow-wrap: anywhere;
}

:host(:not(.has-supporting-text)) .supporting-text {
  display: none;
}

:host(.is-disabled) .label-text {
  color: var(--radio-label-color-disabled);
}

:host(.is-disabled) .supporting-text {
  color: var(--radio-supporting-text-color-disabled);
}

/* Pattern A (slotted) reuse: keep slotted typography color inheriting from
   the controlled label so rich content (icons, links) follows the same
   state-based contrast rules. */
::slotted([slot='label']) {
  color: inherit;
  font: inherit;
}

::slotted([slot='supporting-text']) {
  color: inherit;
  font: inherit;
}

/* ---------- prefers-reduced-motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .visual,
  .dot {
    transition: none;
  }
}
