/*
 * GRO Form
 *
 * The markup every surface renders a GRO form with — the WordPress block and
 * shortcodes (FormRenderer.php), the HQ preview and the GRO landing page — so
 * a form looks the same everywhere. Keep them in step.
 *
 * .gl-form                  the wrapper, one per form, with modifiers:
 *   --signup | --save-to-email | --content-gate    the config's kind;
 *   --popup                                         a popup's form, in the
 *                                                   card of the popup
 *                                                   (assets/blocks/popup)
 *   --stacked | --inline | --split | --compact     design.layout
 *   --boxed | --plain                               design.appearance
 *   --icon                                          design.showIcon
 *   --banner    the form has a banner (design.bannerUrl), the creator's own
 *               image across its top
 *   --image-avatar | --image-logo
 *               the form's picture (design.image, at design.imageUrl): the
 *               creator's profile photo or their logo. None when the form
 *               has no picture or GRO has no http(s) URL for it.
 *               Neither --banner nor --image-* is ever on a popup's form,
 *               whose banner and picture are the popup's
 *               (assets/blocks/popup), on a content gate's own form, or on
 *               any form in a content gate, which shows neither
 *   --brand     brand colours are on (design.useBrandColors). The wrapper's
 *               style attribute then sets --gl-form-accent (the button and
 *               the icon; design.accentColor when set, else brand.accent),
 *               --gl-form-accent-text (the button's text),
 *               --gl-form-background and --gl-form-text (a boxed form's
 *               colours). --gl-form-accent-text is brand.buttonText on
 *               brand.accent, and otherwise (on design.accentColor, or
 *               when brand.buttonText is null or not hex) #fff when
 *               1.05 / (L + 0.05) >= (L + 0.05) / 0.05, else #000, L being
 *               the accent's WCAG 2 relative luminance: #fff up to about
 *               L = 0.1791 (docs/FORMS.md has the whole formula). Without
 *               --brand the theme styles the button.
 * .gl-form__header          the banner and the picture, before the <form>
 *                           (the wrapper's first child) in every layout;
 *                           only on a form with either
 *   .gl-form__header--banner  it holds a banner
 * .gl-form__banner          the banner, an <img> across the form, cropped
 *                           to a 3:1 strip from its centre (a browser
 *                           without aspect-ratio gets the strip from the
 *                           header's padding). On a boxed form it runs to
 *                           the box's edges and takes its top corners (the
 *                           box's padding moves onto the <form>)
 * .gl-form__picture         the picture, an <img> after the banner. With a
 *                           banner, a 72px circle over the banner's bottom
 *                           left corner, half on it, ringed in the box's
 *                           colour, or the page's on a plain form (a logo
 *                           contained in it, on that colour); without one,
 *                           centred above the copy: the photo in a 72px
 *                           circle, the logo at its own shape, at most 200
 *                           by 48px
 * .gl-form__form            the <form>. The view script sets aria-busy on
 *                           it while it submits and adds .gl-form--done once
 *                           it has.
 * .gl-form__copy            the title and the description
 * .gl-form__title           a <p>, so a form adds nothing to the page
 *                           outline; holds .gl-form__icon, an <svg> drawn
 *                           per kind (envelope, heart, lock), and
 *                           .gl-form__title-text
 * .gl-form__description     plain text, line breaks kept; left out of the
 *                           compact layout
 * .gl-form__fields          the row and the opt-in
 * .gl-form__row             the inputs and the button
 * .gl-form__field           a <label> round one input:
 *   .gl-form__field--name   the first name, when the form asks for one
 *   .gl-form__field--email  the email address
 * .gl-form__submit          the button; also .wp-block-button__link and
 *                           .wp-element-button, the theme's button classes
 * .gl-form__optin           the form's checkbox and its label
 *                           (design.optIn): the optional opt-in on Save to
 *                           Email, the required consent on signup and content
 *                           gate forms. At least 24px tall; with --brand the
 *                           box takes --gl-form-accent (accent-color)
 * .gl-form__status          the result line (role=status)
 * .gl-form__success         a <template> holding the success message
 * .gl-form__hp              the honeypot, clipped in place. The rendered
 *                           element repeats this rule inline, so an
 *                           optimizer that drops this stylesheet cannot show
 *                           a reader the field
 * .gl-form-notice           what editors see where a form cannot show
 *
 * Layouts:
 *   stacked  the copy, then each input and the button on a full-width line
 *   inline   the copy, then the inputs and the button in one row, which
 *            wraps only when it runs out of room
 *   split    the copy beside the inputs while both fit, one column after
 *   compact  one slim bar: the icon and title, then the input and button
 *
 * Type and colours otherwise come from the theme. The box, the inputs and
 * the spacing can be tuned through the --gl-form-* custom properties below.
 * Element rules carry the .gl-form prefix so they outrank theme and WP
 * Recipe Maker paragraph, label and input styles.
 */

.gl-form {
  box-sizing: border-box;
  max-width: 100%;
}

/* Zero specificity: a theme's block spacing wins. This only keeps the form
   off its neighbours in themes that space nothing, as many classic themes do. */
:where(.gl-form) {
  margin: 1.5em 0;
}

/* The padding shrinks with the space around it: recipe card templates can
   leave the box only a few hundred pixels on a phone. Brand colours set the
   background and text; without them the box tints whatever it sits on. */
.gl-form--boxed {
  background: var(--gl-form-background, rgba(127, 127, 127, 0.08));
  color: var(--gl-form-text, currentColor);
  border: var(--gl-form-border, 1px solid rgba(127, 127, 127, 0.25));
  border-radius: var(--gl-form-radius, 12px);
  padding: var(--gl-form-padding, clamp(0.75em, 5%, 1.25em));
}

.gl-form--boxed.gl-form--compact {
  padding: var(--gl-form-padding, 0.625em 0.75em);
}

/* A theme that colours paragraphs itself would otherwise put its text colour
   on the brand background. */
.gl-form--brand.gl-form--boxed .gl-form__title,
.gl-form--brand.gl-form--boxed .gl-form__description,
.gl-form--brand.gl-form--boxed .gl-form__optin,
.gl-form--brand.gl-form--boxed .gl-form__status {
  color: inherit;
}

.gl-form .gl-form__form {
  display: flex;
  flex-direction: column;
  gap: var(--gl-form-gap, 0.75em);
  margin: 0;
}

.gl-form__copy {
  display: flex;
  flex-direction: column;
  gap: 0.25em;
  min-width: 0;
}

.gl-form .gl-form__title,
.gl-form .gl-form__description,
.gl-form .gl-form__status {
  margin: 0;
  overflow-wrap: anywhere;
}

.gl-form .gl-form__title {
  display: flex;
  align-items: center;
  gap: 0.5em;
  font-size: var(--gl-form-title-size, 1.125em);
  font-weight: 700;
  line-height: 1.3;
}

.gl-form .gl-form__description {
  white-space: pre-line;
}

.gl-form__icon {
  flex: none;
  width: 1.25em;
  height: 1.25em;
  color: var(--gl-form-accent, currentColor);
}

/* The picture sits in the header, over the banner's edge when there is one. */
.gl-form .gl-form__header {
  position: relative;
  margin: 0 0 16px;
}

/* Whatever the theme puts round its images: a shadow too, which would spill
   past a banner's edges onto the box's. */
.gl-form .gl-form__banner,
.gl-form .gl-form__picture {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  box-shadow: none;
}

/* Across the form, cropped to a 3:1 strip from its centre. */
.gl-form .gl-form__banner {
  width: 100%;
  max-width: none;
  height: auto;
  aspect-ratio: 3 / 1;
  object-fit: cover;
}

/* The same strip in a browser without aspect-ratio (Safari before 15, on an
   iPad that stopped updating): the header is a third of its width tall, and
   the banner fills it. */
@supports not (aspect-ratio: 1 / 1) {
  .gl-form .gl-form__header--banner {
    padding-top: calc(100% / 3);
  }

  .gl-form .gl-form__banner {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
  }
}

/* Without a banner, the picture is centred above the copy. */
.gl-form--image-avatar .gl-form__picture {
  width: 72px;
  max-width: none;
  height: 72px;
  margin: 0 auto;
  border-radius: 50%;
  object-fit: cover;
}

.gl-form--image-logo .gl-form__picture {
  width: auto;
  max-width: min(200px, 100%);
  height: auto;
  max-height: 48px;
  margin: 0 auto;
}

/* With one, it is a 72px circle over the banner's bottom left corner, half
   on it, ringed in the box's colour (the page's on a plain form, below); a
   logo is contained in its circle, on that colour. The copy clears it by
   12px. */
.gl-form__header--banner .gl-form__picture {
  position: absolute;
  bottom: -36px;
  left: 16px;
  box-sizing: border-box;
  width: 72px;
  max-width: none;
  height: 72px;
  max-height: none;
  margin: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 4px
    var(--gl-form-background, var(--wp--preset--color--base, #fff));
  object-fit: cover;
}

.gl-form--image-logo .gl-form__header--banner .gl-form__picture {
  padding: 8px;
  background: var(--gl-form-background, var(--wp--preset--color--base, #fff));
  object-fit: contain;
}

/* A plain form paints no background, so its ring and a logo's circle are the
   page's colour: the brand's would be a disc of it on the page. Each rule is
   the one above with .gl-form--plain in front, so it outranks it. */
.gl-form--plain .gl-form__header--banner .gl-form__picture {
  box-shadow: 0 0 0 4px var(--wp--preset--color--base, #fff);
}

.gl-form--plain.gl-form--image-logo
  .gl-form__header--banner
  .gl-form__picture {
  background: var(--wp--preset--color--base, #fff);
}

.gl-form--image-avatar .gl-form__header--banner,
.gl-form--image-logo .gl-form__header--banner {
  margin-bottom: 48px;
}

/* A banner runs to the edges of a boxed form: the box's padding, the same
   as .gl-form--boxed's, moves onto the form under the header, and the banner
   takes the box's top corners. A negative margin could not undo the
   padding: its 5% would be of the box's width, not of what the box holds. */
.gl-form--boxed.gl-form--banner {
  padding: 0;
}

.gl-form--boxed.gl-form--banner .gl-form__form {
  padding: var(--gl-form-padding, clamp(0.75em, 5%, 1.25em));
  padding-top: 0;
}

.gl-form--boxed.gl-form--compact.gl-form--banner .gl-form__form {
  padding: var(--gl-form-padding, 0.625em 0.75em);
  padding-top: 0;
}

.gl-form--boxed.gl-form--banner .gl-form__banner {
  border-radius: var(--gl-form-radius, 12px) var(--gl-form-radius, 12px) 0 0;
}

.gl-form__fields {
  display: flex;
  flex-direction: column;
  gap: 0.5em;
  min-width: 0;
}

.gl-form__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
}

/* The inputs share the row and the button keeps its own width beside them,
   stretching only once it wraps onto a line of its own. A first name, an
   email and the button still fit one row in a ~640px column. */
.gl-form .gl-form__field {
  display: block;
  flex: 999 1 10em;
  min-width: 0;
  margin: 0;
}

.gl-form .gl-form__submit {
  flex: 1 0 auto;
  max-width: 100%;
  margin: 0;
}

.gl-form--stacked .gl-form__row {
  flex-direction: column;
}

/* A flex basis would be a height in a column. */
.gl-form--stacked .gl-form__field,
.gl-form--stacked .gl-form__submit {
  flex: none;
}

.gl-form .gl-form__field input[type='email'],
.gl-form .gl-form__field input[type='text'] {
  box-sizing: border-box;
  width: 100%;
  max-width: none;
  margin: 0;
  padding: var(--gl-form-input-padding, 0.6em 0.8em);
  font: inherit;
  /* 16px stops iOS Safari zooming the page when the field takes focus. */
  font-size: max(16px, 1em);
  line-height: 1.2;
  color: var(--gl-form-input-color, #1e1e1e);
  background: var(--gl-form-input-background, #fff);
  border: var(--gl-form-input-border, 1px solid rgba(127, 127, 127, 0.6));
  border-radius: var(--gl-form-input-radius, 6px);
  box-shadow: none;
}

.gl-form .gl-form__field input[type='email']:focus-visible,
.gl-form .gl-form__field input[type='text']:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 1px;
}

/* Zero specificity on purpose: whatever the theme does for .wp-element-button
   or button wins. This only keeps it a real-looking button where nothing
   styles it, such as a classic theme on a WordPress without global styles. */
:where(.gl-form__submit) {
  display: inline-block;
  box-sizing: border-box;
  padding: 0.6em 1.2em;
  border: 1px solid transparent;
  border-radius: 6px;
  background: #1e1e1e;
  color: #fff;
  font: inherit;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: normal;
  overflow-wrap: anywhere;
  cursor: pointer;
}

/* Brand colours beat the theme's button colours, hover and focus included. */
.gl-form--brand .gl-form__submit,
.gl-form--brand .gl-form__submit:hover,
.gl-form--brand .gl-form__submit:focus {
  background: var(--gl-form-accent, #1e1e1e);
  border-color: var(--gl-form-accent, #1e1e1e);
  color: var(--gl-form-accent-text, #fff);
}

.gl-form--brand .gl-form__submit:hover {
  filter: brightness(0.92);
}

.gl-form--brand .gl-form__submit:focus-visible {
  outline: 2px solid var(--gl-form-accent, currentColor);
  outline-offset: 2px;
}

.gl-form__form[aria-busy='true'] .gl-form__submit {
  opacity: 0.6;
  pointer-events: none;
}

/* At least 24px tall, a target size WCAG 2.2 counts (2.5.8, the box and its
   label being one target): a one-line label sits centred in it, and a longer
   one keeps the box beside its first line. */
.gl-form .gl-form__optin {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  align-content: center;
  gap: 0.5em;
  min-height: 24px;
  margin: 0;
  font-size: 0.875em;
  font-weight: inherit;
  line-height: 1.4;
  overflow-wrap: anywhere;
  cursor: pointer;
}

.gl-form .gl-form__optin input {
  margin: 0.2em 0 0;
}

/* The box wears the form's accent, as the button does; without brand
   colours it stays the theme's, or the browser's. */
.gl-form--brand .gl-form__optin input {
  accent-color: var(--gl-form-accent);
}

.gl-form__status:empty {
  display: none;
}

/* The view script focuses the status so screen readers read the result; it is
   not a control, so it gets no focus ring. */
.gl-form__status:focus {
  outline: none;
}

.gl-form--done .gl-form__status {
  font-weight: 600;
}

/* Clipped in place rather than moved off-screen: a left offset makes a
   right-to-left page scroll sideways. FormRenderer::HONEYPOT_STYLE repeats
   this declaration inline, for a page whose optimizer dequeued or deferred
   this stylesheet; keep the two the same. */
.gl-form__hp {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* For themes that ship no .screen-reader-text of their own. */
.gl-form .screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Split: the copy beside the inputs while both fit, one column once they do
   not. Flex-wrap alone, on purpose: an inline-size container query would make
   the same choice from the box's own width, but containment leaves the box no
   intrinsic width, and a shrink-to-fit parent (a core Row or Stack, a recipe
   card column, a table cell) then sizes it to its padding (GL-2508). The two
   flex bases and the gap add up to 24em, which a post's content column clears
   and a phone does not; min-width: 0 on the copy and the fields keeps that
   sum the breakpoint. The status line always takes a line of its own, and
   fields without copy fill theirs. Each input's label is centred on the line
   it shares with the button: stretched, it would leave its input at the top.
   The button still stretches to match a taller input. */
.gl-form--split .gl-form__form {
  flex-flow: row wrap;
  align-items: center;
  column-gap: 1.5em;
}

.gl-form--split .gl-form__copy {
  flex: 1 1 10.5em;
}

.gl-form--split .gl-form__fields {
  flex: 1 1 12em;
}

.gl-form--split .gl-form__status {
  flex: 1 1 100%;
}

.gl-form--split .gl-form__field {
  align-self: center;
}

/* Compact: one slim bar, the icon and title then the field and button,
   which wraps onto more lines only when it has to. */
.gl-form--compact .gl-form__form {
  flex-flow: row wrap;
  align-items: center;
  gap: 0.5em 0.75em;
}

.gl-form--compact .gl-form__copy {
  flex: 0 1 auto;
}

.gl-form--compact .gl-form__title {
  font-size: var(--gl-form-title-size, 1em);
}

.gl-form--compact .gl-form__fields {
  flex: 1 1 16em;
}

/* A shorter field keeps the button on the bar beside it. */
.gl-form--compact .gl-form__field {
  flex-basis: 8em;
}

.gl-form--compact .gl-form__status {
  flex: 1 1 100%;
}

@media (prefers-reduced-motion: no-preference) {
  .gl-form--done .gl-form__status {
    animation: gl-form-done 300ms ease-out;
  }

  @keyframes gl-form-done {
    from {
      opacity: 0;
      transform: translateY(0.25em);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }
}
