    :root{
      --cloud-gray:#e5e7eb;
      --obsidian:#000000; --on-obsidian:#ffffff;
      --brand-navy:#1D1E33; /* verified brand color — used for the footer and any solid-black button, in place of true black */
      --paper-white:#ffffff;
      --sand-beige:#e2dfd8;
      --graphite:#5e5d5c;
      --gradient:linear-gradient(90deg,#00c6c6 0%,#00b5f4 20%,#00a1ff 40%,#398cff 50%,#757aff 60%,#906dff 75%,#a162ff 100%);
      --brand-red:#CC242C;
      --muted:#6e6d6b;
      --hero-muted:rgba(255,255,255,0.82);
      --divider:#d4d4d8;
      --font-display:'Inter', ui-sans-serif, system-ui, sans-serif;
      --font-condensed:'Inter Tight', ui-sans-serif, system-ui, sans-serif;
      --font-headline:'Barlow', ui-sans-serif, system-ui, sans-serif;
    }
    *{box-sizing:border-box;}
    body{margin:0;}
    a{color:var(--obsidian); text-decoration:none;}
    a:visited{color:inherit;}
    .btn-focus:focus-visible{outline:3px solid #00a1ff; outline-offset:3px;}
    ::selection{background:#c9e9ff;}
    /* :where() keeps this reset at zero specificity, so a button that also
       carries a style class like .btn-obsidian (e.g. the contact form's
       submit button) still wins its own background/padding from that class
       instead of being blanked out by this generic reset. */
    /* color:inherit here matters beyond tidiness: unlike <a>, a bare
       <button> isn't covered by the `a{color:...}` rule below, and some
       browsers (notably iOS Safari) paint an unstyled button's text in the
       system accent blue instead of the page's ink color. Every ghost-link
       "back"/"volver" button in the ticket flow was relying on this. */
    :where(button.btn-focus){font:inherit; color:inherit; background:none; border:none; padding:0; margin:0; text-align:inherit;}

    /* ghost text link — underline sweep on hover, no shadow anywhere in this system */
    /* align-self:flex-start only matters when this sits inside a
       flex-direction:column container (the footer link lists, the
       contact section's email link) — default align-items:stretch there
       otherwise stretches the link's box to the column's full width, so
       its ::after hover underline (sized to that box, not the text)
       spans edge-to-edge instead of just under the word. No-op anywhere
       else, since it's ignored on a non-flex-item. */
    .ghost-link{position:relative; display:inline-block; align-self:flex-start; font-family:var(--font-display); font-weight:600;}
    .ghost-link::after{content:''; position:absolute; left:0; right:0; bottom:-3px; height:1px; background:currentColor; transform:scaleX(0); transform-origin:left; transition:transform .25s ease;}
    .ghost-link:hover::after{transform:scaleX(1);}
    .ghost-link:visited{opacity:0.72;}
    #contact .ghost-link::after{ content:none; }

    /* buttons — flat, no shadow; feedback via subtle scale + tone shift only */
    .btn-primary{background:var(--brand-red); transition:transform .2s ease, filter .2s ease;}
    .btn-primary:hover{transform:translateY(-1px); filter:brightness(1.06);}
    .btn-obsidian{background:var(--brand-navy); transition:background .2s ease, transform .2s ease;}
    .btn-obsidian:hover{background:#4c5075; transform:translateY(-1px);}
    /* Header "Contact us" — the one .btn-obsidian instance that's brand-red
       instead of navy, at every width (used to only flip red inside the
       mobile off-canvas menu; now consistent on desktop too). */
    #header-actions a.btn-obsidian{ background:var(--brand-red); }
    #header-actions a.btn-obsidian:hover{ background:var(--brand-red); filter:brightness(1.08); transform:translateY(-1px); }

    /* feature cards — value-contrast only, border darkens on hover, never a shadow */
    .card-flat{border:1px solid var(--cloud-gray); transition:border-color .2s ease, background .2s ease;}
    .card-flat:hover{border-color:var(--obsidian);}

    /* Sheen — a single diagonal pass of light on hover, a quiet signal of
       interactivity rather than a shadow lift. Three tints so it reads on any
       surface: sheen-dark (a faint graphite pass) for white cards, sheen-light
       (a faint white pass) for the obsidian CTA card, and sheen-service (a
       lighter tone of the brand red itself, not plain white, plus a slower
       sweep) for the service cards, which invert to brand-red on this hover. */
    .card-sheen{position:relative; overflow:hidden;}
    .card-sheen::after{content:''; position:absolute; inset:0; pointer-events:none; opacity:0; transform:translateX(-130%);}
    .card-sheen.sheen-light::after{background:linear-gradient(115deg, transparent 38%, rgba(255,255,255,0.22) 48%, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0.22) 52%, transparent 62%);}
    .card-sheen.sheen-dark::after{background:linear-gradient(115deg, transparent 38%, rgba(94,93,92,0.10) 48%, rgba(94,93,92,0.22) 50%, rgba(94,93,92,0.10) 52%, transparent 62%);}
    .card-sheen.sheen-service::after{background:linear-gradient(115deg, transparent 38%, rgba(255,178,181,0.32) 48%, rgba(255,214,216,0.62) 50%, rgba(255,178,181,0.32) 52%, transparent 62%);}
    /* Testimonials — a lighter, more neutral gray sweep than sheen-dark's
       graphite tint, plus a subtle grow-on-hover lift for the three cards. */
    .card-sheen.sheen-testimonial::after{background:linear-gradient(115deg, transparent 38%, rgba(190,189,188,0.16) 48%, rgba(210,209,208,0.4) 50%, rgba(190,189,188,0.16) 52%, transparent 62%);}
    .card-sheen:hover::after{opacity:1; animation:sheenSweep .85s cubic-bezier(.4,0,.2,1);}
    .card-sheen.sheen-service:hover::after{animation-duration:1.35s;}
    .testi-card{transition:transform .25s cubic-bezier(.16,1,.3,1), box-shadow .25s ease;}
    .testi-card:hover{transform:scale(1.03); box-shadow:0 20px 40px -18px rgba(0,0,0,0.18);}
    .grow-card{transition:transform .25s cubic-bezier(.16,1,.3,1), box-shadow .25s ease;}
    .grow-card:hover{transform:scale(1.03); box-shadow:0 20px 40px -18px rgba(0,0,0,0.18);}
    @keyframes sheenSweep{ from{transform:translateX(-130%);} to{transform:translateX(130%);} }

    /* services grid — cards invert to obsidian on hover, echoing the nav/footer/Talks
       band's dark tone elsewhere on the page, rather than a generic shadow lift */
    .service-card{background:var(--paper-white); transition:background .2s ease, border-color .2s ease, box-shadow .2s ease; box-shadow:0 0 0 rgba(0,0,0,0);}
    .service-card:hover{background:var(--brand-red); border-color:var(--brand-red); box-shadow:0 24px 48px -14px rgba(0,0,0,0.35);}
    .service-card h3{transition:color .2s ease;}
    .service-card:hover h3{color:var(--on-obsidian);}
    .service-desc{color:var(--graphite); transition:color .2s ease;}
    .service-card:hover .service-desc{color:var(--cloud-gray);}
    .service-card svg{transition:stroke .2s ease;}
    .service-card:hover svg{stroke:var(--on-obsidian);}

    /* services grid — full-page detail cards (services.html): icon badge +
       sub-bullet list need their own hover-to-white rules, same pattern as
       h3/.service-desc/svg above, since the card itself flips to solid
       brand-red on hover. */
    .service-icon-badge{width:44px; height:44px; border-radius:10px; background:rgba(204,36,44,0.08); display:flex; align-items:center; justify-content:center; margin-bottom:18px; transition:background .2s ease;}
    .service-card:hover .service-icon-badge{background:rgba(255,255,255,0.16);}
    .service-bullets{margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:8px;}
    .service-bullet{font-size:13.5px; line-height:1.5; color:var(--graphite); padding-left:14px; position:relative; transition:color .2s ease;}
    .service-bullet-dash{position:absolute; left:0; color:var(--brand-red); transition:color .2s ease;}
    .service-bullet-label{color:var(--obsidian); transition:color .2s ease;}
    .service-card:hover .service-bullet{color:rgba(255,255,255,0.82);}
    .service-card:hover .service-bullet-dash{color:var(--on-obsidian);}
    .service-card:hover .service-bullet-label{color:var(--on-obsidian);}

    /* services.html — alternating text/photo rows (replaces the old card
       grid for the full detail page). Photo reuses .photo-wipe's scroll-in
       curtain reveal, same motion language as #experts portraits. */
    .service-pill{border-radius:28px; padding:56px 48px; margin-bottom:24px; box-shadow:0 16px 40px -20px rgba(0,0,0,0.16);}
    .service-row{display:grid; grid-template-columns:1fr 1fr; gap:64px; align-items:center;}
    .service-row-photo{position:relative;}
    .service-row-badge{position:absolute; bottom:-20px; left:28px; background:var(--paper-white); border-radius:12px; box-shadow:0 16px 36px -14px rgba(0,0,0,0.28); padding:12px 18px; display:flex; align-items:center; gap:12px; max-width:calc(100% - 40px);}
    .service-row-badge .service-icon-badge{width:38px; height:38px; margin-bottom:0; flex-shrink:0;}
    .service-check-list{margin:20px 0 0; padding:0; list-style:none; display:flex; flex-direction:column; gap:12px;}
    .service-check-row{display:flex; align-items:flex-start; gap:10px;}
    .service-check-icon{width:20px; height:20px; border-radius:50%; background:rgba(204,36,44,0.1); display:flex; align-items:center; justify-content:center; flex-shrink:0; margin-top:1px;}
    .service-check-text{font-size:14px; line-height:1.55; color:var(--graphite);}
    .service-check-text strong{color:var(--obsidian);}
    @media (max-width: 900px){
      .service-row{grid-template-columns:1fr; gap:28px;}
      /* desktop alternates which side gets the photo (left/right zigzag),
         so the photo sits before or after the text in source order
         depending on the row. Once this collapses to one column, that
         alternation made every other card stack text-then-photo instead
         of photo-then-text — forcing the photo first keeps all rows
         consistent, photo always above the title. */
      .service-row-photo{order:-1;}
      .service-row-badge{padding:10px 14px; gap:10px;}
      .service-row-badge .service-icon-badge{width:32px; height:32px;}
      .service-pill{padding:36px 24px; border-radius:20px;}
    }

    .avatar-box{transition:border-color .2s ease;}
    .card-flat:hover .avatar-box{border-color:var(--obsidian);}

    /* Contact/social icon buttons — flat brand-navy circle, tone-shift on
       hover only. .social-icon-brand (LinkedIn) shares every rule below with
       .social-icon (mail, etc.) so the two sit side by side as one
       consistent family — same background, same hover, same dark-section
       override — the only difference is the glyph drawn inside, and that
       glyph uses currentColor so it inherits whatever `color` each of
       these rules sets, exactly like the mail icon already did.
       44px is the WCAG 2.5.5 / Material / HIG minimum touch target.
       :visited included everywhere `color` is set below — these still use
       href="#" placeholders, and Safari (unlike Chromium) treats a "#" link
       as already visited against the current page, so `a:visited{color:
       inherit}` up in the reset (higher specificity than a lone class) was
       winning and pulling in the inherited black instead of this white. */
    .social-icon, .social-icon-brand, .social-icon:visited, .social-icon-brand:visited{ display:inline-flex; align-items:center; justify-content:center; width:38px; height:38px; border-radius:50%; background:var(--brand-navy); color:var(--on-obsidian); transition:background .2s ease, color .2s ease, transform .2s ease; }
    .social-icon:hover, .social-icon-brand:hover{ background:#4c5075; transform:translateY(-2px); }
    /* #contact and the footer sit on the obsidian background themselves now,
       so the default hover (fade TO obsidian) would make the icon vanish
       into its own section — invert to a light hover on those two instead. */
    #contact .social-icon, #contact .social-icon-brand, #contact .social-icon:visited, #contact .social-icon-brand:visited, footer .social-icon, footer .social-icon-brand, footer .social-icon:visited, footer .social-icon-brand:visited{ background:rgba(255,255,255,0.1); color:var(--on-obsidian); }
    #contact .social-icon:hover, #contact .social-icon-brand:hover, footer .social-icon:hover, footer .social-icon-brand:hover{ background:var(--paper-white); color:var(--obsidian); }
    @media (prefers-reduced-motion: reduce){ .social-icon, .social-icon-brand{ transition:none !important; } }

    /* Expert-card LinkedIn — a secondary, tertiary-weight action (not the page's
       primary CTA), so it trades down from the 44px touch-target minimum above
       to keep from overpowering a compact card; still comfortably tappable. */
    .social-icon-sm{ width:32px; height:32px; }
    .social-icon-sm svg{ width:14px; height:14px; }

    /* Footer "built by" credit — dim by default so it doesn't compete
       with the copyright line, full opacity on hover/focus. */
    .footer-credit{ display:inline-flex; transition:transform .2s ease; }
    .footer-credit:hover, .footer-credit:focus-visible{ transform:translateY(-1px); }
    @media (prefers-reduced-motion: reduce){ .footer-credit{ transition:none !important; } }

    /* Section eyebrow labels — red pill, white text, uniform above every major heading */
    .eyebrow-pill{ display:inline-flex; align-items:center; gap:6px; background:var(--brand-red); color:var(--on-obsidian); border-radius:999px; padding:6px 16px; }

    input:focus, textarea:focus, select:focus{outline:2px solid var(--obsidian); outline-offset:1px; border-color:var(--obsidian) !important;}

    .plane-float{animation:planeFloat 4.5s ease-in-out infinite; transform-box:fill-box; transform-origin:center;}
    @keyframes planeFloat{ 0%,100%{transform:translateY(0);} 50%{transform:translateY(-7px);} }

    /* Hero banners never fade/rise/wipe in — they should read immediately
       on load, unlike the scroll-scrubbed .reveal used further down the
       page. animation left at none rather than deleting the rule, so the
       .d1–.d4 delay classes already in the markup stay harmless no-ops. */
    .hero-in{opacity:1; transform:none; animation:none;}

    /* Hero H1 — progressive fill-in reveal instead of the generic fade+rise: an
       outlined "ghost" pass of the headline sits underneath, and a solid pass
       wipes open on top — word by word, each on its own delay (--i, set inline
       per word), so it reads like the headline is being written rather than one
       sweep crossing the whole line. Text lives once, in the aria-label, so
       screen readers get it read exactly once rather than twice; both passes
       (and every .fw word inside them) are aria-hidden. This is the title's
       own signature effect, kept deliberately distinct from the plain
       fade-up that .hero-in strips from the rest of the hero above. */
    .fill-h1{ display:grid; grid-template-columns:1fr; color:transparent; }
    .fill-h1 .fill-outline, .fill-h1 .fill-solid{ grid-area:1/1; }
    .fill-h1 .fw{ display:inline-block; }
    .fill-h1 .fill-outline{ color:transparent; -webkit-text-stroke:1px rgba(255,255,255,0.34); }
    .fill-h1 .fill-outline .fw{ opacity:0; animation:fillOutlineIn .45s ease-out forwards; animation-delay:calc(.05s + var(--i) * .11s); }
    @keyframes fillOutlineIn{ to{ opacity:1; } }
    .fill-h1 .fill-solid{ color:var(--on-obsidian); }
    .fill-h1 .fill-solid .fw{ clip-path:inset(-25% 100% -25% -3%); animation:fillWipe .6s cubic-bezier(.22,1,.36,1) forwards; animation-delay:calc(.15s + var(--i) * .13s); }
    @keyframes fillWipe{ to{ clip-path:inset(-25% -6% -25% -3%); } }

    /* Scroll-scrubbed reveal: opacity/translateY are set directly from scroll
       position in JS (see the component script below), so the motion is
       pinned 1:1 to how far the visitor has scrolled — not a fixed-duration
       timer that can finish before they notice it. */
    .reveal{opacity:0; transform:translateY(40px); will-change:opacity,transform;}
    /* Stats row — the count-up should read immediately, not fade in like the
       rest of the page's scroll reveals; only the digits animate. */
    .reveal.reveal-no-fade{opacity:1; transform:none;}
    /* Hero banners never fade in — same rule as .hero-in above, just for
       the sub-pages that use the scroll-scrubbed .reveal system instead
       (their dark photo header, and AviatDo Talks' light one). The JS
       reveal loop sets these via inline style every frame; !important is
       what lets a stylesheet rule still win over that. */
    .page-header-hero .reveal, .talks-bg .reveal{opacity:1 !important; transform:none !important;}

    @media (prefers-reduced-motion: reduce){
      .hero-in, .reveal{animation:none !important; opacity:1 !important; transform:none !important;}
      .plane-float{animation:none !important;}
      .fill-h1 .fill-outline .fw{animation:none !important; opacity:1 !important;}
      .fill-h1 .fill-solid .fw{animation:none !important; clip-path:inset(-25% -6% -25% -3%) !important;}
      .card-sheen::after{animation:none !important; opacity:0 !important;}
      #page-root{position:static !important; transform:none !important;}
      #smooth-spacer{display:none !important;}
    }

    .hero-photo{ background-color:var(--obsidian); background-image:url('images/hero-team.webp'); background-size:cover; background-position:center; }

    /* Sub-page dark banner (services.html, experts.html) — same photo +
       gradient + radial-blob recipe as the home hero/#contact, just a
       shorter strip instead of full viewport height. */
    .page-header-photo{ position:absolute; inset:-12% 0; background-size:cover; will-change:transform; }
    .services-hero-photo{ background-image:url('images/services-hero.webp'); background-position:68% 30%; }
    .experts-hero-photo{ background-image:url('images/experts-hero.webp'); background-position:50% 35%; }
    .privacy-hero-photo{ background-image:url('images/privacy-hero.webp'); background-position:66% 30%; }
    .speakers-hero-photo{ background-image:url('images/speakers-hero.webp'); background-position:50% 32%; }
    .program-hero-photo{ background-image:url('images/program-hero.webp'); background-position:50% 32%; background-size:145%; }
    .about-hero-photo{ background-image:url('images/about-hero.webp'); background-position:50% 32%; }
    .talks-cbta-hero-photo{ background-image:url('images/talks-cbta-cover.webp'); background-position:50% 55%; }
    .resources-hero-photo{ background-image:url('images/resources-hero.webp'); background-position:50% 32%; }
    .partners-hero-photo{ background-image:url('images/partners-hero.webp'); background-position:68% 38%; }
    .about-reasons-bg{ background-image:url('images/about-reasons-bg.webp'); background-size:auto 100%; background-position:right center; background-repeat:no-repeat; }

    /* partners marquee — pure CSS translateX loop, no JS. Track holds the logo set twice;
       looping to -50% is exactly one full set, so the wrap is seamless. */
    .marquee{ position:relative; overflow:hidden; width:100%; }
    .marquee-track{ display:flex; align-items:stretch; gap:12px; width:max-content; animation:marqueeScroll 26s linear infinite; }
    .marquee:hover .marquee-track{ animation-play-state:paused; }
    .marquee-fade{ position:absolute; top:0; bottom:0; width:80px; z-index:1; pointer-events:none; }
    .marquee-fade.left{ left:0; background:linear-gradient(90deg, var(--cloud-gray), transparent); }
    .marquee-fade.right{ right:0; background:linear-gradient(270deg, var(--cloud-gray), transparent); }
    .marquee-track img.mono-hover{ filter:brightness(0); transition:filter .25s ease; }
    .marquee-track img.mono-hover:hover{ filter:none; }
    @keyframes marqueeScroll{ from{ transform:translateX(0); } to{ transform:translateX(-50%); } }
    @media (prefers-reduced-motion: reduce){ .marquee-track{ animation:none; } }

    /* animated stat counters — the displayed number is driven straight from the
       same scroll progress value as the .reveal fade (see the component script
       below), so it counts up from zero exactly as the row scrolls into view —
       not on page load, where it would already be finished before anyone sees it. */

    /* Hero parallax layer — the photo drifts slower than scroll for a sense of depth */
    /* Shifted right of center so the consultants stay clear of the left-aligned
       headline instead of sitting directly behind it. */
    .hero-parallax{ position:absolute; inset:-12% 0; background-color:var(--obsidian); background-image:url('images/hero-team.webp'); background-size:cover; background-position:66% 42%; will-change:transform; }

    /* Talks section backdrop — a CSS class (not an inline style) so the canvas
       runtime's file-reference substitution actually resolves the image. */
    .talks-bg{ background-color:var(--obsidian); background-image:url('images/aviatdo-talks-bg.webp'); background-size:cover; background-position:78% 45%; }

    /* AviatDo 360 section backdrop — image lives on a separate oversized layer
       (like .hero-parallax) so JS can drift it independently of the section. */
    .s360-bg{ position:relative; }
    .s360-parallax{ position:absolute; inset:-12% 0; background-color:var(--obsidian); background-image:url('images/aviatdo-360-bg.jpg'); background-size:cover; background-position:42% 42%; will-change:transform; }
    .s360-parallax.sponsorship-hero-photo{ background-image:url('images/sponsorship-hero.webp'); background-position:62% 38%; }
    .s360-parallax.register-hero-photo{ background-image:url('images/register-hero.webp'); background-position:58% 40%; }

    /* The Venue hero — real drone footage of San Salvador in place of the
       shared s360-bg photo, since this is the one 360° page where the
       actual city/venue footage exists. Plain absolute+cover, no parallax
       drift: video already carries its own motion. */
    .venue-hero{ min-height:520px; display:flex; align-items:flex-end; }
    .venue-hero-video{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
    @media (prefers-reduced-motion: reduce){ .venue-hero-video{ display:none; } .venue-hero{ background-image:url('images/aviatdo-360-venue-poster.webp'); background-size:cover; background-position:center; } }

    /* Editorial photo mosaic — asymmetric bento grid, deliberately not the
       source site's flat scrolling filmstrip. Each tile gets a size role
       (tall/wide/big) via class; dense packing fills the grid without
       needing hand-placed row/column numbers. */
    .venue-mosaic{ display:grid; grid-template-columns:repeat(4,1fr); grid-auto-rows:130px; grid-auto-flow:dense; gap:12px; }
    .venue-mosaic .tile{ position:relative; border-radius:14px; overflow:hidden; background:var(--sand-beige); }
    .venue-mosaic .tile img{ width:100%; height:100%; object-fit:cover; display:block; transition:transform .6s cubic-bezier(.22,1,.36,1); }
    .venue-mosaic .tile:hover img{ transform:scale(1.06); }
    .venue-mosaic .tile.big{ grid-column:span 2; grid-row:span 2; }
    .venue-mosaic .tile.wide{ grid-column:span 2; }
    .venue-mosaic .tile.tall{ grid-row:span 2; }
    .venue-mosaic .tile.full{ grid-column:1 / -1; }
    .venue-mosaic .tile-caption{ position:absolute; left:0; right:0; bottom:0; padding:16px 18px; background:linear-gradient(0deg, rgba(0,0,0,0.65), transparent); color:var(--on-obsidian); font-family:var(--font-condensed); font-size:12px; font-weight:600; letter-spacing:0.03em; opacity:0; transform:translateY(6px); transition:opacity .3s ease, transform .3s ease; }
    .venue-mosaic .tile:hover .tile-caption{ opacity:1; transform:translateY(0); }
    @media (prefers-reduced-motion: reduce){ .venue-mosaic .tile img{ transition:none; } .venue-mosaic .tile-caption{ transition:none; } }

    .track-pill{ font-family:var(--font-condensed); font-size:14px; font-weight:600; letter-spacing:0.03em; color:var(--on-obsidian); background:rgba(255,255,255,0.1); border:1px solid rgba(255,255,255,0.22); border-radius:999px; padding:10px 18px; white-space:nowrap; }

    /* AviatDo 360° Overview — the 4 real forum tracks, tall photo cards
       matching the live aviatdo.com layout (photo + label, no description). */
    .track-photo-card{ position:relative; border-radius:14px; overflow:hidden; aspect-ratio:460/1300; }
    .track-photo-card img{ width:100%; height:100%; object-fit:cover; display:block; transition:transform .5s cubic-bezier(.22,1,.36,1); }
    .track-photo-card:hover img{ transform:scale(1.06); }

    /* Speakers grid — same hover treatment as #experts (photo lifts +
       zooms, name turns brand-red, role scales up), reusing the
       .photo-wipe/.expert-name/.expert-role classes so the two grids
       feel identical, just scoped to #s360-speakers-grid instead of
       #experts since the rules there are id-prefixed. */
    #s360-speakers-grid .photo-wipe{ position:relative; transition:transform .45s cubic-bezier(.22,1,.36,1), box-shadow .45s ease; }
    #s360-speakers-grid .photo-wipe img{ transition:transform .6s cubic-bezier(.22,1,.36,1); }
    #s360-speakers-grid .expert-name{ transition:color .25s ease, transform .25s cubic-bezier(.22,1,.36,1); transform-origin:left center; }
    #s360-speakers-grid .expert-role{ transition:transform .25s cubic-bezier(.22,1,.36,1); transform-origin:left center; }
    #s360-speakers-grid .reveal:hover .photo-wipe{ transform:translateY(-6px); box-shadow:0 24px 48px -16px rgba(0,0,0,0.28); }
    #s360-speakers-grid .reveal:hover .photo-wipe img{ transform:scale(1.08); }
    #s360-speakers-grid .reveal:hover .expert-name{ color:var(--brand-red); transform:scale(1.08); }
    #s360-speakers-grid .reveal:hover .expert-role{ transform:scale(1.05); }

    /* AviatDo Talks — CBTA session speakers, same hover treatment again,
       scoped to #talks-cbta-speakers-grid this time. */
    #talks-cbta-speakers-grid .photo-wipe{ position:relative; transition:transform .45s cubic-bezier(.22,1,.36,1), box-shadow .45s ease; }
    #talks-cbta-speakers-grid .photo-wipe img{ transition:transform .6s cubic-bezier(.22,1,.36,1); }
    #talks-cbta-speakers-grid .expert-name{ transition:color .25s ease, transform .25s cubic-bezier(.22,1,.36,1); transform-origin:left center; }
    #talks-cbta-speakers-grid .expert-role{ transition:transform .25s cubic-bezier(.22,1,.36,1); transform-origin:left center; }
    #talks-cbta-speakers-grid .reveal:hover .photo-wipe{ transform:translateY(-6px); box-shadow:0 24px 48px -16px rgba(0,0,0,0.28); }
    #talks-cbta-speakers-grid .reveal:hover .photo-wipe img{ transform:scale(1.08); }
    #talks-cbta-speakers-grid .reveal:hover .expert-name{ color:var(--brand-red); transform:scale(1.08); }
    #talks-cbta-speakers-grid .reveal:hover .expert-role{ transform:scale(1.05); }

    /* AviatDo 360° sub-nav — persistent tab strip across the 5 forum pages,
       separate from the global site nav (see the "why sub-nav, not a
       dropdown" writeup). Sticky at top:0 rather than below the fixed
       #site-header on purpose: the header is transparent over the hero on
       first paint and only gains a background on scroll, so pinning the
       tab strip to the header's own height would leave a gap; top:0 plus
       the header's own higher z-index (20 vs 15) keeps both correctly
       stacked once scrolled. */
    .s360-tab{ display:inline-block; padding:18px 0; font-family:var(--font-condensed); font-size:14px; font-weight:600; letter-spacing:0.02em; color:var(--graphite); border-bottom:2px solid transparent; white-space:nowrap; }
    .s360-tab:hover{ color:var(--obsidian); }
    .s360-tab.active{ color:var(--obsidian); border-bottom-color:var(--brand-red); }

    /* Program page — day switcher above that day's agenda image (client
       decision: show the agenda as an exported image per day, same as the
       live site, so a new year's program is a file swap in images/ rather
       than dev hours re-editing markup — see aviatdo-360-program.html).
       Filled pill/card look intentionally differs from the underline style
       of .s360-tab above so the two tab systems — page-level nav vs.
       in-page day switch — don't read as the same control. .grow-card
       (defined earlier) gives the agenda image its hover lift. */
    .day-tab{ flex:1 1 150px; font-family:var(--font-condensed); background:var(--paper-white); border:1px solid var(--divider); border-radius:12px; padding:14px 22px; cursor:pointer; text-align:left; transition:border-color .2s ease, background .2s ease; }
    .day-tab:hover{ border-color:var(--obsidian); }
    .day-tab.active{ background:var(--obsidian); border-color:var(--obsidian); }
    .day-tab-label{ display:block; font-size:11px; font-weight:700; letter-spacing:0.05em; text-transform:uppercase; color:var(--brand-red); }
    .day-tab-date{ display:block; margin-top:3px; font-family:var(--font-headline); font-weight:900; font-size:16px; letter-spacing:-0.01em; color:var(--obsidian); }
    .day-tab.active .day-tab-date{ color:var(--on-obsidian); }

    .day-panel{ display:none; }
    .day-panel.active{ display:block; }

    /* aviatdo-360-register.html — ticket picker + checkout. The live site's
       version is a bare Wix ticket widget (plain rows, native number
       inputs, generic "Checkout" button); this rebuilds the same
       ticket/qty/total mechanics with the site's own card + stepper
       language instead, plus an on-page confirm step so a "purchase" here
       feels complete without ever building a real payment form (mockup
       scope — same as the booking modal: no backend, but the interaction
       itself works). */
    .ticket-row{ display:grid; grid-template-columns:1fr auto 132px; align-items:center; gap:20px; padding:22px 28px; border-bottom:1px solid var(--divider); }
    .ticket-row:last-child{ border-bottom:none; }
    .ticket-row-name{ font-size:16px; font-weight:700; }
    .ticket-row-desc{ margin-top:4px; font-size:13px; color:var(--muted); max-width:420px; }
    .ticket-row-price{ font-family:var(--font-headline); font-weight:900; font-size:20px; white-space:nowrap; }

    .qty-stepper{ display:flex; align-items:center; justify-content:flex-end; gap:14px; }
    .qty-btn{ width:32px; height:32px; border-radius:50%; border:1px solid var(--divider); background:var(--paper-white); color:var(--obsidian); font-size:18px; line-height:1; display:flex; align-items:center; justify-content:center; cursor:pointer; transition:border-color .2s ease, background .2s ease; }
    .qty-btn:hover{ border-color:var(--obsidian); }
    .qty-btn:disabled{ opacity:.35; pointer-events:none; }
    .qty-value{ min-width:16px; text-align:center; font-family:var(--font-condensed); font-weight:700; font-size:15px; }

    .order-summary-line{ display:flex; justify-content:space-between; gap:12px; font-size:14px; padding:8px 0; }
    .order-summary-line-name{ color:var(--graphite); }
    .order-summary-line-price{ font-weight:700; white-space:nowrap; }

    @media (prefers-reduced-motion: reduce){ .qty-btn{ transition:none !important; } }

    /* Live pulsing dot — countdown badge */
    .live-dot{ position:relative; width:6px; height:6px; border-radius:50%; background:var(--brand-red); display:inline-block; }
    .live-dot::after{ content:''; position:absolute; inset:-4px; border-radius:50%; border:1.5px solid var(--brand-red); animation:livePing 2.2s cubic-bezier(0,0,0.2,1) infinite; }
    @keyframes livePing{ 0%{ transform:scale(0.6); opacity:0.8; } 75%,100%{ transform:scale(1.8); opacity:0; } }
    @media (prefers-reduced-motion: reduce){ .live-dot::after{ animation:none; display:none; } }

    /* Magnetic CTA — nudges toward the cursor; JS drives translate3d */
    .magnetic{ display:inline-block; transition:transform .15s ease-out; }

    /* Accent underline — a short gradient bar drawn in under a heading, scroll-scrubbed like .reveal */
    .accent-bar{ display:block; width:64px; height:4px; border-radius:2px; background:var(--gradient); margin-top:14px; transform:scaleX(0); transform-origin:left; will-change:transform; }

    /* Services cards — a light 3D tilt toward the cursor, desktop pointer only */
    .tilt-card{ transition:transform .2s cubic-bezier(.16,1,.3,1), border-color .2s ease; transform-style:preserve-3d; }

    /* Portrait/photo frames — no longer clip-path curtain-revealed: scrubbing
       the reveal to raw scroll position meant a photo landed on people's
       faces (or a service photo) mid-crop whenever a visitor arrived via a
       direct link/anchor instead of a slow scroll from above, reading as a
       broken image rather than a reveal. The .reveal wrapper's own
       opacity/translateY fade still gives it motion. */
    .photo-wipe{ }

    /* Expert portraits — modern hover: the photo eases into a gentle zoom while
       its frame lifts on a soft shadow, the name shifts to the brand accent, and
       the name + role scale up slightly from the left edge — enough to read as
       "this one's active" against the rest of the row, without reflowing the grid. */
    #experts .photo-wipe{ position:relative; transition:transform .45s cubic-bezier(.22,1,.36,1), box-shadow .45s ease; }
    #experts .photo-wipe img{ transition:transform .6s cubic-bezier(.22,1,.36,1); }
    #experts .expert-name{ transition:color .25s ease, transform .25s cubic-bezier(.22,1,.36,1); transform-origin:left center; }
    #experts .expert-role{ transition:transform .25s cubic-bezier(.22,1,.36,1); transform-origin:left center; }
    #experts .reveal:hover .photo-wipe, #experts .experts-carousel-card:hover .photo-wipe{ transform:translateY(-6px); box-shadow:0 24px 48px -16px rgba(0,0,0,0.28); }
    #experts .reveal:hover .photo-wipe img, #experts .experts-carousel-card:hover .photo-wipe img{ transform:scale(1.08); }
    #experts .reveal:hover .expert-name, #experts .experts-carousel-card:hover .expert-name{ color:var(--brand-red); transform:scale(1.08); }
    #experts .reveal:hover .expert-role, #experts .experts-carousel-card:hover .expert-role{ transform:scale(1.05); }

    /* Home preview — Our Experts carousel. Finger/trackpad-scrollable, not
       auto-playing — dropped the old arrow buttons (a mistimed double-tap on
       one triggered the browser's native double-tap-to-zoom on mobile) in
       favor of native touch scrolling. "Infinite" here means the track holds
       the card set three times (hidden decorative copy, the real
       accessible one, another hidden decorative copy) with a scroll
       listener (see script.js) that silently snaps scrollLeft back by one
       set width whenever it strays into a buffer copy — so dragging keeps
       going in either direction with no visible seam and no dead end. No
       edge fade mask on purpose: the buffer copies mean there's always more
       carousel to reveal, not a hard edge to soften. */
    .experts-carousel{ display:flex; gap:24px; overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; padding:4px 2px 10px; cursor:grab; user-select:none; }
    .experts-carousel::-webkit-scrollbar{ display:none; }
    .experts-carousel.is-dragging{ cursor:grabbing; scroll-snap-type:none; }
    .experts-carousel.is-dragging .experts-carousel-card{ pointer-events:none; }
    .experts-carousel-card{ flex:0 0 auto; width:220px; }

    /* Contact form <select> fields — Safari renders native select chrome at a
       different height than a same-padding <input> even with identical box
       styles, so appearance is reset and a custom chevron substituted to keep
       height consistent with the text fields around it. */
    .contact-select{
      appearance:none; -webkit-appearance:none; -moz-appearance:none;
      box-sizing:border-box;
      background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235e5d5c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
      background-repeat:no-repeat;
      background-position:right 14px center;
      background-size:14px;
      padding-right:38px !important;
    }

    /* Scroll progress bar */
    #scroll-progress-bar{ position:fixed; top:0; left:0; height:3px; width:0%; background:var(--brand-red); z-index:9999; pointer-events:none; }

    /* Smooth (inertia) scroll — #page-root is pinned and nudged toward the
       real scroll position every frame with a lerp (see the component script),
       so the page glides to a stop instead of jumping to the raw wheel/trackpad
       position. #smooth-spacer is a JS-sized ghost that keeps the native
       scrollbar's range matching the real content height. Lives outside
       #scroll-progress-bar (a sibling, not a child) so the bar — position:fixed
       itself — stays anchored to the true viewport rather than to this
       transformed layer, which would otherwise become its containing block. */
    #page-root.smooth-active{ position:fixed; top:0; left:0; width:100%; will-change:transform; }
    #smooth-spacer{ display:block; }

    @media (prefers-reduced-motion: reduce){
      .magnetic{ transition:none !important; }
      .tilt-card{ transition:none !important; }
      .testi-card{ transition:none !important; }
      .grow-card{ transition:none !important; }
      .accent-bar{ transform:scaleX(1) !important; }
      .hero-parallax{ transform:none !important; }
      .page-header-photo{ transform:none !important; }
      .s360-parallax{ transform:none !important; }
      #experts .photo-wipe, #experts .photo-wipe img, #experts .expert-name, #experts .expert-role{ transition:none !important; }
      #experts .reveal:hover .photo-wipe, #experts .experts-carousel-card:hover .photo-wipe{ transform:none !important; box-shadow:none !important; }
      #experts .reveal:hover .photo-wipe img, #experts .experts-carousel-card:hover .photo-wipe img{ transform:none !important; }
      #experts .reveal:hover .expert-name, #experts .reveal:hover .expert-role, #experts .experts-carousel-card:hover .expert-name, #experts .experts-carousel-card:hover .expert-role{ transform:none !important; }
      #s360-speakers-grid .photo-wipe, #s360-speakers-grid .photo-wipe img, #s360-speakers-grid .expert-name, #s360-speakers-grid .expert-role{ transition:none !important; }
      #s360-speakers-grid .reveal:hover .photo-wipe{ transform:none !important; box-shadow:none !important; }
      #s360-speakers-grid .reveal:hover .photo-wipe img{ transform:none !important; }
      #s360-speakers-grid .reveal:hover .expert-name, #s360-speakers-grid .reveal:hover .expert-role{ transform:none !important; }
      #talks-cbta-speakers-grid .photo-wipe, #talks-cbta-speakers-grid .photo-wipe img, #talks-cbta-speakers-grid .expert-name, #talks-cbta-speakers-grid .expert-role{ transition:none !important; }
      #talks-cbta-speakers-grid .reveal:hover .photo-wipe{ transform:none !important; box-shadow:none !important; }
      #talks-cbta-speakers-grid .reveal:hover .photo-wipe img{ transform:none !important; }
      #talks-cbta-speakers-grid .reveal:hover .expert-name, #talks-cbta-speakers-grid .reveal:hover .expert-role{ transform:none !important; }
    }

    /* Why-AviatDo cards — a left-to-right slide instead of the generic fade+rise,
       so this row reads as a distinct entrance from the rest of the page. */
    .reveal.reveal-slide{ transform:translateX(-60px); }

    /* AviatDo Talks "Next session" card — mirror slide, entering right-to-left,
       so it reads as a distinct, deliberate arrival against the dark band. */
    .reveal.reveal-slide-right{ transform:translateX(72px); }

    /* Get in touch — a taller bottom-to-top rise than the generic fade+rise,
       so the whole contact block reads as a clear, deliberate arrival. */
    .reveal.reveal-rise{ transform:translateY(96px); }

    /* Partners double carousel — each row is plain flex content with no CSS-driven
       animation; JS sets transform directly from scroll position (see script below). */
    .partner-row{ display:flex; align-items:stretch; gap:14px; width:max-content; will-change:transform; }
    @media (prefers-reduced-motion: reduce){ .partner-row{ transform:none !important; } }

    /* Shared type scale — lets the tablet/mobile-web breakpoints below resize headings
       and big numbers with normal CSS specificity instead of !important overrides. */
    .hero-h1{ font-size:72px; font-family:var(--font-headline); }
    .section-h2{ font-size:48px; font-family:var(--font-headline); }
    .num-xl{ font-size:64px; font-family:var(--font-headline); }

    /* ============================================================
       RESPONSIVE — one fluid system, in three tiers, replacing the
       former separate desktop/mobile builds:
         @media (max-width:1080px)  tablet — condense nav spacing,
                                     collapse 3/4-col grids to 2-col
         @media (max-width:900px)   nav — hamburger + off-canvas
                                     drawer takes over from the inline
                                     nav (7 links won't fit gracefully
                                     much above this)
         @media (max-width:767px)   phone — the mobile.html-tuned type
                                     scale, spacing, imagery crops and
                                     single/2-col stacking
       ============================================================ */
    @media (max-width: 1080px){
      header{ padding:20px 24px !important; }
      header nav{ gap:14px !important; }
      header nav a{ font-size:14px !important; }

      #hero > div:nth-child(3){ padding:120px 24px 72px !important; }
      .hero-h1{ font-size:48px; }
      .section-h2{ font-size:36px; }
      .num-xl{ font-size:48px; }

      #stats, #services, #experts{
        padding-left:24px !important; padding-right:24px !important;
      }
      .section-pad-x{ padding-left:24px !important; padding-right:24px !important; }
      #services > div[style*="grid-template-columns:repeat(3"]{ grid-template-columns:repeat(2,minmax(0,1fr)) !important; }
      #why-aviatdo div[style*="grid-template-columns:repeat(3"]{ grid-template-columns:1fr !important; }
      /* The three reasons stack to one column below this width, making
         the section much taller — the background-size:auto height-locked
         map would grow wide enough to sit under that stacked text, so
         drop it here same as the mobile breakpoint does. about.html's
         own "why aviatdo" section has no #why-aviatdo id and isn't
         affected. */
      #why-aviatdo.about-reasons-bg{ background-image:none; }
      #experts > div[style*="grid-template-columns:repeat(4"]{ grid-template-columns:repeat(2,minmax(0,1fr)) !important; }
      #s360-tracks-grid{ grid-template-columns:repeat(2,minmax(0,1fr)) !important; gap:14px !important; }
      #s360-speakers-grid{ grid-template-columns:repeat(2,minmax(0,1fr)) !important; gap:14px !important; }
      .talks-bg div[style*="grid-template-columns:1.1fr 1fr"]{ grid-template-columns:1fr !important; }
      .s360-bg div[style*="grid-template-columns:1.1fr 1fr"]{ grid-template-columns:1fr !important; }
      #testimonials div[style*="grid-template-columns:repeat(3"]{ grid-template-columns:1fr !important; }
      #contact > div[style*="grid-template-columns:minmax(320px"]{ grid-template-columns:1fr !important; }
      footer div[style*="grid-template-columns:1.4fr"]{
        grid-template-columns:repeat(2,minmax(0,1fr)) !important;
      }
      footer div[style*="grid-template-columns:1.4fr"] > div:first-child{ grid-column:1/-1; }
    }

    /* Sticky header — fixed to the viewport at every width (see the HTML
       comment above <header id="site-header"> for why it lives outside
       #page-root). --nav-ink lets every nav link/label reference one
       variable instead of a hardcoded color, so toggling to the scrolled
       state just redefines it once here rather than touching each link. */
    #site-header{ --nav-ink:var(--on-obsidian); transition:background-color .25s ease, box-shadow .25s ease; }
    #site-header.scrolled{ --nav-ink:var(--obsidian); background:rgba(255,255,255,0.96); box-shadow:0 4px 24px -10px rgba(0,0,0,0.18); }
    @supports (backdrop-filter: blur(1px)){
      #site-header.scrolled{ background:rgba(255,255,255,0.82); backdrop-filter:blur(10px); }
    }

    /* ---- Header nav → hamburger + off-canvas drawer ----
       #nav-panel wraps the <nav> links and the lang/contact actions
       block. It stays `display:contents` (invisible to layout) above
       the breakpoint, so header's flex children are exactly
       img/nav/actions — pixel-identical to the original desktop
       markup — then becomes the drawer panel itself below it. Same
       nav markup serves both; nothing is duplicated. */
    #nav-toggle{ display:none; }
    #nav-panel{ display:contents; }
    #nav-backdrop{ display:none; }

    @media (max-width: 900px){
      #nav-toggle{ display:flex; align-items:center; justify-content:center; width:44px; height:44px; cursor:pointer; flex-shrink:0; position:relative; z-index:31; }
      #nav-toggle .burger-bar{ position:absolute; left:11px; right:11px; height:2px; background:var(--nav-ink); border-radius:1px; transition:transform .3s ease, opacity .2s ease, background-color .25s ease; }
      #nav-toggle .burger-bar:nth-child(1){ top:16px; }
      #nav-toggle .burger-bar:nth-child(2){ top:21px; }
      #nav-toggle .burger-bar:nth-child(3){ top:26px; }
      html.nav-open #nav-toggle .burger-bar:nth-child(1){ transform:translateY(5px) rotate(45deg); }
      html.nav-open #nav-toggle .burger-bar:nth-child(2){ opacity:0; }
      html.nav-open #nav-toggle .burger-bar:nth-child(3){ transform:translateY(-5px) rotate(-45deg); }
      /* the burger's bars (now an X) pick up --nav-ink, which #site-header
         flips to obsidian once .scrolled is applied (dark icon for its own
         white bar) — that class tracks scroll position, not menu state, so
         opening the drawer after scrolling left the close X black against
         the navy drawer. Force it white while the drawer is open. */
      html.nav-open #nav-toggle .burger-bar{ background:var(--on-obsidian) !important; }

      #nav-panel{
        display:flex; flex-direction:column; align-items:center !important; gap:26px;
        position:fixed; top:0; right:0; height:100vh; width:min(78vw,320px);
        background:var(--brand-navy); padding:104px 28px 32px; overflow-y:auto;
        transform:translateX(100%); transition:transform .35s cubic-bezier(.16,1,.3,1);
        z-index:30;
      }
      html.nav-open #nav-panel{ transform:translateX(0); }
      header nav{ flex-direction:column; align-items:center !important; gap:22px !important; width:100%; }
      header nav a{ font-size:19px !important; color:var(--on-obsidian) !important; }
      header nav a[aria-current="page"]{ color:var(--brand-red) !important; }
      #header-actions{ flex-direction:column; align-items:center !important; gap:20px !important; width:100%; }

      #nav-backdrop{
        display:block; position:fixed; inset:0; background:rgba(0,0,0,0.55);
        opacity:0; pointer-events:none; transition:opacity .3s ease; z-index:25;
      }
      html.nav-open #nav-backdrop{ opacity:1; pointer-events:auto; }
      html.nav-open, html.nav-open body{ overflow:hidden; }

      /* The logo doubles as "Home" (no separate Home link in the nav by
         design), but it sits earlier in #site-header's DOM order than
         #nav-backdrop with no z-index of its own — so once the drawer is
         open, the backdrop (z-index:25) painted above it and silently ate
         the tap. Lift it above the backdrop so it stays a working way
         back to the homepage while the menu is open. */
      #site-header > a[aria-label="AviatDo home"]{ position:relative; z-index:26; }
    }

    @media (max-width: 767px){
      header{ padding:18px 20px !important; }

      /* ---- imagery: swap to the tighter mobile crops ---- */
      .hero-photo{ background-image:url('images/hero-team-mobile.webp'); background-position:center 15%; }
      .services-hero-photo{ background-image:url('images/services-hero-mobile.webp'); background-position:center 15%; }
      .experts-hero-photo{ background-image:url('images/experts-hero-mobile.webp'); background-position:center 25%; }
      .privacy-hero-photo{ background-image:url('images/privacy-hero-mobile.webp'); background-position:center 15%; }
      .speakers-hero-photo{ background-image:url('images/speakers-hero-mobile.webp'); background-position:center 20%; }
      .program-hero-photo{ background-image:url('images/program-hero-mobile.webp'); background-position:center 30%; }
      .about-hero-photo{ background-image:url('images/about-hero-mobile.webp'); background-position:center 20%; }
      .resources-hero-photo{ background-image:url('images/resources-hero-mobile.webp'); background-position:center 20%; }
      .partners-hero-photo{ background-image:url('images/partners-hero-mobile.webp'); background-position:center 30%; }
      .about-reasons-bg{ background-image:none; }
      .hero-parallax{ background-image:url('images/hero-team-mobile.webp'); background-position:center 15%; }
      .talks-bg{ background-image:url('images/aviatdo-talks-bg-mobile.webp'); background-position:24% 30%; }
      .s360-parallax{ background-image:url('images/aviatdo-360-bg-mobile.jpg'); background-position:50% 30%; }
      .s360-parallax.sponsorship-hero-photo{ background-image:url('images/sponsorship-hero-mobile.webp'); background-position:38% 30%; }
      .s360-parallax.register-hero-photo{ background-image:url('images/register-hero-mobile.webp'); background-position:32% 30%; }

      /* ---- AviatDo 360 registration fees table — stack name/price instead
         of letting them wrap mid-row (wrap left the price sitting flush
         left on some rows and flush right on others, depending on how the
         name text happened to wrap). ---- */
      .fee-row{ flex-direction:column !important; align-items:flex-start !important; }
      .fee-row-price{ text-align:left !important; }
      .ticket-row{ grid-template-columns:1fr !important; row-gap:12px !important; padding:20px !important; }
      .qty-stepper{ justify-content:flex-start !important; }
      #ticket-order-summary{ position:static !important; }
      div[style*="grid-template-columns:1fr 320px"]{ grid-template-columns:1fr !important; }
      #ticket-step1-form div[style*="grid-template-columns:1fr 1fr"], #ticket-step2-form div[style*="grid-template-columns:1fr 1fr"]{ grid-template-columns:1fr !important; }

      /* ---- hero ---- */
      #hero{ min-height:clamp(560px,78vh,760px); }
      #hero > div:nth-child(3){ padding:108px 20px 56px !important; }
      .hero-h1{ font-size:38px; }
      #hero .hero-in.d1{ font-size:11px !important; margin-bottom:16px !important; }
      #hero .hero-in.d3{ font-size:15px !important; margin:16px 0 0 !important; }
      #hero .hero-in.d4{ flex-direction:column; align-items:flex-start; gap:14px !important; margin-top:28px !important; }
      #hero .hero-in.d4 .btn-primary{ display:block; width:100%; text-align:center; }

      /* ---- shared type scale ---- */
      .section-h2{ font-size:30px; }
      .num-xl{ font-size:44px; overflow-wrap:break-word; }
      #stats > div:last-child .num-xl{ font-size:28px; min-height:44px; display:flex; align-items:flex-end; }
      .testi-num{ font-size:32px !important; }
      .eyebrow-pill{ padding:5px 14px; font-size:12px !important; }
      .accent-bar{ width:52px; margin-top:12px; }
      .track-pill{ font-size:13px; padding:9px 16px; }
      .track-photo-card{ aspect-ratio:16/13; }
      .social-icon{ width:34px; height:34px; }
      .social-icon-brand{ width:34px; height:34px; }
      .social-icon-sm{ width:30px; height:30px; }
      .social-icon-sm svg{ width:13px; height:13px; }

      /* ---- scroll-reveal starting offsets (the component script below
             reads this same breakpoint at runtime to match its JS-driven
             progress distances to whichever of these is active) ---- */
      .reveal{ transform:translateY(36px); }
      .reveal.reveal-slide{ transform:translateX(-44px); }
      .reveal.reveal-slide-right{ transform:translateX(52px); }
      .reveal.reveal-rise{ transform:translateY(64px); }

      /* ---- stats: 2x2, thinner hairlines, no explicit `gap` (matches
             the desktop row's own layout technique) — spacing instead
             comes from one-sided padding per cell plus row-gap ---- */
      #stats, #services, #experts{ padding-left:20px !important; padding-right:20px !important; }
      .section-pad-x{ padding-left:20px !important; padding-right:20px !important; }
      #stats{ grid-template-columns:repeat(2,minmax(0,1fr)) !important; row-gap:28px !important; padding-top:72px !important; padding-bottom:72px !important; }
      #stats > div{ padding:0 !important; border-right:none !important; }
      #stats > div:nth-child(odd){ padding-right:16px !important; border-right:1px solid #a3a9b0 !important; }
      #stats > div:nth-child(even){ padding-left:16px !important; }

      /* ---- services: single column, tighter cards ---- */
      #services{ padding-top:8px !important; padding-bottom:96px !important; }
      #services > div[style*="grid-template-columns:repeat(3"]{ grid-template-columns:1fr !important; row-gap:12px !important; }
      #services .service-card{ padding:20px !important; }
      #services .service-card svg{ width:24px !important; height:24px !important; margin-bottom:12px !important; }
      #services .service-card h3{ font-size:18px !important; margin-bottom:8px !important; }
      #services .service-desc{ font-size:14.5px !important; }

      /* ---- why-aviatdo: tighter vertical rhythm ---- */
      #why-aviatdo{ padding:92px 0 !important; }
      #why-aviatdo div[style*="grid-template-columns:repeat(3"]{ gap:28px !important; }
      #why-aviatdo h3{ font-size:18px !important; }
      #why-aviatdo p{ font-size:14.5px !important; }

      /* ---- experts: STAYS 2-column at phone width — mobile.html's
             approved layout never fully stacks this grid to 1 column,
             it just shrinks it; the prior skeleton's max-width:640px
             rule that forced 1fr here has been dropped. ---- */
      #experts{ padding-top:92px !important; padding-bottom:92px !important; }
      #experts > div[style*="grid-template-columns:repeat(4"]{ grid-template-columns:repeat(2,minmax(0,1fr)) !important; gap:18px !important; }
      #experts .expert-name{ font-size:14px !important; }
      #experts .expert-role{ font-size:12px !important; }
      .experts-carousel-card{ width:168px !important; }
      .experts-carousel{ gap:16px !important; }

      /* ---- AviatDo 360° / Talks bands ---- */
      #aviatdo-360{ padding:96px 0 !important; }
      #talks{ padding:100px 0 !important; }
      .talks-bg div[style*="grid-template-columns:1.1fr 1fr"], .s360-bg div[style*="grid-template-columns:1.1fr 1fr"]{ gap:32px !important; }
      #aviatdo-360 img[alt*="AviatDo 360"]{ max-width:230px !important; }
      .s360-card{ padding:20px !important; }
      .s360-date{ padding:15px 16px !important; }
      .s360-date-num{ font-size:34px !important; }
      .s360-date-year{ font-size:13.5px !important; }
      .s360-info-row{ padding:13px 14px !important; }

      /* ---- navy CTA pill (AviatDo 360 overview, Partners, Services) —
         the button text was set to white-space:nowrap for the desktop
         single-row layout, but on phone the row already wraps the button
         onto its own line below the heading; kept as nowrap, the longer
         labels (e.g. "Ver oportunidades de patrocinio →") don't fit that
         line's available width and spill past the button's edge. Letting
         it wrap and go full-width instead gives it as much room as the
         row has, so it never needs more than that. */
      .service-pill .btn-primary{ white-space:normal !important; width:100%; text-align:center; }

      /* ---- partners ---- */
      #partners{ padding-top:72px !important; padding-bottom:72px !important; }
      #partners .card-flat{ width:190px !important; height:126px !important; padding:18px !important; }
      .marquee-track{ gap:10px !important; animation-duration:18s !important; }
      .marquee-fade{ width:36px !important; }
      .partner-row{ gap:12px !important; }

      /* ---- testimonials: single column; the decorative quote icon
             (final/approved — not being redesigned) scales down and
             tucks closer to the corner so it doesn't overwhelm a
             390px-wide screen ---- */
      #testimonials{ padding:92px 0 !important; }
      #testimonials div[style*="grid-template-columns:repeat(3"]{ grid-template-columns:1fr !important; gap:12px !important; }
      #testimonials > svg{ width:220px !important; height:180px !important; top:-16px !important; right:-16px !important; }

      /* ---- contact ---- */
      #contact{ padding:100px 0 112px !important; }
      #contact .ghost-link{ font-size:18px !important; }
      #contact h2{ font-size:30px !important; }
      /* the outer contact grid (intro column + form column) never collapsed
         on phone — minmax(320px,480px) forces its first column to stay at
         least 320px wide even when the whole viewport is narrower than
         that, so the form column got pushed off-screen to the right. */
      #contact > div[style*="grid-template-columns:minmax(320px,480px) 1fr"]{ grid-template-columns:1fr !important; gap:40px !important; }
      /* the form's own First/Last-name, Company/Telephone and Email/Contact-
         method rows are a second, nested 2-up grid (independent of the outer
         minmax(320px,480px) 1fr layout above) — without this it stays
         2-column and its min-content width forces the whole contact grid
         to overflow, clipping the heading and the fields alike. These rows
         sit inside a #contact-form-fields wrapper (form > div > div), one
         level deeper than a direct child, so this needs a descendant
         selector — `form >` alone never matched. */
      #contact form div[style*="grid-template-columns:1fr 1fr"]{ grid-template-columns:1fr !important; }

      /* ---- footer ---- */
      footer{ padding:60px 20px 24px !important; }
      footer div[style*="grid-template-columns:1.4fr"]{ grid-template-columns:1fr !important; gap:24px !important; }
      footer div[style*="grid-template-columns:1.4fr"] > div:first-child{ grid-column:auto; }

      /* ---- AviatDo 360° pages — same single-column-stack treatment as
             the rest of the site's multi-column content grids. These
             sections previously had no .section-pad-x class at all, so
             their 40px side padding never reduced on phone; that's fixed
             at the HTML level (class added), this part only handles the
             grids that need to stop being 2/3/4-across. ---- */
      .s360-bg{ padding-left:20px !important; padding-right:20px !important; }
      #s360-topics-grid, #s360-audience-grid, #s360-hotel-steps-grid, #s360-goodtoknow-grid, #s360-why-partner-grid, .sponsor-grid, .resources-grid, .about-reasons-grid{
        grid-template-columns:1fr !important;
      }

      /* ---- About Us page — quick-facts strip mirrors #stats' own mobile
             treatment (2-across with an alternating divider), and the
             alliance-logo grid drops from 6 to 2 across so the tiles stay
             a legible size instead of shrinking to slivers. ---- */
      .about-facts-grid{
        grid-template-columns:repeat(2,minmax(0,1fr)) !important; row-gap:28px !important;
        padding-top:72px !important; padding-bottom:72px !important;
        padding-left:20px !important; padding-right:20px !important;
      }
      .about-facts-grid > div{ padding:0 !important; border-right:none !important; }
      .about-facts-grid > div:nth-child(odd){ padding-right:16px !important; border-right:1px solid #a3a9b0 !important; }
      .about-facts-grid > div:nth-child(even){ padding-left:16px !important; }
      .about-alliances-grid{ grid-template-columns:repeat(2,minmax(0,1fr)) !important; }
      .about-facts-grid > div:last-child .num-xl{ font-size:28px !important; min-height:44px; display:flex; align-items:flex-end; }
      #s360-venue-intro{ grid-template-columns:1fr !important; gap:32px !important; }
      .venue-hero{ min-height:420px !important; }
      .venue-mosaic{ grid-template-columns:repeat(2,1fr) !important; grid-auto-rows:150px !important; }
      .venue-mosaic .tile{ grid-column:span 1 !important; grid-row:span 1 !important; }
      .venue-mosaic .tile-caption{ opacity:1 !important; transform:none !important; background:linear-gradient(0deg, rgba(0,0,0,0.55), transparent); }
      .s360-day-card{ grid-template-columns:1fr !important; gap:10px !important; padding:24px !important; }
      .day-tab{ flex:1 1 100% !important; }
    }

    /* ---- Booking modal — mockup scheduling calendar opened from the hero
           "Book a consultation" / "Agendar una consulta" CTA. Visual-only:
           picking a date + time and confirming just shows an inline success
           state — no live calendar or backend behind it yet, matching the
           contact form's own demo-stage scope. Sits as a sibling of
           #page-root in the markup (not nested inside it) specifically so
           its position:fixed stays pinned to the real viewport even while
           #page-root carries the smooth-scroll transform on desktop. ---- */
    #booking-overlay, #sponsor-overlay, #resource-gate-overlay{
      position:fixed; inset:0; z-index:200; display:flex; align-items:center; justify-content:center;
      padding:24px; background:rgba(0,0,0,0.6);
      opacity:0; visibility:hidden; transition:opacity .25s ease, visibility 0s linear .25s;
    }
    #booking-overlay.is-open, #sponsor-overlay.is-open, #resource-gate-overlay.is-open{ opacity:1; visibility:visible; transition:opacity .25s ease; }
    html.booking-open, html.booking-open body{ overflow:hidden; }

    .booking-modal{
      position:relative; width:100%; max-width:560px; max-height:88vh; overflow-y:auto;
      background:var(--paper-white); border-radius:16px; padding:36px;
      box-shadow:0 40px 90px -20px rgba(0,0,0,0.45);
      transform:translateY(14px) scale(.98); transition:transform .3s cubic-bezier(.16,1,.3,1);
      /* #booking-overlay sits as a SIBLING of #page-root (see the comment
         above), so it never inherits #page-root's font-family:var(--font-display).
         Without this, any modal text that doesn't set its own font-family
         falls back to the browser's serif default. */
      font-family:var(--font-display); color:var(--obsidian);
    }
    #booking-overlay.is-open .booking-modal, #sponsor-overlay.is-open .booking-modal{ transform:translateY(0) scale(1); }

    .booking-close{
      position:absolute; top:20px; right:20px; width:36px; height:36px; border-radius:50%;
      display:inline-flex; align-items:center; justify-content:center;
      background:var(--cloud-gray); color:var(--obsidian); transition:background .2s ease, color .2s ease;
    }
    .booking-close:hover{ background:var(--obsidian); color:var(--on-obsidian); }

    .booking-field{ margin-bottom:24px; }
    .booking-field-label{ display:block; font-family:var(--font-condensed); font-size:11px; font-weight:600; letter-spacing:0.04em; text-transform:uppercase; color:var(--graphite); margin-bottom:8px; }
    .booking-input{
      width:100%; font-family:var(--font-display); font-size:14px; color:var(--obsidian);
      padding:10px 12px; border:1px solid var(--cloud-gray); border-radius:8px; background:var(--cloud-gray);
    }
    .booking-input::placeholder{ color:var(--muted); }

    /* Specialist picker — an always-visible horizontal row of cards (no
       open/close dropdown), so there's nothing that can pinch/overlap the
       way stacked list options did. Each card reuses the avatar layout the
       success view also uses. */
    .booking-expert-row{ display:grid; grid-template-columns:repeat(4, 1fr); gap:8px; }
    .booking-expert-card{
      display:flex; flex-direction:column; align-items:center; text-align:center; gap:6px;
      padding:12px 8px; border-radius:14px; border:1.5px solid var(--cloud-gray); background:var(--paper-white);
      transition:border-color .15s ease, background .15s ease;
      /* Buttons don't inherit font-family from the page by default — set it
         here so both child spans (name + role) resolve to Inter instead of
         the browser's UA default button font. */
      font-family:var(--font-display);
    }
    .booking-expert-card:hover{ border-color:var(--obsidian); }
    .booking-expert-card.is-selected{ background:rgba(204,36,44,0.06); border-color:var(--brand-red); }
    .booking-avatar{
      width:42px; height:42px; border-radius:50%; overflow:hidden; flex-shrink:0;
      background:var(--cloud-gray); color:var(--graphite); display:flex; align-items:center; justify-content:center;
    }
    .booking-avatar img{ width:100%; height:100%; object-fit:cover; display:block; }
    .booking-expert-card-name{ font-family:var(--font-display); font-size:12px; font-weight:700; color:var(--obsidian); line-height:1.25; }
    .booking-expert-card-role{ font-size:10.5px; color:var(--graphite); line-height:1.25; }
    .booking-expert-chip-text{ display:flex; flex-direction:column; min-width:0; text-align:left; }
    .booking-expert-chip-name{
      font-family:var(--font-display); font-size:14px; font-weight:700; color:var(--obsidian);
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    }
    .booking-expert-chip-role{ font-size:12px; color:var(--graphite); }
    .booking-expert-chip-role:empty{ display:none; }

    /* Scheduling card — a compact sand-tint panel (the same --sand-beige
       token the "Why AviatDo" section uses) holding a single horizontal,
       scrollable strip of upcoming days instead of a full month grid, so
       it stays small and needs no month-jump navigation. */
    .booking-cal{ background:var(--sand-beige); border-radius:18px; padding:16px; }
    .booking-strip-wrap{ display:flex; align-items:center; gap:6px; }
    .booking-strip{
      display:flex; gap:8px; flex:1; overflow-x:auto; scroll-behavior:smooth; scroll-snap-type:x proximity;
      padding:2px 1px; scrollbar-width:none;
    }
    .booking-strip::-webkit-scrollbar{ display:none; }
    /* The button itself is just a layout column (no background/border of its
       own) — only the day-number gets the round "pill" treatment, like the
       circular day buttons the earlier month-grid calendar used. */
    .booking-date-chip{
      scroll-snap-align:start; flex:0 0 auto; width:46px; padding:2px 0 0; border:none; background:none;
      display:flex; flex-direction:column; align-items:center; gap:4px;
      font-family:var(--font-display); color:var(--obsidian); transition:color .15s ease;
    }
    .booking-date-chip:disabled{ color:var(--muted); opacity:.5; cursor:not-allowed; }
    .booking-date-chip-month{
      font-family:var(--font-condensed); font-size:9px; font-weight:700; letter-spacing:0.05em; text-transform:uppercase;
      color:var(--brand-red); height:11px;
    }
    .booking-date-chip-dow{ font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:0.03em; opacity:.65; }
    .booking-date-chip-num{
      width:34px; height:34px; border-radius:50%; display:flex; align-items:center; justify-content:center;
      font-size:15px; font-weight:800; color:inherit; background:var(--paper-white); border:1.5px solid transparent;
      transition:background .15s ease, border-color .15s ease, color .15s ease;
    }
    .booking-date-chip:not(:disabled):hover .booking-date-chip-num{ border-color:var(--obsidian); }
    .booking-date-chip.is-today{ color:var(--brand-red); }
    .booking-date-chip.is-today .booking-date-chip-num{ border-color:var(--brand-red); }
    .booking-date-chip.is-selected .booking-date-chip-num{ background:var(--brand-red) !important; border-color:var(--brand-red) !important; color:var(--on-obsidian) !important; }
    .booking-strip-nav{
      flex-shrink:0; width:28px; height:28px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center;
      background:var(--paper-white); color:var(--obsidian); font-size:15px; line-height:1; transition:background .2s ease, color .2s ease;
    }
    .booking-strip-nav:hover{ background:var(--obsidian); color:var(--on-obsidian); }

    .booking-success-expert{ display:flex; align-items:center; gap:10px; margin-bottom:16px; }
    .booking-success-expert .booking-expert-chip-name{ font-weight:700; }

    .booking-times-section{ margin-top:18px; padding-top:18px; border-top:1px solid rgba(0,0,0,0.08); }
    .booking-times-label{ font-family:var(--font-condensed); font-size:11px; font-weight:600; letter-spacing:0.04em; text-transform:uppercase; color:var(--graphite); margin-bottom:12px; }
    .booking-times{ display:flex; flex-wrap:wrap; gap:8px; }
    .booking-time{
      padding:9px 16px; border-radius:999px; border:1.5px solid var(--paper-white); background:var(--paper-white);
      font-family:var(--font-display); font-size:13px; font-weight:600; color:var(--obsidian);
      transition:background .15s ease, color .15s ease, border-color .15s ease;
    }
    .booking-time:not(:disabled):hover{ border-color:var(--obsidian); }
    .booking-time:disabled{ color:var(--muted); background:transparent; border-color:transparent; opacity:.5; cursor:not-allowed; text-decoration:line-through; }
    .booking-time.is-selected{ background:var(--brand-red); border-color:var(--brand-red); color:var(--on-obsidian); }

    .booking-confirm{
      width:100%; text-align:center; display:block; margin-top:28px; color:var(--on-obsidian);
      font-family:var(--font-condensed); font-weight:600; font-size:13px; letter-spacing:0.05em; text-transform:uppercase;
      padding:15px 24px; border-radius:8px; border:none; cursor:pointer;
    }
    .booking-confirm:disabled{ opacity:.35; pointer-events:none; }

    .booking-success-icon{
      width:52px; height:52px; border-radius:50%; background:var(--brand-red);
      display:flex; align-items:center; justify-content:center; margin-bottom:20px;
    }

    @media (prefers-reduced-motion: reduce){
      #booking-overlay, #sponsor-overlay, #resource-gate-overlay, .booking-modal{ transition:opacity .01s linear !important; transform:none !important; }
    }

    @media (max-width: 640px){
      .booking-modal{ padding:28px 20px; max-height:92vh; }
      .booking-expert-row{ grid-template-columns:repeat(2, 1fr); }
      .booking-contact-row{ grid-template-columns:1fr !important; }
    }
