/* PlanningCharts Globe Hero - everything scoped under #pc-globe-hero so
   FlyNext / Elementor styles (.btn, .badge, .panel, .tag ...) cannot collide.
   The only exception is the .pc-header-* pair below, which by definition styles the site
   header; both class names are prefixed so they cannot collide either. */

/* Header visibility during the pinned story. hero.js adds .pc-header-fade once and toggles
   .pc-header-hidden while the hero is the active ScrollTrigger.
   Fade rather than display:none / visibility:hidden on purpose - the nav keeps its place in the
   tab order, and :focus-within brings it straight back for keyboard users, who otherwise could
   not reach site navigation at all on the homepage. */
/* Pull-to-refresh / scroll-chaining OFF while the hero page is loaded. On a phone the hero owns
   the first gesture, and Chrome-Android's and Safari's pull-to-refresh kept stealing it: the page
   bounced (or reloaded) instead of the story starting. Unscoped on purpose - overscroll-behavior
   only has an effect on the scrolling element (html), not on a nested section. The plugin's CSS
   is enqueued only where the hero renders, so this does not leak to the rest of the site. */
html.pc-hero-engaged,
html.pc-hero-engaged body {
  /* `none`, not `contain`: contain only stops scroll CHAINING, while the
     rubber-band that arms pull-to-refresh still runs. Reported on device as
     "it tries to pull refresh" repeatedly during the story.
     Scoped to .pc-hero-engaged (hero.js adds it only while the hero's ScrollTrigger is active)
     rather than applied to html/body outright: as an unconditional rule it disabled
     pull-to-refresh for the WHOLE page for the whole session, which is a side effect this
     section has no business having once the user has scrolled past it. */
  overscroll-behavior-y: none;
}

.pc-header-fade {
  transition: opacity 0.35s ease;
}

.pc-header-hidden {
  opacity: 0;
  pointer-events: none;
}

.pc-header-hidden:focus-within {
  opacity: 1;
  pointer-events: auto;
}

/* TWO hide/show systems on one element is what made the WordPress build feel unsmooth: an
   Elementor/theme floating header runs its OWN scroll listener and animates itself (Elementor Pro
   applies `animation: elementor-sticky--effects` / a transform slide, themes do the same for
   "hide on scroll down"), while the story is fading the same element. They ran on different
   listeners with different durations, so every scroll-direction change played two competing
   moves. While the hero owns the gesture the story is the single authority: kill the theme's
   motion and let opacity alone drive it. Scoped to .pc-hero-engaged, so the header behaves
   exactly as the theme intends everywhere else on the page.
   Note this only suppresses MOTION - position:fixed and the sticky offsets are untouched, so the
   header still sticks; it just stops animating itself mid-story. */
html.pc-hero-engaged .pc-header-fade {
  animation: none !important;
  transform: none !important;
  transition: opacity 0.35s ease !important;
}

@media (prefers-reduced-motion: reduce) {
  .pc-header-fade {
    transition: none;
  }

  #pc-globe-hero .pc-frame {
    transition: none;
  }
}

/* Block-level host for ScrollTrigger's .pin-spacer. Elementor containers are flex
   (--display:flex), and GSAP warns that pinning a flex item makes the spacer's padding resolve
   wrong - which shows up as leftover space once the pin releases. Must NOT set overflow:hidden
   or a transform: either would break position:fixed on the pinned section. */
/* Carries the hero's own sky gradient too: when iOS drops the pinned layer for a frame during
   the post-step scroll re-sync, whatever is BEHIND the section shows through - previously the
   white page body, i.e. a hard white flash on step arrivals. With the same gradient back here,
   a dropped frame shows sky instead of white and reads as nothing. */
.pc-hero-wrap {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  background: linear-gradient(180deg, #a6bdd6 0%, #c8d7e8 42%, #eaf0f6 100%);
}

#pc-globe-hero {
  position: relative;
  width: 100%;
  overflow: hidden;
  /* NO text selection inside the hero. The section intercepts touch gestures to drive the story, and
     on iOS a press-and-drag that we then preventDefault() can still have armed a text selection -
     Safari then paints its two selection handles (a ~15px system-blue circle with a stem, one per
     end) over the globe. Reported as "two random blue markers"; verified NOT to be any element of
     ours (an exhaustive scan for bright-blue fills at 430x932@3x finds only the 6-7px runway
     prongs). Nothing in a marketing hero needs to be selectable, and the callout/tap-highlight
     suppression removes the other two iOS artefacts of the same gesture. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  height: 100vh;
  background: linear-gradient(180deg, #a6bdd6 0%, #c8d7e8 42%, #eaf0f6 100%);
  /* Typography from the live site (Elementor kit 6). --short-desc / --color-* are the theme's
     own :root tokens; the literals are fallbacks for the Elementor editor and the standalone
     prototype. Source Sans Pro 400/500/600/700 is already enqueued site-wide - the hero adds
     no second font request. */
  font-family:
    var(--short-desc, "Source Sans Pro"),
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    Helvetica,
    Arial,
    sans-serif;
  color: var(--color-text, #2c3131);
  /* headings use the theme's --title-font (PT Serif); everything else Source Sans Pro */
  --pc-heading:
    var(--title-font, "PT Serif"), Georgia, "Times New Roman", serif;
  /* site palette; the old prototype names stay as aliases so nothing downstream has to change */
  --apA: var(--color-primary, #12477b);
  /* brand primary */
  --blue: var(--color-primary, #12477b);
  /* headline accent */
  --navy: var(--color-text, #2c3131);
  /* dark ink */
  --ink: var(--color-text, #2c3131);
  --muted: #676766;
  /* kit --e-global-color-text (body copy) */
  --green: #00b300;
  --orange: #fe850f;
  --grey: #b2b2b2;
  /* content grid: centred max-width container + gutter. Everything horizontal is anchored to
     this grid, not raw viewport %. 1320px matches the theme's .site-container. */
  --maxw: 1320px;
  --gutter: clamp(24px, 3.4vw, 60px);
  /* sticky header height. Correct at first paint; hero.js re-measures and overrides inline
     if the live header differs (e.g. a shrink-on-scroll effect). Update if the header changes. */
  --pc-header: 90px;
  /* Globe centre, as a % of the full section (it bleeds behind the transparent header).
     Must stay inside 37%-63%: the canvas is 126vh tall, so outside that range one of its
     horizontal edges crosses into the viewport and shows as a hard line when zoomed in. */
  --globe-cy: 55%;
  --cw: min(100vw, var(--maxw));
  --cl: max(0px, calc((100vw - var(--maxw)) / 2));
  --edge: calc(var(--cl) + var(--gutter));
  --panel-w: min(560px,
      calc(var(--cw) * 0.42));
  /* intro panel width - things to its right key off this */
  /* Vertical anchor for .panel. hero.js writes the panel transform inline every frame, and an
     inline style beats any media query - so the breakpoint has to change this variable, never
     the transform itself. -50% = vertically centred (desktop), 0 = top-anchored (mobile). */
  --panel-shift: -50%;
  --globe-cx: calc(var(--cl) + var(--cw) * 0.7);
  --ov-cx: calc(var(--cl) + var(--cw) * 0.62);
  /* Overlap-proof overlay geometry. One source of truth for the feature-card width, and every
     overlay's width is capped to the space RIGHT of the text column (viewport minus text column
     minus 48px breathing room) - so an overlay can never be wide enough to reach the text, at
     any viewport width. The left:max() clamps in the overlay rules below then keep each
     overlay's LEFT EDGE at least 24px clear of the card, and the min() wrapper keeps the RIGHT
     EDGE at least 24px inside the viewport (measured 8-36px clipping at 830-1180px without it). */
  --pc-featw: clamp(340px, 32vw, 460px);
  /* base width; hero.js (fitApCardWide) grows the whole card from here into the measured free
     space on desktop, never past the text panel or the featured airport symbol */
  --pc-apw: clamp(320px, 27vw, 440px);
  --pc-chartw: min(50vw,
      900px,
      calc(100vw - var(--edge) - var(--pc-featw) - 48px));
  --pc-fanw: min(52vw,
      796px,
      calc(100vw - var(--edge) - var(--pc-featw) - 48px));
}

#pc-globe-hero *,
#pc-globe-hero *::before,
#pc-globe-hero *::after {
  box-sizing: border-box;
}

/* Layering. The site header is transparent and position:absolute (she-header-transparent-yes),
   so it floats over the hero instead of taking flow space. Background layers therefore run the
   full section height and bleed behind it - clipping them to the header line leaves a hard seam
   across the globe. Only .pc-frame (the content) is inset by the header height. */
/* NO inset transition and NO collapse-state inset anymore: animating the frame 56px up/down on
   every scroll direction change shifted EVERY box (panel, airport card, overlays) right after
   they appeared - reported on-device as "it shows everything, then re-renders and replaces all
   positions". The reserved header space now simply stays constant; 56px of reclaimed room was
   not worth a moving layout. */
#pc-globe-hero .pc-frame {
  position: absolute;
  inset: var(--pc-header, 0px) 0 0 0;
  overflow: hidden;
  z-index: 4;
}

/* left scrim, full-bleed so it does not band at the header line */
#pc-globe-hero::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
  width: calc(var(--cl) + var(--cw) * 0.5);
  background: linear-gradient(90deg,
      rgba(214, 225, 238, 0.9) 60%,
      rgba(214, 225, 238, 0));
}

/* poster = LCP element; covers the globe until WebGL has booted */
#pc-globe-hero .pc-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 3;
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

#pc-globe-hero.pc-booting .pc-poster,
#pc-globe-hero.pc-static .pc-poster {
  opacity: 1;
}

#pc-globe-hero.pc-static #pc-globe,
#pc-globe-hero.pc-static .overlay,
#pc-globe-hero.pc-static .rail,
#pc-globe-hero.pc-static .hint {
  display: none;
}

#pc-globe-hero.pc-static .panel[data-panel="0"] {
  opacity: 1;
}

/* The rendered sphere scales with canvas HEIGHT (the camera's fov is vertical), so height is the
   framing control and width is free. It must be wide enough that both canvas edges fall outside
   the viewport: once the camera zooms in (step 1 is altitude 0.60) the surface fills the canvas
   and any on-screen edge shows as a hard rectangle against the page background.
   Doubling the larger gap between the globe centre and a viewport edge guarantees full cover. */
#pc-globe {
  /* NO will-change / backface-visibility here. A WebGL canvas is already its own compositor
     layer, so promoting it again buys nothing - but on Windows/ANGLE the extra promotion can
     make the layer be re-created mid-animation, which shows up as a one-frame flash exactly at
     the start of a step (this rule was added in 1.3.2, right before those reports). */
  position: absolute;
  top: var(--globe-cy);
  left: var(--globe-cx);
  height: 126vh;
  width: calc(2 * max(var(--globe-cx), 100vw - var(--globe-cx)) + 4vw);
  transform: translate(-50%, -50%);
  z-index: 1;
}

/* A full-bleed, absolutely positioned stacking layer at z-index 3. It is a coordinate space, not
   a surface: with pointer-events left at the default it hit-tests across the entire hero and wins
   over anything painted below it, so a decorative layer could swallow clicks meant for something
   else.
   NOTHING is re-enabled here on purpose. Its only children are the .panel elements, and those
   already carry their own pointer-events pair further down (none by default, auto on the ACTIVE
   panel, kept in sync by hero.js) - that pair exists because the stacked inactive panels would
   otherwise swallow the CTA clicks. A `.stage .panel { pointer-events: auto }` rule here would
   outrank it on specificity and bring that bug straight back. */
#pc-globe-hero .stage {
  position: absolute;
  z-index: 3;
  inset: 0;
  pointer-events: none;
}

/* Seam-blend for the END of the story only - fades in via JS (render(), keyed off vp) as the
   scroll nears step 4, staying hidden for steps 0-3 so it doesn't fog the globe the whole time.
   Sits flush with the hero's own bottom edge (both #pc-globe-hero and .pc-frame clip at that
   line via overflow:hidden, so it can't visually bleed into whatever section follows - it only
   softens the color transition right at that shared edge). z-index:1, below .stage(3)/
   overlays(4)/rating-card(5) so it never covers readable content, but above the globe/scrim.
   Fixed short height + object-fit:cover, not width-driven - the image's real 800x445 (~1.8:1)
   aspect ratio meant stretching it to 110% viewport width made it 1000px+ tall. */
#pc-globe-hero .pc-cloud {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: 0;
  opacity: 0;
  width: 100%;
  object-fit: cover;
  pointer-events: none;
  /* svh pairing, same fallback pattern as #pc-globe-hero's own height: vh shifts a few px every
     time a phone's address bar shows/hides, jittering this strip's height on every such toggle;
     svh stays fixed. Two declarations, not one clamp() with a comma-fallback - browsers that don't
     understand svh discard the whole second declaration and keep the first. */
  height: clamp(90px, 16vh, 200px);
  height: clamp(90px, 16svh, 200px);
  /* fades the image's own top edge from transparent - the source PNG's alpha cuts off sharply
     there, which read as a hard line against the hero's sky instead of a blend. Bottom edge
     stays fully opaque since that's the edge actually meeting the next section. */
  -webkit-mask-image: linear-gradient(to bottom,
      transparent 0%,
      #000 35%,
      #000 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 35%, #000 100%);
  transform: translateY(50%);
}

/* matches the site's .banner-badge */
#pc-globe-hero .eyebrow {
  display: inline-block;
  background: var(--color-text, #2c3131);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  line-height: 150%;
  padding: 6px 16px;
  border-radius: 50px;
  margin-bottom: 16px;
}

/* opacity:0 is still hit-testable, and panels 1-4 sit on top of panel 0 (same position, later
   in source order) - without this they swallow every click on the CTA buttons. hero.js keeps
   this in sync with the active step; the CSS default covers pre-boot and static mode. */
#pc-globe-hero .panel {
  position: absolute;
  left: var(--edge);
  right: auto;
  max-width: var(--panel-w);
  top: 50%;
  transform: translateY(var(--panel-shift));
  will-change: opacity, transform;
  pointer-events: none;
}

#pc-globe-hero .panel[data-panel="0"] {
  pointer-events: auto;
}

/* Initial paint state, in CSS rather than only in JS. The panels are absolutely positioned on top
   of each other and hiding 1-n was done exclusively by GSAP's inline styles - so between first
   paint and the hero bundle executing, ALL of them painted stacked at full opacity. On a throttled
   phone that window is seconds long, it is user-visible, and it inflates the paint candidates
   during the LCP phase (the LCP element here is panel 0's paragraph, measured on production).
   Panel 0 is deliberately excluded: it carries the H1 and the LCP text and must paint immediately.
   GSAP overwrites this inline the moment it runs, so nothing downstream changes. */
#pc-globe-hero .panel:not([data-panel="0"]) {
  opacity: 0;
}

/* Nudges panel 0 up from dead-centre on desktop. Scoped to min-width so it can't leak into the
   mobile media query below, which already re-anchors panel 0 to the top via --panel-shift/top
   overrides of its own - an unscoped rule here would win on specificity and break that.
   42% clipped the eyebrow badge against .pc-frame's overflow:hidden top edge - the panel's own
   content (badge+h1+paragraph+CTA+badges) is tall enough that an 8-point shift ran out of room
   above it. Pulled back to a smaller shift; the 110px floor is just a safety net for short
   viewports, not the fix for that clipping - if it still clips, the shift needs to shrink further. */
@media (min-width: 821px) {
  #pc-globe-hero .panel[data-panel="0"] {
    top: clamp(110px, 47%, 50%);
  }
}

/* headings: PT Serif 700, 52px, line-height 1.2em (kit "secondary" typography) */
#pc-globe-hero .panel[data-panel="0"] h1 {
  font-size: 60px;
}

/* :is(h1, h2) throughout, because only panel 0 carries the page's single <h1> - the four step
   headings in panels 1-4 are <h2> (a page may have exactly one h1, and an audit flagged them).
   Both are type selectors so :is() does not change specificity and nothing else in the cascade
   shifts. Shared rules match either tag; the [data-panel="1..4"] rules target h2 directly. */
#pc-globe-hero .panel :is(h1, h2) {
  font-family: var(--pc-heading);
  font-size: clamp(30px, 3.4vw, 52px);
  line-height: 1.2;
  margin: 0 0 18px;
  font-weight: 700;
  letter-spacing: normal;
  color: var(--color-text, #2c3131);
}

#pc-globe-hero .panel :is(h1, h2) .accent {
  color: var(--apA);
}

#pc-globe-hero .panel p {
  font-size: 16px;
  line-height: 150%;
  color: var(--muted);
  margin: 0;
  max-width: 56ch;
}

#pc-globe-hero .panel .tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 14px;
  color: var(--navy);
  margin-bottom: 14px;
  justify-content: center;
}

#pc-globe-hero .tag .dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
}

/* feature steps live in a floating white card (not the intro) */
#pc-globe-hero .panel[data-panel="1"],
#pc-globe-hero .panel[data-panel="2"],
#pc-globe-hero .panel[data-panel="3"],
#pc-globe-hero .panel[data-panel="4"] {
  /* no `right` here: the base .panel rule already sets right:auto, and repeating it at this
     higher specificity would beat the mobile rule's right:var(--gutter) - which showed up as
     step 1-4 cards having a left gutter but running flush to the right edge on phones. */
  max-width: var(--pc-featw);
  /* single source - the overlay clamps above key off the same var */
  background: #fff;
  border-radius: 22px;
  padding: clamp(26px, 2.2vw, 38px);
  box-shadow: 0 26px 60px rgba(11, 42, 74, 0.2);
  text-align: center;
  /* .tag/.eyebrow/.pill are inline-flex/inline-block, so they centre too */
}

#pc-globe-hero .panel[data-panel="1"] p,
#pc-globe-hero .panel[data-panel="2"] p,
#pc-globe-hero .panel[data-panel="3"] p,
#pc-globe-hero .panel[data-panel="4"] p {
  max-width: none;
}

/* Buttons = the Elementor kit button, verbatim (16px/1.2em Source Sans Pro 600,
   #12477B fill, 1px border, radius 8px, padding 18px 40px, hover inverts to white).
   The site defines only the filled variant, so .btn-outline is that same style with the
   hover/rest states swapped - no invented colours. */
#pc-globe-hero .cta {
  display: flex;
  gap: 16px;
  margin-top: 24px;
  flex-wrap: wrap;
  align-items: flex-start;
}

/* pairs the pill with the primary button specifically, rather than spanning under the whole
   CTA row - button widths are content-driven, not fixed, so this needs an actual wrapper
   rather than a margin-left guess that would break if the button text ever changes. */
#pc-globe-hero .cta-primary {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  position: relative;
}

#pc-globe-hero .btn-icon {
  flex-shrink: 0;
}

#pc-globe-hero .btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.2em;
  padding: 18px 40px;
  border-radius: 8px;
  border: 1px solid var(--apA);
  cursor: pointer;
  text-decoration: none;
  transition:
    background-color 0.2s ease,
    color 0.2s ease;
}

#pc-globe-hero .btn-primary {
  background-color: var(--apA);
  color: #fff;
  box-shadow: 0 4px 20px 0 rgba(18, 71, 123, 0.15);
}

/* TWO separate states, deliberately not one rule any more. Both halves misbehaved on iOS, and only
   on these buttons - every Elementor button on the page activates on the first tap.
   :hover -> gated behind a real hovering pointer. WebKit paints :hover from the mouse-emulation
     sequence a tap fires BEFORE it decides whether to deliver the click, and when the hover changes
     what is rendered it withholds the click and waits for a second tap. A touch device has no
     hover to animate, so gating this costs nothing there; desktop is completely unchanged.
   :focus -> :focus-visible. iOS leaves :focus on a tapped link and does not clear it the way a
     mouse-up does, so the button sat inverted after the tap - the "stays highlighted" report.
     :focus-visible does not match a tap, so keyboard users keep the state and touch users do not.
   Keep them split. Merging them back re-creates both bugs at once. */
@media (hover: hover) and (pointer: fine) {
  #pc-globe-hero .btn-primary:hover {
    background-color: #fff;
    color: var(--apA);
  }
}

/* :active is the touch device's feedback. It paints while the finger is down and clears the moment
   it lifts, so unlike :focus it cannot survive the tap and sit there highlighted, and unlike
   :hover it is not part of the mouse-emulation sequence. */
#pc-globe-hero .btn-primary:focus-visible,
#pc-globe-hero .btn-primary:active {
  background-color: #fff;
  color: var(--apA);
}

#pc-globe-hero .btn-outline {
  background-color: #fff;
  color: var(--apA);
  box-shadow: 0 4px 20px 0 rgba(18, 71, 123, 0.15);
}

/* Same split as .btn-primary above - see the note there for why. */
@media (hover: hover) and (pointer: fine) {
  #pc-globe-hero .btn-outline:hover {
    background-color: var(--apA);
    color: #fff;
  }
}

#pc-globe-hero .btn-outline:focus-visible,
#pc-globe-hero .btn-outline:active {
  background-color: var(--apA);
  color: #fff;
}

#pc-globe-hero .btn:focus-visible {
  outline: 3px solid var(--apA);
  outline-offset: 3px;
}

/* Badge, not an inline pill below the button - sits at the button's top-right corner,
   overlapping outward/upward, per the reference. position:relative on .cta-primary above is
   what this anchors against. */
#pc-globe-hero .pill {
  position: absolute;
  top: 0;
  right: 0;
  transform: translate(15%, -55%);
  z-index: 1;
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
  border-radius: 50px;
  padding: 5px 14px;
  background: #2fae5c;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.18);
  right: 30px;
}

/* store badges: unstyled, always one row. min-width:0 is what lets a flex item shrink below its
   image's intrinsic width - without it nowrap would overflow the panel instead of scaling down. */
#pc-globe-hero .badges {
  display: flex;
  gap: 12px;
  margin-top: 16px;
  align-items: center;
  flex-wrap: nowrap;
}

#pc-globe-hero .badge {
  display: inline-flex;
  line-height: 0;
  min-width: 0;
  flex: 0 1 auto;
}

#pc-globe-hero .badge img {
  display: block;
  max-width: 100%;
  height: auto;
}

/* the standalone preview ships 1x1 data-URI placeholders for the store badges - height:auto
   turned them into big empty squares. Hide placeholders; real store images are unaffected. */
#pc-globe-hero .badge img[src^="data:image/gif"] {
  display: none;
}

/* sits to the right of the intro panel. Keyed off --panel-w rather than a fixed fraction of the
   grid, so it cannot drift back over the CTA buttons when the panel resizes. */
/* rating-bg.png carries its own glow/border baked in, so background-size stretches it to fill
   exactly (100% 100%, not cover) rather than crop those edges on aspect-ratio mismatch */
#pc-globe-hero .rating-card {
  position: absolute;
  z-index: 5;
  left: calc(var(--edge) + var(--panel-w) + 32px);
  /* --pc-rc-bottom is written by hero.js only when this box would cross the scroll hint (measured
     10px overlap at 1440x900); otherwise the designed 10% anchor stands. */
  bottom: var(--pc-rc-bottom, 10%);
  display: flex;
  align-items: center;
  gap: 14px;
  background: url("assets/rating-bg.webp") center/100% 100% no-repeat;
  border-radius: 16px;
  padding: 40px;
  will-change: opacity;
}

#pc-globe-hero .lido-card {
  position: absolute;
  z-index: 5;
  left: calc(var(--edge) + var(--panel-w) + 330px);
  bottom: 10%;
  display: flex;
  align-items: center;
  gap: 14px;
  will-change: opacity;
  padding: 28px 0;
}

#pc-globe-hero .rating-card .rc-icon {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
}

#pc-globe-hero .rating-card .rc-icon img {
  width: 100%;
  height: 100%;
  /* object-fit is what actually fixes the squashed icon. rc-icon.png is 55x60 (taller than wide)
     and the box above is a 38x38 square, so width/height:100% stretched it 9% wider than it should
     be. contain keeps the real aspect ratio - the icon renders 35x38 and is centred in the box, so
     no surrounding layout moves. Changing the img's width/height ATTRIBUTES would not have helped:
     these CSS rules override them. */
  object-fit: contain;
  display: block;
}

#pc-globe-hero .rating-card .rc-top {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

#pc-globe-hero .rating-card .stars {
  display: inline-flex;
  gap: 2px;
}

#pc-globe-hero .rating-card .stars svg {
  width: 13px;
  height: 13px;
  fill: #f5b301;
}

#pc-globe-hero .rating-card .score {
  font-family: var(--pc-heading);
  font-size: 24px;
  font-weight: 800;
  color: #fff;
  line-height: 1;
}

#pc-globe-hero .rating-card .label {
  font-size: 13px;
  font-weight: 600;
  color: #a9c1e8;
}

#pc-globe-hero .rating-card .reviews {
  font-size: 13px;
  font-weight: 500;
  color: #c9d6ec;
  margin-top: 3px;
}

/* airport markers (injected by globe.gl into #pc-globe) */
#pc-globe-hero #pc-globe,
#pc-globe-hero #pc-globe canvas {
  cursor: default;
  /* nothing on the globe is clickable - never suggest otherwise */
}

#pc-globe-hero .gmark {
  pointer-events: none;
  will-change: transform;
}

#pc-globe-hero .marker {
  position: absolute;
  left: 0;
  top: 0;
  width: 58px;
  height: 58px;
  transform: translate(-50%, -50%);
  transform-style: preserve-3d;
  transition: filter 0.3s ease;
  pointer-events: none;
}

#pc-globe-hero .marker .tem {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* .marker .grade is GONE - there is no second element any more. The grade symbol is drawn inside
   the ring's own <svg> (see gradeArt/temRing in hero.js), so it cannot be misaligned by CSS,
   by an engine's 3D flattening, or by anything else: it shares the ring's coordinate system.
   Two earlier attempts to align it as a separate element (matching the centring mechanism, then
   padding + object-fit) fixed phones and left iPadOS wrong - which is what a construction that
   relies on two boxes agreeing looks like when it fails. */

/* all symbols bloom ~30% during the approach into (and throughout) the threat-circles step -
   declared BEFORE .active so the featured airport's 1.5x still wins at equal specificity */
/* All marker scaling lives in the per-frame surface transform in hero.js (base 0.70, featured
   1.00) - it must not be overwritten here, or the symbols would snap back to flat billboards. */
#pc-globe-hero .marker.active {
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45));
  z-index: 5;
}

/* chart name pinned to the AT-2 rectangle's centre - same colour set as the region stroke and
   the chart border, so rectangle, label and chart read as one thing. Shown only during the
   region-highlight window (hero.js toggles .on together with the fill/stroke). */
#pc-globe-hero .pc-region-label {
  position: absolute;
  transform: translate(-50%, -50%);
  background: rgba(18, 71, 123, 0.92);
  color: #fff;
  border: 1.5px solid rgba(90, 175, 255, 0.9);
  border-radius: 8px;
  padding: 5px 14px;
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.06em;
  font-family: inherit;
  white-space: nowrap;
  pointer-events: none;
  box-shadow:
    0 4px 16px rgba(6, 20, 38, 0.45),
    0 0 18px rgba(64, 150, 255, 0.4);
  opacity: 0;
  transition: opacity 0.35s ease;
}

#pc-globe-hero .pc-region-label.on {
  opacity: 1;
}

#pc-globe-hero .overlay {
  position: absolute;
  z-index: 4;
  top: 50%;
  left: var(--ov-cx);
  transform: translate(-50%, -50%);
  will-change: opacity, transform;
  pointer-events: none;
}

/* airport card: never closer than 24px to the text card (measured -4px overlap at 830px wide) */
#pc-globe-hero .overlay[data-ov="2"] {
  left: max(var(--ov-cx),
      calc(var(--edge) + var(--pc-featw) + 24px + var(--pc-apw) / 2));
}

#pc-globe-hero .overlay .ap-card {
  /* --pc-apw-fit is written by hero.js (fitApCardWide) from the measured corridor between the text
     panel and the featured airport symbol; --pc-apw is the pre-JS default. */
  width: var(--pc-apw-fit, var(--pc-apw));
}

#pc-globe-hero .shot {
  margin: 0;
}

#pc-globe-hero .shot img {
  display: block;
  max-width: 100%;
  max-height: 86vh;
  height: auto;
  /* Aspect LOCKED, and object-fit:contain as the backstop. height:auto alone keeps the ratio only
     as long as nothing else sets a height - but this plugin renders inside a WordPress theme, and
     theme/page-builder resets like `img { width: 100%; height: 100% }` or `.elementor img { height:
     auto !important }` are common. With both set, the default object-fit:fill would stretch the
     chart, which is exactly the reported landscape symptom. These two lines make that impossible
     regardless of what any ancestor stylesheet says. */
  aspect-ratio: 1700 / 1201;
  /* = the real pixel size of assets/chart-at2.webp */
  object-fit: contain;
  border-radius: 12px;
  box-shadow: 0 22px 60px rgba(11, 42, 74, 0.4);
}

/* REMOVED: the blue 2px border + blue glow. They were colour-matched to the AT-2 rectangle
   (rgba(90,175,255), the same value as polygonStrokeColor) so that region-highlight -> chart read as
   ONE object transforming. That worked during the morph but persisted afterwards as a blue frame
   around the finished chart - indistinguishable from "the rectangle is still there", which is what
   was reported. The chart now keeps only the neutral lift inherited from .shot img
   (0 22px 60px rgba(11,42,74,0.4)), which is what separates it from the light sky. */
/* Position = preferred spot, clamped from BOTH sides: never left of "text card + 24px", never
   right of "viewport - 24px". Width capped via --pc-chartw so both constraints are satisfiable
   at every viewport width (at 821-900px the old fixed fractions overlapped the text card AND
   clipped offscreen at once - measured, not theoretical). */
#pc-globe-hero .ov-chart {
  /* 50%, not 44%: on desktop the info box and the visual must share one centre line */
  top: 50%;
  width: var(--pc-chartw);
  left: min(max(calc(var(--cl) + var(--cw) * 0.76),
        calc(var(--edge) + var(--pc-featw) + 24px + var(--pc-chartw) / 2)),
      calc(100vw - 24px - var(--pc-chartw) / 2));
}

/* know-how fan: children sized FROM --pc-fanw (s1 59%, snips half-minus-gap) instead of their
   own independent clamps - the wrapper's real width is exactly --pc-fanw, so the same two-sided
   clamp genuinely bounds it (the old per-child clamps made the wrapper wider than any single
   variable knew, which is how it overlapped panel 4 by 39px at 830px). */
#pc-globe-hero .ov-fan {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  left: min(max(calc(var(--cl) + var(--cw) * 0.72),
        calc(var(--edge) + var(--pc-featw) + 24px + var(--pc-fanw) / 2)),
      calc(100vw - 24px - var(--pc-fanw) / 2));
}

#pc-globe-hero .ov-fan .snip {
  position: relative;
}

#pc-globe-hero .ov-fan .s1 {
  width: calc(var(--pc-fanw) * 0.59);
  transform: rotate(-1.5deg);
}

#pc-globe-hero .ov-fan .fan-row {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}

#pc-globe-hero .ov-fan .fan-row .snip {
  width: calc(var(--pc-fanw) / 2 - 8px);
}

#pc-globe-hero .ov-fan .s2 {
  transform: rotate(-3deg);
}

#pc-globe-hero .ov-fan .s3 {
  transform: rotate(3deg);
}

/* max-height still caps the card so it can't grow taller than the frame, but it's non-
   interactive again (pointer-events:none, inherited from .overlay) - making it scrollable
   made it capture scroll/drag gestures that land on it, which sits centered over the globe,
   silently eating normal page-scroll input right where users are most likely to scroll. A
   clipped card beats a story that stops responding to scroll. */
#pc-globe-hero .ap-card {
  position: relative;
  background: #0f2740;
  border-radius: 14px;
  color: #e9eff6;
  box-shadow: 0 20px 55px rgba(6, 20, 38, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.08);
  overflow: hidden;
  font-size: 12px;
  max-height: min(80vh, 640px);
  display: flex;
  flex-direction: column;
}

#pc-globe-hero .apc-head {
  padding: 12px 14px;
  background: #0b1f34;
  flex: 0 0 auto;
}

#pc-globe-hero .apc-title {
  font-weight: 800;
  font-size: 13px;
  line-height: 1.35;
  color: #fff;
}

#pc-globe-hero .apc-body {
  padding: 12px 14px;
}

#pc-globe-hero .apc-sec {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: #8fa8c2;
  margin: 12px 0 7px;
  text-transform: uppercase;
}

#pc-globe-hero .apc-sec:first-child {
  margin-top: 0;
}

#pc-globe-hero .apc-sec-sub {
  text-transform: none;
  font-weight: 500;
  letter-spacing: normal;
  color: #6f88a3;
}

#pc-globe-hero .apc-strip {
  display: flex;
  gap: 3px;
}

#pc-globe-hero .apc-cell {
  flex: 1;
  text-align: center;
}

#pc-globe-hero .apc-bar {
  height: 26px;
  border-radius: 3px;
}

#pc-globe-hero .apc-hr {
  font-size: 9px;
  color: #8fa8c2;
  margin-top: 3px;
}

#pc-globe-hero .apc-leg {
  display: flex;
  gap: 12px;
  font-size: 10px;
  color: #9db4cc;
  margin: 2px 0 8px;
}

#pc-globe-hero .apc-leg i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  margin-right: 4px;
  vertical-align: middle;
}

/* header row: "Runways" label + the NOTAMs pill, side by side */
#pc-globe-hero .apc-rwys-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 7px;
}

#pc-globe-hero .apc-rwys-head .apc-sec {
  margin: 12px 0 0;
}

#pc-globe-hero .apc-notam-btn {
  background: #3fcfae;
  color: #0b1f34;
  border: none;
  border-radius: 20px;
  padding: 6px 14px;
  font-size: 11px;
  font-weight: 700;
  cursor: default;
  white-space: nowrap;
}

/* flex-wrap, not a fixed grid - pill widths vary a lot (CLOSED vs Cat N), so which ones share a
   row depends on their actual text length, same as the reference. | separators sit inline and
   wrap along with whichever pill precedes them. */
#pc-globe-hero .apc-rwys {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

#pc-globe-hero .apc-rwys div {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(160, 190, 230, 0.35);
  border-radius: 20px;
  padding: 6px 12px;
  font-size: 11px;
  color: #cdd9e6;
}

/* closed runway - filled instead of outlined, dark text on teal so CLOSED reads as a status, not just a label */
#pc-globe-hero .apc-rwys div.closed {
  background: #3fcfae;
  border-color: #3fcfae;
  color: #0b1f34;
  font-weight: 700;
}

#pc-globe-hero .rwy-sep {
  color: rgba(160, 190, 230, 0.5);
  font-size: 12px;
  margin: 0 -2px;
}

#pc-globe-hero .apc-mono {
  margin: 0;
  background: #0b1f34;
  border-radius: 8px;
  padding: 9px 10px;
  font:
    11px/1.4 ui-monospace,
    Menlo,
    Consolas,
    monospace;
  color: #cdd9e6;
  white-space: pre-wrap;
}

#pc-globe-hero .apc-mono .thr {
  color: var(--orange);
}

#pc-globe-hero .rail {
  position: absolute;
  right: 26px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 6;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

#pc-globe-hero .rail .d {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(11, 42, 74, 0.3);
  transition: all 0.3s;
}

#pc-globe-hero .rail .d.on {
  background: var(--navy);
  transform: scale(1.4);
}

#pc-globe-hero .hint {
  /* a real <button>: it now performs the scroll when clicked/tapped, so it must be reset from
     the UA button styling and take pointer events (it used to be pointer-events:none) */
  -webkit-appearance: none;
  appearance: none;
  background: none;
  border: 0;
  padding: 6px 10px;
  cursor: pointer;
  position: absolute;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  pointer-events: auto;
  /* SAME typography as the panel sub-text: inherited family, 16px/150%, muted - no uppercase,
     no letter-spacing, no pill. The pill+caps version read as a call-to-action button. */
  font-family: inherit;
  font-size: 16px;
  line-height: 150%;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  /* --navy (#2C3131) at 600 instead of --muted (#676766) at 400: on the light sky the muted grey
     was barely legible. Same family and size as the sub-text, just darker and a touch heavier. */
  color: var(--navy);
  font-weight: 600;
}

/* The text now sits in a small, low-contrast label rather than as bare copy on the sky. Requested
   after the bare version competed with the intro sub-text for attention; the translucent chip reads
   as a hint, and it is still the same family/size as the sub-text (no caps, no letter-spacing) so it
   cannot be mistaken for a primary CTA. */
#pc-globe-hero .hint .hint-label {
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.62);
  border: 1px solid rgba(18, 71, 123, 0.1);
  box-shadow: 0 2px 8px rgba(11, 42, 74, 0.08);
  font-size: 14px;
  line-height: 1.3;
  opacity: 1;
  transition: opacity 0.35s ease;
  text-shadow: 0 1px 12px rgba(255, 255, 255, 0.85);
}

#pc-globe-hero .hint:hover,
#pc-globe-hero .hint:focus-visible {
  opacity: 1;
}

#pc-globe-hero .hint:hover .pc-chevs svg {
  opacity: 0.85;
  animation-play-state: paused;
}

#pc-globe-hero .hint:focus-visible {
  outline: 2px solid var(--apA);
  outline-offset: 3px;
  border-radius: 10px;
}

#pc-globe-hero .hint .pc-chevs {
  display: flex;
  flex-direction: column;
  align-items: center;
}

#pc-globe-hero .hint .pc-chevs svg {
  display: block;
  width: 24px;
  height: 11px;
  margin-top: -3px;
  /* black, not the brand blue (--apA): on the light sky the blue chevrons read as a link/control,
     which is the "it looks clickable" problem in miniature. Neutral ink states "there is more
     below" without implying an action. #111 rather than pure #000 so it sits with the navy label
     instead of punching a hole in the composition. */
  color: #111;
  opacity: 0.22;
  /* 2.8s, from 1.5s: at 1.5s with 0.16s stagger the three chevrons read as a fast blinking strobe
     next to an otherwise calm scene. Slower, with the stagger scaled by the same factor so the
     wave keeps its shape. */
  animation: pc-chev 2.8s ease-in-out infinite;
}

#pc-globe-hero .hint .pc-chevs svg:nth-child(2) {
  animation-delay: 0.3s;
}

@keyframes pc-chev {

  0%,
  100% {
    opacity: 0.18;
  }

  50% {
    opacity: 1;
  }
}

@keyframes pc-bob {

  0%,
  100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(7px);
  }
}

/* Short viewports (laptops at 1366x768, or any browser with toolbars): the intro panel is the
   tallest thing in the hero and was clipping at the frame bottom. Tighten the vertical rhythm
   rather than let the app-store badges get cut off. */
@media (max-height: 820px) {
  #pc-globe-hero .panel :is(h1, h2) {
    font-size: clamp(28px, 3vw, 42px);
    margin-bottom: 14px;
  }

  #pc-globe-hero .eyebrow {
    margin-bottom: 12px;
    font-size: 13px;
    padding: 5px 14px;
  }

  #pc-globe-hero .panel p {
    font-size: 15px;
    max-width: 52ch;
  }

  #pc-globe-hero .cta {
    margin-top: 18px;
    gap: 12px;
  }

  #pc-globe-hero .btn {
    padding: 14px 28px;
  }

  #pc-globe-hero .badges {
    margin-top: 12px;
    gap: 10px;
  }
}

/* mobile header is shorter; JS re-measures and overrides if the live value differs */
@media (max-width: 1024px) {
  #pc-globe-hero {
    --pc-header: 56px;
    --panel-w: min(560px, calc(var(--cw) * 0.44));
  }
}

/* tablet / small laptop: pull the globe in a touch */
@media (max-width: 1180px) {
  #pc-globe-hero {
    --globe-cx: calc(var(--cl) + var(--cw) * 0.64);
  }

  #pc-globe {
    height: 120vh;
  }

  /* height only - width is computed from --globe-cx above */
}

/* Mobile: same pinned scroll story as desktop, stacked instead of side-by-side.
   Content on top, globe underneath it.
   ONE height unit for the section AND the globe anchor - see the height rule below for why it is
   plain vh. Mixing units here is what produced the "globe repositions 2-3 times" report: the
   section measured in one unit while the globe was anchored in another, so a toolbar change moved
   them by different amounts. */
@media (max-width: 820px) {

  /* --panel-shift, not `transform:none`: hero.js writes the transform inline every frame and
     would otherwise drag the top-anchored panel up by half its own height. */
  #pc-globe-hero {
    --gutter: 16px;
    /* 100vh - and this choice is deliberate, having now been wrong in both directions:
         - a LIVE viewport height (dvh / visualViewport) changes while the toolbar animates, so
           GSAP's pin-spacer and the section disagree -> the page jumps on pin entry;
         - 100svh is the height WITH the toolbar shown, so once the toolbar hides the section is
           too short and leaves an empty strip at the bottom (reported with a screenshot).
       On iOS Safari plain 100vh is the LARGE (toolbar-hidden) height and is STATIC: it always
       covers the screen and never changes underneath the pin. Bottom-anchored content therefore
       keeps a toolbar-sized offset (see .hint below). */
    height: 100vh;
    --panel-shift: 0px;
  }

  /* REMOVED: .pc-header-collapsed no longer moves the frame. Reclaiming the hidden header's
     56px meant every scroll-direction change re-laid-out every visible box (panel, airport
     card, overlays) - the on-device "everything shifts after it appears" bug. The header
     still fades; its reserved space just stays put. */
  /* Globe in the lower part of the frame. Square, sized by whichever axis is tighter, so it can
     never end up wider than the screen can show - an oversized canvas relying on overflow
     clipping is what left dead space beside the sphere. */
  /* Here the canvas box cannot be pushed off-screen - it is what sizes the sphere, and the
     layout needs the globe confined to the lower half. So soften the edge instead: once the
     camera zooms in the surface fades out circularly rather than ending in a hard rectangle. */
  #pc-globe {
    /* Sized so the WHOLE sphere fits between the text card and the section's bottom edge:
       at top:64vh the box extends 29vh below its centre, so 58vh is the largest diameter that
       cannot be clipped. 150vw/110vh overflowed the section and the sphere was cut off flat.
       top in vh, NOT %: a percentage resolves against the SECTION, and while the pin is engaged
       the section is transform-positioned - the percentage then lagged the section by a frame,
       which is what made the globe jump 2-3 times while scrolling in. vh is fixed per
       orientation, matches the section's own unit exactly, so the globe stays put. */
    --gsize: min(122vw, 58vh);
    left: 50%;
    top: 64vh;
    width: var(--gsize);
    height: var(--gsize);
    transform: translate(-50%, -50%);
    /* Fade band tightened to the outer 8% (was the outer 26%, starting at 74%). The mask only
       has to hide the canvas's own straight edge; at 74% it was erasing a quarter of the canvas
       radius, and on the zoomed-in steps (airport symbols is altitude 0.60, where the sphere
       fills the whole canvas) that erased band fell ON the globe - the sphere dissolved into a
       broad white haze and its shape was barely readable on mobile. */
    -webkit-mask-image: radial-gradient(circle closest-side,
        #000 92%,
        transparent 100%);
    mask-image: radial-gradient(circle closest-side,
        #000 92%,
        transparent 100%);
  }

  #pc-globe-hero::before {
    display: none;
  }

  /* left scrim is a two-column device */

  /* copy pinned to the top of the frame (globe sits below it), centred horizontally to match
     the site's own hero, which is centre-aligned. No card background on mobile - per the Figma
     reference, the intro panel's text floats directly over the globe/gradient, same as desktop.
     Panels 1-4 still get their own white card via the [data-panel] override below - unaffected,
     since that rule sets its own background at higher specificity regardless of this one. */
  #pc-globe-hero .panel {
    left: var(--gutter);
    right: var(--gutter);
    max-width: none;
    top: var(--gutter);
    bottom: auto;
    text-align: center;
  }

  /* flex rows do not follow text-align - centre them explicitly. Everything else in the panel
     (.eyebrow, .tag, .pill) is inline-block/inline-flex and centres from text-align above. */
  #pc-globe-hero .cta,
  #pc-globe-hero .badges {
    justify-content: center;
  }

  /* must restate every property the desktop [data-panel] rule sets, or it wins here on
     specificity (1,2,0 vs 1,1,0) - a media query adds none */
  /* tightened from padding:20px/h1 up to 30px/10px margins - this is the space being reclaimed
     for the airport card below, which was clipping its own TAF section with the old sizing.
     Fixed height (not content-driven) + flex-centred text - all 4 steps share the exact same
     top AND footprint now, instead of the box's bottom edge shifting with each step's text
     length. Value is a guess at what fits the longest of the 4 paragraphs - verify visually
     and adjust if any step's text is tight or the box looks oversized for the shortest one.
     Bumped up from 150-210 to fit the h1 at 36px now - that made the content taller than the
     old box, pressing the tag right up against the top with no breathing room. */
  #pc-globe-hero .panel[data-panel="1"],
  #pc-globe-hero .panel[data-panel="2"],
  #pc-globe-hero .panel[data-panel="3"],
  #pc-globe-hero .panel[data-panel="4"] {
    background: #fff;
    padding: 14px;
    max-width: none;
    /* min-height, NOT height. A fixed height cannot grow, so the longest paragraph was simply cut
       off inside the white box - and the clamp was only ever "a guess at what fits" (see above).
       Measured: on a 375x629 iPhone 12 mini the box computes to 214px while panel 2's content
       needs 215px, so it clipped by 1px in Chrome's metrics and by more under real iOS font
       rendering; at 320px wide it clipped by up to 22px. min-height keeps every card the same
       size when the text fits - which is the reason the fixed height existed - and lets the one
       long card grow instead of losing a line. justify-content:center still centres short cards. */
    min-height: clamp(190px, 34svh, 240px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    border-radius: 18px;
    box-shadow: 0 12px 34px rgba(11, 42, 74, 0.16);
  }

  #pc-globe-hero .panel[data-panel="0"] h1 {
    font-size: 36px;
    margin-bottom: 6px;
  }

  /* panels 1-4 had no mobile override at all, so they fell back to the desktop clamp's 30px
     floor - too big for these smaller feature cards. */
  #pc-globe-hero .panel[data-panel="1"] h2,
  #pc-globe-hero .panel[data-panel="2"] h2,
  #pc-globe-hero .panel[data-panel="3"] h2,
  #pc-globe-hero .panel[data-panel="4"] h2 {
    font-size: 24px;
    margin-bottom: 6px;
  }

  #pc-globe-hero .eyebrow {
    font-size: 14px;
    padding: 5px 12px;
    margin-bottom: 6px;
  }

  #pc-globe-hero .panel p {
    font-size: 16px;
    max-width: none;
  }

  /* spacing matched to the site's own mobile hero (reference screenshot 2026-08-10):
     ~26px text->CTAs (also leaves headroom for the floating Save-10% pill), ~18px
     CTAs->store badges - the old 10px/8px pressed all three rows into one clump */
  #pc-globe-hero .cta {
    gap: 10px;
    margin-top: 26px;
    flex-wrap: nowrap;
  }

  /* 8px/16px matches the site's other buttons on mobile - unchanged, and it was never the problem.
     line-height IS: it was 26px on a 14px font, which silently added ~9px of height on top of the
     padding and made these buttons visibly taller than every other button on the page (26 + 16 =
     42px against 16.8 + 16 = 32.8px). Line-height was doing padding's job. With 1.2em the box is
     the padding plus the text, which is what the rest of the site does. */
  #pc-globe-hero .btn {
    gap: 9px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px 16px;
    font-size: 14px;
    line-height: 1.2em;
  }

  /* flex:1 matches .btn's flex:1 above - without it, .cta-primary (wrapping the primary button +
     pill) had no grow factor of its own, so it stayed at its natural width while the outline
     button grew to fill the row, throwing off the 50/50 split and wrapping to two lines.
     align-items:stretch (overriding the desktop rule's flex-start) makes the button inside fill
     this column's full width, matching the outline button - flex-start left it sized to its own
     text instead. Only scoped to mobile: on desktop, without the flex:1-forced equal columns,
     stretch would instead widen the button to match the pill's (wider) natural text width. */
  #pc-globe-hero .cta-primary {
    min-width: 0;
    align-items: stretch;
  }

  /* now a badge floating at the button's corner (see base .pill rule) rather than in-flow
     content, so it's no longer width-constrained by this column - just a smaller size for
     the smaller screen. */
  #pc-globe-hero .pill {
    font-size: 10.5px;
    padding: 4px 11px;
  }

  #pc-globe-hero .badges {
    gap: 12px;
    margin-top: 18px;
  }

  /* overlays sit over the globe, i.e. in the lower half. Shifted up 8pts together with #pc-globe
     above (68%->60%) to close the dead gap between the text card and the globe - kept in sync
     with the globe's own shift so overlay content stays aligned to it across steps 2-4. */
  #pc-globe-hero .overlay {
    left: 50%;
    top: 62%;
  }

  /* ov=2 (the airport card) specifically gets more room than the shared top:62% above -
     ov-chart/ov-fan (steps 3/4) stay at 62%, untouched, since they weren't clipping. Combined
     with the shrunk text panel above, this is genuinely more vertical budget, not just a
     smaller max-height fighting the same constraint.
     Pushed from 52% to 57% - the text panel above grew ~40px taller for the 36px h1 fix, which
     was eating directly into this gap and causing an overlap. max-height trimmed to match
     (57% start = less room left before the viewport's bottom edge than 52% had). */
  /* left:50% must be restated HERE: the desktop [data-ov="2"] left-clamp above is (0,2,0)
     specificity and would beat this block's plain .overlay{left:50%} on phones.
     top/max-height come from hero.js's sizeApCard() (measured free space below the text
     panel) - the static values are only the pre-JS fallback. */
  /* top-anchored: fallback mirrors sizeApCard's maths (gutter + fixed panel height + 12px);
     transform restated so the pre-render state matches what render() writes (no -50% Y) */
  #pc-globe-hero .overlay[data-ov="2"] {
    transform-origin: top center;
    top: var(--pc-ov2-top,
        calc(var(--gutter) + clamp(190px, 34svh, 240px) + 12px));
    left: 50%;
    transform: translate(-50%, 0);
  }

  #pc-globe-hero .overlay .ap-card {
    width: min(86vw, 330px);
    max-height: var(--pc-ov2-maxh, min(59svh, 520px));
    font-size: 11px;
  }

  #pc-globe-hero .apc-body {
    padding: 9px 12px;
  }

  #pc-globe-hero .apc-sec {
    margin: 8px 0 5px;
  }

  #pc-globe-hero .apc-mono {
    padding: 7px 8px;
    font-size: 10px;
    line-height: 1.3;
  }

  #pc-globe-hero .apc-rwys div {
    padding: 4px 10px;
  }

  #pc-globe-hero .shot img {
    max-height: 42svh;
  }

  #pc-globe-hero .ov-chart {
    left: 50%;
    width: 94vw;
  }

  #pc-globe-hero .ov-fan {
    left: 50%;
    gap: 8px;
  }

  #pc-globe-hero .ov-fan .s1 {
    width: 60vw;
  }

  #pc-globe-hero .ov-fan .fan-row {
    gap: 8px;
  }

  #pc-globe-hero .ov-fan .fan-row .snip {
    width: 40vw;
  }

  /* the hint STAYS on mobile: hiding it is why users did not realise they had to scroll */
  #pc-globe-hero .hint {
    /* Fallback for engines without dvh: a fixed reserve big enough for a mobile browser bar. */
    bottom: calc(env(safe-area-inset-bottom, 0px) + 62px);
    font-size: 11.5px;
    gap: 5px;
  }

  /* TOOLBAR-AWARE, which is what both previous attempts were missing. The section is 100vh = the
     toolbar-HIDDEN height, so whenever the browser's bottom bar is on screen it overlays the last
     ~50-60px of the section - that is where the hint disappeared behind Safari's nav bar on the
     sub-steps. (100vh - 100dvh) IS the current bar height: 0 when it is hidden, its real height
     when it is shown. So the hint keeps a constant 22px of air above whatever is actually there,
     instead of guessing a reserve that is too big (68px, "there is still much space") or too small
     (26px, "hidden behind the bottom nav bar"). */
  @supports (height: 100dvh) {
    #pc-globe-hero .hint {
      /* max(), NOT a sum. (100vh - 100dvh) is the browser bar's height and the bar is drawn OVER
         the home-indicator area, so adding env(safe-area-inset-bottom) on top counted that area
         twice - ~34px of wasted space below the chevrons on device. The clearance needed is
         whichever single obstruction is taller: the browser bar (Safari/Chrome) or the home
         indicator (standalone/PWA, where there is no bar and dvh == vh).
         +8px, not 22: the hint's own 6px of bottom padding already adds visible air. */
      bottom: calc(max(100vh - 100dvh, env(safe-area-inset-bottom, 0px)) + 8px);
    }
  }

  #pc-globe-hero .hint .hint-label {
    padding: 3px 10px;
    font-size: 12px;
  }

  #pc-globe-hero .hint {
    font-size: 15px;
  }

  /* no separate mobile box any more: the 0.70 base scale in hero.js already renders every
     symbol at ~41px, well under a 44px touch target, so mobile and desktop stay consistent. */
  #pc-globe-hero .rating-card,
  #pc-globe-hero .lido-card {
    left: 50%;
    /* --pc-rc-base = the DESIGNED scale for this breakpoint, --pc-rc-fit = the measured shrink
       hero.js applies when the strip between the text panel and the scroll hint is too small.
       Split in two so JS never has to know which media query is in force. */
    --pc-rc-base: 1;
    transform: translateX(-50%) scale(calc(var(--pc-rc-base) * var(--pc-rc-fit, 1)));
    transform-origin: top center;
    bottom: auto;
  }

  #pc-globe-hero.pc-rc-hide .rating-card {
    display: none;
    /* set by hero.js only when the card cannot fit without overlapping */
  }

  #pc-globe-hero .rating-card {
    /* --pc-rc-top is written by hero.js (sizeIntroCards) from the measured gap between the text
       panel and the scroll hint. The percentage is only the pre-JS fallback - as a fixed value it
       put the card 32px on top of the hint on a real device. */
    top: var(--pc-rc-top, 72%);
  }

  #pc-globe-hero .lido-card {
    top: calc(65% + 140px);
  }

  /* keep the step rail on mobile - it is the only progress cue once the hint is gone */
  #pc-globe-hero .rail {
    right: 10px;
    gap: 9px;
  }

  #pc-globe-hero .rail .d {
    width: 7px;
    height: 7px;
  }
}

@media (max-width: 480px) {

  #pc-globe-hero .rating-card,
  #pc-globe-hero .lido-card {
    --pc-rc-base: 0.75;
  }

  #pc-globe-hero .rating-card {
    top: var(--pc-rc-top, 77%);
  }

  #pc-globe-hero .lido-card {
    top: calc(68% + 140px);
  }
}

/* NARROW phones (iPhone SE 1st gen / SE 2016 class, 320px wide).
   Measured at 320x568: the intro panel came to 513px inside a 512px frame, and because .pc-frame
   is overflow:hidden the three app-store badges (y 540..584) were clipped away entirely - not just
   off-screen but unreachable, so the download links did not exist on those devices.
   Nothing here is a guess; each value targets a child that WRAPS at 320px and does not at 360px:
     eyebrow    52px -> 31px at 360px  (the badge text takes a second line)
     h1        130px -> 86px at 375px  (36px type over three lines)
     paragraph 161px -> 140px
     CTA row    70px -> 44px           (the two buttons stack)
   Gated at 340px, NOT 360px: a 360x640 Android already fits (445px panel in a 584px frame) and
   must not be shrunk. The CTA is left free to wrap - two buttons of this length genuinely do not
   fit one line at 320px - so the height is recovered from type instead. */
@media (max-width: 340px) {
  #pc-globe-hero .panel[data-panel="0"] h1 {
    font-size: 30px;
    line-height: 1.15;
  }

  #pc-globe-hero .eyebrow {
    font-size: 12px;
    padding: 5px 10px;
    margin-bottom: 8px;
  }

  #pc-globe-hero .panel[data-panel="0"] p {
    font-size: 13px;
    line-height: 1.42;
  }

  /* Tighter button box, still well above the 44px tap target. */
  #pc-globe-hero .btn {
    padding: 11px 14px;
    font-size: 15px;
  }

  /* Stack the two CTAs instead of letting them share a 320px row. Side by side each button got
     ~137px, too narrow for its label, so both wrapped mid-phrase ("Explore / Globe",
     "Try 3 Days / Free") - readable but visibly broken. Full width fits each label on one line.
     Costs ~30px of the 118px this breakpoint just freed up, so it is affordable here and nowhere
     wider - hence it lives inside the 340px gate rather than in the shared mobile block. */
  #pc-globe-hero .cta {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }

  #pc-globe-hero .cta-primary {
    align-items: stretch;
  }

  #pc-globe-hero .btn {
    justify-content: center;
  }
}

/* very short phones: the intro panel is the tallest step, give the globe less room */
@media (max-width: 820px) and (max-height: 700px) {
  #pc-globe {
    --gsize: min(118vw, 52vh);
    top: 62vh;
  }

  #pc-globe-hero .overlay {
    top: 66%;
  }

  /* NOTE: no [data-ov="2"] top override here anymore - sizeApCard() (hero.js) now positions
     and caps the airport card from measured free space at EVERY height, this band included. */
  /* drop the two
     monospace blocks (METAR/TAF raw text) and their headers instead of scaling the whole card
     into illegibility. Threat strip, runways and legend stay. */
  /* METAR/TAF stay in place: the card is scaled to fit now (see sizeApCard), so nothing is
     hidden and nothing is cropped. */
  /* fan: 29px overlap at 640px height - shrink the images, not the layout */
  #pc-globe-hero .ov-fan {
    gap: 6px;
  }

  #pc-globe-hero .ov-fan .s1 {
    width: 48vw;
  }

  #pc-globe-hero .ov-fan .fan-row .snip {
    width: 33vw;
  }

  #pc-globe-hero .panel p {
    font-size: 14px;
    padding-bottom: 14px;
  }
}

/* kit button override at the site's own mobile breakpoint. font-size matches the max-width:820px
   rule above - this one comes later in the file, so at equal specificity it was winning and
   silently overriding that 14px back to 16px on anything narrower than 767px (i.e. most phones). */
/* Comes AFTER the 820px block, so at equal specificity this is what actually applies on a phone -
   it has to carry the same values or it silently undoes them (which is exactly what this block did
   to font-size once before, per the note above it). Same box as .elementor-button. */
@media (max-width: 767px) {
  #pc-globe-hero .btn {
    font-size: 14px;
    line-height: 1.2em;
    padding: 8px 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  #pc-globe-hero .hint .pc-chevs svg {
    animation: none;
    opacity: 0.6;
  }
}

/* ---------------- compact landscape (phone/small tablet turned sideways) ----------------
   Triggered by HEIGHT, not by orientation alone: what breaks the stacked layout is a short
   viewport, whatever the device calls itself. Text left, globe right - the desktop arrangement,
   scaled down - because that is what a wide, short viewport actually has room for. */
@media (max-height: 560px) and (min-aspect-ratio: 13/10) {
  #pc-globe-hero {
    --gutter: 14px;
    --panel-shift: -50%;
  }

  /* text column on the left, vertically centred */
  #pc-globe-hero .panel {
    left: var(--gutter);
    right: auto;
    top: 50%;
    bottom: auto;
    max-width: min(50vw, 460px);
    text-align: left;
  }

  #pc-globe-hero .panel[data-panel="0"] {
    top: 50%;
  }

  #pc-globe-hero .panel[data-panel="1"],
  #pc-globe-hero .panel[data-panel="2"],
  #pc-globe-hero .panel[data-panel="3"],
  #pc-globe-hero .panel[data-panel="4"] {
    /* auto height: the portrait rule pins a fixed 190-240px box that does not fit here */
    height: auto;
    max-width: min(46vw, 420px);
    padding: 12px 14px;
    border-radius: 14px;
  }

  #pc-globe-hero .panel[data-panel="0"] h1 {
    font-size: 26px;
    margin-bottom: 4px;
  }

  #pc-globe-hero .panel[data-panel="1"] h2,
  #pc-globe-hero .panel[data-panel="2"] h2,
  #pc-globe-hero .panel[data-panel="3"] h2,
  #pc-globe-hero .panel[data-panel="4"] h2 {
    font-size: 19px;
    margin-bottom: 3px;
  }

  #pc-globe-hero .panel p {
    font-size: 13px;
    line-height: 1.4;
  }

  #pc-globe-hero .eyebrow {
    font-size: 11px;
    padding: 3px 10px;
    margin-bottom: 5px;
  }

  #pc-globe-hero .cta {
    margin-top: 10px;
    gap: 8px;
  }

  #pc-globe-hero .btn {
    padding: 7px 13px;
    font-size: 12.5px;
  }

  #pc-globe-hero .badges {
    margin-top: 8px;
    gap: 7px;
  }

  #pc-globe-hero .badge img {
    height: 26px;
    width: auto;
  }

  /* globe on the right, sized by the short axis so it always fits */
  #pc-globe {
    --gsize: min(74vw, 168svh);
    left: 74%;
    top: 50vh;
    width: var(--gsize);
    height: var(--gsize);
    -webkit-mask-image: radial-gradient(circle closest-side, #000 88%, transparent 100%);
    mask-image: radial-gradient(circle closest-side, #000 88%, transparent 100%);
  }

  /* overlays sit over the globe half, never over the text column */
  #pc-globe-hero .overlay,
  #pc-globe-hero .overlay[data-ov="2"] {
    /* 78%, and the cards are capped at 38vw: at 72% the airport card still reached back over the
       text column (caught by the cross-domain QA gate, not by eye).
       top:50% (of .pc-frame), NOT 50svh: the text panel centres inside the frame, which is inset
       by the header - measuring the overlay against the viewport instead put it 28px lower, so the
       two boxes were not on a shared centre line. */
    left: 78%;
    top: 50%;
    transform: translate(-50%, -50%);
  }

  #pc-globe-hero .overlay .ap-card {
    width: min(38vw, 290px);
    max-height: none;
    /* scale-to-fit handles it (sizeApCard) - never crop */
    font-size: 10px;
  }

  /* centred scaling: with a top origin a fit-scaled card drifts off the shared centre line */
  #pc-globe-hero .overlay[data-ov="2"] {
    transform-origin: center;
  }

  #pc-globe-hero .apc-mono {
    display: none;
    /* no vertical budget for the raw METAR/TAF blocks here */
  }

  #pc-globe-hero .ov-chart {
    left: 76%;
    /* env(safe-area-inset-right): in landscape on a notched phone the right 34-50px are behind the
       notch/rounded corner, and at left:76% the chart's right edge lands within 19px of the viewport
       edge - so its right side was being clipped by the hardware, which reads as the image being
       squashed or cut. Subtracting the inset keeps the whole chart on glass. */
    width: min(calc(44vw - env(safe-area-inset-right, 0px)), 560px);
  }

  #pc-globe-hero .ov-fan {
    left: 76%;
  }

  #pc-globe-hero .ov-fan .s1 {
    width: 26vw;
  }

  #pc-globe-hero .ov-fan .fan-row .snip {
    width: 18vw;
  }

  #pc-globe-hero .shot img {
    max-height: 74svh;
  }

  #pc-globe-hero .rating-card,
  #pc-globe-hero .lido-card {
    display: none;
    /* nothing to spare vertically */
  }

  #pc-globe-hero .hint {
    left: 26%;
    bottom: 8px;
    font-size: 13px;
  }

  #pc-globe-hero .rail {
    right: 8px;
    gap: 7px;
  }
}