/* ==========================================================================
   FLUENT FORMS -> BYS DESIGN TOKEN MAPPING LAYER
   --------------------------------------------------------------------------
   Technique: Global Form Styling From One Place (Fluent Forms-first)
   Studio rule 3: every production form is Fluent Forms, styled centrally from
   the BYS tokens. This file is the "one place".

   THIS IS A MAPPING LAYER, NOT A DESIGN LAYER.
   Every colour, type and spacing value must resolve to a var(--client-*)
   token. A literal value here is a defect, with exactly two allowed
   exceptions, each commented inline where it appears:
     1. Structural values with no token equivalent (e.g. border-width: 1px).
     2. Accessibility floors, where a hard minimum IS the requirement
        (44px touch target, 16px field font size).

   --------------------------------------------------------------------------
   WHY --client-* AND NOT --gcid-* / --gvid-*
   --------------------------------------------------------------------------
   Divi's Design Variables emit as --gcid-<slug> (colour) and --gvid-<slug>
   (number) into :root, BUT ONLY THE ONES A DIVI MODULE ON THAT PAGE ACTUALLY
   USES. Verified 2026-07-20 in this sandbox:
     /                            -> 0 BYS variables emitted
     /multi-level-preset-cascade/ -> 4 of 10 colours, 7 of 10 numbers
     /style-guide/                -> all 10 colours, all 10 numbers
   A form styled from var(--gcid-bys-muted) would therefore render correctly
   on one page and fall back to nothing on another. Page-dependent form
   styling is worse than no system at all.

   The child theme's :root tokens in style.css are unconditional - present on
   every page, no Divi module required. Fluent Forms is theme-level output,
   not a Divi module, so the theme-side tokens are the correct source for it.
   Studio rule 1 keeps the two systems value-identical from one scale, so
   this consumes the same scale by a reliable route.

   CONSEQUENCE: the two token systems MUST stay in sync (studio rule 1).
   If someone changes a Divi Design Variable without changing the matching
   :root token in style.css, forms will silently drift from the rest of the
   site. That is the maintenance cost of this approach and it is real.

   --------------------------------------------------------------------------
   SCOPING
   --------------------------------------------------------------------------
   Every selector is scoped to  .fluentform .frm-fluent-form  (both classes
   are Fluent-owned). This is deliberate:
     - It cannot leak to Divi's native Email Optin in the Theme Builder
       footer, or to the theme search form, both of which render on the same
       page as the reference form.
     - Specificity is 0,3,0, which beats Fluent's own base rules in
       fluent-forms-public.css (0,2,0, e.g. ".fluentform .ff-el-form-control")
       without needing !important and without depending on stylesheet order.

   Fluent's Pro styler is neutralised separately: form meta _ff_selected_style
   is set to 'ffs_inherit_theme', so no Fluent theme CSS is loaded and the
   submit button carries .ff_btn_no_style. See CLAUDE.md.

   Verified against Fluent Forms + Fluent Forms Pro 6.2.7, Divi 5.9.0.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. TEXT INPUTS, EMAIL, TEL, SELECT, TEXTAREA
   Fluent gives every one of these the same .ff-el-form-control class.
   -------------------------------------------------------------------------- */
.fluentform .frm-fluent-form .ff-el-form-control {
    color:            var(--client-text);
    background-color: var(--client-bg);

    /* border-width/style are structural: no token equivalent. Colour is tokenised. */
    border:        1px solid var(--client-muted);
    border-radius: var(--client-space-xs);

    font-family: var(--client-font-body);
    /* --client-text-base floors at 1rem/16px, which satisfies the iOS
       no-zoom-on-focus requirement at 390px. See §6.6 of the plan. */
    font-size:   var(--client-text-base);
    line-height: 1.5; /* structural ratio, unitless; no token equivalent. */

    padding: var(--client-space-xs) var(--client-space-sm);
    width:   100%;

    /* Accessibility floor: 44px minimum touch target. A hard minimum IS the
       requirement here, so the literal is intentional, not an untokenised value. */
    min-height: 44px;
}

.fluentform .frm-fluent-form textarea.ff-el-form-control {
    /* Textarea grows from the same floor; 44px would be too short to be usable. */
    min-height: calc(44px * 2);
    resize:     vertical;
}

/* Select keeps its native control affordance; only colour/type/space are mapped. */
.fluentform .frm-fluent-form select.ff-el-form-control {
    cursor: pointer;
}

/* Placeholder text. */
.fluentform .frm-fluent-form .ff-el-form-control::placeholder {
    color:   var(--client-muted);
    opacity: 1; /* structural: Firefox dims placeholders by default. */
}


/* --------------------------------------------------------------------------
   2. FOCUS
   CSS has no gap here, unlike Divi's native form modules, which cannot
   express a focus state at all (see plan Appendix A.3).
   :focus-visible keeps the ring off mouse clicks but on for keyboard users.
   -------------------------------------------------------------------------- */
.fluentform .frm-fluent-form .ff-el-form-control:focus,
.fluentform .frm-fluent-form .ff-el-form-control:focus-visible {
    border-color: var(--client-primary);
    /* 2px outline + 2px offset are structural ring geometry, not design values.
       The colour is tokenised, which is what carries the 3:1 contrast. */
    outline:        2px solid var(--client-primary);
    outline-offset: 2px;
}

.fluentform .frm-fluent-form .ff-el-form-check-input:focus-visible,
.fluentform .frm-fluent-form .ff-btn-submit:focus-visible {
    outline:        2px solid var(--client-primary);
    outline-offset: 2px;
}


/* --------------------------------------------------------------------------
   3. LABELS
   -------------------------------------------------------------------------- */
.fluentform .frm-fluent-form .ff-el-input--label label {
    color:        var(--client-text);
    font-family:  var(--client-font-heading);
    font-size:    var(--client-text-sm);
    font-weight:  600; /* structural weight; the type scale tokens carry size only. */
    margin-bottom: var(--client-space-xs);
    display:      inline-block;
}

/* Required marker. Fluent renders the asterisk as a ::before/::after on the
   label and colours it var(--fluentform-danger), i.e. Fluent's own red.
   Fluent's rule is
     .fluentform .ff-el-input--label.ff-el-is-required.asterisk-right label:after
   which is (0,4,2). This sheet is enqueued BEFORE fluent-forms-public.css, so
   an equal-specificity rule would lose. Matching the full class chain and
   adding .frm-fluent-form takes this to (0,5,2), which wins without
   !important. Both asterisk positions are covered so the mapping does not
   silently break if the global label layout setting is changed.

   NOTE: this is the REQUIRED marker, not a validation error state. It is
   mapped to --client-error as of 2026-07-20, now that the token exists.
   Rationale: the asterisk is the same "you must attend to this field" signal
   the inline error carries, so the two reading as one colour is correct.
   Fluent's own default already colours it var(--fluentform-danger), which now
   resolves to --client-error via §6, so this rule and Fluent's default agree
   rather than fight. It is kept explicit so the mapping does not depend on
   Fluent's variable coverage staying as it is. */
.fluentform .frm-fluent-form .ff-el-input--label.ff-el-is-required.asterisk-right label::after,
.fluentform .frm-fluent-form .ff-el-input--label.ff-el-is-required.asterisk-left label::before {
    color: var(--client-error);
}


/* --------------------------------------------------------------------------
   4. FIELD GROUP RHYTHM
   -------------------------------------------------------------------------- */
.fluentform .frm-fluent-form .ff-el-group {
    margin-bottom: var(--client-space-md);
}


/* --------------------------------------------------------------------------
   5. CHECKBOX AND RADIO
   Markup is:  .ff-el-form-check > label.ff-el-form-check-label
                                     > input.ff-el-form-check-input + span
   The whole label is the hit area, which is how the 44px target is reached -
   the native control itself is only ~13-16px and cannot be enlarged reliably.
   -------------------------------------------------------------------------- */
.fluentform .frm-fluent-form .ff-el-form-check {
    margin-bottom: var(--client-space-xs);
}

.fluentform .frm-fluent-form .ff-el-form-check-label {
    display:     flex;
    align-items: center;
    gap:         var(--client-space-xs);
    cursor:      pointer;

    color:       var(--client-text);
    font-family: var(--client-font-body);
    font-size:   var(--client-text-base);

    /* Accessibility floor: makes the full label a >=44px touch target. */
    min-height: 44px;
}

.fluentform .frm-fluent-form .ff-el-form-check-input {
    /* accent-color tints the native control from a token, so checked state
       resolves from Primary rather than Fluent's default blue. */
    accent-color: var(--client-primary);

    /* Accessibility floor: the control itself, inside the 44px label. */
    width:     24px;
    height:    24px;
    flex:      0 0 auto;
    margin:    0;
    cursor:    pointer;
}


/* --------------------------------------------------------------------------
   6. VALIDATION / ERROR STATES  --  ACTIVE as of 2026-07-20
   --------------------------------------------------------------------------
   Tony approved the semantic token --client-error (#b3261e) on 2026-07-20.
   It is defined in style.css :root, mirrored in theme.json, and mirrored as
   the Divi Design Variable "Error" (gcid-bys-error) per studio rule 1.
   #b3261e clears 4.5:1 against --client-bg (#ffffff) for error text and is far
   enough from --client-accent (#c8961e) not to be confused with it.

   THE CENTRAL ROUTE. Fluent funnels every one of its own error colours
   through a single CSS custom property, --fluentform-danger. Re-pointing that
   one variable at the token covers Fluent's whole error surface without
   chasing individual selectors.

   Measured 2026-07-20, because the two halves live in different files:
     - DECLARED in fluentform-public-default.css as
         :root { ... --fluentform-danger:#f56c6c ... }
       That file IS enqueued on this page. _ff_selected_style=ffs_inherit_theme
       suppresses Fluent's per-STYLE theme CSS, not this public default sheet -
       do not assume the setting removes the variable.
     - CONSUMED by 7 rules in fluent-forms-public.css, all scoped .fluentform
       (0,2,0 or less): required asterisk :before/:after, .ff-el-is-error
       .ff-el-form-control border-color, .ff-el-is-error check labels,
       .text-danger, and the file-upload remove control.
   Redeclaring the property here on .fluentform .frm-fluent-form (0,3,0) beats
   the :root declaration (0,1,0) and is also the nearer ancestor, so it wins on
   both counts, with no !important. All 7 consumers re-point in one line.

   Anything Fluent adds to that variable in a future version inherits this
   automatically. That is why this routes through the variable rather than
   enumerating selectors.

*/
.fluentform .frm-fluent-form {
    --fluentform-danger: var(--client-error);
}

/* Explicit belt-and-braces mapping. These are NOT redundant: they guarantee
   the two highest-traffic error surfaces resolve to the token even if a future
   Fluent version stops routing them through --fluentform-danger. Verified to
   agree with the variable route above rather than override a different value. */
.fluentform .frm-fluent-form .ff-el-is-error .ff-el-form-control {
    border-color: var(--client-error);
}

.fluentform .frm-fluent-form .error.text-danger {
    color:      var(--client-error);
    font-family: var(--client-font-body);
    font-size:  var(--client-text-sm);
    margin-top: var(--client-space-xs);
}

/* Error state must not be signalled by colour alone (WCAG 1.4.1). Fluent
   already pairs the colour with literal error text under the field, which
   satisfies this; the thicker border is reinforcement, not the sole signal. */
.fluentform .frm-fluent-form .ff-el-is-error .ff-el-form-control:focus,
.fluentform .frm-fluent-form .ff-el-is-error .ff-el-form-control:focus-visible {
    border-color: var(--client-error);
    outline:      2px solid var(--client-error);
}

/* NOTE: there is deliberately no --client-success token. Success reuses
   --client-primary (see §7). Reusing the brand green for success reads as
   correct; reusing it for error would not. Tony's call to revisit. */


/* --------------------------------------------------------------------------
   7. SUCCESS MESSAGE
   Reuses --client-primary. There is no dedicated success token; unlike the
   error case, reusing the brand green for success is defensible rather than
   misleading, so this is mapped now and flagged rather than blocked.
   Tony may still prefer a distinct --client-success token - see §6.
   -------------------------------------------------------------------------- */
.fluentform .ff-message-success {
    color:            var(--client-primary);
    background-color: var(--client-bg);
    border:           1px solid var(--client-primary); /* width/style structural. */
    border-radius:    var(--client-space-xs);
    padding:          var(--client-space-sm);
    font-family:      var(--client-font-body);
    font-size:        var(--client-text-base);
}


/* --------------------------------------------------------------------------
   8. SUBMIT BUTTON
   Values are matched BY TOKEN to the approved "BYS Button - Primary" element
   preset and its two nested group presets, so the form's button and a Divi
   Button module resolve to the same computed values:
       background  Primary        (preset: gcid-bys-primary   = --client-primary)
       text        Background     (preset: gcid-bys-background = --client-bg)
       font-size   Text Base      (preset: gvid-bys-text-base = --client-text-base)
       weight      600            (preset: BYS Button Type)
       radius      Space XS       (preset: BYS Button Shape)
       padding     Space S / M    (preset: element-level spacing)
   Fluent emits .ff_btn_no_style here because the form's button_style is
   'no_style', so Fluent contributes no competing colour block of its own.
   -------------------------------------------------------------------------- */
.fluentform .frm-fluent-form .ff-btn-submit {
    background-color: var(--client-primary);
    color:            var(--client-bg);

    border:        1px solid transparent; /* structural; keeps size stable on hover. */
    border-radius: var(--client-space-xs);

    font-family: var(--client-font-heading);
    font-size:   var(--client-text-base);
    font-weight: 600;

    padding:       var(--client-space-sm) var(--client-space-md);
    margin-bottom: var(--client-space-sm);
    cursor:        pointer;

    /* Accessibility floor: 44px minimum touch target. */
    min-height: 44px;
}

.fluentform .frm-fluent-form .ff-btn-submit:hover {
    background-color: var(--client-secondary);
    color:            var(--client-bg);
}


/* --------------------------------------------------------------------------
   9. COMPACT VARIANT  --  .bys-form--compact
   --------------------------------------------------------------------------
   A REUSABLE, OPT-IN modifier. Any page activates it by wrapping the Fluent
   shortcode in <div class="bys-form--compact"> ... </div>. Everything below is
   scoped under that ancestor class, so the default (roomy) mapping above is
   untouched for forms that do not opt in.

   WHY THIS EXISTS (Tony, 2026-07-20): the measured BYS standard-form references
   run ~20px field spacing, 40-42px controls, 16px input text, with sensible
   fields paired two-up. The default mapping's inter-field rhythm is
   --client-space-md (20 -> 36px), which reads loose next to those references.
   Compact tightens the rhythm to 16-20px and pairs the four short single-line
   fields, WITHOUT changing the form's structure (studio rule 4: no schema
   drift). Pairing is driven purely off Fluent's own stable [data-name]
   attribute via :has(), so form 5 stays byte-identical in the database.

   STILL TOKEN-DRIVEN. Every colour/type/space value resolves to a --client-*
   token or to an accessibility floor expressed with max()/a literal minimum,
   exactly like the base layer. No new token was added: the 16-20px gap is
   max(1rem, --client-space-sm), i.e. the existing Space S clamp floored at the
   16px readability minimum.

   TOUCH TARGETS AND MOBILE TEXT ARE INHERITED, NOT WEAKENED. Compact only
   changes layout (grid) and inter-field rhythm; the base rules still supply
   min-height:44px on controls/submit and font-size:--client-text-base
   (>=16px) on inputs. Pairing is gated behind >=600px so phones stack to one
   column and never shrink a field below a usable width.
   -------------------------------------------------------------------------- */

/* The fieldset is the direct parent of every .ff-el-group (verified in the
   rendered markup). Grid it so paired fields share a row and the row-gap owns
   the vertical rhythm. */
.bys-form--compact .fluentform .frm-fluent-form fieldset {
    display:               grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap:            var(--client-space-sm);
    /* 16px floor / 20px cap: the compact rhythm target. max() floors the
       existing Space S clamp at the 16px readability minimum. */
    row-gap:               max(1rem, var(--client-space-sm));
    align-items:           start;
}

/* Fluent's functional hidden inputs (nonce, referer) live inside the fieldset;
   keep them out of the grid so they never claim a cell. display:none does not
   affect their submission. */
.bys-form--compact .fluentform .frm-fluent-form fieldset > input[type="hidden"] {
    display: none;
}

/* Every group spans the full width by default; the grid row-gap replaces the
   base per-group margin so spacing is not applied twice. */
.bys-form--compact .fluentform .frm-fluent-form .ff-el-group {
    grid-column:   1 / -1;
    margin-bottom: 0;
}

/* Pairing: the four short single-line fields sit two-up from 600px up. They are
   matched on Fluent's own [data-name] so no container_class or structural
   change is needed. DOM order (name, email, phone, referral) already yields the
   sensible pairs name+email / phone+referral. */
@media (min-width: 600px) {
    .bys-form--compact .fluentform .frm-fluent-form .ff-el-group:has([data-name="full_name"]),
    .bys-form--compact .fluentform .frm-fluent-form .ff-el-group:has([data-name="email"]),
    .bys-form--compact .fluentform .frm-fluent-form .ff-el-group:has([data-name="phone"]),
    .bys-form--compact .fluentform .frm-fluent-form .ff-el-group:has([data-name="referral_source"]) {
        grid-column: span 1;
    }
}

/* Compact also tightens the label-to-field gap (half of Space XS). */
.bys-form--compact .fluentform .frm-fluent-form .ff-el-input--label label {
    margin-bottom: calc(var(--client-space-xs) / 2);
}
