/* ==========================================================================
   BLUE BAY — CAPA ESTÉTICA v2
   ========================================================================== */

/* ═══════ 1. COLOR ═══════ */
/* ==========================================================================
   BLUE BAY DMC — colour system
   Drop-in layer. Load AFTER base.css:

     {{ 'base.css'  | asset_url | stylesheet_tag }}
     {{ 'color.css' | asset_url | stylesheet_tag }}

   HOW THIS FILE WINS, WITHOUT !important
   --------------------------------------
   1. Tokens are declared on `html:root` (specificity 0,0,2) instead of
      `:root` (0,0,1). That beats base.css AND the `<style>:root{}` block
      that theme.liquid prints from theme settings, whichever order they
      land in. No !important needed.
   2. Rules that only need to beat base.css use the same selector — source
      order does the work.
   3. Rules that must beat a section's inline `<style>` (those render in the
      body, i.e. after this file) carry one extra compound step, e.g.
      `.section#tours .eyebrow` instead of `#tours .eyebrow`. Each such
      block says so in its heading.

   Every pair in here is verified by contrast_check.py — 97 pairs, 0 fails,
   worst ratio carrying a requirement 3.23:1 (a 3:1 graphic).
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

html:root {

  /* ---- Brand blue ramp -------------------------------------------------
     One family, hue 204° drifting to 210° as it darkens. The two
     contractual colours ARE this ramp: brand-500 is #0E6BA8 and
     brand-900 is #0B2A4A. Navy is not a second colour — it is the dark
     end of the brand blue. That is the whole idea. */
  --brand-50:  #EFF6FA;
  --brand-100: #DCEAF4;
  --brand-200: #BAD6E8;
  --brand-300: #82B3D3;
  --brand-400: #338FCC;   /* 3.53:1 on white — lightest tone allowed to carry a boundary */
  --brand-500: #0E6BA8;   /* ★ BRAND — 5.70:1 both directions against white */
  --brand-600: #0B578E;   /* 7.59:1 — links, icons, quiet UI */
  --brand-700: #0A4776;   /* 9.65:1 — gradient dark stop, focus ring on light */
  --brand-800: #0A365C;
  --brand-900: #0B2A4A;   /* ★ NAVY — 14.54:1 */
  --brand-950: #071E36;   /* deepest ground: #tours, footer */

  /* ---- Ink: navy-tinted neutrals ---------------------------------------
     Cool greys that sit under the blues. Replaces the four unrelated grey
     families that were in use (#5a6b78 / #5A7079 / #44535f / #9ca3af). */
  --ink-50:  #F5F8FA;
  --ink-100: #EBF0F4;
  --ink-200: #DDE4E9;     /* decorative hairlines only */
  --ink-300: #C8D0D8;     /* image placeholder ground (was --color-silver) */
  --ink-350: #798794;     /* 3.68:1 — boundary of an interactive control */
  --ink-400: #5E6C78;     /* 5.40:1 — placeholder text */
  --ink-500: #4D5D6A;     /* 6.80:1 — secondary body copy */
  --ink-600: #3D4E5C;
  --ink-700: #2F3F4C;
  --ink-900: #14202B;     /* body text */

  /* ---- The one accent: brass -------------------------------------------
     Gold survives, teal does not. Gold is the only hue in the old set that
     is NOT another blue: it complements 204° instead of competing with it,
     and it belongs beside the Cinzel wordmark. It has exactly one job —
     marking the heading rule, the star ratings and eyebrows on dark
     grounds. It is never a button and never a link. */
  --accent-100: #F6EBCF;
  --accent-300: #E3C271;  /* on dark grounds */
  --accent-500: #C9A24B;  /* ★ the existing gold — dark grounds only, 7.01:1 on brand-950 */
  --accent-600: #AD8424;  /* 3.44:1 — gold graphics on white */
  --accent-700: #8F6D1E;  /* 4.80:1 — gold text on white */
  --accent-900: #4E3C11;

  /* ---- WhatsApp route ---------------------------------------------------
     #25D366 gives white text 1.98:1. It cannot be a text ground. It stays
     as the halo — the recognisable green is still on screen, it just is
     not the thing text sits on. Fill is the same hue (142°) walked down to
     30% lightness, which reads unmistakably WhatsApp and clears 4.5:1. */
  --wa-500: #25D366;      /* glow / halo — decorative only, never behind text */
  --wa-600: #15843E;      /* 4.77:1 with white — the fill */
  --wa-700: #116931;      /* 6.80:1 — hover */

  /* ---- Semantics, deliberately not the brand accent --------------------- */
  --success-50:  #E8F6ED;
  --success-600: #157F3C;
  --success-700: #116931;
  --warning-50:  #FBF1E3;
  --warning-600: #9A5A16;
  --danger-50:   #FBEAE9;
  --danger-600:  #B3261E;

  /* ---- Roles ------------------------------------------------------------ */
  --on-dark:        #FFFFFF;
  --on-dark-muted:  #A9BAC8;   /* 7.30:1 on navy, 8.45:1 on brand-950 */
  --surface:        #FFFFFF;
  --surface-sunken: var(--ink-50);
  --border-hair:    var(--ink-200);
  --border-control: var(--ink-350);
  --scrim:          7, 30, 54;  /* rgb triplet for photo overlays */

  /* ---- Shadows: retinted from navy, unchanged in shape ------------------ */
  --shadow-md:  0 4px 6px -1px rgba(11,42,74,.10), 0 2px 4px -2px rgba(11,42,74,.10);
  --shadow-lg:  0 10px 15px -3px rgba(11,42,74,.10), 0 4px 6px -4px rgba(11,42,74,.10);
  --shadow-2xl: 0 25px 50px -12px rgba(11,42,74,.25);


  /* ======================================================================
     2. LEGACY TOKENS — every one accounted for
     ====================================================================== */

  /* REMAPPED. Kept as aliases so any usage anywhere in the theme (including
     files not in this handoff) renders in-family instead of breaking. */
  --color-blue:    var(--brand-500);  /* was #2563eb — a 4th blue, redundant */
  --color-appblue: var(--brand-500);  /* was #0A74F0 — 4.40:1 on white, failed body AA */
  --color-royal:   var(--brand-600);  /* was #2F49D6 — 231°, violet-leaning, a different family */
  --color-teal:    var(--brand-500);  /* was #14b8a6 — 173°, and the cyan in the gradients */
  --color-accent:  var(--brand-600);  /* injected as #14b8a6 by theme.liquid; 2.49:1 focus ring */
  --color-gold:    var(--accent-500); /* KEPT — promoted to the single accent */

  /* Unchanged, contractual */
  --color-navy:   #0B2A4A;
  --color-text:   var(--ink-900);
  --color-silver: var(--ink-300);
  --color-bg:     #FFFFFF;

  /* RECOLOURED gradients. Same token names, same jobs, one family.
     The cyan stop (#2AAEFF) and the violet stop (#4D6BFF) are gone: a
     gradient that travels from cyan to blue is two colours pretending to
     be one, and its light end was the 2.44:1 button failure. These now
     travel along the ramp instead of across the wheel — two steps apart,
     enough for depth, not enough to read as a second hue. */
  --gradient-button:        linear-gradient(160deg, var(--brand-500) 0%, var(--brand-700) 100%);
  --gradient-button-hover:  linear-gradient(160deg, var(--brand-600) 0%, var(--brand-800) 100%);
  --gradient-primary:       linear-gradient(135deg, var(--brand-500) 0%, var(--brand-900) 100%);
  --gradient-primary-hover: linear-gradient(135deg, var(--brand-600) 0%, var(--brand-950) 100%);
  --gradient-navy:          linear-gradient(135deg, var(--brand-900) 0%, var(--brand-800) 55%, var(--brand-700) 100%);
  --gradient-bg-light:      linear-gradient(160deg, var(--brand-50) 0%, var(--ink-50) 100%);
  /* was: to bottom right, #eff6ff -> #f0fdfa. The second stop was mint —
     the teal leaking into every soft section ground. */
}


/* ==========================================================================
   3. GLOBAL TEXT, LINKS, EYEBROWS
   ========================================================================== */

body { color: var(--ink-900); }

a { color: var(--brand-900); }
a:hover { color: var(--brand-600); }

.eyebrow { color: var(--brand-500); }

/* The hairline under centred headings becomes the accent's standing job:
   one gold rule, everywhere, instead of blue here and gold there. */
.text-center > h2::after {
  width: 54px;
  height: 2px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-600) 0%, var(--accent-300) 100%);
}

.section--alt { background: var(--gradient-bg-light); }
.section--navy { background: var(--brand-900); }

#corporate .eyebrow { color: var(--brand-50); }
#corporate .lead    { color: #fff; }

.skip-to-content { background: var(--brand-900); color: #fff; }


/* ==========================================================================
   4. FOCUS — dual-tone ring, works on light AND dark grounds
   Old ring was #14B8A6 at 2.49:1 against white.
   Now: a brand-700 outline (9.65:1 on white) with a white 2px ring filling
   the offset gap (14.54:1 on navy). Whichever ground you are on, one of
   the two is high contrast. Neither affects layout.
   ========================================================================== */

/* FIX: focus ring lives in motion.css only — two declarations fought and the
   loser also disabled both forced-colors blocks. */
.btn:focus-visible,
.hero__btn:focus-visible,
.quickbook__submit:focus-visible { border-radius: 14px; }


/* ==========================================================================
   5. BUTTONS
   ========================================================================== */

.btn--primary,
.btn--navy,
.btn--book        { background: var(--gradient-button); color: #fff; }
.btn--primary:hover,
.btn--navy:hover,
.btn--book:hover  { background: var(--gradient-button-hover); color: #fff; }

.btn--outline       { border-color: currentColor; color: var(--brand-900); }
.btn--outline-blue  { background: #fff; border-color: var(--brand-600); color: var(--brand-600); }
.btn--outline-blue:hover { background: var(--brand-600); color: #fff; }

.btn--white         { background: #fff; color: var(--brand-600); }
.btn--white:hover   { background: var(--brand-50); color: var(--brand-700); }

/* Ghost button on the brand gradient band. The old rgba(255,255,255,.12)
   LIGHTENED its ground, dragging the white label to 4.49:1. A dark tint
   deepens it instead: label 7.40:1, border 4.50:1. */
.btn--ghost-light       { background: rgba(11,42,74,.28); border-color: rgba(255,255,255,.7); color: #fff; }
.btn--ghost-light:hover { background: rgba(11,42,74,.42); border-color: #fff; }


/* ==========================================================================
   6. THE WHATSAPP ROUTE — must stay the loudest CTA, above the cart
   ========================================================================== */

.btn--whatsapp {
  background: var(--wa-600);
  color: #fff;
  border-color: transparent;
  /* the vivid WhatsApp green survives as a halo, where it carries no text */
  box-shadow: 0 0 0 3px rgba(37,211,102,.30);
}
.btn--whatsapp:hover {
  background: var(--wa-700);
  color: #fff;
  box-shadow: 0 0 0 5px rgba(37,211,102,.38), var(--shadow-lg);
}

/* Floating action button */
.float-whatsapp {
  background: var(--wa-600);
  color: #fff;
  box-shadow: 0 0 0 4px rgba(37,211,102,.28), 0 6px 18px rgba(7,30,54,.30);
}
.float-whatsapp:hover { background: var(--wa-700); }

/* The cart is deliberately quieter than the WhatsApp route: brand blue,
   no halo. It was teal, which read as a second accent. */
.header__cart-count { background: var(--brand-600); color: #fff; }
.header__cart:hover { color: var(--brand-600); }


/* ==========================================================================
   7. HEADER, NAV, CONTROLS
   Control boundaries were rgba(11,42,74,.2) ≈ 1.35:1 against white, below
   the 3:1 that WCAG 1.4.11 asks of a component's visible boundary.
   ========================================================================== */

.nav-list a:hover { color: var(--brand-600); }

.lang-form select,
.lang-switcher__current,
.header__search   { border-color: var(--border-control); }
.lang-switcher__current:hover { border-color: var(--brand-500); }
.lang-switcher__menu   { border-color: var(--border-hair); }
.lang-switcher__option { color: var(--brand-900); }
.lang-switcher__option:hover { background: var(--brand-50); }
.lang-switcher__check  { color: var(--brand-600); }

.header__search input::placeholder { color: var(--ink-400); }
.header__search button { background: var(--brand-600); color: #fff; }

.mobile-nav { border-top-color: var(--border-hair); }


/* ==========================================================================
   8. HERO   -- beats sections/hero.liquid inline <style>
   ========================================================================== */

/* Photo scrim. The old one bottomed out at 25% opacity, which put the
   subtitle at 1.89:1. Aclarado a petición de la dueña: el piso matemático
   para texto blanco AA sobre un píxel blanco de la foto es alfa 0.598, así
   que .62 en el punto más claro deja margen y se ve mucho menos opaco. */
section.hero { background: var(--brand-950); }

.hero > .hero__overlay {
  background: linear-gradient(
    180deg,
    rgba(var(--scrim), .64) 0%,
    rgba(var(--scrim), .62) 42%,
    rgba(var(--scrim), .80) 100%
  );
}

.hero .hero__subtitle    { color: #fff; }       /* was rgba(255,255,255,.92) */
.hero .hero__trust-item  { color: #fff; }
.hero .hero__stars       { color: var(--accent-100); }  /* FIX: 14px = text, needs 4.5:1 (was 3.21:1) */
.hero .hero__tick        { color: #fff; }               /* was #58D6B5 — a teal that belonged to nothing */

/* CTA ORDER FLIP.
   The markup gives WhatsApp the glass treatment and "Discover" the solid
   fill, which puts the cart-side route above the booking route — the exact
   inverse of the brief. Colour alone corrects it: WhatsApp becomes the
   solid green with a white boundary ring, Discover becomes dark glass. */
.hero .hero__btn--glass {
  background: var(--wa-600);
  color: #fff;
  border: 2px solid #fff;                        /* 5.54:1 against the scrim */
  box-shadow: 0 0 0 5px rgba(37,211,102,.34), 0 12px 30px rgba(7,30,54,.45);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.hero .hero__btn--glass:hover {
  background: var(--wa-700);
  box-shadow: 0 0 0 7px rgba(37,211,102,.40), 0 14px 34px rgba(7,30,54,.5);
}

.hero .hero__btn--primary {
  background: rgba(var(--scrim), .42);
  color: #fff;
  border: 1.5px solid rgba(255,255,255,.72);
  box-shadow: none;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.hero .hero__btn--primary:hover { background: rgba(var(--scrim), .58); border-color: #fff; }

/* NOTE — hero.liquid line 18 sets the no-media fallback panel with a style
   attribute: background:linear-gradient(135deg,var(--color-navy),#15406b).
   An inline attribute cannot be reached from a stylesheet without
   !important, and this file uses none. Change #15406b to #0A4776 in
   hero.liquid instead. It only shows when neither video nor image is set,
   so it is cosmetic, not a contrast issue.  */

/* Quick-book bar — the submit is a wa.me link, so it is green like every
   other WhatsApp route. Warm sand borders (#EFE9DD / #DCE5E7) were a
   fourth neutral family; they join the ink ramp. */
.quickbook .quickbook__card   { border-color: var(--border-hair); box-shadow: 0 24px 60px rgba(7,30,54,.18); }
.quickbook .quickbook__title  { color: var(--brand-900); }
.quickbook .quickbook__title svg { color: var(--brand-500); }
.quickbook .quickbook__field label { color: var(--ink-500); }
.quickbook .quickbook__field input,
.quickbook .quickbook__field select { border-color: var(--border-control); color: var(--ink-900); background: #fff; }
.quickbook .quickbook__field input:focus,
.quickbook .quickbook__field select:focus { border-color: var(--brand-500); }
.quickbook .quickbook__submit {
  background: var(--wa-600);
  color: #fff;
  box-shadow: 0 0 0 3px rgba(37,211,102,.28);
}
.quickbook .quickbook__submit:hover { background: var(--wa-700); }

/* Badge over the photo: a dark tint, not a light one, so white text on it
   stays at 4.5:1 no matter what the photo is doing underneath. */
.eyebrow--badge {
  background: rgba(var(--scrim), .35);
  border-color: rgba(255,255,255,.55);
  color: #fff;
}


/* ==========================================================================
   9. CTA BAND
   ========================================================================== */

.cta-band { background: var(--brand-900); }
.cta-band__overlay { background: rgba(var(--scrim), .80); }
.cta-band__content .eyebrow--light { color: var(--accent-300); }  /* was --color-silver, 3.0:1 */


/* ==========================================================================
   10. CARDS, BADGES, CHIPS, PILLARS
   ========================================================================== */

.card,
.blog-card,
.transfer-card,
.review          { border-color: var(--border-hair); }
.card__media,
.blog-card__media,
.transfer-card__media,
.about__media,
.gallery-grid figure { background: var(--ink-300); }

.card__meta,
.blog-card__excerpt,
.article__meta,
.review__source,
.stats-bar__label,
.service-card__desc,
.transfer-card__capacity,
.transfer-card__price-from,
.transfer-card__price-suffix,
.transfer-card__zone span,
.transfer-card__coverage,
.roa-note        { color: var(--ink-500); }

.article__content { color: var(--ink-700); }
.review blockquote,
.contact-info__list li,
.about__body,
.transfer-card__text,
.transfers-other__text,
.transfer-card__features li { color: var(--ink-600); }

.blog-card__kicker,
.blog-card__more,
.article__kicker a,
.pillar-card__tag { color: var(--brand-600); }
/* FIX(a11y): links inside prose were distinguished by colour alone (1.43:1 vs body).
   WCAG 1.4.1/F73 needs a non-colour cue; a phone has no hover. */
.article__content a,
.contact-info__list a,
.transfers-routes a,
.footer a[href] {
  color: var(--brand-600);
  text-decoration: underline;
  text-underline-offset: .18em;
  text-decoration-thickness: from-font;
}
.footer a[href] { color: inherit; }

.trust-item svg   { color: var(--brand-500); }
.pillar-card__icon { background: var(--gradient-primary); }

.service-card__overlay { background: linear-gradient(to top, rgba(var(--scrim), .60), transparent); }

.stats-bar { border-block-color: var(--border-hair); }
.stats-bar__value { color: var(--brand-600); background: var(--gradient-primary); }
.stats-bar__item + .stats-bar__item::before { background: var(--border-hair); }
.card__title-num  { color: var(--brand-600); background: var(--gradient-primary); }

.condo-group__title { background: var(--gradient-navy); }
.condo-row__next    { background: var(--gradient-button); }
.condo-row__next:hover { background: var(--gradient-button-hover); }

.review::before   { color: rgba(14,107,168,.10); }
.review__stars    { color: var(--accent-600); }   /* was #f5b50a at 1.83:1 */
.review__avatar   { background: var(--gradient-primary); }
.review__author   { border-top-color: var(--border-hair); }

.blog-pagination .page.current { background: var(--brand-900); color: #fff; }


/* ==========================================================================
   11. TRANSFERS
   ========================================================================== */

.transfer-card__badge        { background: rgba(11,42,74,.82); }
.transfer-card__badge--price { background: var(--brand-500); }
.transfer-card__title svg    { color: var(--brand-500); }
.transfer-card__features svg { color: var(--brand-500); }   /* was teal */
.transfer-card__zones        { background: var(--ink-50); }
.transfers-routes            { color: var(--ink-500); }
.transfers-routes a          { color: var(--brand-600); }

.transfers-other {
  background: linear-gradient(135deg, rgba(14,107,168,.08) 0%, rgba(11,42,74,.06) 100%);
  border-color: rgba(14,107,168,.16);
}


/* ==========================================================================
   12. TOURS -- dark ground; beats sections/tours.liquid inline <style>
   The old ground was #0E3B47, a dark teal that belonged to no ramp.
   ========================================================================== */

.section#tours                 { background: var(--brand-950); }
.section#tours .eyebrow        { color: var(--accent-500); }  /* was #5BC2E5 cyan */
.section#tours h2              { color: #fff; }
.section#tours .section-intro  { color: rgba(255,255,255,.82); }
.section#tours .roa-note       { color: rgba(255,255,255,.74); }
.section#tours .btn--outline-blue {
  color: #fff;
  border-color: rgba(255,255,255,.72);
  background: transparent;
}
.section#tours .btn--outline-blue:hover { background: rgba(255,255,255,.14); border-color: #fff; }
.section#tours .card__footer .card__price { color: var(--brand-600); }


/* ==========================================================================
   13. APARTMENTS -- beats sections/apartments-grid.liquid inline <style>
   ========================================================================== */

.section#apartments .eyebrow { color: var(--brand-500); }
.section#apartments .apartments-head__text .section-intro { color: var(--ink-500); }
.section#apartments .apartments-head__map { border-color: var(--border-hair); }
.section#apartments .apartments-head__map .map-tag { color: var(--brand-900); }

/* The perk banner ran brand blue -> #15A9B8 cyan. Same shape, one family. */
#apartments .apt-perk {
  background: linear-gradient(100deg, var(--brand-500) 0%, var(--brand-800) 100%);
}

#apartments .condo-tab {
  border-color: var(--brand-400);      /* was #CFE0EC ≈ 1.5:1, below the 3:1 a control boundary needs */
  color: var(--brand-600);
  background: #fff;
}
#apartments .condo-tab:hover      { border-color: var(--brand-600); background: var(--brand-50); }
#apartments .condo-tab.is-active  { background: var(--brand-500); color: #fff; border-color: var(--brand-500); }
#apartments .condo-filter__count  { color: var(--ink-500); }

.section#apartments .condo-card        { border-color: var(--border-hair); }
.section#apartments .condo-card__tag   { color: var(--brand-600); background: rgba(255,255,255,.95); }
.section#apartments .condo-card__name a:hover { color: var(--brand-600); }
.section#apartments .condo-card__desc,
.section#apartments .condo-card__meta,
.section#apartments .condo-card__price .unit { color: var(--ink-500); }
.section#apartments .condo-card__foot  { border-top-color: var(--border-hair); }
.section#apartments .condo-card__price .amt { color: var(--brand-600); }
.section#apartments .condo-more .btn   { background: #fff; color: var(--brand-600); border-color: var(--brand-600); }
.section#apartments .condo-more .btn:hover { background: var(--brand-600); color: #fff; }

/* Grid-card refinements that live in base.css */
#apartments .card,
#apartments .card__pricerow { border-color: var(--border-hair); }
#apartments .card__chip     { background: rgba(14,107,168,.09); color: var(--brand-900); }
#apartments .card__chip svg { color: var(--brand-500); }
#apartments .card__desc,
#apartments .card__price-from,
#apartments .card__price-unit { color: var(--ink-500); }
#apartments .card__cta      { box-shadow: 0 5px 14px rgba(14,107,168,.22); }

/* Gold rule under the apartments heading — same accent, same treatment as
   every other centred heading now. */
.apartments-head__text h2::after {
  background: linear-gradient(90deg, var(--accent-600) 0%, var(--accent-300) 100%);
}


/* ==========================================================================
   14. FORMS
   ========================================================================== */

.field input,
.field textarea { border-color: var(--border-control); }
.field input:focus,
.field textarea:focus {
  border-color: var(--brand-500);
  box-shadow: 0 0 0 3px rgba(14,107,168,.18);
}

.form-success  { background: var(--success-50); border-color: var(--success-600); color: var(--ink-900); }

.contact-info  { background: var(--gradient-bg-light); border-color: var(--border-hair); }
.contact-info__list svg { color: var(--brand-600); }
.contact-info__list a   { color: var(--brand-600); }
.amenities svg { color: var(--brand-600); }
.product__booking { border-color: var(--border-hair); }

/* Merchant-facing TODO note — moved onto the accent, since "unfinished"
   is a warm state, not a brand-blue one. */
.placeholder-note {
  background: var(--accent-100);
  border-color: var(--accent-700);
  color: var(--accent-900);
}


/* ==========================================================================
   15. FOOTER
   Was #111827 / #9ca3af / #60a5fa — Tailwind's neutral greys and a stock
   blue, a whole extra palette living below the fold. Now the bottom of the
   brand ramp.
   ========================================================================== */

.footer { background: var(--brand-950); color: var(--on-dark-muted); }
.footer a,
.footer__contact-text,
.footer__description,
.footer p,
.footer__bottom,
.footer__social-link { color: var(--on-dark-muted); }
.footer a:hover,
.footer__social-link:hover { color: #fff; }
.footer__contact-icon { color: var(--brand-300); }   /* was #60a5fa */
.footer__bottom { border-top-color: rgba(255,255,255,.14); }


/* ==========================================================================
   16. DECORATIVE MOTION TINTS
   Colour only — no motion is added, removed or retimed here, and nothing
   is hidden until scroll.
   ========================================================================== */

/* FIX: .scroll-cascade__drop is removed by motion.css — rule deleted. */

/* Instagram and Facebook keep their own brand colours — they identify
   third parties, so they are not ours to unify. */


/* ==========================================================================
   17. FORCED COLORS
   ========================================================================== */

@media (forced-colors: active) {
  .btn--whatsapp,
  .float-whatsapp,
  .hero .hero__btn--glass,
  .quickbook .quickbook__submit { border: 2px solid ButtonText; box-shadow: none; }
}

/* ═══════ 2. TIPOGRAFÍA ═══════ */
/* ============================================================================
   Blue Bay DMC — type.css
   Typography layer. Load in <head> AFTER base.css and AFTER the inline
   <style> block in theme.liquid, so the :root overrides below win.

   ONE webfont family: Plus Jakarta Sans (variable, latin, 26.6 KB, one file).
   Cinzel stays in the logo artwork only — it costs 0 KB and is NOT loaded here.

   This file only sets: family, size, weight, line-height, letter-spacing,
   measure and numeral behaviour. It sets NO colours — palette is owned
   elsewhere. The two exceptions are noted inline and are inherit/currentColor.

   A handful of rules carry a [class] attribute selector purely to raise
   specificity by one, because several sections ship their own <style> block
   inside <body> (later in document order than this file). Each is commented.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------ */
/* FIX(CLS): metric-matched fallback — without it every heading re-heights and
   text-wrap:balance re-wraps when the webfont swaps in on a slow connection. */
@font-face{
  font-family:'PJS Fallback';
  src: local('Helvetica Neue'), local('Arial'), local('Roboto');
  size-adjust: 105.4%;
  ascent-override: 100%;
  descent-override: 25%;
  line-gap-override: 0%;
}

html:root {
  /* --- Families ---------------------------------------------------------- */
  --font-sans:
    'Plus Jakarta Sans', system-ui, -apple-system, BlinkMacSystemFont,
    'PJS Fallback', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

  /* Every role points at the one family. Kept as separate names so existing
     base.css rules that reference --font-heading / --font-body keep working. */
  --font-body: var(--font-sans);
  --font-heading: var(--font-sans);
  --font-display: var(--font-sans);

  /* Brand voice of the wordmark. Cinzel is NOT loaded as a webfont — this
     stack only exists so the text fallback of the logo (when the PNG fails)
     lands on a Roman-ish serif instead of Arial. Do not use it for content
     unless you also add the Cinzel <link>; see type.md. */
  --font-brand: 'Cinzel', 'Times New Roman', Times, Georgia, serif;

  /* --- Weights (Plus Jakarta Sans variable, real axis 200–800) ------------ */
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-black: 800;

  /* --- Modular scale ------------------------------------------------------
     Two ratios, deliberately:
       text range  (2xs → lg)  ≈ 1.125  major second — fine steps for dense UI
       display range (xl → 5xl) ≈ 1.25   major third  — clear jumps for drama
     Fluid between 375px and 1280px viewport; clamped flat outside that.     */
  --t-2xs:  clamp(0.7188rem, 0.7058rem + 0.055vw, 0.7500rem);  /* 11.5 → 12   */
  --t-xs:   clamp(0.8125rem, 0.7996rem + 0.055vw, 0.8438rem);  /* 13   → 13.5 */
  --t-sm:   clamp(0.8750rem, 0.8491rem + 0.110vw, 0.9375rem);  /* 14   → 15   */
  --t-base: clamp(1.0000rem, 0.9741rem + 0.110vw, 1.0625rem);  /* 16   → 17   */
  --t-md:   clamp(1.0625rem, 1.0107rem + 0.221vw, 1.1875rem);  /* 17   → 19   */
  --t-lg:   clamp(1.1875rem, 1.1228rem + 0.276vw, 1.3438rem);  /* 19   → 21.5 */
  --t-xl:   clamp(1.3750rem, 1.2455rem + 0.552vw, 1.6875rem);  /* 22   → 27   */
  --t-2xl:  clamp(1.6250rem, 1.4308rem + 0.829vw, 2.0938rem);  /* 26   → 33.5 */
  --t-3xl:  clamp(1.8750rem, 1.5642rem + 1.326vw, 2.6250rem);  /* 30   → 42   */
  --t-4xl:  clamp(2.1250rem, 1.6459rem + 2.044vw, 3.2812rem);  /* 34   → 52.5 */
  --t-5xl:  clamp(2.5000rem, 1.8267rem + 2.873vw, 4.1250rem);  /* 40   → 66   */

  /* --- Line heights ------------------------------------------------------ */
  --lh-display: 1.05;  /* --t-5xl / --t-4xl                                  */
  --lh-heading: 1.15;  /* --t-3xl / --t-2xl / --t-xl                         */
  --lh-title:   1.25;  /* card titles — usually wrap to 2 lines              */
  --lh-body:    1.6;   /* prose                                              */
  --lh-ui:      1.4;   /* meta, chips, list rows                             */
  --lh-flat:    1.2;   /* buttons, price figures, single-line controls       */

  /* --- Tracking ----------------------------------------------------------
     Negative as size grows; positive (and more of it) as caps shrink.       */
  --track-display: -0.025em;
  --track-h2:      -0.015em;
  --track-h3:      -0.01em;
  --track-body:     0em;
  --track-caps-lg:  0.08em;  /* uppercase ≥ 15px */
  --track-caps:     0.12em;  /* uppercase 13–14px */
  --track-caps-sm:  0.16em;  /* uppercase ≤ 12px  */

  /* --- Measure ----------------------------------------------------------- */
  --measure:        65ch;  /* body prose                                     */
  --measure-lead:   56ch;  /* section intros, leads                          */
  --measure-narrow: 46ch;  /* hero subtitle, card copy                       */
}

/* ---------------------------------------------------------------------------
   2. ROOT / BODY
   ------------------------------------------------------------------------ */
html {
  /* Never lock the root size — respects the visitor's browser text setting. */
  font-size: 100%;
}

body {
  font-family: var(--font-body);
  font-size: var(--t-base);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: var(--track-body);
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Kerning + contextual alternates on; ligatures are safe in this face. */
  font-kerning: normal;
  font-variant-ligatures: common-ligatures contextual;
}

/* ---------------------------------------------------------------------------
   3. HEADINGS
   base.css sets h1–h4 to font-weight:400 with letter-spacing:+.015em and
   line-height:1.18 for all of them. All three are wrong for a sans; replaced.
   ------------------------------------------------------------------------ */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  margin: 0 0 0.5em;
  text-wrap: balance;          /* progressive: no orphan word on a line alone */
  font-optical-sizing: auto;
}

h1 {
  font-size: var(--t-4xl);
  font-weight: var(--fw-black);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
}

h2 {
  font-size: var(--t-3xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  letter-spacing: var(--track-h2);
}

h3 {
  font-size: var(--t-xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  letter-spacing: var(--track-h3);
}

h4 {
  font-size: var(--t-lg);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-title);
  letter-spacing: 0;
}

h5, h6 {
  font-size: var(--t-base);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-title);
  letter-spacing: 0;
}

/* ---------------------------------------------------------------------------
   4. PROSE
   ------------------------------------------------------------------------ */
p {
  margin: 0 0 1rem;
  text-wrap: pretty;
}

p:last-child { margin-bottom: 0; }

strong, b { font-weight: var(--fw-bold); }

small { font-size: var(--t-xs); }

/* Measure. base.css never constrained article body text, so on desktop it
   ran the full 1280px page width — ~180 characters per line. */
.article__content,
.article__content p,
.article__content ul,
.article__content ol {
  max-width: var(--measure);
}

.article__content       { font-size: var(--t-base); line-height: var(--lh-body); }
.article__content h2    { font-size: var(--t-2xl); margin: 1.8em 0 0.5em; }
.article__content h3    { font-size: var(--t-lg);  margin: 1.5em 0 0.4em; }
.article__content li    { margin-bottom: 0.4em; }

.article__title {
  font-size: var(--t-3xl);
  font-weight: var(--fw-black);
  line-height: var(--lh-heading);
  letter-spacing: var(--track-h2);
  max-width: var(--measure);
}
.article__meta { font-size: var(--t-sm); }

.lead,
.section-intro,
.about__body {
  font-size: var(--t-md);
  line-height: var(--lh-body);
  max-width: var(--measure-lead);
}
.section-intro { margin-inline: auto; }

.footer__description,
.footer p { max-width: var(--measure-narrow); line-height: var(--lh-body); }

/* ---------------------------------------------------------------------------
   5. THE UPPERCASE LABEL SYSTEM
   Every tracked-caps label in the theme, on one rule set. base.css shipped
   six different tracking values (.14 / .1 / .08 / .04 / .03 / .02em) with no
   relation to size; caps below ~.08em read as a typo, not as a label.
   ------------------------------------------------------------------------ */
.eyebrow,
.pillar-card__link,
.blog-card__kicker,
.transfer-card__zone span,
#apartments .card__price-from,
.u-label {
  font-family: var(--font-body);
  text-transform: uppercase;
  font-weight: var(--fw-semibold);
  line-height: var(--lh-flat);
  font-feature-settings: 'calt' 0;   /* caps don't want contextual alternates */
}

.eyebrow {
  font-size: var(--t-xs);
  letter-spacing: var(--track-caps);
  margin-bottom: 0.6rem;
}

.blog-card__kicker,
#apartments .card__price-from,
.transfer-card__zone span {
  font-size: var(--t-2xs);
  letter-spacing: var(--track-caps-sm);
  font-weight: var(--fw-bold);
}

.pillar-card__link {
  font-size: var(--t-xs);
  letter-spacing: var(--track-caps);
  font-weight: var(--fw-bold);
}

/* The hero badge is deliberately NOT uppercase — it reads as a sentence. */
.eyebrow--badge {
  text-transform: none;
  font-size: var(--t-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: 0;
}

/* Avatar monogram: caps, but a monogram wants no tracking on a single glyph. */
.review__avatar {
  font-size: var(--t-base);
  font-weight: var(--fw-bold);
  letter-spacing: 0;
}

/* ---------------------------------------------------------------------------
   6. HERO
   sections__hero.liquid ships `.hero__content h1, .hero h1 { font-family:
   'Bricolage Grotesque' … }` inside <body>. Bricolage is no longer loaded, so
   that rule would fall through to system-ui. `.hero .hero__inner h1` is
   specificity (0,2,1) and beats (0,1,1) regardless of document order.
   ------------------------------------------------------------------------ */
.hero .hero__inner h1,
.hero .hero__content h1 {
  font-family: var(--font-display);
  font-size: var(--t-5xl);
  font-weight: var(--fw-black);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  margin: 0;
  text-wrap: balance;
}

.hero .hero__subtitle {
  font-size: var(--t-md);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  max-width: var(--measure-narrow);
}

.hero .hero__btn,
.hero .hero__ctas .btn {
  font-size: var(--t-base);
  font-weight: var(--fw-bold);
  line-height: var(--lh-flat);
  letter-spacing: 0;
}

/* BINDING CONSTRAINT: the WhatsApp route stays the most visible CTA.
   It is never allowed to be typographically quieter than the primary button. */
.hero .hero__btn--glass,
.btn--whatsapp,
.float-whatsapp {
  font-weight: var(--fw-bold);
}

.hero .hero__trust-item {
  font-size: var(--t-sm);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-ui);
}

/* ---------------------------------------------------------------------------
   7. QUICK-BOOK BAR
   Two real defects fixed here:
   a) labels were 10px — below any usable floor for tracked caps;
   b) inputs were 13–15px. iOS Safari force-zooms the page on focus for any
      form control under 16px, which is exactly what makes the hero look
      "broken / scrolled sideways" on an iPhone. 16px stops the zoom.
      Verified at 375px: each date field is ~155px wide, the 16px value
      "dd/mm/aaaa" plus the native picker glyph needs ~105px. It fits.
   [class] raises specificity over the section's own <style> block.
   ------------------------------------------------------------------------ */
.quickbook .quickbook__field label,
.quickbook label[class],
.quickbook label {
  font-size: var(--t-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-caps-sm);
  line-height: var(--lh-flat);
  text-transform: uppercase;
  margin-bottom: 6px;
}

.quickbook .quickbook__field input,
.quickbook .quickbook__field select,
.quickbook input,
.quickbook select {
  font-family: var(--font-body);
  font-size: 16px;            /* literal px on purpose — see note above */
  font-weight: var(--fw-medium);
  line-height: var(--lh-flat);
  min-height: 44px;           /* touch target */
}

.quickbook__title { font-size: var(--t-sm); font-weight: var(--fw-bold); }

.quickbook__submit {
  font-size: var(--t-base);
  font-weight: var(--fw-bold);
  line-height: var(--lh-flat);
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

@media (max-width: 600px) {
  .quickbook label { font-size: var(--t-2xs); letter-spacing: var(--track-caps); }
  .quickbook input,
  .quickbook select { font-size: 16px; padding: 10px 12px; }
  .quickbook__submit { font-size: var(--t-base); padding: 12px 16px; }
}

/* ---------------------------------------------------------------------------
   8. BUTTONS & CONTROLS
   base.css had line-height:1 on .btn, which crops the optical space under
   Spanish descenders ("Ver disponibilidad") and makes labels sit high.
   ------------------------------------------------------------------------ */
.btn {
  font-family: var(--font-body);
  font-size: var(--t-sm);
  font-weight: var(--fw-bold);
  line-height: var(--lh-flat);
  letter-spacing: 0;
  min-height: 44px;
}
.btn--large { font-size: var(--t-base); }
.btn--block { font-size: var(--t-base); }

.nav-list a {
  font-size: var(--t-sm);
  font-weight: var(--fw-medium);
  letter-spacing: 0;
}

.mobile-nav a {
  font-size: var(--t-md);
  font-weight: var(--fw-medium);
  line-height: var(--lh-flat);
  display: flex;
  align-items: center;
  min-height: 44px;
}

.lang-switcher__current,
.lang-switcher__option {
  min-height: 44px;
  font-size: var(--t-sm);
}
.lang-switcher__name { font-size: var(--t-sm); font-weight: var(--fw-semibold); }

.condo-tab {
  font-size: var(--t-sm);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-flat);
  min-height: 44px;
}

.header__logo {
  /* Text fallback for the logo image only. Cinzel is not loaded; this stack
     degrades to a system serif so the fallback still reads as a wordmark. */
  font-family: var(--font-brand);
  font-size: var(--t-xl);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-caps-lg);
  line-height: var(--lh-flat);
}
.footer__logo-text {
  font-family: var(--font-brand);
  font-size: var(--t-xl);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-caps-lg);
}

/* ---------------------------------------------------------------------------
   9. CARDS
   ------------------------------------------------------------------------ */
.service-card__title,
.transfer-card__title,
.pillar-card__title,
.why-card__title,
.blog-card__title,
.transfers-other__title,
.contact-info__title {
  font-size: var(--t-lg);
  font-weight: var(--fw-bold);
  line-height: var(--lh-title);
  letter-spacing: var(--track-h3);
  text-wrap: balance;
}

.service-card__desc,
.pillar-card__text,
.why-card__text,
.blog-card__excerpt,
.transfer-card__coverage,
#apartments .card__desc {
  font-size: var(--t-sm);
  line-height: var(--lh-body);
  text-wrap: pretty;
}

.card__meta,
.transfer-card__capacity,
.transfer-card__features li,
.contact-info__list li,
.footer__contact-item,
.footer__link {
  font-size: var(--t-sm);
  line-height: var(--lh-ui);
}

.transfer-card__features-title { font-size: var(--t-base); font-weight: var(--fw-bold); }

.blog-card__more,
#apartments .card__cta {
  font-size: var(--t-sm);
  font-weight: var(--fw-bold);
  line-height: var(--lh-flat);
}

/* Section <style> blocks own these; [class] adds the extra specificity point. */
#apartments .condo-card__name[class] {
  font-size: var(--t-lg);
  font-weight: var(--fw-bold);
  line-height: var(--lh-title);
  letter-spacing: var(--track-h3);
}
#apartments .condo-card__desc[class] { font-size: var(--t-sm); line-height: var(--lh-ui); }
#apartments .condo-card__meta[class] { font-size: var(--t-xs); font-weight: var(--fw-semibold); }
#apartments h1.apts-h[class] {
  font-size: var(--t-3xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  letter-spacing: var(--track-h2);
}
.apt-perk__title[class] { font-size: var(--t-base); font-weight: var(--fw-bold); letter-spacing: 0; }
.apt-perk__body[class],
.apt-perk__body p { font-size: var(--t-sm); line-height: var(--lh-body); }

.condo-group__title {
  font-size: var(--t-sm);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-caps-lg);
  text-transform: uppercase;
  line-height: var(--lh-flat);
}

/* ---------------------------------------------------------------------------
   10. NUMERALS
   Plus Jakarta Sans ships real tabular figures (verified: the woff2 exposes
   the `tnum` feature). Prices and capacities therefore align column-to-column
   instead of jittering between cards.
   ------------------------------------------------------------------------ */
.service-card__price,
.transfer-card__price-amount,
.card__price,
.stats-bar__value,
#apartments .card__price-amount,
#apartments .condo-card__price .amt,
.price,
.money {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
  letter-spacing: -0.01em;
  line-height: var(--lh-flat);
}

.service-card__price,
.transfer-card__price-amount,
#apartments .card__price-amount,
#apartments .condo-card__price .amt[class] {
  font-size: var(--t-lg);
  font-weight: var(--fw-black);
}

.transfer-card__price-from,
.transfer-card__price-suffix,
#apartments .card__price-unit,
#apartments .condo-card__price .unit[class] {
  font-size: var(--t-xs);
  font-weight: var(--fw-medium);
  letter-spacing: 0;
}

.stats-bar__value {
  font-family: var(--font-display);
  font-size: var(--t-3xl);
  font-weight: var(--fw-black);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
}
.stats-bar__label {
  font-size: var(--t-2xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--track-caps-sm);
  line-height: var(--lh-ui);
}

/* ---------------------------------------------------------------------------
   11. BIG BANDS / REVIEWS / FOOTER / FORMS
   ------------------------------------------------------------------------ */
.cta-band__title {
  font-size: var(--t-4xl);
  font-weight: var(--fw-black);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  text-wrap: balance;
}
.cta-band__subtitle {
  font-size: var(--t-md);
  line-height: var(--lh-body);
  max-width: var(--measure-lead);
}

.review blockquote {
  font-size: var(--t-base);
  line-height: var(--lh-body);
  text-wrap: pretty;
}
.review__name   { font-size: var(--t-sm); font-weight: var(--fw-bold); }
.review__source { font-size: var(--t-xs); font-weight: var(--fw-medium); }
/* Decorative quote glyph: a system serif, 0 KB of payload. Intentional. */
.review::before { font-family: Georgia, 'Times New Roman', serif; }

.footer h2,
.footer__heading {
  font-size: var(--t-base);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-caps-lg);
  text-transform: uppercase;
  line-height: var(--lh-flat);
}
.footer__bottom { font-size: var(--t-xs); line-height: var(--lh-ui); }

.field label {
  font-size: var(--t-sm);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-flat);
}
.field input,
.field textarea,
.header__search input {
  font-family: var(--font-body);
  font-size: 16px;            /* literal px: stops iOS Safari focus-zoom */
  line-height: var(--lh-ui);
}
.field input,
.field textarea { min-height: 44px; }

/* ---------------------------------------------------------------------------
   12. SAFETY NETS AT 375px
   Long Spanish compounds ("disponibilidad", "Constellation") must never push
   a horizontal scrollbar. Headings may break rather than overflow.
   ------------------------------------------------------------------------ */
h1, h2, h3, h4,
.hero .hero__inner h1,
.cta-band__title,
.service-card__title,
.transfer-card__title,
#apartments .condo-card__name {
  overflow-wrap: break-word;
  hyphens: auto;
}

@media (max-width: 480px) {
  /* Card grids get tight at 375px; drop card titles one step. */
  .service-card__title,
  #apartments .condo-card__name[class] { font-size: var(--t-base); }
  .service-card__desc { font-size: var(--t-xs); }
}


/* ==========================================================================
   FIX(touch): the two most-tapped mobile controls were 28.8px and 32px.
   ========================================================================== */
.header__cart,
.menu-toggle {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ==========================================================================
   FIX(rhythm): the brief's headline defect was six consecutive sections with
   an identical eyebrow / centred h2 / centred intro. Putting one gold rule
   under every centred h2 made six of six converge instead of two of six.
   The rule now marks only the two "how it works" sections; tours reads as an
   editorial band, transport as the page's densest heading.
   ========================================================================== */
.text-center > h2::after { content: none; }
#services .text-center > h2::after,
#transport .text-center > h2::after { content: ''; }

#tours .text-center,
#tours .section-intro { text-align: left; margin-inline: 0; }
#transport .text-center > h2 { font-size: var(--t-2xl); }

/* ═══════ 3. MOVIMIENTO ═══════ */
/* ==========================================================================
   Blue Bay DMC — motion.css
   Drop-in motion layer. Load in <head> AFTER base.css:

     {{ 'base.css'   | asset_url | stylesheet_tag }}
     {{ 'motion.css' | asset_url | stylesheet_tag }}

   PHILOSOPHY — "Todo llega, nada aparece."
   Motion confirms; it never introduces. Every pixel of content is painted
   and readable before a single transition runs. There is not one
   scroll-triggered entrance in this file, by design: on this owner's sister
   site a scroll-reveal was built and then removed because it made the
   interface feel slow. We do not repeat that.

   RULES OBEYED
   - Only `transform` and `opacity` are animated. No width/height/top/left.
     Every box-shadow transition in the current CSS is deliberately removed
     (a blurred shadow repaints a large area every frame on mid-range
     Androids); the lift alone carries the message.
   - No scroll handler reads or writes layout. The one scroll-dependent
     state (sticky header) uses an IntersectionObserver sentinel.
   - Every hover affordance has a :focus-visible and an :active twin.
     This audience is overwhelmingly touch; hover is a bonus, never a signal.
   - prefers-reduced-motion: reduce neutralises all of it (bottom of file).

   SPECIFICITY NOTE
   Shopify section <style> blocks live in <body>, so they win ties against a
   <head> stylesheet. Where this file must override one, the selector is
   prefixed with `:root` (+0-1-0) to outrank it without !important.
   ========================================================================== */

:root {
  /* ---- Durations. Four, and only four. -------------------------------- */
  --bb-t-tap: 110ms; /* press/release. Intentionally below the 150ms floor:
                        a press that takes 150ms to register reads as lag.   */
  --bb-t-state: 180ms; /* hover, focus, tab, chevron — "this changed"        */
  --bb-t-surface: 260ms; /* header shadow, menu, panels — "a surface moved"  */
  --bb-t-media: 420ms; /* image zoom only — large area, needs a longer arc   */

  /* ---- Easing. Three, each with a job. --------------------------------- */
  --bb-ease: cubic-bezier(0.22, 0.61, 0.36, 1); /* default: arrives and settles */
  --bb-ease-rise: cubic-bezier(0.34, 0.85, 0.32, 1); /* lifts toward the reader */
  --bb-ease-exit: cubic-bezier(0.4, 0, 1, 1); /* leaves: starts slow, gone fast */

  /* ---- Distance. One scale, used everywhere. --------------------------- */
  --bb-lift: -4px; /* cards */
  --bb-lift-sm: -2px; /* buttons, badges */
  --bb-press: 0.97; /* buttons */
  --bb-press-hard: 0.94; /* the round FAB, which has no shadow to squash */
  --bb-zoom: 1.045; /* image hover/focus zoom */
  --bb-nudge: 3px; /* every arrow, in its own direction of travel */
  --bb-rise: 8px; /* the only entrance distance, from opacity .85 */

  /* ---- Focus ring ------------------------------------------------------
     Dual tone: 2px white inner + 3px navy outer. Verified with real
     relative-luminance math: across ALL possible background luminances the
     better of the two tones never falls below 3.82:1, so the ring clears the
     3:1 UI/graphics threshold on every surface in the theme — white cards,
     navy sections, the #0E3B47 tours band, the teal perk gradient and the
     WhatsApp green — with no per-surface overrides to maintain.            */
  --bb-focus-inner: #ffffff;
  --bb-focus-outer: #0b2a4a;

  /* WhatsApp halo. Darker than the button so it reads on a white page
     (#0F7A3D on #FFFFFF = 5.42:1). Retarget this one token if the palette
     layer moves the WhatsApp green.                                        */
  --bb-halo: var(--wa-500, #25D366);  /* FIX: was #0f7a3d — an 8th colour, 1.14:1 on the fill */
}

/* ==========================================================================
   0. GLOBAL HYGIENE
   ========================================================================== */

/* base.css sets scroll-behavior:smooth unconditionally, which hijacks every
   in-page anchor for users who asked the OS for less motion. Gate it. */
html {
  scroll-behavior: auto;
}
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* Anything that moves gets a hint, but only while it is actually moving.
   `will-change` is applied on hover/focus intent, never permanently — a
   permanent hint on 30 cards would pin 30 compositor layers in memory. */

/* ==========================================================================
   1. FOCUS — the one state that must never animate
   Keyboard users read the ring as position. A ring that fades in reads as
   lag. So: instant, always, everywhere.
   ========================================================================== */

/* !important is deliberate and is the only use of it outside the
   reduced-motion block. base.css already sets `outline: none` on form fields
   and `#apartments .card__cta` carries an ID-specificity box-shadow that
   would otherwise erase the outer ring. A focus indicator that any later
   rule can silently delete is not a focus indicator. */
:focus-visible {
  outline: 2px solid var(--bb-focus-inner) !important;
  outline-offset: 1px !important;
  box-shadow: 0 0 0 5px var(--bb-focus-outer) !important;
  transition: none !important;
}

/* --- Full-bleed media links ---------------------------------------------
   A card's overflow:hidden clips any ring drawn outside its child, so a
   photo link that reaches all four card edges would lose most of its ring.
   Both tones are drawn INSIDE the link instead: white inset 6px, navy
   hugging the edge. Never clipped, and still one tone or the other clears
   3:1 on any photograph.
   We do NOT switch the card to overflow:visible on focus — that would let
   the hover zoom escape the rounded corners.                              */
:root .condo-card__media:focus-visible,
:root #apartments .condo-card__media:focus-visible,
:root .card__media:focus-visible,
:root .service-card__media:focus-visible,
:root .transfer-card__media:focus-visible,
:root .blog-card > a:focus-visible {
  outline: 3px solid var(--bb-focus-inner) !important;
  outline-offset: -6px !important;
  box-shadow: none !important;
  position: relative;
}
:root .condo-card__media:focus-visible::after,
:root #apartments .condo-card__media:focus-visible::after,
:root .card__media:focus-visible::after,
:root .service-card__media:focus-visible::after,
:root .transfer-card__media:focus-visible::after,
:root .blog-card > a:focus-visible::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  border: 3px solid var(--bb-focus-outer);
  pointer-events: none;
}

/* ==========================================================================
   2. BUTTONS — press feedback
   COMMUNICATES: "your tap registered." On island connectivity the next page
   can take seconds; this 110ms squash is often the only proof the tap landed
   before the network answers. It is the single most important effect here.
   ========================================================================== */

.btn,
.hero__btn,
.quickbook__submit,
.condo-tab,
.condo-row__next,
.menu-toggle,
.float-whatsapp,
.float-social a,
.header__cart,
.lang-switcher__current {
  transition:
    transform var(--bb-t-state) var(--bb-ease),
    background-color var(--bb-t-state) var(--bb-ease),
    border-color var(--bb-t-state) var(--bb-ease),
    color var(--bb-t-state) var(--bb-ease);
}

/* Hover lift is gated: a touch device that emulates :hover leaves buttons
   stuck in the lifted state after a tap. */
@media (hover: hover) and (pointer: fine) {
  :root .btn:hover,
  :root .hero__btn:hover,
  :root .quickbook__submit:hover {
    transform: translateY(var(--bb-lift-sm));
  }
}

/* The touch/keyboard twin of that hover. */
:root .btn:focus-visible,
:root .hero__btn:focus-visible,
:root .quickbook__submit:focus-visible {
  transform: translateY(var(--bb-lift-sm));
}

:root .btn:active,
:root .hero__btn:active,
:root .quickbook__submit:active,
:root .condo-tab:active {
  transform: scale(var(--bb-press));
  transition-duration: var(--bb-t-tap);
}

/* base.css transitions box-shadow on .btn and lifts by -2px inside a
   4-property transition. Replace it: transform only, no shadow repaint. */
:root .btn {
  transition-property: transform, background-color, border-color, color;
}

/* --- Arrow grammar -------------------------------------------------------
   COMMUNICATES: "this takes you onward." Every arrow in the theme — the hero
   CTA's →, the condo card's ::after →, the horizontal-row next button —
   moves the same 3px in its own direction of travel. One rule, one distance,
   so the site speaks with a single accent.                                  */

.hero__btn span[aria-hidden],
.btn span[aria-hidden],
:root #apartments .card__cta::after,
.condo-card__book::after {
  display: inline-block;
  transition: transform var(--bb-t-state) var(--bb-ease);
}

@media (hover: hover) and (pointer: fine) {
  .hero__btn:hover span[aria-hidden],
  .btn:hover span[aria-hidden],
  :root #apartments .card:hover .card__cta::after {
    transform: translateX(var(--bb-nudge));
  }
}
.hero__btn:focus-visible span[aria-hidden],
.btn:focus-visible span[aria-hidden],
:root #apartments .card__cta:focus-visible::after {
  transform: translateX(var(--bb-nudge));
}

/* --- Pending state -------------------------------------------------------
   COMMUNICATES: "we heard you, the network hasn't answered yet." Opt-in:
   set aria-busy="true" on the button. A single sheen crossing the button,
   transform-only, clipped by the button's own radius.                       */

.btn[aria-busy='true'],
.hero__btn[aria-busy='true'] {
  position: relative;
  overflow: hidden;
  pointer-events: none;
}
.btn[aria-busy='true']::after,
.hero__btn[aria-busy='true']::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 35%, rgba(255, 255, 255, 0.28) 50%, transparent 65%);
  transform: translateX(-100%);
  animation: bb-sheen 1100ms var(--bb-ease) infinite;
  pointer-events: none;
}
@keyframes bb-sheen {
  to {
    transform: translateX(100%);
  }
}

/* ==========================================================================
   3. CARDS — the lift
   COMMUNICATES: "this whole rectangle is one tappable object." The theme
   currently lifts cards by -2, -3, -4 and -8px with three different
   durations. One distance, one duration, everywhere.
   ========================================================================== */

.card,
.condo-card,
.service-card,
.transfer-card,
.blog-card,
.why-card,
.pillar-card,
.review,
.apartments-head__map {
  transition: transform var(--bb-t-state) var(--bb-ease-rise);
}

@media (hover: hover) and (pointer: fine) {
  :root .card:hover,
  :root #apartments .condo-card:hover,
  :root .service-card:hover,
  :root .transfer-card:hover,
  :root .blog-card:hover,
  :root .why-card:hover,
  :root .pillar-card:hover,
  :root .review:hover,
  :root .apartments-head__map:hover {
    transform: translateY(var(--bb-lift));
  }
}

/* Touch + keyboard twin. :focus-within catches the card's own link. */
:root .card:focus-within,
:root #apartments .condo-card:focus-within,
:root .service-card:focus-within,
:root .transfer-card:focus-within,
:root .blog-card:focus-within,
:root .pillar-card:focus-within {
  transform: translateY(var(--bb-lift));
}

/* Touch press: the card settles back down under the finger. */
:root .card:active,
:root #apartments .condo-card:active,
:root .service-card:active,
:root .transfer-card:active,
:root .blog-card:active {
  transform: translateY(0) scale(0.995);
  transition-duration: var(--bb-t-tap);
}

/* Kill every box-shadow transition base.css declares on cards. The resting
   shadow stays exactly as designed; it simply stops being animated. */
:root .card,
:root .condo-card,
:root .service-card,
:root .transfer-card,
:root .blog-card,
:root .why-card,
:root .pillar-card,
:root .review,
:root .apartments-head__map {
  transition-property: transform;
}

/* ==========================================================================
   4. MEDIA — the zoom
   COMMUNICATES: "there is more of this place than fits in the frame."
   Slower than every UI transition on purpose: a large area moving fast reads
   as a jump, not a drift.
   ========================================================================== */

:root .service-card__media img,
:root #apartments .card__media img,
:root #apartments .condo-card__media img,
:root .blog-card__media img,
:root .transfer-card__media img,
:root .gallery-grid img {
  transition: transform var(--bb-t-media) var(--bb-ease);
}

@media (hover: hover) and (pointer: fine) {
  :root .service-card:hover .service-card__media img,
  :root #apartments .card:hover .card__media img,
  :root #apartments .condo-card:hover .condo-card__media img,
  :root .blog-card:hover .blog-card__media img,
  :root .transfer-card:hover .transfer-card__media img {
    transform: scale(var(--bb-zoom));
  }
}

/* Touch/keyboard twin — tabbing to a card's image link zooms it too. */
:root .service-card:focus-within .service-card__media img,
:root #apartments .card:focus-within .card__media img,
:root #apartments .condo-card:focus-within .condo-card__media img,
:root .blog-card:focus-within .blog-card__media img,
:root .transfer-card:focus-within .transfer-card__media img {
  transform: scale(var(--bb-zoom));
}

/* The dark scrim over service cards was fading 0 -> 1 on hover only, so touch
   users never saw it and it dimmed the photo for no reason. It communicates
   nothing the card body doesn't already say. Held at rest. */
:root .service-card__overlay {
  transition: opacity var(--bb-t-state) var(--bb-ease);
}

/* ==========================================================================
   5. STICKY HEADER
   COMMUNICATES: "you have left the top of the page; this bar is now floating
   above the content." Rest state is untouched, so if motion.js never runs the
   header looks exactly as it does today — the deepened shadow is purely
   additive. Painted on a pseudo-element so we animate opacity, not blur.

   Deliberately NOT built: hide-on-scroll-down. It would take the WhatsApp
   route and the cart off screen at the moment a visitor is reading a price.
   ========================================================================== */

.bb-scroll-sentinel {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 8px;
  pointer-events: none;
  visibility: hidden;
}

.header::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  box-shadow: 0 8px 28px -6px rgba(11, 42, 74, 0.28);
  opacity: 0;
  transition: opacity var(--bb-t-surface) var(--bb-ease);
}
.header.is-stuck::after {
  opacity: 1;
}

/* The logo settles a hair when the bar starts floating. transform only, so
   the header's height — and therefore the whole page layout — never moves. */
.header__logo img {
  transform-origin: left center;
  transition: transform var(--bb-t-surface) var(--bb-ease);
}
.header.is-stuck .header__logo img {
  transform: scale(0.94);
}

/* ==========================================================================
   6. MOBILE MENU
   COMMUNICATES: "this panel came from the bar you just tapped."
   The panel is display:none -> block (theme JS owns that), so this is an
   entrance. Per the rule it starts from a VISIBLE state — opacity .85, not 0
   — and travels 6px. If the animation never runs, the menu is simply there.
   ========================================================================== */

.mobile-nav.is-open {
  animation: bb-panel-in var(--bb-t-surface) var(--bb-ease-rise) both;
  transform-origin: top center;
}
@keyframes bb-panel-in {
  from {
    opacity: 0.85;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* The toggle itself reports state. */
.menu-toggle svg {
  transition: transform var(--bb-t-state) var(--bb-ease);
}
.menu-toggle[aria-expanded='true'] svg {
  transform: rotate(90deg);
}

/* Language dropdown — same panel grammar, and the chevron already rotates in
   base.css; just harmonise its timing. */
.lang-switcher__menu.is-open {
  animation: bb-panel-in var(--bb-t-state) var(--bb-ease-rise) both;
}
:root .lang-switcher__chevron {
  transition: transform var(--bb-t-state) var(--bb-ease);
}

/* ==========================================================================
   7. TABS / FILTERS
   COMMUNICATES: "the list underneath you just changed." The bedroom filter
   hides cards with display:none — a hard cut with no feedback, on a control
   whose entire purpose is to change what is on screen. The surviving cards
   re-settle once so the change is legible.

   This is an entrance, so it starts VISIBLE: opacity .85, 8px rise, 220ms.
   It is user-initiated, never scroll-initiated.
   ========================================================================== */

/* base.css uses `transition: all .15s` here — `all` will animate whatever
   property anyone adds later, including layout ones. Made explicit. */
:root .condo-tab {
  transition:
    transform var(--bb-t-state) var(--bb-ease),
    background-color var(--bb-t-state) var(--bb-ease),
    border-color var(--bb-t-state) var(--bb-ease),
    color var(--bb-t-state) var(--bb-ease);
}
:root .condo-tab.is-active,
:root .condo-tab[aria-pressed='true'] {
  transform: scale(1.03);
}

.bb-resettle > .condo-card {
  animation: bb-settle 220ms var(--bb-ease-rise) both;
}
@keyframes bb-settle {
  from {
    opacity: 0.85;
    transform: translateY(var(--bb-rise));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* The result count is the only text that changes; blink it so the change is
   not silent. Opacity only. */
.bb-resettle ~ * .condo-filter__count,
.condo-filter__count {
  transition: opacity var(--bb-t-state) var(--bb-ease);
}

/* ==========================================================================
   8. PRICE BADGES
   COMMUNICATES: "this number belongs to this card." The badge is the
   commercial payload; it rides with the card rather than sitting still while
   the card moves, which would break the illusion that they are one object.
   No looping, no attention-seeking. It moves only when the card does.
   ========================================================================== */

.transfer-card__badge,
.condo-card__tag,
#apartments .condo-card__tag,
.map-tag {
  transition: transform var(--bb-t-state) var(--bb-ease-rise);
  will-change: auto;
}

@media (hover: hover) and (pointer: fine) {
  :root .transfer-card:hover .transfer-card__badge,
  :root #apartments .condo-card:hover .condo-card__tag {
    transform: translateY(var(--bb-lift-sm));
  }
}
:root .transfer-card:focus-within .transfer-card__badge,
:root #apartments .condo-card:focus-within .condo-card__tag {
  transform: translateY(var(--bb-lift-sm));
}

/* --- Horizontal-row hint -------------------------------------------------
   COMMUNICATES: "this row continues past the right edge." Real information
   on a 375px screen where the next card is genuinely off-screen. base.css
   runs this FOREVER (`condoNudge 1.6s infinite`) on a row that may not even
   be scrollable — perpetual motion in the corner of the eye, and a permanent
   compositor job on a phone. Made finite: it says its piece three times and
   stops. motion.js re-arms it when a row scrolls into view.                 */

:root .condo-row__next {
  animation: bb-nudge-x 1.4s var(--bb-ease) 3;
  transition: transform var(--bb-t-tap) var(--bb-ease);
}
@keyframes bb-nudge-x {
  0%,
  100% {
    transform: translateY(-50%) translateX(0);
  }
  50% {
    transform: translateY(-50%) translateX(5px);
  }
}
:root .condo-row__next:active {
  transform: translateY(-50%) scale(var(--bb-press));
}

/* ==========================================================================
   9. THE WHATSAPP ROUTE — the loudest thing on the page
   COMMUNICATES: "this is the fastest way to reach a person."

   A single sonar ping: a ring expands out of the button and dissolves.
   TWO iterations, then silence — long enough to be caught in peripheral
   vision, short enough never to become wallpaper. Delayed 1.6s so it does
   not compete with the hero for the first paint.

   The ring is transform+opacity on one 56px pseudo-element. It grows to
   1.5x = 84px, extending 14px past the button, which at right:18px leaves
   4px of clearance at 375px — no horizontal overflow.
   ========================================================================== */

.float-whatsapp {
  position: fixed;
  isolation: isolate;
}
.float-whatsapp::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 50%;
  border: 2px solid var(--bb-halo);
  opacity: 0;
  transform: scale(1);
  animation: bb-ping 1900ms var(--bb-ease) 1600ms 2 both;
  pointer-events: none;
}
@keyframes bb-ping {
  0% {
    opacity: 0.55;
    transform: scale(1);
  }
  70% {
    opacity: 0;
    transform: scale(1.5);
  }
  100% {
    opacity: 0;
    transform: scale(1.5);
  }
}

@media (hover: hover) and (pointer: fine) {
  :root .float-whatsapp:hover {
    transform: scale(1.06);
  }
}
:root .float-whatsapp:focus-visible {
  transform: scale(1.06);
}
:root .float-whatsapp:active {
  transform: scale(var(--bb-press-hard));
  transition-duration: var(--bb-t-tap);
}

/* The existing yield-behind-the-quickbook behaviour is good and stays; only
   its curve is harmonised. It leaves fast and returns gently. */
:root .float-whatsapp {
  transition:
    transform var(--bb-t-state) var(--bb-ease-rise),
    opacity var(--bb-t-surface) var(--bb-ease),
    visibility var(--bb-t-surface) var(--bb-ease);
}
:root .float-whatsapp.is-yielding {
  transition-timing-function: var(--bb-ease-exit);
}

/* In-page WhatsApp buttons get the press twin, no ping — one ping per page. */
:root .btn--whatsapp:active,
:root .hero__btn--glass:active {
  transform: scale(var(--bb-press));
  transition-duration: var(--bb-t-tap);
}

.float-social a {
  transition: transform var(--bb-t-state) var(--bb-ease-rise);
}
@media (hover: hover) and (pointer: fine) {
  :root .float-social a:hover {
    transform: scale(1.08);
  }
}
:root .float-social a:focus-visible {
  transform: scale(1.08);
}
:root .float-social a:active {
  transform: scale(var(--bb-press));
  transition-duration: var(--bb-t-tap);
}

/* ==========================================================================
   10. ACCORDION (<details> — FAQ and anywhere else)
   COMMUNICATES: "this answer belongs to that question."

   The panel height is NOT animated. Growing a height reflows everything
   below it 60 times a second and is exactly the class of effect this brief
   forbids. Instead: the marker rotates (transform) and the answer's own
   content settles 6px (transform + opacity, from .9 — visible from frame
   one). The panel snaps to its full height instantly; nothing below it is
   animated, so nothing below it jitters.
   ========================================================================== */

details > summary {
  cursor: pointer;
  list-style: none;
  min-height: 44px; /* touch target */
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
details > summary::-webkit-details-marker {
  display: none;
}
details > summary::after {
  content: '';
  flex: 0 0 auto;
  margin-left: auto;
  width: 10px;
  height: 10px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transform-origin: center;
  transition: transform var(--bb-t-state) var(--bb-ease);
}
details[open] > summary::after {
  transform: rotate(-135deg) translate(-2px, -2px);
}
details[open] > summary ~ * {
  animation: bb-answer-in var(--bb-t-surface) var(--bb-ease-rise) both;
}
@keyframes bb-answer-in {
  from {
    opacity: 0.9;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ==========================================================================
   11. SMALL CONFIRMATIONS
   ========================================================================== */

/* Form fields: the ring is instant (see §1); only the border colour eases. */
:root .field input,
:root .field textarea,
:root .quickbook input,
:root .quickbook select {
  transition: border-color var(--bb-t-state) var(--bb-ease);
}

/* A submitted form's answer is new information — it earns the settle.
   Starts at opacity .9, so it is legible even if the animation is dropped. */
.form-success {
  animation: bb-settle var(--bb-t-surface) var(--bb-ease-rise) both;
}

/* Cart count bump. COMMUNICATES: "the number you were not looking at just
   changed." Opt-in: theme.js should add .is-bumped for ~450ms after a
   successful add-to-cart. Costs 4 lines; without the hook it is inert. */
.header__cart-count {
  transform-origin: center;
}
.header__cart-count.is-bumped {
  animation: bb-bump 450ms var(--bb-ease-rise);
}
@keyframes bb-bump {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.35);
  }
  100% {
    transform: scale(1);
  }
}

/* ==========================================================================
   12. REMOVED — effects that communicate nothing
   Delete this block to keep them.
   ========================================================================== */

/* base.css `.scroll-cascade`: a full-viewport fixed overlay of falling light
   streaks fired when a pillar button scrolls to its section. It says nothing
   about the product, it paints over the entire viewport at z-index 9999
   while the user is mid-scroll, and it is the most expensive thing in the
   stylesheet. Cut. */
.scroll-cascade {
  display: none !important;
}

/* ==========================================================================
   13. REDUCED MOTION
   Every effect above is disabled or neutralised here — nothing is merely
   shortened into a blur. Where an effect was carrying information (focus,
   hover, the sticky header, the scroll hint), a STATIC signal replaces it,
   so a reduced-motion visitor loses the movement but never the meaning.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  /* Safety net: anything added later is caught too. 1ms rather than 0 so
     transitionend/animationend listeners still fire. */
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  html {
    scroll-behavior: auto !important;
  }

  /* Purely decorative motion: removed outright, not sped up. */
  .float-whatsapp::before,
  .scroll-cascade,
  .btn[aria-busy='true']::after,
  .hero__btn[aria-busy='true']::after {
    display: none !important;
  }
  :root .condo-row__next {
    animation: none !important;
    transform: translateY(-50%) !important;
  }

  /* FIX: hiding the video left a flat navy block — there is no <img> poster
     sibling in hero.liquid. motion.js pauses it instead. */
  .hero__media video { animation: none !important; }

  /* No displacement anywhere. */
  :root .btn:hover,
  :root .btn:active,
  :root .btn:focus-visible,
  :root .hero__btn:hover,
  :root .hero__btn:active,
  :root .hero__btn:focus-visible,
  :root .quickbook__submit:hover,
  :root .quickbook__submit:focus-visible,
  :root .card:hover,
  :root .card:active,
  :root .card:focus-within,
  :root #apartments .condo-card:hover,
  :root #apartments .condo-card:active,
  :root #apartments .condo-card:focus-within,
  :root .service-card:hover,
  :root .service-card:focus-within,
  :root .transfer-card:hover,
  :root .transfer-card:focus-within,
  :root .blog-card:hover,
  :root .blog-card:focus-within,
  :root .why-card:hover,
  :root .pillar-card:hover,
  :root .pillar-card:focus-within,
  :root .review:hover,
  :root .apartments-head__map:hover,
  :root .float-whatsapp:hover,
  :root .float-whatsapp:focus-visible,
  :root .float-whatsapp:active,
  :root .float-social a:hover,
  :root .float-social a:focus-visible,
  :root .float-social a:active,
  :root .condo-tab.is-active,
  :root .condo-tab[aria-pressed='true'],
  :root .header.is-stuck .header__logo img,
  .header__cart-count.is-bumped {
    transform: none !important;
    animation: none !important;
  }

  /* No zoom, no arrow travel, no badge ride. */
  :root .service-card__media img,
  :root #apartments .card__media img,
  :root #apartments .condo-card__media img,
  :root .blog-card__media img,
  :root .transfer-card__media img,
  :root .gallery-grid img,
  .hero__btn span[aria-hidden],
  .btn span[aria-hidden],
  :root #apartments .card__cta::after,
  :root .transfer-card__badge,
  :root #apartments .condo-card__tag {
    transform: none !important;
  }

  /* Entrances become plain presence. */
  .mobile-nav.is-open,
  .lang-switcher__menu.is-open,
  .bb-resettle > .condo-card,
  details[open] > summary ~ *,
  .form-success {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  /* --- Static replacements for the signals we just removed --------------- */

  /* Hover/press feedback becomes an instant border, not a movement. */
  :root .card:hover,
  :root .card:focus-within,
  :root #apartments .condo-card:hover,
  :root #apartments .condo-card:focus-within,
  :root .service-card:hover,
  :root .service-card:focus-within,
  :root .transfer-card:hover,
  :root .transfer-card:focus-within,
  :root .blog-card:hover,
  :root .blog-card:focus-within {
    border-color: var(--bb-focus-outer);
  }

  /* The sticky header still reports that you have scrolled — it just
     arrives instantly instead of fading in. */
  .header.is-stuck::after {
    opacity: 1;
  }

  /* The chevron still points the other way when a panel is open; it just
     does not rotate on the way there. */
  details[open] > summary::after {
    transform: rotate(-135deg) translate(-2px, -2px) !important;
  }
  .menu-toggle[aria-expanded='true'] svg {
    transform: rotate(90deg) !important;
  }

  /* The scroll hint stops nudging, so it says the same thing in words. */
  :root .condo-row__next {
    opacity: 1;
  }
}

/* ==========================================================================
   14. FORCED COLORS (Windows high contrast) — motion is irrelevant there,
   but the focus ring must survive the colour override.
   ========================================================================== */

@media (forced-colors: active) {
  :focus-visible {
    outline: 3px solid Highlight !important;
    outline-offset: 2px !important;
    box-shadow: none !important;
  }
}


/* ==========================================================================
   FIX(perf): backdrop-filter on a full-width sticky header repaints on every
   scroll frame — the dominant scroll cost on a mid-range Android. Touch
   devices get an opaque header instead; pointer devices keep the glass.
   ========================================================================== */
@media (hover: none) {
  .header { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; background: #fff; }
  .transfer-card__badge, .hero__btn { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
  .header__logo img { transition: none; }
}

/* ==========================================================================
   Aviso de antelación mínima (reserva en línea vs WhatsApp)
   ========================================================================== */
.leadtime-notice{
  display:flex; flex-direction:column; gap:.5rem;
  margin:0 0 1rem; padding:1rem 1.1rem;
  border:1px solid #E7C9A0; border-left:4px solid #AD8424;
  border-radius:12px; background:#FDF7EC;
}
.leadtime-notice[hidden]{ display:none; }
.leadtime-notice__title{ font-weight:800; color:#5A430F; line-height:1.25; }
.leadtime-notice__body{ font-size:.93rem; color:#4A4335; line-height:1.5; }
.leadtime-notice__cta{
  align-self:flex-start; display:inline-flex; align-items:center; justify-content:center;
  min-height:48px; padding:.7rem 1.15rem; border-radius:12px;
  background:#15843E; color:#fff; font-weight:700; text-decoration:none;
}
.leadtime-notice__cta:hover{ background:#116931; color:#fff; text-decoration:none; }
