/* =========================================================================
   FunLida Craft Layer — Stage 4 (W6)
   Loads after funlida-motion.css. Interaction craft: tap targets, the full
   state matrix, CTA hierarchy, and the contact form.
   Revert: novamira/disable-file on this file.

   SCOPE NOTE ON THE HEADER.
   Stage 1 carried a scope guard: "nothing targets the header, nav or
   mega-menu." That guard existed so type and colour work could not disturb
   Max Mega Menu. Two rules here deliberately cross it (section 1a), because
   the mobile menu toggle and the cart icon are the two worst tap targets on
   the site and W6 exists to fix exactly that. They change box size only —
   no colour, no type, no layout mode. Verified: menu still opens/closes.

   WIDTH SCOPING.
   Controls (arrows, icon buttons, form fields) get their minimum at every
   width, because a 41px input is wrong on desktop too. Text links only get
   expanded padding at <=1024px, where thumbs are the input device — doing
   it everywhere would add ~108px of dead space to the desktop footer for
   no benefit.
   ========================================================================= */


/* --- 1. TAP TARGETS -------------------------------------------------------
   Audited at 390px: 31 interactive elements under 44x44. Each group below
   names its measured size. Target is 44x44 (FRONTEND-PLAN W6).           */

/* 1a. Header controls. See SCOPE NOTE above. -------------------------------
   Mobile menu toggle, measured 28x38 computed / 17x23 rendered. This is the
   only way into navigation on a phone. Padding-only growth keeps the three
   bars centred in the content box exactly where Max Mega Menu draws them. */
.mega-menu-toggle .mega-toggle-block button.mega-toggle-animated {
  min-width: 44px;
  min-height: 44px;
  box-sizing: border-box;
}

/* The box above computes to 44x44, but Max Mega Menu's generated style.css
   puts `transform: scale(0.6)` on the same button, so the RENDERED target
   was 26x26 — a tap target can only be as big as its painted box. Two
   competing declarations had to be beaten, both from higher-specificity
   selectors than a plain class chain:

     style.css      #mega-menu-wrap-menu-1 ... .mega-toggle-animated  (1,3,0)
                    transform: scale(.6)
     funlida-nav.css #mega-menu-wrap-menu-1 .mega-toggle-animated     (1,1,0)
                    width: 34px; padding: 8px 0 !important

   This selector is (1,3,1) so it clears both, and repeats !important on
   padding only because nav.css declared it there.

   VISIBLE CONSEQUENCE, ACCEPTED: undoing the 0.6 scale returns the bars to
   the 28x22 box funlida-nav.css:89 already specifies, so the hamburger
   renders ~28px wide instead of ~17px. It is bigger and easier to hit,
   which is the point of W6. */
#mega-menu-wrap-menu-1 .mega-menu-toggle .mega-toggle-block button.mega-toggle-animated {
  transform: none;
  width: 44px;
  height: 44px;
  padding: 11px 8px !important;
  display: flex !important;
  align-items: center;
  justify-content: center;
}

/* Cart / account icon in the header, measured 19x19. inline-flex centring
   grows the hit box without moving the glyph off its optical position. */
.elementor-widget-icon a.elementor-icon,
.fl-header-account a.elementor-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}

/* 1b. Teacher-strip controls, measured 40x40. ---------------------------- */
.fl-hts-arrows .fl-hts-prev,
.fl-hts-arrows .fl-hts-next,
.fl-hstrip-ctrl .fl-hstrip-prev,
.fl-hstrip-ctrl .fl-hstrip-next {
  width: 44px;
  height: 44px;
  flex: none;
}

/* "View all", measured 72x21. Inline-flex so the underline still hugs the
   text while the target fills the row height. */
.fl-hts-controls .fl-hts-viewall {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* 1c. Social icons, measured 36x36 (footer) and 40x40 (contact). --------- */
.elementor-social-icons-wrapper .elementor-grid-item a.elementor-social-icon {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* 1d. Buttons that fell just short, measured 306x42 / 144x41. ------------ */
.fl-section .elementor-button,
.fl-plan-grid .fl-plan-btn .elementor-button,
.wpforms-container .wpforms-form button.wpforms-submit,
.fl-newsletter-btn {
  min-height: 44px;
}

/* 1e. Form fields, measured 298x43 and 330x41. -------------------------- */
.wpforms-container .wpforms-form input.wpforms-field-medium,
.wpforms-container .wpforms-form input.wpforms-field-large,
.wpforms-container .wpforms-form select,
.fl-newsletter-input {
  min-height: 44px;
}

/* 1f. Footer link lists, measured 330x26 x6 plus the legal column. -------
   Touch widths only — see WIDTH SCOPING above. */
@media (max-width: 1024px) {
  .elementor-icon-list-items .elementor-icon-list-item > a {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
}

/* NOT CHANGED, ON PURPOSE: .elementor-accordion-title.
   The audit flags it at 23px tall, but it is an inline <a> nested inside
   .elementor-tab-title, which is the real control and already measures
   360x58. Padding the inner element would double-pad the row and move the
   chevron. Making it block-level widens the click area to the full row
   without touching the parent's box. */
.elementor-accordion .elementor-tab-title .elementor-accordion-title {
  display: block;
  width: 100%;
}


/* --- 2. STATE MATRIX ------------------------------------------------------
   default / hover / focus-visible / active / disabled.
   focus-visible shipped in Stage 1 (funlida-system.css) and hover shipped
   in Stage 3 (funlida-motion.css). This completes active and disabled,
   which had no styling at all — a disabled button was indistinguishable
   from an enabled one.                                                    */

.fl-section .elementor-button:disabled,
.fl-section .elementor-button[disabled],
.fl-section .elementor-button[aria-disabled="true"],
.wpforms-container .wpforms-form button.wpforms-submit:disabled,
.fl-newsletter-btn:disabled,
.fl-newsletter-btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
  filter: grayscale(0.35);
}

/* A disabled control must not respond to hover — otherwise it reads as
   available and the click that follows does nothing. */
.fl-section .elementor-button:disabled:hover,
.fl-section .elementor-button[disabled]:hover,
.wpforms-container .wpforms-form button.wpforms-submit:disabled:hover,
.fl-newsletter-btn:disabled:hover {
  transform: none;
  box-shadow: none;
}

/* Text links get a visible pressed state too, not just buttons. */
.fl-section a:not(.elementor-button):active,
.fl-hts-controls .fl-hts-viewall:active {
  opacity: 0.7;
}


/* --- 3. CTA HIERARCHY -----------------------------------------------------
   Audited: 8 buttons, 7 of them the same filled magenta pill. When
   everything is primary, nothing is.

   primary   (filled)   hero, final CTA, featured plan, newsletter
   secondary (outlined) repeated asks — "Your Classroom", non-featured plans

   Only the repeated asks are demoted. The hero and the closing CTA keep
   full weight, per FRONTEND-PLAN W6.                                     */

.fl-class .elementor-button,
.fl-plan-grid .fl-plan-card:not(.fl-plan-featured) .fl-plan-btn .elementor-button {
  background-color: transparent;
  color: var(--fl-primary-500);
  border: 2px solid var(--fl-primary-500);
  box-shadow: none;
}

.fl-class .elementor-button:hover,
.fl-plan-grid .fl-plan-card:not(.fl-plan-featured) .fl-plan-btn .elementor-button:hover {
  background-color: var(--fl-primary-500);
  color: var(--fl-surface-card);
  border-color: var(--fl-primary-500);
}

/* The featured tier keeps the filled treatment, so the recommended card
   now carries elevation 4, the sheen, AND the only filled button in the
   row. Three signals agreeing. */
.fl-plan-grid .fl-plan-card.fl-plan-featured .fl-plan-btn .elementor-button {
  background-color: var(--fl-primary-500);
  color: var(--fl-surface-card);
  border: 2px solid var(--fl-primary-500);
}


/* --- 4b. FLUENT FORMS -----------------------------------------------------
   The contact form moved from WPForms Lite to Fluent Forms so submissions are
   actually stored (Lite keeps no record, so a bounced notification meant a
   lost enquiry). Same visual system as the WPForms rules below, which are
   kept because the registration popup still uses WPForms.

   Fluent Forms is far less aggressive than WPForms about resetting styles —
   no `* { background: none }` blanket — so none of this needs !important. */

.fluentform .ff-el-input--label label {
  font-family: var(--fl-font-body);
  font-size: var(--fl-text-sm);
  font-weight: var(--fl-weight-medium);
  color: var(--fl-ink-900);
  margin-bottom: 6px;
}

.fluentform .ff-el-form-control {
  font-family: var(--fl-font-body);
  font-size: var(--fl-text-base);
  color: var(--fl-ink-900);
  background-color: var(--fl-surface-card);
  border: 1px solid var(--fl-border);
  border-radius: var(--fl-radius-control);
  padding: 10px 14px;
  min-height: 44px;                 /* tap target, same rule as everything else */
  box-shadow: none;
  transition:
    border-color var(--fl-dur-fast) var(--fl-ease-out),
    box-shadow var(--fl-dur-fast) var(--fl-ease-out);
}

.fluentform .ff-el-form-control:focus:not(:focus-visible) {
  border-color: var(--fl-primary-500);
  box-shadow: 0 0 0 3px var(--fl-a-primary-15);
  outline: none;
}

/* Keyboard focus keeps a real outline. Same trap as the WPForms block below:
   a bare :focus rule here would delete the focus-visible ring. */
.fluentform .ff-el-form-control:focus-visible {
  border-color: var(--fl-primary-500);
  box-shadow: 0 0 0 3px var(--fl-a-primary-15);
  outline: var(--fl-focus-ring);
  outline-offset: var(--fl-focus-offset);
}

.fluentform .ff-el-is-error .ff-el-form-control { border-color: var(--fl-error); }
.fluentform .text-danger,
.fluentform .error.text-danger { color: var(--fl-error); font-size: var(--fl-text-sm); }
.fluentform .ff-el-input--label.ff-el-is-required label:after { color: var(--fl-error); }

.fluentform .ff-btn-submit {
  font-family: var(--fl-font-display);
  font-weight: var(--fl-weight-medium);
  font-size: var(--fl-text-base);
  color: var(--fl-surface-card);
  background-color: var(--fl-primary-500);
  border: 2px solid var(--fl-primary-500);
  border-radius: var(--fl-radius-pill);
  padding: 10px 26px;
  min-height: 44px;
  cursor: pointer;
  box-shadow: var(--fl-shadow-1);
  transition:
    background-color var(--fl-dur-fast) var(--fl-ease-out),
    box-shadow var(--fl-dur-fast) var(--fl-ease-out),
    transform var(--fl-dur-fast) var(--fl-ease-out);
}
.fluentform .ff-btn-submit:hover {
  background-color: var(--fl-primary-600);
  border-color: var(--fl-primary-600);
  box-shadow: var(--fl-shadow-1-hover);
  transform: translateY(-2px);
}
.fluentform .ff-btn-submit:active { transform: translateY(0); }

.ff-message-success {
  border: 1px solid var(--fl-success);
  border-radius: var(--fl-radius-card);
  background-color: var(--fl-surface-card);
  color: var(--fl-ink-900);
  padding: 16px 18px;
}


/* --- 4. THE WPFORMS CONTACT FORM ------------------------------------------
   The least finished thing on the page, and it showed: the submit button
   rendered #066AAB — WPForms' default BLUE, on a magenta site.

   THEME THROUGH THE PLUGIN'S VARIABLES, NOT AGAINST ITS CSS.
   The first attempt set background-color on the button directly. It lost:
   wpforms-full.min.css ships
     div.wpforms-container-full button[type="submit"]:not(:hover):not(:active)
   at (0,4,1), above a plain class chain, and the whole file is built on
   `* { background-color: initial }` resets. Out-specifying that means an
   !important arms race against a plugin that updates itself.

   WPForms exposes a documented custom-property API instead, which is what
   those rules actually read from. Setting the variables re-themes the form
   through the plugin's own mechanism and survives plugin updates.        */

.wpforms-container,
.wpforms-container-full,
div.wpforms-container-full {
  /* Both, and both to the SAME value. WPForms resolves the resting colour as
     var(--...-alt, var(--...-base)) on :not(:hover):not(:active), so "alt"
     is the at-rest colour, not the hover colour — setting it to primary-600
     shipped the hover tint as the default state. Hover is handled by the
     explicit rule further down. */
  --wpforms-button-background-color: var(--fl-primary-500);
  --wpforms-button-background-color-alt: var(--fl-primary-500);
  --wpforms-button-text-color: var(--fl-surface-card);
  --wpforms-button-border-radius: var(--fl-radius-pill);
  --wpforms-field-border-color: var(--fl-border);
  --wpforms-field-border-radius: var(--fl-radius-control);
  --wpforms-field-text-color: var(--fl-ink-900);
  --wpforms-label-color: var(--fl-ink-900);
  --wpforms-label-sublabel-color: var(--fl-ink-600);
  --wpforms-label-error-color: var(--fl-error);
}


.wpforms-container .wpforms-form input[type="text"],
.wpforms-container .wpforms-form input[type="email"],
.wpforms-container .wpforms-form input[type="tel"],
.wpforms-container .wpforms-form input[type="url"],
.wpforms-container .wpforms-form select,
.wpforms-container .wpforms-form textarea {
  font-family: var(--fl-font-body);
  font-size: var(--fl-text-base);
  color: var(--fl-ink-900);
  background-color: var(--fl-surface-card);
  border: 1px solid var(--fl-border);
  border-radius: var(--fl-radius-control);
  padding: 10px 14px;
  box-shadow: none;
  transition:
    border-color var(--fl-dur-fast) var(--fl-ease-out),
    box-shadow var(--fl-dur-fast) var(--fl-ease-out);
}

/* Pointer focus gets the soft brand ring. NOTE the :not(:focus-visible) —
   without it this rule (0,3,1) outranks the `input:focus-visible { outline }`
   from funlida-system.css (0,2,0) and silently deletes the keyboard focus
   ring, because :focus matches whenever :focus-visible does. Caught in QA.
   Keyboard users keep the real outline; mouse users get the ring only. */
.wpforms-container .wpforms-form input[type="text"]:focus:not(:focus-visible),
.wpforms-container .wpforms-form input[type="email"]:focus:not(:focus-visible),
.wpforms-container .wpforms-form textarea:focus:not(:focus-visible),
.wpforms-container .wpforms-form select:focus:not(:focus-visible) {
  border-color: var(--fl-primary-500);
  box-shadow: 0 0 0 3px var(--fl-a-primary-15);
  outline: none;
}

/* Keyboard focus: brand ring AND the system outline, both.

   THE ONE !important IN THIS FILE, AND WHY IT IS CORRECT.
   wpforms-full.min.css ships `div.wpforms-container-full * { outline: none }`
   — a blanket outline reset across every descendant, plus per-input :focus
   longhands. Measured: :focus-visible matched on the field and the ring
   variable resolved to `2px solid #E4487A`, yet computed outline stayed
   `none`, so a longhand was still winning the cascade.

   This is not the Stage 1/2 known-bad pattern. That was about REMOVING
   load-bearing !important from our own legacy CSS. This ADDS one, narrowly
   scoped to four form fields, to guarantee a keyboard focus indicator that
   a third-party blanket reset would otherwise delete. Losing a focus ring
   is an accessibility failure, not a style preference — it is worth winning
   outright. */
.wpforms-container .wpforms-form input[type="text"]:focus-visible,
.wpforms-container .wpforms-form input[type="email"]:focus-visible,
.wpforms-container .wpforms-form textarea:focus-visible,
.wpforms-container .wpforms-form select:focus-visible {
  border-color: var(--fl-primary-500);
  box-shadow: 0 0 0 3px var(--fl-a-primary-15);
  outline: var(--fl-focus-ring) !important;
  outline-offset: var(--fl-focus-offset) !important;
}

.wpforms-container .wpforms-form label.wpforms-field-label {
  font-family: var(--fl-font-body);
  font-size: var(--fl-text-sm);
  font-weight: var(--fl-weight-medium);
  color: var(--fl-ink-900);
}

/* Required marker and validation messages on the system's semantic colour,
   which Stage 1 added but nothing had used yet. */
.wpforms-container .wpforms-form .wpforms-required-label {
  color: var(--fl-error);
}

.wpforms-container .wpforms-form label.wpforms-error,
.wpforms-container .wpforms-form em.wpforms-error {
  font-family: var(--fl-font-body);
  font-size: var(--fl-text-sm);
  color: var(--fl-error);
}

.wpforms-container .wpforms-form input.wpforms-error,
.wpforms-container .wpforms-form textarea.wpforms-error {
  border-color: var(--fl-error);
}

.wpforms-container .wpforms-confirmation-container-full {
  border-radius: var(--fl-radius-card);
  border: 1px solid var(--fl-success);
  background-color: var(--fl-surface-card);
  color: var(--fl-ink-900);
}

/* The blue button. */
.wpforms-container .wpforms-form button[type="submit"].wpforms-submit {
  font-family: var(--fl-font-display);
  font-weight: var(--fl-weight-medium);
  font-size: var(--fl-text-base);
  color: var(--fl-surface-card);
  background-color: var(--fl-primary-500);
  border: 2px solid var(--fl-primary-500);
  border-radius: var(--fl-radius-pill);
  padding: 10px 26px;
  cursor: pointer;
  box-shadow: var(--fl-shadow-1);
  transition:
    background-color var(--fl-dur-fast) var(--fl-ease-out),
    box-shadow var(--fl-dur-fast) var(--fl-ease-out),
    transform var(--fl-dur-fast) var(--fl-ease-out);
}

.wpforms-container .wpforms-form button[type="submit"].wpforms-submit:hover {
  background-color: var(--fl-primary-600);
  border-color: var(--fl-primary-600);
  box-shadow: var(--fl-shadow-1-hover);
  transform: translateY(-2px);
}

.wpforms-container .wpforms-form button[type="submit"].wpforms-submit:active {
  transform: translateY(0);
}


/* --- 5. (removed) WHATSAPP ROW HIDE ---------------------------------------
   A CSS hide briefly lived here. It is gone because the row itself was
   deleted from the Elementor data for Home (133), Contact (136) and the
   footer (157), which is the real fix rather than painting over it.
   WeChat and Facebook were removed the same way at the client's request.

   Note for whoever comes next: these elements live in the `_elementor_data`
   POST META, not in `post_content`. Editing post_content has no effect on
   what renders — that cost an hour to discover. */


/* --- 6. "WHY CHOOSE FUNLIDA" CARDS ---------------------------------------
   Correcting a Stage 3 judgement call. I skipped these then, reasoning they
   were a description list rather than cards. Looking at them rendered, that
   was wrong: they are white boxes with square corners, no border and no
   shadow, sitting on a pink tint — which reads as unstyled default, not as
   a deliberate list. Every other card on the page got the material
   treatment in Stage 3, so these were left as the only flat surfaces.

   Same elevation language as the rest of the system: hairline edge,
   step-1 shadow, card radius, step-2 on hover.                          */

.fl-why-grid .fl-why-item {
  background-color: var(--fl-surface-card);
  border: 1px solid var(--fl-border-soft);
  border-radius: var(--fl-radius-card);
  box-shadow: var(--fl-shadow-1);
  /* Side padding is deliberately tight. These columns are only ~215px wide at
     1440, so 26px each side cost enough measure to push "Real-Life English"
     onto two lines and "Colorful & Interactive Lessons" onto three. 16px
     keeps the card feeling padded without eating the headline. */
  padding: 20px 16px 22px;
  height: 100%;                 /* equal heights across each row */
  transition:
    transform var(--fl-dur-base) var(--fl-ease-out),
    box-shadow var(--fl-dur-base) var(--fl-ease-out);
}

.fl-why-grid .fl-why-item:hover {
  transform: translateY(-3px);
  box-shadow: var(--fl-shadow-2-hover);
}

/* The magenta diamond floated slightly above the title's cap height, which
   read as misaligned rather than intentional. */
.fl-why-grid .fl-why-item .fl-diamond {
  margin-top: 7px;
  flex: none;
}

.fl-why-grid .fl-why-title {
  margin-bottom: 6px;
}

.fl-why-grid .fl-why-text {
  line-height: var(--fl-leading-body);
  color: var(--fl-ink-600);
}

@media (prefers-reduced-motion: reduce) {
  .fl-why-grid .fl-why-item:hover { transform: none; }
}


/* --- 7. TESTIMONIAL MARQUEE ----------------------------------------------
   Replaces the wrapping grid. At 5 reviews the grid broke to 4+1 and left a
   dead row; a track takes any number of reviews without degrading.

   GRACEFUL DEGRADATION: the animation only runs once funlida-motion.js has
   cloned the card set and added .is-looping. Until then (or if JS fails) the
   marquee is simply a horizontally scrollable row — never a broken loop that
   scrolls into empty space.

   Speed is constant per card: --fl-tst-n is injected by funlida-enqueue.php
   from the live testimonial count, so adding reviews makes the loop longer,
   not faster.                                                            */

.fl-tst-marquee {
  width: 100%;
  overflow-x: auto;              /* fallback: scrollable */
  overflow-y: hidden;
  padding-block: 6px 14px;       /* room for card shadows */
  scrollbar-width: none;
}
.fl-tst-marquee::-webkit-scrollbar { display: none; }

.fl-tst-marquee.fl-marquee-on {
  overflow-x: hidden;            /* JS is driving it */
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 44px, #000 calc(100% - 44px), transparent 100%);
}

/* Elementor containers default to column; force a single nowrap row. */
.fl-tst-marquee .fl-tst-track {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 24px;
  width: max-content;
  max-width: none;
}

.fl-tst-marquee .fl-tst-track.is-looping {
  /* 4s per card. At 7s the loop measured ~52px/s, which is real movement but
     slow enough that a visitor glancing at the section reads it as static. */
  animation: fl-tst-scroll calc(var(--fl-tst-n, 5) * 4s) linear infinite;
}

/* Pause on hover so a reader can finish a review, and on focus so keyboard
   users are not chasing a moving target. */
.fl-tst-marquee:hover .fl-tst-track.is-looping,
.fl-tst-marquee:focus-within .fl-tst-track.is-looping {
  animation-play-state: paused;
}

.fl-tst-marquee .fl-tst-track .fl-tst-card {
  flex: 0 0 320px;
  width: 320px;
}

/* Stage 2's alignment rule centres section content, which is right for
   headings and wrong for a 380-character review — centred ragged text is hard
   to read once it passes a couple of lines. Reviews read left, attribution
   sits under them. */
.fl-tst-marquee .fl-tst-card .fl-tst-quote,
.fl-tst-marquee .fl-tst-card .fl-tst-quote p,
.fl-tst-marquee .fl-tst-card .fl-tst-stars,
.fl-tst-marquee .fl-tst-card .fl-tst-name {
  text-align: left;
}

/* Attribution pinned to the bottom, so names line up across cards of
   different quote lengths instead of floating mid-card. margin-top on the
   author is more reliable here than margin-bottom on the quote, because the
   author is the last flex child. */
.fl-tst-marquee .fl-tst-card .fl-tst-author {
  margin-top: auto;
  padding-top: 18px;
}


/* --- 8. TESTIMONIALS: WHITE CARDS, FULL BLEED ----------------------------
   The solid magenta fill was the last unresolved item from the original
   diagnosis ("low-contrast testimonials: white body text on #E4487A fails
   comfortable reading contrast at 14px"). W1 called for exactly this fix and
   it never got done: supporting text moves to a white card with dark ink,
   and magenta stays as the accent.

   design.css sets the magenta fill and white text with !important, so these
   need !important to land. That is overriding a legacy declaration, not
   removing one — the pattern Stage 1 and 2 proved is safe.               */

/* Full bleed: break out of the boxed container so the track uses the whole
   viewport instead of stopping at the 1140px content column. */
.fl-tst-marquee {
  width: 100vw;
  max-width: 100vw;
  margin-inline: calc(50% - 50vw);
  padding-inline: 0;
}

.fl-tst-marquee .fl-tst-card {
  background: var(--fl-surface-card) !important;
  background-color: var(--fl-surface-card) !important;
  border: 1px solid var(--fl-border-soft);
  box-shadow: var(--fl-shadow-3), inset 0 0 0 1px rgba(255,255,255,.6) !important;
  color: var(--fl-ink-900);
  position: relative;
}

.fl-tst-marquee .fl-tst-card:hover {
  box-shadow: var(--fl-shadow-3-hover), inset 0 0 0 1px rgba(255,255,255,.6) !important;
}

.fl-tst-marquee .fl-tst-card .fl-tst-quote p,
.fl-tst-marquee .fl-tst-card .fl-tst-quote .elementor-widget-container p {
  color: var(--fl-ink-900) !important;
  font-size: var(--fl-text-base);
  line-height: 1.65;
}

.fl-tst-marquee .fl-tst-card .fl-tst-name,
.fl-tst-marquee .fl-tst-card .fl-tst-name .elementor-heading-title {
  color: var(--fl-ink-900) !important;
  font-size: var(--fl-text-base);
}

/* Stars keep the gold token — now legible against white rather than
   competing with a magenta ground. */
.fl-tst-marquee .fl-tst-card .fl-tst-stars .elementor-heading-title {
  color: var(--fl-star) !important;
  font-size: 15px;
  letter-spacing: 3px;
}

/* One magenta accent per card: an oversized quote glyph behind the text.
   This is where the brand colour earns its place, instead of flooding the
   whole surface. */
.fl-tst-marquee .fl-tst-card::before {
  content: '\201C';
  position: absolute;
  top: 4px;
  right: 20px;
  font-family: var(--fl-font-display);
  font-size: 82px;
  line-height: 1;
  color: var(--fl-primary-500);
  opacity: 0.16;
  pointer-events: none;
}

/* Name reads as attribution, not as a heading competing with the quote. */
.fl-tst-marquee .fl-tst-card .fl-tst-author {
  border-top: 1px solid var(--fl-border-soft);
}

/* -50% moves past exactly one copy of the set; the extra half-gap keeps the
   seam invisible, since the gap sits between the two copies too. */
@keyframes fl-tst-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-50% - 12px), 0, 0); }
}

@media (max-width: 767px) {
  .fl-tst-marquee .fl-tst-track .fl-tst-card {
    flex-basis: 280px;
    width: 280px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fl-tst-marquee .fl-tst-track.is-looping { animation: none; }
  .fl-tst-marquee.fl-marquee-on {
    overflow-x: auto;            /* let them scroll it themselves instead */
    -webkit-mask-image: none;
    mask-image: none;
  }
}
