/* styles/forms.css
 * Form controls from board A5L5JX. Boxed fields by default, underline only for .inline-form.
 * Light is the default; inverse applies inside .surface--inverse, .surface--inverse-textured
 * or .forms-inverse. Buttons are not styled here; use styles/actions.css classes.
 * The focus ring is the global :focus-visible rule in utilities.css (2px, --focus-ring,
 * which surfaces.css turns mist on inverse). The board draws field, check and segment rings
 * 4px out (--focus-offset: 4px); the inline email keeps 3px around its 44px target.
 *
 * Markup contract
 *   .field > label.field__label + .input|.textarea|.select-field > .select + .field__help | .field__error
 *   Control: aria-describedby -> help/error id; aria-invalid="true" when in error.
 *   .field__error is a role="alert" region that is always in the DOM and empty until an error
 *   exists (empty hides it). Fill it on error, clear it when fixed; to repeat the same message,
 *   clear then fill again. Errors and .form-message--error carry an icon and text, never color alone.
 *   .check > input[type=checkbox|radio] + span
 *   .segmented[role=radiogroup][aria-label] > label.segmented__item > input[type=radio] + span
 *   .search > input.input (label is .sr-only)
 *   .input-group > .input + button        .inline-form > label + input.inline-form__input + button
 *   .form-message[role=alert|status]  (the live region must exist in the DOM before it is filled)
 */
@layer forms {
  :root {
    --field-h: 44px;
    --field-bg: var(--white);
    --field-fg: var(--ink);
    --field-border: var(--field-edge);
    --field-border-hover: var(--ink);
    --field-border-focus: var(--fern);
    --field-placeholder: var(--ink-55);
    --field-help: var(--ink-55);
    --field-icon: var(--ink-muted);
    --field-error: var(--error);
    --field-success: var(--success);
    --field-disabled-bg: var(--paper);
    --field-disabled-border: var(--line-2);
    --field-disabled-fg: var(--ink-55);
    --field-autofill-bg: var(--mist);
    --field-hover-lift: var(--elevation-low);
    --field-check-bg: var(--fern);
    --field-check-fg: var(--white);
    --field-check-disabled-bg: var(--line-2);
    --field-radio: var(--fern);
    --field-radio-disabled-bg: var(--white);
    --field-seg-border: var(--rule-edge);
    --field-seg-label: var(--ink-2);
    --field-seg-bg: var(--ink);
    --field-seg-edge: var(--fern);
    --field-seg-fg: var(--white);
    --field-seg-hover: var(--mist);
    --field-seg-hover-fg: var(--ink);
    --field-seg-note: var(--fern);
    --field-inline-border: var(--ink);
    --field-inline-placeholder: var(--ink-2);
    --field-inline-submit: var(--fern);
    --field-group-gap: var(--space-12);
    --icon-chevron: url("/assets/figures/ds/chevron-down.svg");
    --icon-check: url("/assets/figures/ds/check.svg");
    --icon-alert: url("/assets/figures/ds/circle-alert.svg");
    --icon-success: url("/assets/figures/ds/circle-check.svg");
    --icon-search: url("/assets/figures/ds/search.svg");
    --icon-arrow: url("/assets/figures/ds/arrow-right.svg");
  }

  .forms-inverse {
    --focus-ring: var(--mist);
  }

  .surface--inverse,
  .surface--inverse-textured,
  .forms-inverse {
    --field-bg: transparent;
    --field-fg: var(--white);
    --field-border: var(--white-55);
    --field-border-hover: var(--white-90);
    --field-border-focus: var(--white);
    --field-placeholder: var(--white-70);
    --field-help: var(--white-70);
    --field-icon: var(--white-70);
    --field-error: var(--error-on-inverse);
    --field-success: var(--success-on-inverse);
    --field-disabled-bg: var(--white-5);
    --field-disabled-border: var(--white-15);
    --field-disabled-fg: var(--white-40);
    --field-autofill-bg: var(--fern-app);
    --field-hover-lift: 0 0 transparent;
    --field-check-bg: var(--white);
    --field-check-fg: var(--fern);
    --field-check-disabled-bg: var(--white-15);
    --field-radio: var(--white);
    --field-radio-disabled-bg: transparent;
    --field-seg-border: var(--white-55);
    --field-seg-label: var(--white);
    --field-seg-bg: var(--white);
    --field-seg-edge: var(--white);
    --field-seg-fg: var(--fern);
    --field-seg-hover: var(--white-15);
    --field-seg-hover-fg: var(--white);
    --field-seg-note: currentcolor;
    --field-inline-border: var(--white-55);
    --field-inline-placeholder: var(--white-70);
    --field-inline-submit: var(--white);
    --field-group-gap: var(--space-20);
  }

  /* Field wrapper: label, control, help or error */
  .field {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    min-width: 0;
    color: var(--field-fg);
  }

  .field__label {
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
  }

  .field__help,
  .field__error {
    font-size: 13px;
    line-height: 1.4;
  }

  .field__help {
    color: var(--field-help);
  }

  .field__error {
    display: flex;
    align-items: flex-start;
    gap: var(--space-6);
    color: var(--field-error);
  }

  .field__error::before {
    content: "";
    flex: none;
    width: 16px;
    height: 16px;
    margin-top: 1px;
    background-color: currentcolor;
    mask: var(--icon-alert) center / contain no-repeat;
  }

  .field__error:empty {
    display: none;
  }

  /* Text input, textarea, select. Hover and focus edges are 2px drawn inside (a 1px border
     plus a 1px inset ring), so the box never changes size and the text never moves. */
  .input,
  .textarea,
  .select {
    --focus-offset: 4px;
    --field-ring: transparent;
    --field-lift: 0 0 transparent;

    display: block;
    width: 100%;
    min-height: var(--field-h);
    padding: 0 var(--space-14);
    border: 1px solid var(--field-border);
    border-radius: var(--radius-sm);
    background-color: var(--field-bg);
    color: var(--field-fg);
    font-family: var(--font-body);
    font-size: 16px; /* 16px stops iOS zoom on focus */
    line-height: 1.4;
    box-shadow: var(--field-lift), inset 0 0 0 1px var(--field-ring);
    transition: box-shadow var(--dur-fast), border-color var(--dur-fast);
  }

  .textarea {
    min-height: 120px;
    padding: var(--space-12) var(--space-14);
    line-height: 1.45;
    resize: vertical;
  }

  .select {
    padding-right: var(--space-40);
    appearance: none;
    cursor: pointer;
  }

  /* No choice yet: the empty first option reads as a placeholder */
  .select:not(:disabled):has(option[value=""]:checked) {
    color: var(--field-placeholder);
  }

  /* Chevron is a mask on the wrapper so it follows the surface */
  .select-field {
    position: relative;
    display: block;
    min-width: 0;
    color: var(--field-fg);
  }

  .select-field::after {
    content: "";
    position: absolute;
    top: 50%;
    right: var(--space-14);
    width: 18px;
    height: 18px;
    background-color: var(--field-icon);
    mask: var(--icon-chevron) center / contain no-repeat;
    transform: translateY(-50%);
    pointer-events: none;
  }

  .select-field:has(.select:disabled)::after {
    background-color: var(--field-disabled-fg);
  }

  .select option {
    color: var(--ink);
    background: var(--white);
  }

  .input::placeholder,
  .textarea::placeholder {
    color: var(--field-placeholder);
    opacity: 1;
  }

  /* State precedence: disabled, focus-visible, invalid, hover, default */
  .input:hover:not(:disabled, [aria-invalid="true"]),
  .textarea:hover:not(:disabled, [aria-invalid="true"]),
  .select:hover:not(:disabled, [aria-invalid="true"]) {
    --field-ring: var(--field-border-hover);
    --field-lift: var(--field-hover-lift);

    border-color: var(--field-border-hover);
  }

  .input[aria-invalid="true"],
  .textarea[aria-invalid="true"],
  .select[aria-invalid="true"] {
    border-color: var(--field-error);
  }

  .input:focus-visible,
  .textarea:focus-visible,
  .select:focus-visible {
    --field-ring: var(--field-border-focus);
    --field-lift: 0 0 transparent;

    border-color: var(--field-border-focus);
  }

  .input:disabled,
  .textarea:disabled,
  .select:disabled {
    --field-ring: transparent;
    --field-lift: 0 0 transparent;

    border-color: var(--field-disabled-border);
    background-color: var(--field-disabled-bg);
    color: var(--field-disabled-fg);
    opacity: 1; /* the board draws disabled colors; reset.css would fade them again */
    cursor: not-allowed;
  }

  .input:disabled::placeholder,
  .textarea:disabled::placeholder {
    color: var(--field-disabled-fg);
  }

  /* Autofill paints the fill as the last shadow layer so hover and focus edges stay on top.
     The two selectors stay separate: one unknown pseudo would drop a combined list. */
  .input:autofill,
  .textarea:autofill,
  .select:autofill {
    box-shadow: var(--field-lift), inset 0 0 0 1px var(--field-ring), inset 0 0 0 100px var(--field-autofill-bg);
    -webkit-text-fill-color: var(--field-fg);
    caret-color: var(--field-fg);
  }

  .input:-webkit-autofill,
  .textarea:-webkit-autofill,
  .select:-webkit-autofill {
    box-shadow: var(--field-lift), inset 0 0 0 1px var(--field-ring), inset 0 0 0 100px var(--field-autofill-bg);
    -webkit-text-fill-color: var(--field-fg);
    caret-color: var(--field-fg);
  }

  .inline-form__input:autofill {
    box-shadow: inset 0 0 0 100px var(--field-autofill-bg);
    -webkit-text-fill-color: var(--field-fg);
  }

  .inline-form__input:-webkit-autofill {
    box-shadow: inset 0 0 0 100px var(--field-autofill-bg);
    -webkit-text-fill-color: var(--field-fg);
  }

  /* Static autofill look for demos and server-filled values */
  .is-autofilled {
    background-color: var(--field-autofill-bg);
  }

  /* Checkbox and radio: the whole label row is the hit target (44px tall for one line).
     The 20px control sits on the first line of a 24px label line. Its 1.5px edge (2px on
     hover) is a 1px border plus an inset ring, because Chrome floors fractional borders. */
  .check {
    display: inline-flex;
    align-items: flex-start;
    gap: var(--space-12);
    min-height: var(--field-h);
    padding-block: 10px;
    color: var(--field-fg);
    font-size: 16px;
    line-height: 1.5;
    cursor: pointer;
  }

  .check:has(input:disabled) {
    color: var(--field-disabled-fg);
    cursor: not-allowed;
  }

  /* The board centres a 1.5px edge on a 20px box: outer 21.5, inner 18.5. The box is 21.5px
     with the edge inside (a 1px border plus a 0.5px inset ring, since Chrome paints a 1.5px
     border as 1px), and -0.75px margins keep the 20px footprint. The ring sits 4px off the
     drawn 20px box, so 3.25px off this one. */
  .check input {
    --focus-offset: 3.25px;
    --check-edge: var(--field-border);
    --check-ring: 0.5px;

    display: grid;
    flex: none;
    place-content: center;
    width: 21.5px;
    height: 21.5px;
    margin: 1.25px -0.75px -0.75px;
    border: 1px solid var(--check-edge);
    border-radius: calc(var(--radius-sm) + 0.75px);
    background-color: var(--field-bg);
    box-shadow: var(--field-lift, 0 0 transparent), inset 0 0 0 var(--check-ring) var(--check-edge);
    appearance: none;
    cursor: inherit;
    transition: box-shadow var(--dur-fast), border-color var(--dur-fast);
  }

  .check input[type="radio"] {
    border-radius: var(--radius-pill);
  }

  .check input[type="checkbox"]::before {
    content: "";
    width: 14px;
    height: 14px;
    background-color: var(--field-check-fg);
    mask: var(--icon-check) center / contain no-repeat;
    transform: scale(0);
  }

  .check input:hover:not(:disabled, :checked, [aria-invalid="true"]) {
    --check-edge: var(--field-border-hover);
    --check-ring: 1px;
    --field-lift: var(--field-hover-lift);
  }

  .check input[type="checkbox"]:checked {
    --check-edge: var(--field-check-bg);

    background-color: var(--field-check-bg);
  }

  .check input[type="checkbox"]:checked::before {
    transform: scale(1);
  }

  .check input[type="radio"]:checked {
    --check-edge: var(--field-radio);

    background-image: radial-gradient(circle, var(--field-radio) 0 4.75px, transparent 5.25px);
  }

  .check input[aria-invalid="true"] {
    --check-edge: var(--field-error);
  }

  .check input:disabled {
    --check-edge: var(--field-disabled-border);

    opacity: 1;
    background-color: var(--field-disabled-bg);
  }

  .check input[type="checkbox"]:checked:disabled {
    --check-edge: var(--field-disabled-border);

    background-color: var(--field-check-disabled-bg);
  }

  .check input[type="checkbox"]:checked:disabled::before {
    background-color: var(--field-disabled-fg);
  }

  .check input[type="radio"]:checked:disabled {
    --check-edge: var(--field-disabled-border);

    background-color: var(--field-radio-disabled-bg);
    background-image: radial-gradient(circle, var(--field-disabled-fg) 0 4.75px, transparent 5.25px);
  }

  fieldset.field {
    margin: 0;
    padding: 0;
    border: 0;
  }

  legend.field__label {
    padding: 0;
    margin-bottom: var(--space-4);
  }

  /* Segmented toggle: real radios in a radiogroup. Segments are 34px visuals; ::after
     extends each one to a 44px target. */
  .segmented {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 3px;
    border: 1px solid var(--field-seg-border);
    border-radius: var(--radius-sm);
    color: var(--field-seg-label);
  }

  .segmented__item {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--space-8);
    min-height: 34px;
    padding: 0 var(--space-16);
    border-radius: 2px;
    font-size: 15px;
    font-weight: 500;
    line-height: 1.2;
    cursor: pointer;
    transition: background-color var(--dur-fast), color var(--dur-fast);
  }

  .segmented__item::after {
    content: "";
    position: absolute;
    inset: -5px 0;
  }

  .segmented__item input {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    appearance: none;
    cursor: inherit;
  }

  .segmented__item:hover:not(:has(input:checked), :has(input:disabled)) {
    background: var(--field-seg-hover);
    color: var(--field-seg-hover-fg);
    font-weight: 600;
  }

  .segmented__item:has(input:checked) {
    background: var(--field-seg-bg);
    box-shadow: inset 0 0 0 1px var(--field-seg-edge);
    color: var(--field-seg-fg);
    font-weight: 600;
  }

  .segmented__item:has(input:focus-visible) {
    outline: 2px solid var(--focus-ring);
    outline-offset: 4px;
  }

  .segmented__item:has(input:disabled) {
    opacity: 0.42;
    cursor: not-allowed;
  }

  .segmented__note {
    color: var(--field-seg-note);
    font-size: 13px;
    font-weight: 600;
  }

  .segmented__item:has(input:checked) .segmented__note {
    color: inherit;
  }

  /* Search: leading icon, hidden label */
  .search {
    position: relative;
    display: block;
    min-width: 0;
  }

  .search::before {
    content: "";
    position: absolute;
    top: 50%;
    left: var(--space-14);
    z-index: 1;
    width: 18px;
    height: 18px;
    background-color: var(--field-icon);
    mask: var(--icon-search) center / contain no-repeat;
    transform: translateY(-50%);
    pointer-events: none;
  }

  .search .input {
    padding-left: 42px;
  }

  /* The board draws no clear button; Escape still clears a search field */
  .search .input::-webkit-search-cancel-button {
    appearance: none;
  }

  /* Button-attached input: boxed input and a button side by side; the button wraps below
     when the row is too narrow. On fern the action is an arrow link, 20px from the field. */
  .input-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-12) var(--field-group-gap);
  }

  .input-group > .input,
  .input-group > .field {
    flex: 1 1 12rem;
    min-width: 0;
  }

  .input-group > button {
    flex: none;
    min-height: var(--field-h);
  }

  /* Inline sentence form: "Get the next essay by email: ____ Subscribe ->". The field keeps
     a 44px target; its text and underline sit at the bottom, on the sentence's last line. */
  .inline-form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-8) var(--space-12);
    color: var(--field-fg);
  }

  .inline-form > label {
    font-family: var(--font-display);
    font-size: 20px;
    line-height: 1.5;
  }

  .inline-form__input {
    flex: 0 1 240px;
    min-width: 0;
    min-height: var(--field-h);
    padding: 20px 0 4px;
    border: 0;
    border-bottom: 1px solid var(--field-inline-border);
    border-radius: 0;
    background: transparent;
    color: var(--field-fg);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.2;
  }

  .inline-form__input::placeholder {
    color: var(--field-inline-placeholder);
    opacity: 1;
  }

  .inline-form__input:hover:not(:disabled, [aria-invalid="true"]) {
    border-bottom-color: var(--field-border-hover);
  }

  .inline-form__input[aria-invalid="true"] {
    padding-bottom: 3px;
    border-bottom: 2px solid var(--field-error);
  }

  .inline-form__input:focus-visible {
    --focus-offset: 3px;

    padding-bottom: 3px;
    border-bottom: 2px solid var(--field-border-focus);
    border-radius: var(--radius-sm);
  }

  .inline-form__input:disabled {
    opacity: 1;
    background: var(--field-disabled-bg);
    color: var(--field-disabled-fg);
    cursor: not-allowed;
  }

  /* A bare submit is the text submit: label plus arrow. Classed buttons keep their own look. */
  .inline-form > button:not([class]) {
    display: inline-flex;
    align-items: center;
    gap: var(--space-6);
    min-height: var(--field-h);
    padding: 20px 0 4px;
    border: 0;
    background: none;
    color: var(--field-inline-submit);
    font-family: var(--font-body);
    font-size: 16px;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
  }

  .inline-form > button:not([class])::after {
    content: "";
    flex: none;
    width: 16px;
    height: 16px;
    background-color: currentcolor;
    mask: var(--icon-arrow) center / contain no-repeat;
  }

  .inline-form .field__error {
    flex: 1 0 100%;
  }

  /* Form message: form-level status above the submit. Icon in the role color, text in the
     surface text color; tinted fill 8%, edge 25%. */
  .form-message {
    --message-role: var(--field-error);

    display: flex;
    align-items: flex-start;
    gap: var(--space-10);
    padding: calc(var(--space-14) - 1px) calc(var(--space-16) - 1px); /* the board edge is drawn inside its padding */
    border: 1px solid color-mix(in srgb, var(--message-role) 25%, transparent);
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--message-role) 8%, transparent);
    color: var(--field-fg);
    font-size: 15px;
    line-height: 1.45;
  }

  .form-message::before {
    content: "";
    flex: none;
    width: 18px;
    height: 18px;
    margin-top: 2px;
    background-color: var(--message-role);
    mask: var(--icon-alert) center / contain no-repeat;
  }

  .form-message--success {
    --message-role: var(--field-success);
  }

  .form-message--success::before {
    mask-image: var(--icon-success);
  }

  @media (forced-colors: active) {
    .input,
    .textarea,
    .select,
    .check input {
      border-color: FieldText;
    }

    .check input:checked {
      background-color: Highlight;
    }

    .check input::before {
      background-color: HighlightText;
    }

    .segmented__item:has(input:checked) {
      outline: 2px solid Highlight;
    }
  }
}
