/* ==========================================================================
   FORMS
   ==========================================================================
   Two parts, kept separate on purpose:

     PART 1 — LAYOUT   how form fields sit in the column framework
     PART 2 — BRAND    how they look

   Change Part 2 per site. Part 1 should rarely need touching.

   SCOPE: `.formbody`, not `.ce_form .formbody`. Contao uses the same wrapper
   for the form CONTENT ELEMENT and for every member module — login, lost
   password, change password, personal data, registration. They render the
   same .widget markup, so scoping to .ce_form left every member form
   completely unstyled while the contact form looked finished.

   Two files would have been the wrong fix: they would race to style one
   .widget at equal specificity and drift apart, which is the same reasoning
   that keeps list typography in one place.
   ========================================================================== */


/* ==========================================================================
   PART 1 — LAYOUT
   ==========================================================================
   Contao renders form fields as .widget divs inside .formbody. This makes
   .formbody behave as a framework row, so a `col-*` class on a form field
   works exactly as it does on a content element inside an article — same
   widths, same gutter, same stacking.

   Editors set the width through the Theme Toolbox, which already offers the
   column options on every form field type. No template override is needed;
   this is done entirely in CSS.

   The column WIDTHS come from framework_v3 — they are plain flex-basis
   values and apply to any flex child. Only the row behaviour and the
   stacking are repeated here, because those are scoped to `.row` in the
   framework and .formbody is markup we do not control.
   ========================================================================== */

.formbody {
  display: flex;
  flex-wrap: wrap;

  /* Same tokens the framework's rows use, so form gutters match page
     gutters and respond to the same per-site dial. */
  --gap-x: var(--row-gap-x);
  --gap-y: var(--row-gap-y);
  gap: var(--gap-y) var(--gap-x);
}

/* Default every child to a full line, so a field with no col-* class takes
   its own row and Contao's own children (error messages) behave.

   :where() keeps this at ZERO specificity on purpose — the col-* classes
   must win, and this file loads after the framework, so a normal selector
   here would beat them on source order and flatten every column. */
:where(.formbody) > * {
  flex: 0 1 100%;
  min-width: 0;
}

/* Row gaps handle the spacing between fields, so widgets carry no margin
   of their own — otherwise the two would compound. */
.formbody > .widget {
  margin: 0;
}

/* Stacking, mirroring the framework's own breakpoints. Higher specificity
   than the col-* widths, so these win below the breakpoint.
   `.no-stack` on the form opts out, exactly as it does on a row. */
@media (max-width: 992px) {
  form:not(.no-stack) .formbody > .col-2-3,
  form:not(.no-stack) .formbody > .col-3-4,
  form:not(.no-stack) .formbody > .col-3-5,
  form:not(.no-stack) .formbody > .col-2-5 {
    flex-basis: 100%;
  }

  /* Quarters, thirds and 30% step down to a half before stacking, and fifths
     to a third — exactly the ramp framework_v3 gives a .row. Kept in step by
     hand because .formbody is markup we do not control, so it cannot simply
     carry .row. */
  form:not(.no-stack) .formbody > .col-1-4,
  form:not(.no-stack) .formbody > .col-1-3,
  form:not(.no-stack) .formbody > .col-30 {
    flex-basis: calc(50% - var(--gap-x, 0px) * 0.5);
  }
  form:not(.no-stack) .formbody > .col-20 {
    flex-basis: calc(100% / 3 - var(--gap-x, 0px) * 2 / 3);
  }
}

@media (max-width: 600px) {
  form:not(.no-stack) .formbody > .col-1-2,
  form:not(.no-stack) .formbody > .col-1-4,
  form:not(.no-stack) .formbody > .col-1-3,
  form:not(.no-stack) .formbody > .col-30 {
    flex-basis: 100%;
  }
  form:not(.no-stack) .formbody > .col-20 {
    flex-basis: calc(50% - var(--gap-x, 0px) * 0.5);
  }
}

@media (max-width: 480px) {
  form:not(.no-stack) .formbody > .col-20 { flex-basis: 100%; }
}

/* The label sits above its control. */
.formbody {
    label { display: block; }

    /* Controls fill their column. Without this an input keeps its browser
       default size (roughly 20 characters) and ignores the column entirely. */
    input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]), select, textarea {
      width: 100%;
      max-width: 100%;
    }

    textarea {
      display: block;
      resize: vertical;      /* horizontal resizing would break the column */
    }

    /* Checkbox and radio groups: the control sits beside its label. */
    .checkbox_container label, .radio_container label { display: inline-block; }

    /* ==========================================================================
       PART 2 — BRAND
       ==========================================================================
       Colours come from the tokens in website.css. Adjust the values here per
       site; the layout above is unaffected by anything in this section.
       ========================================================================== */

    input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]), select, textarea {
      /* Cornerstone: a 2px navy hairline and a 6px radius, per the Contact design,
         on the design's 48px control height. Type is pinned to 1rem so the height
         doesn't drift with the surrounding band's font-size. */
      box-sizing: border-box;
      min-height: 48px;
      padding: 10px 16px;
      border: 2px solid var(--heading);
      border-radius: 6px;
      background-color: var(--white);
      color: var(--heading);
      font: inherit;         /* controls do not inherit type by default */
      /* AFTER the `font` shorthand — it resets font-size, so setting the size above
         it silently does nothing. Pinned so the control keeps the design's 48px
         height whatever the surrounding band's type size is. */
      font-size: 1rem;
      line-height: 1.5;
    }
    textarea { min-height: 130px; }
    /* the design's message box */

    /* FOCUS — deliberately explicit.
       website_standard.css sets `outline: none` on form fields and replaces it
       with nothing, which leaves keyboard users unable to see where they are
       (WCAG 2.4.7). This restores a visible focus ring. Do not remove it
       without providing another visible indicator. */
    input:focus-visible, select:focus-visible, textarea:focus-visible {
      outline: 2px solid var(--prime);
      outline-offset: 2px;
      border-color: var(--prime);
    }

    label {
      margin-bottom: var(--space-8);
      /* Cornerstone: the design labels fields in semibold body at full size, not
         the smaller default. #333B44 is the design's own label grey (no token). */
      font-family: var(--type-body);
      font-size: 1rem;
      font-weight: 600;
      color: #333B44;
    }

    /* The asterisk on a required field. */
    span.mandatory { color: var(--second); }

    /* Placeholder text is the designs' own muted grey, not body grey — at
       --grey-dark (#404040) a placeholder read as a filled-in answer. A select
       showing its prompt option is a placeholder too, so it gets the same colour
       while nothing real is chosen. */
    ::placeholder {
      color: var(--placeholder);
      opacity: 1;            /* Firefox dims placeholders by default */
    }
    select:has(option[value=""]:checked) { color: var(--text-muted); }   /* the prompt is read as text: WCAG AA (8 Oct) */
    select option { color: var(--heading); }
    /* the real options stay dark */

    /* Validation messages. */
    p.error, .widget .error {
      color: var(--second);
      font-size: 0.875em;
    }

    .widget.error input, .widget.error select, .widget.error textarea { border-color: var(--second); }

    /* Buttons use the site's .btn rules in website.css — only the
       form-specific spacing is set here. */
    .widget-submit button { margin-bottom: 0; }

    /* ==========================================================================
       ALTCHA ("I'm not a robot") — no control chrome
       ==========================================================================
       The spam-protection widget ships as a bordered, boxed control. It is not a
       field the visitor fills in and the designs don't draw it at all, so it
       reads as a quiet checkbox line rather than another input. The widget sets
       its own look through custom properties, and it renders in the normal DOM
       (no shadow root), so `.altcha` — the box that actually carries the border —
       can be reached directly.
       ========================================================================== */
    .widget-altcha {
      --altcha-border-width: 0;
      --altcha-border-radius: 0;
      --altcha-color-border: transparent;
      --altcha-max-width: none;
    }
    .widget-altcha .altcha {
      border: 0;
      border-radius: 0;
      background: none;
      padding-inline: 0;
      max-width: none;
    }
}
