/* ============================================================
   flyExclusive — Luxury Style System v2.0 (site-wide layer)
   Loaded AFTER the Webflow export stylesheet on every page.
   Source: design_handoff_luxury_style (README v2.0).
   Palette unchanged; treatment shifts: sharp 0px corners,
   hairline detailing, ghost buttons, Light 300 display type,
   .32em eyebrows, cinematic imagery with sanctioned overlays.
   The .fex-nav embed is self-scoped and intentionally untouched.
   ============================================================ */

/* ---- Galano Grotesque Light (signature display weight) ---- */
@font-face{
  font-family:'Galanogrotesque';
  src:url('../fonts/GalanoGrotesque-Light.otf') format('opentype');
  font-weight:300;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'Galano Grotesque';
  src:url('../fonts/GalanoGrotesque-Light.otf') format('opentype');
  font-weight:300;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'Galano Grotesque';
  src:url('../fonts/GalanoGrotesque-Regular.otf') format('opentype');
  font-weight:400;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'Galano Grotesque';
  src:url('../fonts/GalanoGrotesque-Medium.otf') format('opentype');
  font-weight:500;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'Galano Grotesque';
  src:url('../fonts/GalanoGrotesque-SemiBold.otf') format('opentype');
  font-weight:600;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'Galano Grotesque';
  src:url('../fonts/GalanoGrotesque-Bold.otf') format('opentype');
  font-weight:700;font-style:normal;font-display:swap;
}

/* ---- Design tokens ---- */
:root{
  --fe-navy-900:#00274D;
  --fe-navy-800:#002B54;
  --fe-navy:#003A70;
  --fe-navy-600:#0B3D6E;
  --fe-blue:#299FCF;
  /* Accessible blue for small text on light backgrounds. --fe-blue is 3.0:1
     on white, which fails AA for the 12px eyebrows; this is 5.5:1. */
  --fe-blue-600:#17709A;
  --fe-blue-400:#6DB3D6;
  --fe-blue-300:#9CC4DE;
  --fe-blue-200:#BFD6E7;
  --fe-ink:#0B1F2A;
  --fe-slate:#5B6B78;
  --fe-surface-blue:#D3DCE8;
  --fe-surface-grey:#EDEDE9;
  --fe-line:#E1E7EE;
  --fe-canvas:#F5F7FA;
  --fe-paper:#FFFFFF;
  --fe-success:#2E7D4F;
  --fe-warning:#8A6420;
  --fe-error:#B23B3B;
  --lux-font:'Galanogrotesque','Galano Grotesque','Poppins','Century Gothic',system-ui,sans-serif;
  --lux-track-eyebrow:.32em;
  --lux-track-caps:.06em;
  /* Re-point Webflow's own vars at the luxury palette */
  --steel-blue:#003A70;
  --midnight-blue:#00274D;
  --dark-slate-blue:#00274D;
}

/* ============================================================
   1 · GLOBAL TYPE RE-SKIN  (Open Sans / Roboto → Galano)
   ============================================================ */
body{
  font-family:var(--lux-font);
  font-size:16px;
  line-height:1.7;
  color:var(--fe-ink);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
h1,h2,h3,h4,h5,h6{
  font-family:var(--lux-font) !important;
  color:var(--fe-navy);
  line-height:1.1;
}
h1,h2{font-weight:300;letter-spacing:.01em}
h3,h4{font-weight:400}
h5,h6{font-weight:500}
p{
  font-family:var(--lux-font);
  font-weight:400;
  font-size:16px;
  line-height:1.7;
  color:var(--fe-ink);
}
li{font-family:var(--lux-font)}
/* Site-wide typeface unification: Webflow sets Open Sans/Roboto via
   hundreds of class rules; [class] ties their specificity and wins by
   order. Icon fonts are exempted. */
[class]:not([class*="fa-"]):not(.fa):not(.fas):not(.fab):not(.far):not([class*="w-icon"]):not([class*="icon-"]){
  font-family:var(--lux-font);
}
/* Headings: defeat class-level colors on light canvases.
   On-dark contexts re-assert white below (must stay later in order). */
h1[class],h2[class],h3[class],h4[class]{color:var(--fe-navy)}
/* On imagery / dark fields, headings stay white by context (these sit
   after the h1[class] rule and win by order) */
.new-hero-section :is(h1,h2,h3,h4,h5,h6),
.new-footer :is(h1,h2,h3,h4,h5,h6),
[class*="dark"] :is(h1,h2,h3,h4),
.core-values-left__wrap :is(h1,h2,h3,h4),
.jet-card__left-container :is(h1,h2,h3,h4,h5,h6),
[class*="hero"] :is(h1,h2,h3){
  color:#fff;
}
blockquote{
  border-left:2px solid var(--fe-blue);
  font-family:var(--lux-font);
}
.heading{font-family:var(--lux-font);font-weight:300;color:var(--fe-navy)}

/* Standard internal hero H1: was Galano 600 uppercase w/ hard text-shadow */
.internal-hero__h1{
  font-family:var(--lux-font);
  font-weight:300;
  letter-spacing:.01em;
  text-transform:none;
  text-shadow:none;
  line-height:1.08;
  /* Floor matches .lux-hero-copy h1's clamp(30px,...) — this legacy hero was
     the only one bottoming out at 40px, and a 40px floor cannot fit a long
     single word: "PASSENGER" rendered 434px wide inside a 300px column at
     375px, and body's overflow-x:hidden clipped it mid-word. The 5.2vw slope
     is unchanged, so at 768px and up this still computes to the same size. */
  font-size:clamp(30px,5.2vw,64px);
  color:#fff;
}
/* A flat 30px floor is still wider than a small phone can take when the
   headline holds a long uppercase token — "BOMBARDIER", "MAINTENANCE",
   "Electrostatic" each overran their column at 320px. The floor has to scale
   too, so it becomes its own clamp below the Webflow phone breakpoint: 6.4vw
   reaches exactly 30px at 480px, which is where the rule above takes over, so
   the two meet without a step.

   The three modifiers are named explicitly: each sets its own fixed font-size
   in the Webflow sheet at two-class specificity (.fractional 55px, .reef 90px,
   .rocko 48/32px), so a bare .internal-hero__h1 here would lose to all of them
   and those heroes would keep clipping. */
@media screen and (max-width:480px){
  .internal-hero__h1,
  .internal-hero__h1.fractional,
  .internal-hero__h1.reef,
  .internal-hero__h1.rocko{font-size:clamp(21px,6.4vw,30px)}
}

/* .new-hero-section is a flex column, so its children take the default
   min-width:auto and refuse to shrink below their content's min-content
   width — one long word in the h1 then pushes the whole hero past the
   viewport. Nothing here relies on that intrinsic width. */
.new-hero-section > *{min-width:0}
.internal-hero__sub-text{
  font-family:var(--lux-font);
  font-weight:400;
  line-height:1.7;
  max-width:760px;
}

/* The legal pages spell third-party policy URLs out in full, both as link text
   and as plain running text ("Visiting https://www.flyexclusive.com/..."). A
   bare URL is one unbreakable token — the Google partners link measured 396px
   at a 375px viewport — and `anywhere` is the only value that breaks it:
   `break-word` still refuses a mid-"word" break when the run offers no break
   opportunity of its own.

   Scoped to the legal sections rather than to links, because the California
   notice overflows on an <li> whose URL is not marked up as a link at all.
   Inside ordinary prose this is inert; it only engages where a single token
   genuinely cannot fit. */
.privacy-policy-section{overflow-wrap:anywhere}

/* ---- Orphan control (no single word hanging on a last line) ----
   Headings and short display copy get `balance`, which evens the line
   lengths of a few-line block; body copy gets `pretty`, which pulls a
   word down from the line above rather than leaving one alone. Both are
   line-breaking only — no size, spacing or box changes — so a browser
   without support simply wraps the way it does today.
   Excludes nav/footer link lists, where a two-line item balancing to
   1+1 words reads worse than the orphan does. */
h1,h2,h3,h4,h5,h6,
blockquote,figcaption,dt,
.lux-eyebrow,.lux-stat__label,.internal-hero__h1,.heading{
  text-wrap:balance;
}
p,li,dd,label,summary,
.internal-hero__sub-text{
  text-wrap:pretty;
}
/* Card and tile copy runs two or three lines, and `pretty` declines to act on
   a block that short — it leaves "Complete private jet interior /
   refurbishment." alone. `balance` splits the same sentence evenly instead,
   which puts a second word back on the last line. */
.lux-prog-card p,.lux-feature-card p,.lux-icon-card p,.lux-tier-card p,
.lux-snap-card p,.lux-card p,.lux-person-card p,.lux-quote-card p,
.lux-hero-card p,.lux-program-panel p,.lux-alert p,.lux-band-copy p,
.lux-stat p,.lux-spec-list li,.lux-benefit-list li,.lux-ticklist li,
.lux-steps li,.lux-check,.lux-card-label,.lux-progress-label,
.lux-scrim-caption,.lux-fade-caption{
  text-wrap:balance;
}
.fex-nav li,.new-footer li,.w-dropdown-list li{text-wrap:initial}

/* Phones: five legacy headings whose closing two words are wider than the
   column at their inherited size, so no wrapping strategy can keep them
   together — the last word had to sit alone. Each size below is the measured
   fit for a ~327px column at 390px wide, and applies to phones only. */
@media (max-width:600px){
  .home-slide__h1{font-size:28px}
  .join-heading_h2{font-size:30px}
  .fractional-terms_h1{font-size:28px}
  .learn-more__h2{font-size:23px}
  .centered-text__h2{font-size:21px}
}

/* ============================================================
   2 · SHAPE — kill radii & shadows (hairline world)
   ============================================================ */
img{height:auto}

.new__cta,.footer_pop-up-cta,
.pf-l-card,.pf-r-card,.qp-card,.comp-card-a,
.plane-report-block,.receipt-block,.message-block,
.aircraft-size-card,.airport-return-card,.calblock,
.jet-card__form-block,.pop-up__form-block,.div-block-23,
.pfcard-pill,.pfcard-li-pill,
.shadow-two,.shadow-three,.lc-minidiv,
.sale-leaseback__collection-item,.ck-modal,
.w-input,.w-select,.w-tab-link,.w-dropdown-list,
input,textarea,select,
.fs-cc-prefs_button,.fs-cc-button-alt,.fs-cc-banner_button,.fs-cc-manager_button,
.fs-cc-banner_container,.fs-cc-prefs_content{
  border-radius:0 !important;
}
.pf-l-card,.pf-r-card,.qp-card,.comp-card-a,
.plane-report-block,.receipt-block,.message-block,
.aircraft-size-card,.airport-return-card,.calblock,
.shadow-two,.shadow-three,.lc-minidiv,
.sale-leaseback__collection-item,.ck-modal{
  box-shadow:none !important;
  border:1px solid var(--fe-line);
}
.jet-card__form-block,.pop-up__form-block{box-shadow:none !important}

/* Form fields: quiet hairline boxes with a precise focus state
   (submit/button inputs are buttons, not fields — excluded, and so is
   [type=range]: a slider is a track and a thumb, not a box, and the hairline
   border drew a visible rectangle around the whole control. This selector is
   (0,6,1) and beats any single-class component rule, so the carve-out has to
   live here rather than in .lux-share__range — see the .lux-share block.) */
.w-input,.w-select,
input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=image]):not([type=range]),
textarea,select{
  font-family:var(--lux-font);
  border:1px solid var(--fe-line);
  background-color:#fff;
}
.w-input:focus,.w-select:focus,input:focus,textarea:focus,select:focus{
  border-color:var(--fe-blue);
  outline:0;
  box-shadow:0 0 0 1px var(--fe-blue);
}

/* Visible keyboard focus everywhere */
:focus-visible{outline:2px solid var(--fe-blue);outline-offset:2px}

/* ============================================================
   3 · BUTTONS — ghost / hairline system
   ============================================================ */
.new__cta,.w-button{
  font-family:var(--lux-font);
  font-size:12px;
  font-weight:600;
  letter-spacing:.22em;
  text-transform:uppercase;
  transition:all .3s ease;
}
/* Webflow's default button (form submits etc.): ghost navy */
.w-button{
  background-color:transparent;
  border:1px solid var(--fe-navy);
  color:var(--fe-navy);
  padding:15px 34px;
}
.w-button:hover{background-color:var(--fe-navy);color:#fff}
.new__cta{
  padding:17px 36px;
  background-color:transparent;
  border:1px solid var(--fe-navy);
  color:var(--fe-navy);
}
.new__cta:hover{background-color:var(--fe-navy);color:#fff}

/* Solid emphasis (one per screen) */
.new__cta.dark-blue{background-color:var(--fe-navy);border:1px solid var(--fe-navy);color:#fff}
.new__cta.dark-blue:hover{background-color:var(--fe-navy-900);border-color:var(--fe-navy-900)}

/* Steel-blue solid → solid navy emphasis (literal hexes live in
   high-specificity compound rules, so these are !important) */
.new__cta.light-blue,.new__cta.internal-nav-cta,.new__cta.white-cta{
  background-color:var(--fe-navy) !important;
  border:1px solid var(--fe-navy) !important;
  color:#fff !important;
}
.new__cta.light-blue:hover,.new__cta.internal-nav-cta:hover,.new__cta.white-cta:hover{
  background-color:var(--fe-navy-900) !important;
  border-color:var(--fe-navy-900) !important;
}
/* Any CTA on the deep-navy footer field reads ghost white */
.new-footer .new__cta{
  background-color:transparent !important;
  border:1px solid rgba(255,255,255,.55) !important;
  color:#fff !important;
  width:auto !important;
}
.new-footer .new__cta:hover{
  background-color:#fff !important;
  border-color:#fff !important;
  color:var(--fe-navy-900) !important;
}

/* On-dark variants */
.new__cta.white-outline{background-color:transparent;border:1px solid rgba(255,255,255,.55);color:#fff}
.new__cta.white-outline:hover{background-color:#fff;border-color:#fff;color:var(--fe-navy-900)}
.new__cta.white-solid{background-color:#fff;border:1px solid #fff;color:var(--fe-navy-900)}
.new__cta.white-solid:hover{background-color:var(--fe-blue-300);border-color:var(--fe-blue-300);color:var(--fe-navy-900)}

/* Hero context: primary reads solid white on imagery, secondary ghost white */
.new-hero-section .new__cta.light-blue{background-color:#fff !important;border-color:#fff !important;color:var(--fe-navy-900) !important}
.new-hero-section .new__cta.light-blue:hover{background-color:var(--fe-blue-300) !important;border-color:var(--fe-blue-300) !important}

/* Below 480px the Webflow sheet sizes these buttons with `width:50%` (30% above
   that). A percentage has no relationship to the label inside it, and these
   labels are uppercase at .22em tracking: "Current Career Opportunities" needs
   153px, the 50% box gave it 115px, and the difference was clipped — the word
   "Opportunities" alone cannot fit, so wrapping does not rescue it either.

   width:auto lets the box follow its own text again. These are display:block in
   this context, so they land full-bleed in the column, which is the usual shape
   for a phone CTA and matches .hero-slider__cta.full-width elsewhere.

   The three-class selectors are spelled out because each one outranks a bare
   .new__cta.light-blue and would otherwise keep its own percentage. .full-width
   is deliberately absent: 100% is already what it wants. */
@media screen and (max-width:479px){
  .new__cta.light-blue,
  .new__cta.light-blue-copy,
  .new__cta.light-blue.centered-text__cta,
  .new__cta.light-blue.career-centered__cta-copy,
  .new__cta.light-blue-copy.career-centered__cta-copy,
  .new__cta.light-blue.fractional-cta,
  .new__cta.light-blue-copy.fractional-cta,
  .new__cta.light-blue.safety__cta{width:auto}
}

/* ============================================================
   4 · HERO & IMAGERY TREATMENTS
   ============================================================ */
/* Base hero scrim: black gradients → deep navy cinematic fade */
.new-hero-section{
  background-image:linear-gradient(180deg,rgba(0,25,50,.10) 0%,rgba(0,25,50,.42) 55%,rgba(0,25,50,.78) 100%);
}
/* Uniform cinematic scrim over EVERY hero variant (30+ combo classes
   define their own photos): guarantees legible light type site-wide */
.new-hero-section{position:relative}
.new-hero-section::after{
  content:"";
  position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(0,25,50,.14) 0%,rgba(0,25,50,.30) 55%,rgba(0,25,50,.66) 100%);
  pointer-events:none;
  z-index:0;
}
.new-hero-section > *{position:relative;z-index:1}

/* Treatment A composition for standard hero content: accent rule,
   constrained measure. Webflow scroll interactions leave hero copy at
   partial opacity — the luxury language is still, so pin it visible. */
.new-home-hero__content-container{
  /* 960 rather than 760 so a three-word headline at the 64px cap ("Investing
     in Sustainability" needs ~810px) holds one line instead of hanging its
     last word; .internal-hero__sub-text keeps the old measure. */
  max-width:960px;
  width:auto;
  margin-left:0;
  border-left:2px solid var(--fe-blue);
  padding-left:26px;
}
.new-hero-section *,
.new-home-hero__content-container,
.new-home-hero__content-container *,
[class*="hero"] :is(h1,h2,h3,h4,p,a,div,span,li){
  opacity:1 !important;
  transform:none !important;
}
.new-home-hero__content-container{padding-top:0}
/* Phones: the 26px indent cost the headline the ~6px it needed to keep
   "AVIATION COMPANY" together on one line. The accent rule stays. */
@media (max-width:600px){
  .new-home-hero__content-container{padding-left:16px}
}
.internal-hero__h1{margin-top:0}
.internal-hero__cta-wrap:empty{display:none}

/* Hide Webflow empty-state placeholders ("No items found.") and
   empty CMS bindings left in the static export. A collection item
   whose bindings exported empty is a template husk — hide it whole. */
.w-dyn-empty,.w-dyn-bind-empty{display:none !important}
img[src=""]{display:none}
/* Card lists whose items exported as pure husks (scoped — some pages
   wrap REAL static content plus stray empty binds in one dyn item) */
.newsroom__tab-pane .w-dyn-item:has(.w-dyn-bind-empty),
.featured-newsroom-posts .w-dyn-item:has(.w-dyn-bind-empty),
.newsroom-archive .w-dyn-item:has(.w-dyn-bind-empty){display:none}

/* The "Our Aircraft" CMS collection exports empty on every page that
   carries it (charter, our-fleet, charter-copy): all bindings are
   w-dyn-bind-empty, so it rendered as a broken white husk — on
   production today as well. Restyled as an editorial full-bleed cabin
   image band; its heading becomes the caption (Treatment A). The empty
   CMS list stays hidden. FLAGGED in redesign notes. */
.our-aircraft-section{
  display:flex;
  align-items:flex-end;
  justify-content:flex-start;
  min-height:460px;
  background-image:linear-gradient(180deg,rgba(0,25,50,.06) 30%,rgba(0,25,50,.74) 100%),url('../images/luxury/lux-challenger-cabin-aft.jpg');
  background-size:cover;
  background-position:50% 62%;
  padding:64px 40px;
}
.our-aircraft-section .our-fleet__clw{display:none !important}
.our-aircraft-section .our-aircraft__container{margin:0;width:auto}
.our-aircraft-section .our-fleet__h1{
  color:#fff;
  font-weight:300;
  font-size:clamp(30px,3.4vw,40px);
  text-transform:none;
  border-left:2px solid var(--fe-blue);
  padding-left:22px;
  margin:0;
}

/* index.html: navy scrim over the hero marketing video so the light
   display type holds against the bright sky; content lifted above */
.section-26 .w-background-video::after{
  content:"";
  position:absolute;
  inset:0;
  background:linear-gradient(180deg,rgba(0,25,50,.22) 0%,rgba(0,25,50,.34) 55%,rgba(0,25,50,.55) 100%);
  pointer-events:none;
  z-index:1;
}
.section-26 .container-1478{position:relative;z-index:2}
.safety__cta{width:fit-content !important;margin-left:auto;margin-right:auto}

/* about.html: value badges sized down to quiet marks */
.core-values__icon{width:64px;height:auto}

/* Fleet detail pages (challenger-350, citation-*): the aircraft CMS
   collection exports empty — hero, quick stats and comfort blurb are
   husks with w-dyn-bind-empty fields (broken on production today).
   Hidden until the collection exports with data. FLAGGED. */
.fleet-detail-hero:has(.w-dyn-bind-empty),
.fleet-quick-stats:has(.w-dyn-bind-empty),
.fly-in-comfort:has(.w-dyn-bind-empty){display:none}

/* newsroom.html: every post is CMS-bound and exports empty — the
   husks are hidden globally; collapse the reserved space they left */
.featured-newsroom-posts,.featured-newsroom__wrap,
.newsroom__tabs-content,.newsroom__tab-pane,.newsroom-archive{
  min-height:0;height:auto;
}

/* who-we-are/our-fleet.html: hero content sat at the viewport edge */
.new-hero-section.our-fleet__hero{padding-left:40px;padding-right:40px}
.our-fleet__hero .text-span{font-weight:300;text-transform:none}

/* charter.html detail work */
.scroll__gif{display:none}
._3-col-grid__item-wrap{border-top:1px solid var(--fe-line);padding-top:28px}
._3-col-grid__icon{display:none}
._3-col__heading{font-weight:400;letter-spacing:.02em}
.updated__text-field,.select-field{background-color:#fff}
/* Webflow slider chrome: no grey default field */
.w-slider{background-color:transparent}

/* ---- Per-page hero art (navy scrim over site imagery) ---- */
.new-hero-section.charter__hero{
  background-image:url('../images/luxury/lux-challenger-reflection.jpg');
  background-position:68% 40%;
  background-size:cover;
}
/* mro / avionics / careers shared hero: navy scrim over the
   technician photo, parallax attachment stilled */
.new-hero-section.careers__hero{
  background-image:url('../images/P1024387-1.png');
  background-position:50% 40%;
  background-size:cover;
  background-attachment:scroll;
}
.new-hero-section.updated-about__hero{
  background-image:url('../images/2c6225cc10ffea677b7c209b1f6693a7.webp');
  background-position:50% 30%;
  background-size:cover;
}

/* ============================================================
   5 · FOOTER — deep navy field, hairline detailing
   ============================================================ */
.new-footer{background-color:var(--fe-navy-900)}
.footer-quick-links__container{border-left:1px solid rgba(255,255,255,.28)}
.footer__header{font-family:var(--lux-font);font-weight:300;color:#fff}
/* Review 2026-08-07 · 3 — the base sheet leaves 54px under "How can we help?",
   which reads as a gap rather than as a heading grouped with its button. */
.footer__header{margin-bottom:26px}
.footer__secondary-header{
  font-family:var(--lux-font);
  font-size:11px;font-weight:600;
  letter-spacing:var(--lux-track-eyebrow);
  text-transform:uppercase;
  color:var(--fe-blue-300);
}
.footer-phone__text,.footer-quick-link__link-block,.footer__copyright-text{
  font-family:var(--lux-font);
  color:var(--fe-blue-200);
}
/* phone block reads at quick-link scale, not display scale */
.footer-phone__text{font-size:16px;font-weight:400;line-height:125%}
.footer-phone__item{margin-bottom:8px}
/* Review 2026-08-07 · 2 — the numbers were the only underlined text in the
   footer. The .link class picks up the global anchor underline; the printed
   format stays xxx.xxx.xxxx and the tel: href keeps its +1. */
.footer-phone__text.link{text-decoration:none}
.footer-phone__text.link:hover{text-decoration:none;color:#fff}
.footer-quick-link__link-block{transition:color .3s ease}
.footer-quick-link__link-block:hover{color:#fff}
.footer_pop-up-cta{
  background-color:transparent;
  border:1px solid rgba(255,255,255,.55);
  color:#fff;
  font-family:var(--lux-font);
  font-size:12px;font-weight:600;
  letter-spacing:.22em;text-transform:uppercase;
  transition:all .3s ease;
}
.footer_pop-up-cta:hover{background-color:#fff;color:var(--fe-navy-900)}

/* ============================================================
   6 · LUXURY UTILITIES (per-page building blocks)
   ============================================================ */
.lux-eyebrow{
  font-family:var(--lux-font);
  font-size:12px;font-weight:600;
  letter-spacing:var(--lux-track-eyebrow);
  text-transform:uppercase;
  /* Not --fe-blue: at 12px this is normal-size text and needs 4.5:1.
     --fe-blue is 3.0:1 on white and 2.7:1 on --fe-canvas. */
  color:var(--fe-blue-600);
  margin:0 0 18px;
}
/* --ondark: flat dark fills (navy sections, cta band) where blue-300 is ~8:1.
   --onphoto: over photography, where blue-300 is not reliable against a bright
   frame — white plus a shadow is. Two modifiers instead of one modifier and a
   silent override that made --ondark render white in heroes and blue on bands. */
.lux-eyebrow--ondark{color:var(--fe-blue-300)}
.lux-eyebrow--onphoto{color:#fff;text-shadow:0 1px 6px rgba(0,0,0,.55)}

/* Section divider: hairlines flanking the turbine mark. Was a 5px rotated sky
   square; the mark is the brand turbine now, at 20px because the twelve blades
   are unreadable at bullet size. Source art is 80x80, so 20px is a 4x render.
   The five variants are the supplied divider styles ("Turbine logo divider
   styles/export") translated to the component system — that folder's markup is
   email-safe tables, which is not how the site builds anything. */
.lux-divider{display:flex;align-items:center;gap:16px;margin:0 auto;max-width:1180px;padding:0 40px}
.lux-divider::before,.lux-divider::after{content:"";flex:1;height:1px;background:var(--fe-line)}
.lux-divider span{
  width:20px;height:20px;flex:none;
  background:url("../images/turbine-sky.png") center/contain no-repeat
}
/* navy mark on the same hairlines */
.lux-divider--navy span{background-image:url("../images/turbine-navy.png")}
/* sky rules fading out to nothing, navy mark — the most emphatic of the set */
.lux-divider--fade::before{background:linear-gradient(90deg,rgba(41,159,207,0),var(--fe-blue))}
.lux-divider--fade::after{background:linear-gradient(90deg,var(--fe-blue),rgba(41,159,207,0))}
.lux-divider--fade span{background-image:url("../images/turbine-navy.png")}
/* the quietest: light sky mark */
.lux-divider--subtle span{background-image:url("../images/turbine-lightsky.png")}
/* on a navy band or over imagery */
.lux-divider--ondark::before,.lux-divider--ondark::after{background:#7FA8C7}
.lux-divider--ondark span{width:22px;height:22px;background-image:url("../images/turbine-white.png")}

/* C · Hairline frame — matted image */
.lux-frame{border:1px solid var(--fe-line);padding:10px;background:#fff}

/* A · Gradient scrim caption (bottom-left, accent rule) */
.lux-scrim{position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,25,50,0) 40%,rgba(0,25,50,.9) 100%);pointer-events:none}
.lux-scrim-caption{position:absolute;left:24px;right:24px;bottom:24px;border-left:2px solid var(--fe-blue);padding-left:18px;pointer-events:none}

/* B · Framed overlay box (centered) */
.lux-tint{position:absolute;inset:0;background:rgba(0,25,50,.28);pointer-events:none}
.lux-framed-box{border:1px solid rgba(255,255,255,.6);background:rgba(0,39,77,.25);padding:22px 30px;text-align:center}

/* ---- Stat rows: key figures, set as an editorial row -----------------------
   Was a bordered row of cells split by vertical hairlines — a box with a rule
   above, a rule below and a rule between every cell. Three problems with it,
   and the client rejected the result:

   1. It read as a table, and specifically as a BROKEN one. The row drew its own
      top rule while each cell drew its own bottom rule, and the vertical splits
      came from a box-shadow applied to every cell with no :last-child
      exception — so a stray hairline always hung off the row's right edge.
   2. Four hairline greys (--fe-line, 1.2:1 on white) enclosing a 30px figure
      is a lot of structure around very little content: ~114px of box height
      for three short facts.
   3. The figures are the whole point of the component and they were the
      quietest thing in it.

   Now: no box and no splits at all. The figures carry the row, each under a
   short --fe-blue accent rule, separated by air. That removes the entire class
   of adjacency bug above — nothing needs to know which cells sit next to which,
   so it is correct at any column count auto-fit chooses (see the grid rules
   further down this file) without a single breakpoint.

   Markup is unchanged: .lux-stat-row / .lux-stat / .lux-stat-number /
   .lux-stat-label, exactly as the 20 pages using it already ship. */
.lux-stat-row{
  display:flex;border:0;
  /* Row gap is the wrapped-line gutter; there is no column gap because each
     cell already carries generous inline padding. */
  gap:clamp(30px,3.4vw,46px) 0;
  padding:clamp(6px,1vw,12px) 0;
}
/* Column flex on the cell so the label can be pinned to the bottom — see
   .lux-stat-label. Cells already stretch to the tallest in their line under both
   the flex base and the grid override, which is what makes that pin align the
   labels across the row. */
.lux-stat{
  flex:1;min-width:0;padding:0 clamp(14px,1.8vw,26px);text-align:center;border:0;
  display:flex;flex-direction:column;
}
/* The accent rule, and the component's only ornament. Per-cell rather than
   per-row so it is immune to how the cells wrap. */
.lux-stat::before{
  content:'';display:block;width:26px;height:2px;background:var(--fe-blue);
  margin:0 auto clamp(15px,1.5vw,20px);
}
.lux-stat-number{
  font-family:var(--lux-font);font-weight:300;
  /* Up from a flat 30px. This is the figure the section exists to show. */
  font-size:clamp(32px,3.4vw,44px);line-height:1.05;letter-spacing:.01em;
  color:var(--fe-navy);
  /* Several rows put figures of differing digit counts side by side
     ("11,000+" beside "7"); tabular figures keep them optically aligned. */
  font-variant-numeric:tabular-nums;
  margin:0;
}
.lux-stat-label{
  font-family:var(--lux-font);font-size:11.5px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--fe-slate);
  /* balance, not pretty: measured better on the two- and three-word labels
     these rows carry ("US DOWNDRAFT BOOTHS", "MONTHLY MEMBERSHIP FEE"). */
  text-wrap:balance;
  /* margin-top:auto pins the label to the bottom of its cell so all the labels
     in a line sit on one level. Three rows carry a value that wraps to two
     lines ("2015–2024", "NYSE: FLYX", "Private Pilot"); without this that cell's
     label alone dropped ~22px below its neighbours'. padding-top carries the
     minimum gap, since the auto margin cannot also be a spacing value. */
  margin:0;margin-top:auto;padding-top:12px;
}
/* --word: for a stat whose value is a word rather than a figure ("Short-field",
   "Reconfigurable"). At the numeral size a single long unbreakable word is
   wider than its cell and pushed the whole page into horizontal scroll on
   mobile. Numeric stats are untouched. */
.lux-stat-number--word{font-size:clamp(23px,2.5vw,32px);line-height:1.2;overflow-wrap:break-word}
/* One figure size per row. --word is applied per cell, so four rows ended up
   setting some figures at the full size and others at the word size in the same
   line — "2" and "Part 145" large either side of a small "Gulfstream IV", which
   reads as a rendering fault rather than a decision. A row carrying any long
   value takes the word size throughout; all-figure rows keep the display size.
   Done here rather than by editing the markup so it holds for whatever content
   these rows carry later. */
.lux-stat-row:has(.lux-stat-number--word) .lux-stat-number{
  font-size:clamp(23px,2.5vw,32px);line-height:1.2;
}

/* --- Grouped figures -----------------------------------------------------
   .lux-stat-row is the flat case and stays the default. This is for a copy
   deck that supplies its own groupings and where flattening them loses the
   argument the grouping makes — mro.html "Above the Industry Average" reads
   facility capacity / response time / connectivity, three different kinds of
   claim, and a six-across row of figures says only "here are six numbers".
   Built as a <dl>: each group is a term (the kind of claim) with its figures
   as the definitions. Works on paper and on --navy; the dark overrides are at
   the foot of this block.
   The nested <div> per figure is required, not decorative: a bare dt/dd pair
   cannot be a flex item of its own, and `dd`'s 40px indent has to be reset
   somewhere that is not the group. (That 40px is the UA default stylesheet, not
   the Webflow export — the export carries no `dd` rule at all. Named precisely
   because the reset looks removable otherwise, and it is not.)
   auto-fit rather than repeat(3,1fr): a fixed three-track grid overflowed below
   ~760px, and the floor is 240px rather than the 190px a single .lux-stat cell
   gets because a group carries a tracked caps term ("RESPONSE TIME") above a
   wrapping figure description. */
.lux-metricset{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:clamp(30px,3.6vw,60px);
  margin:0;padding:0;
}
/* align-self:start, not the grid default of stretch. The groups do not carry
   the same number of figures (three / two / one on mro.html), and stretching
   left 100px and 200px of empty box under the shorter two — invisible while the
   group has no ground or bottom rule of its own, and visible the moment one is
   added. */
.lux-metricset__group{
  margin:0;padding-top:clamp(18px,2vw,24px);
  border-top:1px solid var(--fe-line);
  display:flex;flex-direction:column;gap:clamp(20px,2.4vw,30px);
  align-self:start;min-width:0;
}
/* dt, so it needs the eyebrow treatment spelled out rather than borrowed. */
.lux-metricset__label{
  font-family:var(--lux-font);font-size:10.5px;font-weight:600;
  letter-spacing:.24em;text-transform:uppercase;
  color:var(--fe-blue-600);margin:0;
}
/* margin:0 defeats `dd`'s 40px UA indent, which pushed every figure inward
   inside its own grid track. */
.lux-metricset__item{margin:0}
.lux-metricset__num{
  display:block;font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,3.1vw,40px);line-height:1.05;letter-spacing:.01em;
  color:var(--fe-navy);font-variant-numeric:tabular-nums;
}
.lux-metricset__desc{
  display:block;margin-top:8px;
  font-family:var(--lux-font);font-size:13px;line-height:1.6;
  color:var(--fe-slate);
}
.lux-section--navy .lux-metricset__group{border-top-color:rgba(255,255,255,.18)}
.lux-section--navy .lux-metricset__label{color:var(--fe-blue-300)}
.lux-section--navy .lux-metricset__num{color:#fff}
.lux-section--navy .lux-metricset__desc{color:var(--fe-blue-200)}

/* Card: image on top, label row with sky arrow. No outline — the photograph
   is the card's edge. Row padding loses its horizontal inset so the label
   aligns to the image, which is what the border used to justify. */
.lux-card{background:#fff}
.lux-card-row{padding:16px 0 0;display:flex;align-items:center;justify-content:space-between}
.lux-card-label{font-family:var(--lux-font);font-size:16px;font-weight:500;letter-spacing:.04em;color:var(--fe-navy)}
.lux-card-arrow{color:var(--fe-blue)}
.lux-card .lux-img-wrap{overflow:hidden}
.lux-card .lux-img-wrap img{transition:transform .4s ease}
.lux-card:hover .lux-img-wrap img{transform:scale(1.03)}

/* Text link with trailing arrow */
.lux-link{
  font-family:var(--lux-font);
  font-size:12px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;
  color:var(--fe-navy);text-decoration:none;
  transition:color .3s ease;
}
.lux-link:hover{color:var(--fe-blue);text-decoration:none}
.lux-link--ondark{color:var(--fe-blue-300)}
.lux-link--ondark:hover{color:#fff}

/* ============================================================
   7 · MOTION DISCIPLINE
   ============================================================ */
/* The luxury language is still and editorial: Webflow scroll-reveal
   interactions (fade/slide-in via inline opacity/transform on
   [data-w-id]) are neutralized so content is always present. Menus,
   modals and dropdowns hide via display/height, so they are unaffected. */
[data-w-id]{opacity:1 !important}
/* IX2 also animates some class-targeted wrappers without data-w-id */
.new-full-page__form-block{opacity:1 !important;transform:none !important}
[data-w-id]:not(.w-slide):not(.w-slider-mask):not([class*="slider"]):not([class*="w-dropdown"]):not([class*="w-nav"]){
  transform:none !important;
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}

/* ============================================================
   7 · COMPONENT LIBRARY (promoted from design-library.html)
   ------------------------------------------------------------
   Promoted 2026-07-27 so every page can use the catalogued
   components without duplicating CSS per page. design-library.html
   remains the live reference/preview for these same classes —
   edit them HERE, not there, and keep the two in sync.
   Carousel behaviour lives in js/lux-carousel.js.
   ============================================================ */
/* ==========================================================================
   NEW COMPONENTS — candidates for promotion into css/luxury.css
   All use the existing --fe-* tokens and var(--lux-font); 0-radius,
   hairline-first, ghost-button language to match Luxury Style System v2.0.
   ========================================================================== */

/* Icon button */
.lux-icon-btn{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--fe-navy);background:transparent;color:var(--fe-navy);cursor:pointer;transition:all .3s ease}
.lux-icon-btn:hover{background:var(--fe-navy);color:#fff}
.lux-icon-btn svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.8}

/* Segmented control (radio group, no JS) */
.lux-segmented{position:relative;display:inline-flex;border:1px solid var(--fe-navy);margin:0;padding:0}
.lux-segmented input{position:absolute;opacity:0;pointer-events:none}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.lux-segmented label{font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--fe-navy);padding:11px 22px;cursor:pointer;transition:all .2s ease;border-right:1px solid var(--fe-navy)}
.lux-segmented label:last-child{border-right:0}
.lux-segmented input:checked + label{background:var(--fe-navy);color:#fff}
.lux-segmented input:focus-visible + label{outline:2px solid var(--fe-blue);outline-offset:-2px}

/* Breadcrumbs */
.lux-breadcrumbs{display:flex;align-items:center;flex-wrap:wrap;gap:6px;list-style:none;margin:0;padding:0;font-family:var(--lux-font);font-size:12px;letter-spacing:.04em;color:var(--fe-slate)}
.lux-breadcrumbs a{color:var(--fe-slate);text-decoration:none}
.lux-breadcrumbs a:hover{color:var(--fe-navy)}
.lux-breadcrumbs li{display:flex;align-items:center;gap:6px}
.lux-breadcrumbs li:not(:last-child)::after{content:"/";color:var(--fe-line);margin-left:6px}
.lux-breadcrumbs li[aria-current="page"]{color:var(--fe-navy);font-weight:600}

/* Pagination */
.lux-pagination{display:flex;align-items:center;gap:4px;list-style:none;margin:0;padding:0}
.lux-pagination a,.lux-pagination span{display:flex;align-items:center;justify-content:center;min-width:36px;height:36px;font-family:var(--lux-font);font-size:12px;font-weight:600;color:var(--fe-navy);text-decoration:none;border:1px solid transparent}
.lux-pagination a:hover{border-color:var(--fe-line)}
.lux-pagination .is-current{background:var(--fe-navy);color:#fff}
.lux-pagination .is-disabled{color:var(--fe-line);pointer-events:none}

/* Tabs */
.lux-tabs{width:100%;max-width:520px}
.lux-tablist{display:flex;border-bottom:1px solid var(--fe-line);gap:4px}
.lux-tab{font-family:var(--lux-font);font-size:11.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--fe-slate);background:none;border:0;border-bottom:2px solid transparent;padding:12px 6px;margin-right:22px;cursor:pointer;transition:color .2s ease}
.lux-tab:hover{color:var(--fe-navy)}
.lux-tab[aria-selected="true"]{color:var(--fe-navy);border-bottom-color:var(--fe-blue)}
.lux-tabpanel{padding:18px 2px 0;font-size:13.5px;color:var(--fe-ink);line-height:1.7}
.lux-tabpanel[hidden]{display:none}

/* Steps / stepper */
.lux-steps{display:flex;list-style:none;margin:0;padding:0;width:100%;max-width:560px}
.lux-steps li{flex:1;text-align:center;position:relative;font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--fe-slate)}
.lux-steps li::before{content:"";display:block;width:100%;height:2px;background:var(--fe-line);margin-bottom:10px}
.lux-steps li.is-done::before,.lux-steps li.is-active::before{background:var(--fe-blue)}
.lux-steps li.is-active{color:var(--fe-navy)}
.lux-steps li .num{display:block;font-family:var(--lux-font);font-weight:300;font-size:20px;color:var(--fe-navy);margin-bottom:2px;letter-spacing:0;text-transform:none}

/* Jump nav */
.lux-jumpnav{display:flex;gap:22px;flex-wrap:wrap;list-style:none;margin:0;padding:14px 0;border-top:1px solid var(--fe-line);border-bottom:1px solid var(--fe-line)}
.lux-jumpnav a{font-family:var(--lux-font);font-size:11.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--fe-navy);text-decoration:none;opacity:.55;transition:opacity .2s ease}
.lux-jumpnav a:hover,.lux-jumpnav a.is-active{opacity:1}

/* Nav doc mock (static, non-interactive reference only) */
.lux-navdoc{width:100%;border:1px solid var(--fe-line);background:var(--fe-navy-900);padding:14px 22px;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.lux-navdoc-logo{color:#fff;font-family:var(--lux-font);font-weight:300;font-size:16px}
.lux-navdoc-links{display:flex;gap:20px;list-style:none;margin:0;padding:0}
.lux-navdoc-links a{color:rgba(255,255,255,.85);text-decoration:none;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.lux-navdoc-cta{border:1px solid rgba(255,255,255,.6);color:#fff;font-size:10.5px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;padding:8px 18px}

/* Footer doc mock */
.lux-footerdoc{width:100%;background:var(--fe-navy-900);padding:26px 28px;display:flex;justify-content:space-between;align-items:center;gap:20px;flex-wrap:wrap}
.lux-footerdoc p{color:var(--fe-blue-200);font-size:12px;margin:0}

/* Text field label pattern */
.lux-field{display:flex;flex-direction:column;gap:6px;width:100%;max-width:340px;text-align:left}
.lux-field label{font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--fe-navy)}
.lux-field input,.lux-field textarea,.lux-field select{padding:12px 14px;font-size:14px}

/* Checkbox / radio (custom) */
.lux-check,.lux-radio-opt{display:flex;align-items:center;gap:10px;font-family:var(--lux-font);font-size:14px;color:var(--fe-ink);cursor:pointer}
.lux-check input,.lux-radio-opt input{width:18px;height:18px;accent-color:var(--fe-navy);cursor:pointer}

/* Switch */
.lux-switch{display:inline-flex;align-items:center;gap:12px;cursor:pointer;font-family:var(--lux-font);font-size:13px;color:var(--fe-ink)}
.lux-switch input{position:absolute;opacity:0;width:0;height:0}
.lux-switch .track{width:44px;height:24px;background:var(--fe-line);position:relative;transition:background .25s ease;flex:none}
.lux-switch .track::after{content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;background:#fff;transition:transform .25s ease;box-shadow:0 1px 2px rgba(0,0,0,.25)}
.lux-switch input:checked + .track{background:var(--fe-navy)}
.lux-switch input:checked + .track::after{transform:translateX(20px)}
.lux-switch input:focus-visible + .track{outline:2px solid var(--fe-blue);outline-offset:2px}

/* Search field */
.lux-search-field{position:relative;width:100%;max-width:320px}
.lux-search-field input{width:100%;padding:11px 14px 11px 38px}
.lux-search-field svg{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:15px;height:15px;stroke:var(--fe-slate);fill:none;stroke-width:2}

/* Inline form row */
.lux-form-row{display:flex;gap:0;width:100%;max-width:420px}
/* min-width:0 because flex:1 sets the basis to 0 but leaves min-width:auto,
   and an <input>'s intrinsic minimum is its `size` attribute — around 180px.
   Against a flex:none button that is another 163px, the pair could not fit a
   320px screen and pushed the row off the right edge. */
.lux-form-row input{flex:1;min-width:0;border-right:0;padding:13px 14px}
.lux-form-row button{flex:none}

/* Field validation messages */
.lux-field-msg{font-family:var(--lux-font);font-size:12px;margin-top:5px;display:flex;align-items:center;gap:6px}
.lux-field-msg.is-error{color:var(--fe-error)}
.lux-field-msg.is-success{color:var(--fe-success)}
.lux-field--error input{border-color:var(--fe-error)}
.lux-field--success input{border-color:var(--fe-success)}

/* Alerts */
.lux-alert{display:flex;gap:12px;align-items:flex-start;border-left:3px solid var(--fe-navy);background:var(--fe-canvas);padding:14px 18px;font-size:13.5px;line-height:1.6;max-width:480px;text-align:left}
.lux-alert svg{flex:none;width:18px;height:18px;stroke:var(--fe-navy);fill:none;stroke-width:2;margin-top:2px}
.lux-alert b{display:block;font-weight:600;color:var(--fe-navy);margin-bottom:2px;font-size:13px}
.lux-alert.is-info{border-color:var(--fe-blue)}
.lux-alert.is-info svg{stroke:var(--fe-blue)}
.lux-alert.is-success{border-color:var(--fe-success)}
.lux-alert.is-success svg{stroke:var(--fe-success)}
.lux-alert.is-warning{border-color:var(--fe-warning)}
.lux-alert.is-warning svg{stroke:var(--fe-warning)}
.lux-alert.is-error{border-color:var(--fe-error)}
.lux-alert.is-error svg{stroke:var(--fe-error)}

/* Badges / tags */
.lux-badge{display:inline-flex;align-items:center;gap:6px;font-family:var(--lux-font);font-size:10.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;padding:5px 11px;border:1px solid var(--fe-navy);color:var(--fe-navy)}
.lux-badge.is-solid{background:var(--fe-navy);color:#fff}
.lux-badge.is-blue{border-color:var(--fe-blue);color:var(--fe-blue)}
.lux-badge.is-success{border-color:var(--fe-success);color:var(--fe-success)}
.lux-badge.is-warning{border-color:var(--fe-warning);color:var(--fe-warning)}
.lux-badge.is-error{border-color:var(--fe-error);color:var(--fe-error)}
.lux-badge.is-muted{border-color:var(--fe-line);color:var(--fe-slate)}

/* Toast */
.lux-toast{display:flex;align-items:center;gap:12px;background:var(--fe-navy-900);color:#fff;padding:14px 18px;font-size:13px;max-width:360px;border-left:3px solid var(--fe-blue);box-shadow:0 12px 30px rgba(0,25,50,.25)}
.lux-toast svg{flex:none;width:16px;height:16px;stroke:var(--fe-blue-300);fill:none;stroke-width:2}
.lux-toast-demo-btn{margin:0 auto}
#dl-toast-live{position:fixed;left:50%;bottom:32px;transform:translate(-50%,20px);opacity:0;pointer-events:none;transition:all .35s ease;z-index:80}
#dl-toast-live.is-shown{opacity:1;transform:translate(-50%,0)}

/* Progress bar */
.lux-progress{width:100%;max-width:340px}
.lux-progress-track{height:4px;background:var(--fe-line);position:relative}
.lux-progress-fill{position:absolute;left:0;top:0;bottom:0;background:var(--fe-blue)}
.lux-progress-label{display:flex;justify-content:space-between;font-family:var(--lux-font);font-size:10.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--fe-slate);margin-bottom:8px}

/* Skeleton loader */
.lux-skeleton{width:100%;max-width:320px;display:flex;flex-direction:column;gap:10px}
.lux-skeleton .bar{height:12px;background:linear-gradient(90deg,var(--fe-line) 25%,var(--fe-surface-blue) 37%,var(--fe-line) 63%);background-size:400% 100%;animation:luxShimmer 1.6s ease-in-out infinite}
.lux-skeleton .bar.w-60{width:60%}
.lux-skeleton .bar.w-100{width:100%}
.lux-skeleton .bar.img{height:120px}
@keyframes luxShimmer{0%{background-position:100% 0}100%{background-position:-100% 0}}
@media (prefers-reduced-motion:reduce){.lux-skeleton .bar{animation:none}}

/* Tooltip (CSS only) */
.lux-tooltip{position:relative;display:inline-flex;border-bottom:1px dotted var(--fe-slate);cursor:help;font-size:14px;color:var(--fe-ink)}
.lux-tooltip::after{content:attr(data-tip);position:absolute;left:50%;bottom:calc(100% + 8px);transform:translateX(-50%) translateY(4px);background:var(--fe-navy-900);color:#fff;font-size:11.5px;line-height:1.4;padding:7px 10px;white-space:nowrap;opacity:0;visibility:hidden;transition:all .2s ease;pointer-events:none}
.lux-tooltip:hover::after,.lux-tooltip:focus-visible::after{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}

/* Spinner */
.lux-spinner{width:28px;height:28px;border:2px solid var(--fe-line);border-top-color:var(--fe-navy);border-radius:50%;animation:luxSpin .7s linear infinite}
@media (prefers-reduced-motion:reduce){.lux-spinner{animation-duration:2.2s}}
@keyframes luxSpin{to{transform:rotate(360deg)}}

/* Table */
.lux-table{width:100%;border-collapse:collapse;font-family:var(--lux-font);font-size:13.5px}
.lux-table th,.lux-table td{border-bottom:1px solid var(--fe-line);padding:12px 16px;text-align:left}
.lux-table thead th{font-size:10.5px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--fe-slate);border-bottom:1px solid var(--fe-ink)}
.lux-table tbody tr:hover{background:var(--fe-canvas)}

/* Comparison / tier table */
.lux-compare{width:100%;border-collapse:collapse;font-family:var(--lux-font);font-size:13.5px}
.lux-compare th,.lux-compare td{border:1px solid var(--fe-line);padding:14px 18px;text-align:center}
.lux-compare th:first-child,.lux-compare td:first-child{text-align:left;color:var(--fe-slate)}
.lux-compare thead th{font-weight:500;color:var(--fe-navy);font-size:15px}
.lux-compare thead th.is-featured{background:var(--fe-navy);color:#fff}
.lux-compare td.is-featured{background:var(--fe-surface-blue)}
.lux-compare .yes{color:var(--fe-blue)}
.lux-compare .no{color:var(--fe-line)}
/* Row-header links — the fleet table's first column points at each aircraft's
   page. .lux-link is the wrong component for the job: it is an uppercase,
   .2em-letterspaced micro link, and applied here it made every aircraft name
   read as a second column eyebrow rather than as a name. These read as names,
   with a hairline underline carrying the affordance the box no longer does. */
.lux-compare tbody th{font-weight:400}
.lux-compare tbody th a{
  font-family:var(--lux-font);font-size:14.5px;font-weight:500;
  color:var(--fe-navy);text-decoration:none;
  border-bottom:1px solid var(--fe-blue-300);
  transition:color .3s ease,border-color .3s ease;
}
.lux-compare tbody th a:hover,
.lux-compare tbody th a:focus-visible{color:var(--fe-blue-600);border-color:var(--fe-blue-600)}
@media (prefers-reduced-motion:reduce){.lux-compare tbody th a{transition:none}}

/* Scroll box for a .lux-compare wider than the viewport (the six-row fleet
   table on /our-fleet/). body sets overflow-x:hidden, so a table that overflows
   is clipped with no way to reach the far columns — it has to scroll inside its
   own box instead. min-width holds the five columns at a legible width rather
   than letting "Premium super-midsize" crush to one word per line at 390px. */
.lux-tablescroll{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}
.lux-tablescroll>.lux-compare{min-width:640px}

/* Definition / spec list */
.lux-spec-list{width:100%;max-width:420px;margin:0;border-top:1px solid var(--fe-line)}
.lux-spec-list div{display:flex;justify-content:space-between;gap:16px;padding:11px 0;border-bottom:1px solid var(--fe-line);font-family:var(--lux-font);font-size:13.5px}
.lux-spec-list dt{color:var(--fe-slate);font-weight:400}
.lux-spec-list dd{margin:0;color:var(--fe-navy);font-weight:500;text-align:right}

/* Accordion (native details/summary) */
.lux-accordion{width:100%;max-width:520px;border-top:1px solid var(--fe-line)}
.lux-accordion details{border-bottom:1px solid var(--fe-line)}
.lux-accordion summary{list-style:none;display:flex;justify-content:space-between;align-items:center;gap:16px;padding:16px 4px;cursor:pointer;font-family:var(--lux-font);font-size:14.5px;font-weight:500;color:var(--fe-navy)}
.lux-accordion summary::-webkit-details-marker{display:none}
.lux-accordion summary::after{content:"+";font-weight:300;font-size:20px;color:var(--fe-blue);transition:transform .25s ease}
.lux-accordion details[open] summary::after{transform:rotate(45deg)}
.lux-accordion .a-body{padding:0 4px 18px;color:var(--fe-slate);font-size:13.5px;line-height:1.7}

/* Timeline */
.lux-timeline{list-style:none;margin:0;padding:0;border-left:1px solid var(--fe-line);width:100%;max-width:420px;text-align:left}
.lux-timeline li{position:relative;padding:0 0 26px 24px}
/* turbine bullet, sized up from the old 9px diamond so the blades read. Half of
   12px back off the rail keeps it centred on the 1px border. */
.lux-timeline li::before{content:"";position:absolute;left:-6.5px;top:-1px;width:14px;height:14px;background:url("../images/turbine-sky.png") center/contain no-repeat}
.lux-timeline .t-label{font-family:var(--lux-font);font-size:10.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);margin-bottom:4px}
.lux-timeline .t-title{font-family:var(--lux-font);font-size:15px;font-weight:500;color:var(--fe-navy)}

/* Vertical timeline chart — richer sibling of .lux-timeline. That one is a
   compact label+title stepper; this one carries a date, a heading, prose and
   an optional progress state per milestone. Use it for company history,
   delivery schedules and multi-stage onboarding; use .lux-timeline when you
   only need two lines per step.
   The rail is a left border on each item, transparent on the last, so it
   stops at the final marker instead of running past it. */
.lux-timeline-chart{list-style:none;margin:0;padding:0;width:100%;max-width:560px;text-align:left}
.lux-timeline-chart>li{position:relative;padding:0 0 30px 32px;border-left:1px solid var(--fe-line)}
.lux-timeline-chart>li:last-child{padding-bottom:0;border-left-color:transparent}
/* turbine marker, matching .lux-timeline's mark language. State was carried by
   fill and border on a diamond; it is carried by the mark's colour now —
   light sky = upcoming, sky = done, navy with a hairline ring = current.
   The paper circle behind the art matters: the rail is the li's own left border
   and would otherwise show through the turbine's open centre. Round, not square,
   so it disappears behind the roughly circular mark. */
.lux-timeline-chart>li::before{
  content:"";position:absolute;left:-6.5px;top:1px;width:14px;height:14px;
  background:url("../images/turbine-lightsky.png") center/contain no-repeat var(--fe-paper);
  border-radius:50%
}
.lux-timeline-chart>li.is-done::before{background-image:url("../images/turbine-sky.png")}
.lux-timeline-chart>li.is-current::before{
  background-image:url("../images/turbine-navy.png");
  outline:1px solid var(--fe-blue-300);outline-offset:3px
}
.lux-timeline-chart .tc-date{font-family:var(--lux-font);font-size:10.5px;font-weight:600;letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;color:var(--fe-blue-600);margin:0 0 6px}
.lux-timeline-chart .tc-title{font-family:var(--lux-font);font-size:17px;font-weight:500;line-height:1.35;color:var(--fe-navy);margin:0}
.lux-timeline-chart .tc-body{font-family:var(--lux-font);font-size:13.5px;font-weight:400;line-height:1.65;color:var(--fe-slate);margin:6px 0 0}
/* Reveal-on-scroll variant. The hidden state is gated on .is-armed, which
   js/lux-reveal.js adds only once it knows it can animate the items back in —
   so with JS off the timeline is simply visible, never stranded invisible.
   The rail is on the <li>, so fading the item fades its rail segment too,
   which is what makes the line appear to draw itself downward. */
/* No transition on the hidden state: arming happens after first paint, and a
   transition there would fade the items OUT in front of anyone already looking
   at them. The transition belongs on the reveal. */
.lux-timeline-chart--reveal.is-armed>li{opacity:0;transform:translateY(14px)}
.lux-timeline-chart--reveal.is-armed>li.is-inview{
  opacity:1;
  transform:none;
  transition:opacity .8s cubic-bezier(.22,1,.36,1),transform .8s cubic-bezier(.22,1,.36,1)
}
@media (prefers-reduced-motion:reduce){
  .lux-timeline-chart--reveal.is-armed>li{opacity:1;transform:none;transition:none}
}

/* Dark surfaces (navy sections, over imagery) */
.lux-timeline-chart--invert>li{border-left-color:rgba(255,255,255,.22)}
/* same three states on dark: the masking circle becomes the dark surface, and
   the current mark goes white rather than navy so it still reads as the accent */
.lux-timeline-chart--invert>li::before{background-color:var(--fe-navy-900)}
.lux-timeline-chart--invert>li.is-done::before{background-image:url("../images/turbine-sky.png")}
.lux-timeline-chart--invert>li.is-current::before{background-image:url("../images/turbine-white.png");outline-color:rgba(255,255,255,.4)}
.lux-timeline-chart--invert .tc-date{color:var(--fe-blue-400)}
.lux-timeline-chart--invert .tc-title{color:#fff}
.lux-timeline-chart--invert .tc-body{color:rgba(255,255,255,.72)}

/* Split milestone timeline — the imagery-led sibling of .lux-timeline-chart.
   Each milestone is a full-width row: a 4:3 photograph on one side, a large
   year with title and prose on the other, alternating sides down the page. The
   rail runs down the CENTRE, between the two halves, and the turbine marker
   sits on it at each row's vertical middle.
   Use it when the history IS the story of the page and there is a photograph
   per milestone; use .lux-timeline-chart when the milestones are copy only —
   this one is roughly six times taller for the same number of entries.

   The rail track and its progress fill are elements, not pseudo-elements on
   the <ol>: the only legal children of a list are list items, and the fill
   needs to be a separate box from the track so it can be scaled without
   scaling the hairline it runs over. js/lux-timeline.js pins both to the first
   and last MARKER (rather than the wrapper's full height, which would leave
   half a row of rail hanging past each end) and drives the fill from scroll
   position. With JS off, both simply span the wrapper — a full, static rail. */
.lux-timeline-split{position:relative;max-width:1180px;margin-left:auto;margin-right:auto}
.lux-timeline-split .ts-rail{position:absolute;left:50%;top:0;bottom:0;width:1px;background:var(--fe-line);transform:translateX(-.5px)}
.lux-timeline-split .ts-rail-fill{position:absolute;left:0;top:0;width:2px;height:100%;background:var(--fe-blue-600);transform:translateX(-.5px);transform-origin:top}
.lux-timeline-split .ts-items{list-style:none;margin:0;padding:0}
/* margin:0 is load-bearing, not tidiness. The Webflow export carries a bare
   `li{margin:4px 0 4px 36px}`, which indents every row 36px and so puts the
   row's own 50% — where the marker hangs — 18px right of the rail's 50%. */
.lux-timeline-split .ts-items>li{position:relative;display:flex;align-items:center;gap:clamp(56px,9vw,130px);margin:0;padding:clamp(36px,5vw,60px) 0}
/* alternation. Second row and every other one after it puts the photograph on
   the right; the DOM order is media-then-copy throughout, so reading order
   stays consistent no matter which side a row's photograph lands on. */
.lux-timeline-split .ts-items>li:nth-child(even){flex-direction:row-reverse}
/* turbine marker, in the same three states as .lux-timeline-chart: light sky =
   upcoming, sky = done, navy with a hairline ring = current. Slightly larger
   here (17px) because the rows around it are far bigger. The paper circle
   behind the art masks the rail, which would otherwise show through the
   turbine's open centre.
   A real element rather than a pseudo-element on the row: the rail script has
   to measure where the first and last marker actually sit, and a
   pseudo-element cannot be measured. State stays on the <li>, matching
   .lux-timeline-chart's API.
   Vertical centring is done with a negative margin, not translateY(-50%), so
   that the marker's centre always lands at offsetTop + half its height — the
   rail script measures it in layout coordinates, which a transform would move
   the marker away from. The horizontal centring is a transform, harmlessly:
   nothing measures x. */
.lux-timeline-split .ts-mark{
  position:absolute;left:50%;top:50%;z-index:2;
  width:17px;height:17px;margin-top:-8.5px;transform:translateX(-50%);border-radius:50%;
  background:url("../images/turbine-lightsky.png") center/contain no-repeat var(--fe-paper)
}
.lux-timeline-split .ts-items>li.is-done .ts-mark{background-image:url("../images/turbine-sky.png")}
.lux-timeline-split .ts-items>li.is-current .ts-mark{
  background-image:url("../images/turbine-navy.png");
  outline:1px solid var(--fe-blue-300);outline-offset:3px
}
.lux-timeline-split .ts-media{flex:1;min-width:0;margin:0;overflow:hidden;aspect-ratio:4/3}
.lux-timeline-split .ts-media img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .5s cubic-bezier(.22,1,.36,1)}
.lux-timeline-split .ts-items>li:hover .ts-media img{transform:scale(1.03)}
.lux-timeline-split .ts-copy{flex:1;min-width:0}
/* The year is the display type of this component — it does the work the small
   uppercase .tc-date does in the chart, at 4x the size. */
.lux-timeline-split .ts-year{font-family:var(--lux-font);font-weight:300;font-size:clamp(44px,5vw,64px);line-height:1;letter-spacing:.01em;color:var(--fe-navy);margin:0 0 16px}
.lux-timeline-split .ts-title{font-family:var(--lux-font);font-weight:400;font-size:20px;line-height:1.35;color:var(--fe-navy);margin:0 0 10px;max-width:30ch}
.lux-timeline-split .ts-body{font-family:var(--lux-font);font-weight:400;font-size:14.5px;line-height:1.7;color:var(--fe-slate);margin:0;max-width:44ch}
/* .ts-title and .ts-body are both optional per row: a milestone can be a year
   and a headline with no prose, or a year and a sentence with no headline. */
.lux-timeline-split .ts-title+.ts-body{margin-top:0}

/* .ts-stage is the box js/lux-timeline.js pins in stepped mode. Unstyled here
   beyond the positioning context the rail needs, so that without JS it is an
   ordinary block and the rules above are the whole component. */
.lux-timeline-split .ts-stage{position:relative}
@media (prefers-reduced-motion:reduce){
  .lux-timeline-split .ts-media img{transition:none}
}

/* Single column. The centre rail moves to the left edge and the two halves
   stack, photograph above copy; the marker moves with the rail to the top of
   the row, where the row actually begins, instead of floating beside its
   middle. Both flex-direction rules are reset, alternation included — there is
   only one column to alternate within. */
@media (max-width:860px){
  .lux-timeline-split .ts-rail{left:8px}
  .lux-timeline-split .ts-items>li,
  .lux-timeline-split .ts-items>li:nth-child(even){
    flex-direction:column;align-items:stretch;
    gap:clamp(18px,3vw,24px);padding:0 0 clamp(34px,7vw,52px) clamp(30px,6vw,44px)
  }
  .lux-timeline-split .ts-items>li:last-child{padding-bottom:0}
  .lux-timeline-split .ts-mark{left:8px;top:6px;margin-top:0}
  .lux-timeline-split .ts-year{font-size:clamp(36px,10vw,50px);margin-bottom:12px}
  .lux-timeline-split .ts-title{font-size:18px}
}

/* ---- Stepped mode: one milestone open at a time ------------------------------
   Everything below is gated on .is-stepped, which js/lux-timeline.js adds only
   when it can actually drive the sequence. With JS off — or under
   prefers-reduced-motion, where pinning the page and morphing type would be
   exactly the wrong thing — none of it applies and the module stays the plain
   in-flow timeline above.

   The component turns into a scroll TRACK, one --ts-step of height per
   milestone, with the stage sticky inside it. Nothing scrolls past: all eight
   rows are on screen for the whole track and the list morphs in place. The
   focused row carries its full photograph, year, title and prose; the rest
   collapse to a thumbnail and a year. That is what makes the last step show the
   entire history collapsed behind Today — the requirement the plain in-flow
   version cannot meet, because there the earlier rows have long gone off the
   top of the screen.

   Sizes that have to respond to the viewport are custom properties the script
   sets from measurement rather than clamp()s: the stage is a fixed box that a
   photograph, seven collapsed rows and up to seven lines of prose all have to
   fit inside, and that sum cannot be expressed in vh. */
/* Track height = one stage plus one step per milestone. Sticky only holds while
   its container still has room, so the height of the stage itself is dead
   scroll distance as far as stepping is concerned: the sequence gets
   count × --ts-step of PINNED travel, and the stage releases the moment the
   last step ends. Sizing the track as count × step alone spends the final step
   and a half scrolling the stage off the screen instead. */
.lux-timeline-split.is-stepped{
  --ts-step:46vh;          /* pinned scroll distance per milestone */
  --ts-collapsed-h:40px;   /* thumbnail height of a closed row */
  --ts-media-h:300px;      /* photograph height of the open row — script-fitted */
  --ts-row-gap:14px;
  --ts-top:96px;           /* under the fixed header; script measures the real one */
  --ts-stage-h:calc(100vh - var(--ts-top) - 24px);
  height:calc(var(--ts-stage-h) + var(--ts-count,8) * var(--ts-step))
}
.lux-timeline-split.is-stepped .ts-stage{
  position:sticky;top:var(--ts-top);
  height:var(--ts-stage-h);
  display:flex;align-items:center
}
.lux-timeline-split.is-stepped .ts-items{width:100%}
/* Rows lose their generous in-flow padding: in stepped mode the gap between
   them is the only spacing, and it has to stay small enough that seven closed
   rows and one open one share a single screen.

   Alternation is also dropped — photograph always left of the rail, copy always
   right. It is the right call for the in-flow module, where each milestone is a
   standalone band with a screen to itself, and the wrong one here: with eight
   rows stacked 14px apart, alternating sides throws every other year label to
   the far edge of its half and the closed sequence reads as scatter instead of
   an index. Tested both; this is the one that scans. The in-flow fallback keeps
   the alternation. */
.lux-timeline-split.is-stepped .ts-items>li,
.lux-timeline-split.is-stepped .ts-items>li:nth-child(even){
  padding:0;flex-direction:row;align-items:center;
  gap:clamp(20px,3vw,40px);
  opacity:.5;
  transition:opacity .45s ease
}
.lux-timeline-split.is-stepped .ts-items>li+li{margin-top:var(--ts-row-gap)}
.lux-timeline-split.is-stepped .ts-items>li.is-focus{opacity:1}
/* The photograph is driven by HEIGHT here, not by the width of its half: height
   is what the stage has a fixed budget of, and aspect-ratio turns it back into
   a width. It is also the one property that can animate — the in-flow version's
   `aspect-ratio` box on a `flex:1` parent has no animatable size at all. */
.lux-timeline-split.is-stepped .ts-media,
.lux-timeline-split.is-stepped .ts-items>li:nth-child(even) .ts-media{
  aspect-ratio:auto;display:flex;align-items:center;justify-content:flex-end
}
.lux-timeline-split.is-stepped .ts-media img{
  height:var(--ts-collapsed-h);width:auto;max-width:100%;aspect-ratio:4/3;
  transition:height .55s cubic-bezier(.22,1,.36,1)
}
.lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-media img{height:var(--ts-media-h)}
/* Closed rows keep their year and title — the two lines that make the row an
   index entry you can read at a glance — and drop the prose, which is what the
   open row is for. max-height rather than display:none so it can animate; the
   cap only has to exceed the longest body (2021, seven lines). */
.lux-timeline-split.is-stepped .ts-year{
  font-size:20px;margin:0;
  transition:font-size .55s cubic-bezier(.22,1,.36,1),margin .55s cubic-bezier(.22,1,.36,1)
}
.lux-timeline-split.is-stepped .ts-title{
  font-size:13.5px;font-weight:400;margin:0;max-width:38ch;
  transition:font-size .55s cubic-bezier(.22,1,.36,1),margin .55s cubic-bezier(.22,1,.36,1)
}
.lux-timeline-split.is-stepped .ts-body{
  max-height:0;opacity:0;overflow:hidden;
  transition:max-height .55s cubic-bezier(.22,1,.36,1),opacity .35s ease,margin .55s
}
.lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-year{font-size:clamp(38px,4.2vw,58px);margin:0 0 12px}
.lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-title{font-size:19px;margin:0 0 10px}
.lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-body{max-height:16em;opacity:1}
/* The open row's marker reads as the position on the rail. Scale, not a colour
   change: the three turbine states already mean something here. */
.lux-timeline-split.is-stepped .ts-mark{transition:transform .45s cubic-bezier(.22,1,.36,1)}
.lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-mark{transform:translateX(-50%) scale(1.3)}

/* Short screens. A laptop at 720px has ~560px of stage once the fixed header
   and the bottom inset are paid for, and seven closed rows plus the longest
   milestone's prose do not fit that at the sizes above — the script would
   shrink the photograph to nothing trying. Buying the space back here keeps
   stepped mode available down to about 700px tall; below that the script gives
   up and leaves the plain in-flow timeline. */
@media (max-height:880px){
  .lux-timeline-split.is-stepped{--ts-collapsed-h:32px;--ts-row-gap:9px}
  .lux-timeline-split.is-stepped .ts-year{font-size:18px}
  .lux-timeline-split.is-stepped .ts-title{font-size:12.5px}
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-year{font-size:clamp(30px,3.4vw,44px);margin:0 0 8px}
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-title{font-size:17px;margin:0 0 8px}
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-body{font-size:13.5px}
}
/* No hover-zoom in stepped mode: the photograph is already animating its own
   height, and the two transforms fight. */
.lux-timeline-split.is-stepped .ts-items>li:hover .ts-media img{transform:none}
/* Measurement guard. The script's fit pass opens the tallest milestone, reads
   settled heights and closes it again, all within one frame; every transition
   above has to be off while it does, or it measures an animation mid-flight and
   sizes the photograph to a height that was never real. !important because it
   must beat all of them, and it is applied for a single frame. */
.lux-timeline-split.is-measuring *{transition:none!important}

@media (max-width:860px){
  /* Closed rows stay horizontal — a thumbnail beside its year — because seven
     stacked columns would not fit a phone screen. Only the open row becomes a
     column, photograph above copy, which is the in-flow mobile layout. */
  .lux-timeline-split.is-stepped{--ts-collapsed-h:32px;--ts-row-gap:10px;--ts-step:58vh}
  .lux-timeline-split.is-stepped .ts-items>li,
  .lux-timeline-split.is-stepped .ts-items>li:nth-child(even){
    flex-direction:row;align-items:center;
    gap:14px;padding:0 0 0 clamp(30px,6vw,44px)
  }
  .lux-timeline-split.is-stepped .ts-items>li.is-focus,
  .lux-timeline-split.is-stepped .ts-items>li.is-focus:nth-child(even){
    flex-direction:column;align-items:stretch;gap:12px
  }
  .lux-timeline-split.is-stepped .ts-media,
  .lux-timeline-split.is-stepped .ts-items>li:nth-child(even) .ts-media{
    flex:0 0 auto;justify-content:flex-start
  }
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-media{flex:0 0 auto}
  .lux-timeline-split.is-stepped .ts-mark{top:50%;margin-top:-8.5px}
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-mark{top:16px;margin-top:0}
  .lux-timeline-split.is-stepped .ts-year{font-size:16px}
  /* A closed row on a phone is its thumbnail and its year, nothing else. The
     title is what makes the desktop index readable and what makes this not fit:
     with it, seven closed rows plus one open milestone need more than a phone
     screen and the script abandons stepped mode altogether. Same max-height
     treatment as the body so it still animates rather than popping. */
  .lux-timeline-split.is-stepped .ts-title{
    max-height:0;opacity:0;overflow:hidden;max-width:26ch;
    transition:max-height .55s cubic-bezier(.22,1,.36,1),opacity .35s ease,margin .55s
  }
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-title{max-height:4em;opacity:1}
  .lux-timeline-split.is-stepped{--ts-collapsed-h:28px;--ts-row-gap:8px}
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-year{font-size:clamp(30px,8vw,40px);margin:0 0 6px}
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-title{font-size:15px;margin:0 0 6px}
  .lux-timeline-split.is-stepped .ts-items>li.is-focus .ts-body{font-size:12.5px;line-height:1.6}
}

/* Program list — a stacked, hairline-divided index of programs. One row per
   program: title + description + inline CTA on the left, a small landscape
   image on the right, collapsing to a single column on mobile.
   Use instead of .lux-grid--4 of .lux-prog-card when there are more than four
   programs to show; the card grid stops scanning well past four, and a
   full-width image per block (six of them) makes the section enormous. */
.lux-program-list{list-style:none;margin:0;padding:0;width:100%}
.lux-program-list>li{border-top:1px solid var(--fe-line)}
.lux-program-list>li:last-child{border-bottom:1px solid var(--fe-line)}

.lux-program-list .pl-item{
  display:grid;
  grid-template-columns:minmax(0,1fr) clamp(160px,22vw,280px);
  align-items:center;
  gap:clamp(1.25rem,4vw,3.5rem);
  padding:clamp(1.4rem,2.6vw,2.1rem) 0;
  text-decoration:none;
  color:inherit;
}

.lux-program-list .pl-title{
  font-family:var(--lux-font);font-weight:400;
  font-size:clamp(1.25rem,2.2vw,1.75rem);
  line-height:1.25;letter-spacing:-.01em;
  color:var(--fe-navy);margin:0;
  transition:color .4s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}
.lux-program-list .pl-desc{
  font-family:var(--lux-font);font-size:13.5px;font-weight:400;line-height:1.65;
  color:var(--fe-slate);margin:.5rem 0 0;max-width:52ch
}
.lux-program-list .pl-cta{
  display:inline-flex;align-items:center;gap:.5em;margin-top:.9rem;
  font-family:var(--lux-font);font-size:10.5px;font-weight:600;
  letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;
  color:var(--fe-blue-600)
}
.lux-program-list .pl-cta svg{
  width:1.05em;height:1.05em;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .45s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}

.lux-program-list .pl-media{
  position:relative;overflow:hidden;aspect-ratio:16/10;background:var(--fe-surface-grey)
}
.lux-program-list .pl-media img{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .9s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}

/* A partner tile carrying a logo instead of a photograph. .pl-media crops its
   image to fill, which is right for a frame and wrong for a mark: a logo has to
   sit inside the tile whole, on a ground it was drawn against. Navy rather than
   the surface grey because these marks are drawn for dark. */
.lux-program-list .pl-media--mark{
  background:var(--fe-navy);display:grid;place-items:center;
  padding:clamp(20px,4vw,48px)
}
.lux-program-list .pl-media--mark img{
  width:100%;height:auto;max-height:100%;object-fit:contain
}

/* --seal: a small accreditation seal rather than a partner wordmark. Sits on
   --mark and only changes how the artwork is fitted.

   --mark sets width:100% because a partner lockup is delivered large and should
   fill the tile. Accreditation seals are not: the ARG/US plate in this repo is
   150px wide and the Wyvern Wingman badge 108px, so width:100% upscales them
   ~1.2x and ~1.7x, and at 1.7x the badge's own type goes soft while the 1431px
   IS-BAO seal beside it stays sharp — the row then reads as a rendering fault.

   width:auto lets each mark sit at its natural size, capped by the tile, so
   nothing is ever enlarged. The lighter padding is what keeps that from looking
   lost: at --mark's clamp(20px,4vw,48px) the 16/10 tile leaves only ~79px of
   height for the artwork, which would shrink the two large seals to a third of
   the tile to match two small ones. At this padding the four render 115 / 115 /
   131 / 131px at 1440 — a 16px spread, so the column reads as one set. Note what
   that is and is not: the two small marks land at their NATIVE height and the two
   large ones land at the cap below. Nothing is measured against 798px or 1431px.

   aspect-ratio:auto plus an explicit height is the load-bearing part, and not a
   style preference. "Never enlarge, always fit" is exactly max-width and
   max-height at 100% on an auto-sized image — and a percentage max-height needs
   a DEFINITE parent height to resolve against. .pl-media has none: its height
   comes from aspect-ratio, which leaves the percentage unresolvable, and the
   1431px IS-BAO seal then rendered 180px tall inside a 131px content box,
   clipped top and bottom by .pl-media's own overflow:hidden — easy to miss,
   because a round seal loses its edges quietly. Wrapping the cap in
   min(100%,150px) instead is worse: the function collapses and every seal
   renders 0x0. Both MEASURED on the way here.

   The height reproduces --mark's box rather than changing it: 22vw is the grid
   column .pl-item gives this tile, so 13.75vw is that column at 16/10, and the
   100px/175px bounds are the same clamp endpoints. Same tile, definite height.

   Used by who-we-are/safety-certification.html #verification. */
.lux-program-list .pl-media--seal{
  padding:clamp(14px,2vw,22px);
  aspect-ratio:auto;
  height:clamp(100px,13.75vw,175px);
}
/* The height cap is arithmetic, not a percentage, and that is the whole point of
   this rule. MEASURED: a percentage max-height on the mark is ignored outright
   here — the 1089x798 SMS seal computed max-height:100% and still used 172.75px
   inside a 131px content box, clipped by .pl-media's overflow:hidden, and it
   behaved identically whether the tile was --mark's grid or a definite-height
   flex box. So the cap is written as the box it has to fit:
     content height = clamp(100px,13.75vw,175px) - 2 x clamp(14px,2vw,22px)
                    = clamp(72px,9.75vw,131px)
   Exact wherever both clamps are mid-range (768-1100px), and up to 7px
   conservative above that, where the padding clamps out before the height does.
   Conservative is the correct direction: it under-fills by a hair, it can never
   overflow. If either value above changes, recompute this one. */
.lux-program-list .pl-media--seal img{
  width:auto;max-width:100%;height:auto;max-height:clamp(72px,9.75vw,131px)
}
/* Same breakpoint the component stacks at. Stacked, the tile is full-width and
   16/9, which would give it ~370px of height on a phone and let the two
   large-source seals render three times the size of the two small ones, which
   stay pinned at their native 115px — the size spread this variant exists to
   remove, reappearing at the other end. A flat 180px tile with a 140px ceiling
   holds all four within 115-140px, and nothing is enlarged. 140px clears the
   padding at every width in this range (149px of room at 767px, 152px at 390px),
   so it is a fit, not a crop. */
@media (max-width:767px){
  /* Two classes on the tile, and that is the point: this block sits BEFORE the
     component's own mobile block, which sets .pl-media{aspect-ratio:16/9} at
     (0,2,0) and would win on order. (0,3,0) settles it. Until this was written
     the tile kept its shape only because an explicit height outranks an
     aspect-ratio regardless — a coincidence holding a rule up, which is the kind
     of thing that breaks the next time either value moves. */
  .lux-program-list .pl-media.pl-media--seal{height:180px;aspect-ratio:auto}
  .lux-program-list .pl-media--seal img{max-height:140px}
}

/* hover: the image breathes, the arrow advances, the title deepens. Nothing
   moves the row itself — the hairlines must stay put.

   Scoped to a.pl-item, not .pl-item. These were written when every row was a
   link, and :hover matches any element, so a non-link row got the full
   link treatment: who-we-are/safety-certification's four accreditation rows are
   <div class="pl-item"> (they are statements, not destinations) and every one of
   their titles darkened under the cursor, offering a click that does nothing.
   The extra element in the selector is the whole fix — nothing else changes for
   the pages whose rows really are links. */
.lux-program-list a.pl-item:hover .pl-media img,
.lux-program-list a.pl-item:focus-visible .pl-media img{transform:scale(1.05)}
/* ...except a logo, which reads as a mistake when it swells. */
.lux-program-list a.pl-item:hover .pl-media--mark img,
.lux-program-list a.pl-item:focus-visible .pl-media--mark img{transform:none}
.lux-program-list a.pl-item:hover .pl-cta svg,
.lux-program-list a.pl-item:focus-visible .pl-cta svg{transform:translateX(4px)}
.lux-program-list a.pl-item:hover .pl-title,
.lux-program-list a.pl-item:focus-visible .pl-title{color:var(--fe-navy-900)}

/* --reading: for a register whose descriptions ARE the content rather than a
   caption under a title. .pl-desc is 13.5px because a program row's job is to
   get you to the program page, where the reading happens; an accreditation row
   has no page behind it, so its explanation is the last word on the subject and
   13.5px under a 28px title makes the substance the smallest type in the
   section. 15px on a 60ch measure is the reading size the .lux-split copy
   columns use one step down. Used by
   who-we-are/safety-certification.html #verification. */
.lux-program-list--reading .pl-desc{font-size:15px;line-height:1.7;max-width:60ch}

/* aspect-ratio has wide support, but keep a floor so an unsupporting browser
   does not collapse the media to zero height */
@supports not (aspect-ratio:16/10){
  .lux-program-list .pl-media{min-height:130px}
}

@media (max-width:767px){
  .lux-program-list .pl-item{
    grid-template-columns:1fr;
    gap:1rem;
    padding:1.35rem 0
  }
  /* image first on mobile: it is the fastest thing to recognise when the rows
     are stacked and the titles all look alike at small sizes */
  .lux-program-list .pl-media{order:-1;aspect-ratio:16/9}
  .lux-program-list .pl-desc{max-width:none}
}

/* Program tabs — the six programs listed down the left, one detail panel
   on the right. Only one program shows at a time, but the full range stays
   scannable, and the panel is a fixed region so switching does not reflow the
   page. Driven by js/lux-tabs.js via [data-lux-tabs].
   Sibling of .lux-program-list: use that when every program should be
   readable at once, this when only one should. */
.lux-program-tabs{width:100%}

/* The selector is a horizontal row sitting on one hairline. It used to be a
   column beside the panel, which left a tall empty block under a four-item
   list. Scrolls sideways on narrow screens rather than wrapping ragged. */
.lux-program-tabs .pt-nav{
  display:flex;
  gap:clamp(1.25rem,3vw,2.75rem);
  border-bottom:1px solid var(--fe-line);
  margin-bottom:clamp(1.75rem,3.5vw,3rem);
  overflow-x:auto;
  scrollbar-width:none;-ms-overflow-style:none
}
.lux-program-tabs .pt-nav::-webkit-scrollbar{display:none}

.lux-program-tabs .pt-tab{
  appearance:none;-webkit-appearance:none;
  position:relative;flex:0 0 auto;
  background:none;border:0;text-align:left;
  padding:0 0 clamp(.7rem,1.4vw,1rem);
  cursor:pointer;
  font-family:var(--lux-font);font-weight:400;
  font-size:clamp(.95rem,1.15vw,1.1rem);
  line-height:1.3;letter-spacing:-.005em;
  color:var(--fe-slate);
  white-space:nowrap;
  transition:color .35s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}
.lux-program-tabs .pt-tab:hover{color:var(--fe-navy)}

/* the selected program: navy, with a blue rule laid over the nav hairline.
   It scales from the centre and the label keeps its weight, so nothing in the
   row shifts as you move along it. */
.lux-program-tabs .pt-tab::after{
  content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;
  background:var(--fe-blue);transform:scaleX(0);
  transition:transform .4s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}
.lux-program-tabs .pt-tab[aria-selected="true"]{color:var(--fe-navy)}
.lux-program-tabs .pt-tab[aria-selected="true"]::after{transform:scaleX(1)}

/* Panel: media beside the copy, across the full width the nav used to share
   with a mostly-empty column. */
.lux-program-tabs .pt-panel[hidden]{display:none}
.lux-program-tabs .pt-panel{
  display:grid;
  grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);
  gap:clamp(1.75rem,4vw,3.5rem);
  align-items:center
}
.lux-program-tabs .pt-media{
  position:relative;overflow:hidden;aspect-ratio:16/9;
  background:var(--fe-surface-grey);margin:0
}
.lux-program-tabs .pt-media img{width:100%;height:100%;object-fit:cover;display:block}
.lux-program-tabs .pt-title{
  font-family:var(--lux-font);font-weight:400;
  font-size:clamp(1.35rem,2.4vw,1.9rem);line-height:1.25;letter-spacing:-.01em;
  color:var(--fe-navy);margin:0
}
.lux-program-tabs .pt-desc{
  font-family:var(--lux-font);font-size:14px;line-height:1.7;
  color:var(--fe-slate);margin:.6rem 0 0;max-width:52ch
}
.lux-program-tabs .pt-cta{
  display:inline-flex;align-items:center;gap:.5em;margin-top:1.1rem;
  font-family:var(--lux-font);font-size:10.5px;font-weight:600;
  letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;
  color:var(--fe-blue-600);text-decoration:none
}
.lux-program-tabs .pt-cta svg{
  width:1.05em;height:1.05em;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .45s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}
.lux-program-tabs .pt-cta:hover svg,
.lux-program-tabs .pt-cta:focus-visible svg{transform:translateX(4px)}

/* the incoming panel settles in rather than snapping. Applied by the JS on
   switch only, so the first paint is not animated. */
@keyframes luxPanelIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.lux-program-tabs .pt-panel.is-entering{animation:luxPanelIn .55s cubic-bezier(.22,1,.36,1) both}

@supports not (aspect-ratio:16/9){
  .lux-program-tabs .pt-media{min-height:200px}
}

/* side-by-side gets cramped before the phone breakpoint, so the panel stacks
   here rather than at 767px. The nav stays a horizontal scroller. */
@media (max-width:860px){
  .lux-program-tabs .pt-panel{grid-template-columns:1fr;gap:1.25rem}
  .lux-program-tabs .pt-desc{max-width:60ch}
}

@media (max-width:767px){
  /* full-bleed edges for the scroller so the last tab is not clipped mid-word
     against the wrap padding */
  .lux-program-tabs .pt-nav{gap:1.5rem}
  .lux-program-tabs .pt-tab{font-size:.95rem}
}

@media (prefers-reduced-motion:reduce){
  .lux-program-tabs .pt-panel.is-entering{animation:none}
  .lux-program-tabs .pt-tab,
  .lux-program-tabs .pt-tab::after,
  .lux-program-tabs .pt-cta svg{transition:none}
}

/* Avatar group */
.lux-avatar-group{display:flex}
.lux-avatar{width:42px;height:42px;border-radius:50%;background:var(--fe-navy);color:#fff;display:flex;align-items:center;justify-content:center;font-family:var(--lux-font);font-size:13px;font-weight:500;border:2px solid #fff;margin-left:-12px}
.lux-avatar:first-child{margin-left:0}
.lux-avatar.is-blue{background:var(--fe-blue)}
.lux-avatar.is-more{background:var(--fe-canvas);color:var(--fe-navy);border-color:var(--fe-line)}

/* Rating */
.lux-rating{display:inline-flex;align-items:center;gap:8px}
.lux-rating .stars{color:var(--fe-blue);font-size:16px;letter-spacing:2px}
.lux-rating .stars .dim{color:var(--fe-line)}
.lux-rating .count{font-family:var(--lux-font);font-size:12px;color:var(--fe-slate)}

/* Tier / pricing card */
/* No outline. .is-featured was signalled by a navy border; the navy .t-head
   fill below already says it louder, so the state survives the change. The head's
   bottom rule stays — that separates content rather than boxing it. */
.lux-tier-card{background:#fff;width:100%;max-width:300px;text-align:left}
.lux-tier-card .t-head{padding:0 0 18px;border-bottom:1px solid var(--fe-line)}
.lux-tier-card.is-featured .t-head{background:var(--fe-navy);border-color:var(--fe-navy);padding:22px 24px}
.lux-tier-card .t-head h4{margin:0 0 6px;font-family:var(--lux-font);font-weight:400;font-size:19px;color:var(--fe-navy)}
.lux-tier-card.is-featured .t-head h4{color:#fff}
.lux-tier-card .t-price{font-family:var(--lux-font);font-weight:300;font-size:26px;color:var(--fe-navy)}
.lux-tier-card.is-featured .t-price{color:#fff}
.lux-tier-card ul{list-style:none;margin:0;padding:18px 0 0}
.lux-tier-card li{font-size:13px;color:var(--fe-ink);padding:8px 0;display:flex;gap:10px;align-items:flex-start}
/* turbine bullet. margin-top drops from 8px to 5px because the mark went from
   5px to 11px and would otherwise sit low against the first line of text. */
.lux-tier-card li::before{content:"";width:13px;height:13px;background:url("../images/turbine-sky.png") center/contain no-repeat;margin-top:4px;flex:none}

/* Quote / testimonial card */
/* A quote, not a boxed quote: no outline and no inset, so it sits on the page
   like the rest of the copy. */
.lux-quote-card{background:none;padding:0;max-width:460px;text-align:left}
.lux-quote-card blockquote{margin:0 0 16px;font-family:var(--lux-font);font-weight:300;font-size:19px;line-height:1.5;color:var(--fe-navy);border:0;padding:0}
.lux-quote-card .q-attr{display:flex;align-items:center;gap:12px}
.lux-quote-card .q-attr b{display:block;font-size:13px;color:var(--fe-navy);font-weight:500}
.lux-quote-card .q-attr span{font-size:11.5px;color:var(--fe-slate)}

/* Person / leadership card */
.lux-person-card{width:100%;max-width:230px;text-align:left}
.lux-person-card img{width:100%;aspect-ratio:4/5;object-fit:cover;filter:grayscale(.1)}
.lux-person-card .p-name{font-family:var(--lux-font);font-weight:500;font-size:15px;color:var(--fe-navy);margin:14px 0 2px}
.lux-person-card .p-role{font-family:var(--lux-font);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--fe-slate)}

/* ---- Leadership index ----------------------------------------------------
   The leadership page's entire content is these cards, so they run wider than
   the 230px .lux-person-card used as a supporting element elsewhere: the cap
   comes off and the grid decides the width. Four across on desktop, two on
   tablet, one on phone.

   The card is an anchor, and its hover is deliberately the .lux-program-list
   idiom — image breathes, arrow advances, name deepens, nothing shifts the
   layout. The Webflow original covered the photograph with a translucent
   "See Bio" overlay on hover, which is invisible to touch and to keyboards;
   the cue is a permanent line of text here instead. */
.lux-person-grid{display:grid;gap:clamp(24px,3.2vw,48px);grid-template-columns:repeat(auto-fit,minmax(230px,1fr));width:100%}
@media (min-width:1024px){
  /* auto-fit would put five in a row on a wide viewport once the cards are
     uncapped, and a fifth empty column reads as a missing person. */
  .lux-person-grid{grid-template-columns:repeat(4,1fr)}
}
.lux-person-card--link{max-width:none;display:block;text-decoration:none;color:inherit}
/* The scale has to be clipped by something, and the img itself cannot clip
   its own transform. */
.lux-person-card--link .p-photo{display:block;position:relative;overflow:hidden;aspect-ratio:4/5;background:var(--fe-surface-grey)}
.lux-person-card--link .p-photo img{width:100%;height:100%;display:block;transition:transform .9s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))}
.lux-person-card--link .p-name{transition:color .4s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))}
/* .p-role is a <p> and picks up the global paragraph margin, which lands as
   dead space between the role and the "See bio" line below it. */
.lux-person-card--link .p-role{margin:0}
.lux-person-card .p-more{
  display:inline-flex;align-items:center;gap:.5em;margin:12px 0 0;
  font-family:var(--lux-font);font-size:10.5px;font-weight:600;
  letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;
  color:var(--fe-blue-600)
}
.lux-person-card .p-more svg{
  width:1.05em;height:1.05em;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .45s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}
.lux-person-card--link:hover .p-photo img,
.lux-person-card--link:focus-visible .p-photo img{transform:scale(1.05)}
.lux-person-card--link:hover .p-more svg,
.lux-person-card--link:focus-visible .p-more svg{transform:translateX(4px)}
.lux-person-card--link:hover .p-name,
.lux-person-card--link:focus-visible .p-name{color:var(--fe-navy-900)}
@supports not (aspect-ratio:4/5){
  .lux-person-card--link .p-photo{min-height:280px}
}

/* Feature checklist card */
.lux-feature-card{background:none;padding:0;max-width:340px;text-align:left}
.lux-feature-card h4{margin:0 0 14px;font-family:var(--lux-font);font-weight:400;font-size:17px;color:var(--fe-navy)}
.lux-feature-card ul{list-style:none;margin:0;padding:0}
.lux-feature-card li{display:flex;gap:10px;align-items:flex-start;padding:7px 0;font-size:13.5px;color:var(--fe-ink)}
.lux-feature-card svg{flex:none;width:15px;height:15px;stroke:var(--fe-blue);fill:none;stroke-width:2.4;margin-top:3px}
/* --2col: for a list long enough that a single column outruns the photograph it
   is set beside. .lux-split img is align-self:center, so once the copy column is
   taller than the 4:3 media the split loses its edge alignment and the copy
   overhangs top AND bottom — measured on mro/maintenance.html at 1536px, seven
   41px rows gave a 537px column against a 422px photograph, a 57px overhang each
   side. Two columns bring the same seven rows to ~164px.
   Not .lux-ticklist--2col: that is auto-fit with a 280px floor, which in a
   ~563px split column still resolves to one track. This is an explicit pair.
   Single column below 900px, where there is no photograph beside it to match
   and two columns of ticks would be 130px wide. */
@media (min-width:900px){
  .lux-feature-card--2col ul{
    display:grid;grid-template-columns:1fr 1fr;
    column-gap:clamp(20px,2.2vw,32px);
  }
  .lux-feature-card--2col li{min-width:0}
}

/* ---- Benefit list ---------------------------------------------------------
   A run of short benefits, each a titled line and a supporting one, set beside
   a photograph or a carousel in a .lux-split. .lux-feature-card's list is the
   right component when a benefit fits on one line; this is its two-line
   sibling. The tick and the rules between rows are deliberately the
   .lux-program-panel ul idiom, so a page can carry both without them reading
   as two unrelated components. */
.lux-benefit-list{list-style:none;margin:0;padding:0;border-top:1px solid var(--fe-line)}
.lux-benefit-list li{display:flex;gap:14px;align-items:flex-start;padding:15px 0;border-bottom:1px solid var(--fe-line)}
.lux-benefit-list svg{flex:none;width:17px;height:17px;stroke:var(--fe-blue);fill:none;stroke-width:2.4;margin-top:4px}
.lux-benefit-list b{
  display:block;font-family:var(--lux-font);font-weight:500;
  font-size:15.5px;line-height:1.35;color:var(--fe-navy);margin-bottom:3px;
}
.lux-benefit-list span{display:block;font-family:var(--lux-font);font-size:13.5px;line-height:1.6;color:var(--fe-slate)}

/* ---- Program panel pair -------------------------------------------------
   Two side-by-side programs presented as the primary content of a page:
   a large photograph, a display-scale heading, a lead, a checklist, and a
   "perfect for" footnote. This is the heavyweight sibling of
   .lux-feature-card — reach for that one when the pair is a supporting
   detail, and for this when the comparison IS the page.
   Panels stretch to equal height and the footnote is pinned to the bottom,
   so two panels with different amounts of copy still line up. */
/* min(420px,100%), not a bare 420px: minmax() treats its floor as a hard
   minimum, so on a 390px viewport a 420px floor made the track wider than the
   container and the whole page scrolled sideways. */
.lux-program-pair{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(420px,100%),1fr));gap:clamp(20px,2.6vw,34px);align-items:stretch}
.lux-program-panel{display:flex;flex-direction:column;background:none}
.lux-program-panel > img{width:100%;aspect-ratio:16/10;object-fit:cover;display:block}
/* Horizontal padding gone with the outline, so the copy starts on the
   photograph's left edge instead of floating inside a phantom box. */
.lux-program-panel .p-body{display:flex;flex-direction:column;flex:1;padding:clamp(22px,2.2vw,30px) 0 0}
.lux-program-panel .lux-eyebrow{margin-bottom:10px}
.lux-program-panel h3{
  margin:0 0 16px;font-family:var(--lux-font);font-weight:300;
  font-size:clamp(24px,2.6vw,34px);line-height:1.12;letter-spacing:.01em;color:var(--fe-navy);
}
.lux-program-panel .p-lead{font-family:var(--lux-font);font-size:clamp(14.5px,1.15vw,16px);line-height:1.7;color:var(--fe-slate);margin:0}
/* --evenrule — line every horizontal boundary of a two-panel comparison up
   across the row: the rule above the tick lists first of all, but with it the
   headings, the footnotes and the buttons. Same concern as .lux-grid--evenheads,
   solved for the whole panel rather than the h3 alone.

   A flex panel can only pin its ends. It pins its foot today (.p-fit and
   .lux-actions both take margin-top:auto), so all the slack in the shorter panel
   collects in one place, and where that lands decides which boundaries line up:

     slack above .p-fit  (today)  -> rule sits at (content above the rule),
                                     so the rules part company as soon as the two
                                     leads wrap to different line counts.
     slack into the lead          -> rule sits at (panel height - content below
                                     the rule), so they part company as soon as a
                                     tick item wraps instead.

   Membership hits the first at >=1350px (a four-line lead beside a three-line
   one) and the second at ~960-1150px (the bonus-depreciation tick wraps). MEASURED
   both ways before reaching for subgrid, so nobody re-derives the one-liner: it
   fixes one band and breaks the other.

   Subgrid is the only construction that holds at every width, because it stops
   distributing slack and instead gives each strip of the panel a shared track
   sized to the taller side. Six tracks: image, heading, lead, list, footnote,
   button. .p-body is display:contents so its children become the panel's own
   grid items — the alternative, a second nested subgrid, would have to inset its
   tracks by .p-body's padding and stop matching the parent's.

   Consequences of flattening, all of them handled just below: the padding-top
   .p-body carried moves to the h3's margin, and the two margin-top:auto pins are
   released, since a shared track already does what they were approximating.

   Gated on min-width:960px because row-gap must be 0 for six stacked tracks not
   to be pushed 26px apart, and once the pair collapses to one column that same
   row-gap is the only thing separating the two panels. MEASURED: the collapse is
   between 940px and 960px (2 x min(420px) + gap inside .lux-wrap--wide), which is
   also why the component's existing 900px image-ratio query is not the hook to
   hang this on. Below the gate nothing changes, and nothing needs to: one column
   means no panel is beside another.

   Opt-in, like --evenheads, because equal tracks only flatter a row whose panels
   are a genuine like-for-like comparison. On a row of unrelated cards it just
   pads the short ones out to the tallest. */
@supports (grid-template-rows:subgrid){
  @media (min-width:960px){
    .lux-program-pair--evenrule{grid-template-rows:repeat(6,auto);row-gap:0}
    .lux-program-pair--evenrule .lux-program-panel{grid-row:span 6;display:grid;grid-template-rows:subgrid}
    .lux-program-pair--evenrule .p-body{display:contents}
    .lux-program-pair--evenrule .p-body > h3{margin-top:clamp(22px,2.2vw,30px)}
    .lux-program-pair--evenrule .p-fit,
    .lux-program-pair--evenrule .lux-actions{margin-top:0}
  }
}
.lux-program-panel ul{list-style:none;margin:22px 0 0;padding:22px 0 0;border-top:1px solid var(--fe-line);display:grid;gap:12px}
.lux-program-panel li{display:flex;gap:11px;align-items:flex-start;font-size:14.5px;line-height:1.5;color:var(--fe-ink)}
.lux-program-panel li svg{flex:none;width:16px;height:16px;stroke:var(--fe-blue);fill:none;stroke-width:2.4;margin-top:3px}
/* Review 2026-08-07 · 33 — the tick marks came off the membership programme
   lists. The li is display:flex with list-style:none, so dropping the svg would
   otherwise leave the text with no mark at all and no indent to sit against.
   Keyed on :not(:has(svg)) rather than a modifier class on the <ul>: the lists
   carry no class, and this way deleting the svg IS the whole edit anywhere else
   the idiom is used next. A dot, not a "•" glyph — the bullet then scales and
   colours with the design tokens instead of the font's own punctuation. */
.lux-program-panel li:not(:has(svg))::before{
  content:"";flex:none;
  width:5px;height:5px;border-radius:50%;
  background:var(--fe-blue);
  margin-top:8px;
}
/* margin-top:auto is what pins this to the panel foot; the two panels' lists
   are different lengths and without it the footnotes sat at different heights. */
.lux-program-panel .p-fit{margin:auto 0 0;padding-top:22px;font-size:13.5px;line-height:1.6;color:var(--fe-slate)}
.lux-program-panel .p-fit strong{color:var(--fe-navy);font-weight:600}
/* Pinned the same way .p-fit is, and for the same reason: a panel whose lead
   runs two lines shorter than its neighbour's would otherwise sit its button
   two lines higher. Panels carry either a .p-fit or a .lux-actions, not both. */
.lux-program-panel .lux-actions{margin:auto 0 0;padding-top:24px;justify-content:flex-start}
/* When a panel carries both, .p-fit owns the auto margin and the button row
   rides directly under it — two items with margin-top:auto would split the
   free space and strand the button at the panel foot. */
.lux-program-panel .p-fit + .lux-actions{margin-top:0;padding-top:18px}
/* Same eyebrow-scale arrow link as .lux-program-tabs .pt-cta on the home page,
   so the two program presentations end on an identical call to action. It
   sits after .p-fit, which carries the margin-top:auto, so the footnote and CTA
   travel to the panel foot together and the two CTAs line up. */
.lux-program-panel .p-cta{
  display:inline-flex;align-items:center;gap:.5em;margin-top:1.1rem;
  font-family:var(--lux-font);font-size:10.5px;font-weight:600;
  letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;
  color:var(--fe-blue-600);text-decoration:none
}
.lux-program-panel .p-cta svg{
  width:1.05em;height:1.05em;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .45s var(--ease-smooth,cubic-bezier(.25,.1,.25,1))
}
.lux-program-panel .p-cta:hover svg,
.lux-program-panel .p-cta:focus-visible svg{transform:translateX(4px)}
@media (prefers-reduced-motion:reduce){
  .lux-program-panel .p-cta svg{transition:none}
}
/* Single column below the 2x420px + gap the grid needs; the aspect ratio is
   relaxed so a full-width photo does not eat the whole screen. */
@media (max-width:900px){
  .lux-program-panel > img{aspect-ratio:16/9}
}

/* ---- Program split (expanding photo panels) -------------------------------
   The same two-programme comparison as .lux-program-pair, presented as two
   full-bleed photographs that answer one question ("How do you fly?") rather
   than two cards to read in parallel. Pointing at a panel widens it, lifts its
   photograph, and reveals the lead, the checklist and the button; its neighbour
   yields the space. Reach for this when the CHOICE is the point and the detail
   is secondary — .lux-program-pair stays the right call when both columns are
   meant to be read side by side and compared line for line.

   Not named *-hero: [class*="hero"] carries a global opacity pin from the
   Webflow export, and any component whose name contains it inherits that.

   All of it is CSS. The sibling-yields-space half needs a parent that knows one
   of its children is hovered, which is :has() — already relied on elsewhere in
   this file (.lux-program-panel li:not(:has(svg))), so it is not a new
   requirement. No JS, no state attribute, nothing to keep in sync. */
.lux-program-split{display:flex;gap:2px;min-height:620px}
.lux-program-split .ps-panel{
  position:relative;overflow:hidden;display:flex;flex:1;
  transition:flex .5s cubic-bezier(.4,0,.2,1);
}
.lux-program-split .ps-panel > img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transform:scale(1);transition:transform .6s ease;
}
/* Two stops of navy: near-opaque at the foot so the heading holds at any crop,
   and a top stop that darkens on open so the revealed copy has a field to sit
   on instead of whatever the photograph happens to be doing up there.

   The middle stop is .65, where the design file draws .55. MEASURED against
   both photographs, because the top of the revealed lead lands almost exactly
   on this stop and both images are bright there — a near-white cabin on one,
   open sky on the other. Composited over those pixels, .55 puts the 15px lead
   at 3.37:1, under the 4.5:1 normal-size text needs; .65 with a solid-white
   lead (below) reaches 4.67:1 on the worst of the two, which is the family
   photograph at the stacked mobile crop. Deepening further would also work but
   takes more of the photograph with it, and the photograph is the point of the
   component. The heading clears at any of these values — at 34px it is large
   text and needs only 3.0:1.

   The second, top-down gradient is not in the design file. It exists for the
   eyebrow, which the design pins to the panel's top corner — the one place the
   programme scrim is at its thinnest (.1 until a panel opens). Over the bright
   cabin ceiling the label measured 1.50:1 with no vignette at all: not a
   marginal miss, unreadable.

   .40 fading out by 20% is the gentlest vignette that does real work. It is
   NOT enough to certify the label at rest, and no reasonable value is: the
   label sits 7-11% down, so any gradient that has begun to fade by then is
   already thin where the glyphs are. MEASURED the whole range — even .92
   reaches only 3.73:1 resting, and clearing 4.5:1 needs a band that holds full
   strength past the label and then cuts, which is a dark stripe across the top
   of both photographs and the end of the design's clean frame.
   So this is where it lands, and it is a deliberate exception:
     open / stacked (top .55)  eyebrow 5.1-6.0:1   certified
     resting  (top .10)        eyebrow 2.2-3.2:1   carried by the text shadow
   Everything else in the component is certified in every state. If the resting
   label is ever judged too weak, the fix is not a heavier scrim — it is moving
   the eyebrow down beside the heading, where the scrim is .92 and it measures
   better than 9:1. See the note on the eyebrow rule below. */
.lux-program-split .ps-scrim{
  position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to bottom,
      rgba(0,29,58,.40) 0%,
      rgba(0,29,58,0) 20%),
    linear-gradient(to top,
      rgba(0,29,58,.92) 0%,
      rgba(0,39,77,.65) 45%,
      rgba(0,39,77,var(--ps-top,.1)) 100%);
  transition:background .4s ease;
}
.lux-program-split .ps-body{
  position:relative;display:flex;flex-direction:column;justify-content:flex-end;
  width:100%;padding:clamp(26px,3.2vw,44px) clamp(24px,3.4vw,48px);
}
/* Pinned to the panel's top corner rather than sitting in the column flow, so
   the label stays put while the copy below it grows and shrinks.

   The shadow is heavier than .lux-eyebrow--onphoto's, and it is doing real
   work, not styling: this label sits where the scrim is thinnest and is the one
   piece of type in the component that does NOT reach 4.5:1 on scrim alone while
   the panels rest (2.2-3.2:1 — see the measurements on .ps-scrim). Two shadows
   rather than the design's single soft one: a tight, near-opaque halo that hugs
   the glyph edges and does the legibility work, under the design's wide 14px
   bloom, which alone spreads too far to darken a stroke much.

   WCAG ratios cannot express a shadow, so unlike the rest of this component
   that gap is not closed by measurement — it is closed by a technique, and the
   two frames behind these labels are the evidence. If either photograph is ever
   swapped, look at this. The fix, if looking is not enough, is in the .ps-scrim
   note: move the eyebrow, do not thicken the scrim. */
.lux-program-split .ps-panel .lux-eyebrow{
  position:absolute;top:clamp(26px,3.2vw,44px);left:clamp(24px,3.4vw,48px);
  margin:0;font-size:clamp(13px,1.3vw,18px);
  text-shadow:0 1px 2px rgba(0,29,58,.9), 0 1px 14px rgba(0,29,58,.7);
}
.lux-program-split .ps-panel h3{
  margin:0;color:#fff;font-family:var(--lux-font);font-weight:300;
  font-size:clamp(24px,2.6vw,34px);line-height:1.15;letter-spacing:.01em;
}
/* Collapsed to a zero-height clipping box. The copy stays in the DOM and in the
   accessibility tree at all times — it is the substance of the section, and it
   should be readable to a crawler and a screen reader whether or not a pointer
   ever arrives. */
.lux-program-split .ps-reveal{
  overflow:hidden;max-height:0;opacity:0;transform:translateY(16px);
  transition:max-height .5s cubic-bezier(.4,0,.2,1),
             opacity .35s ease .1s,
             transform .45s ease .05s;
}
/* Solid white, not the design's 85%: see the contrast note on .ps-scrim. The
   85% was buying a step of hierarchy under the heading, which the size
   difference already carries on its own. */
.lux-program-split .ps-reveal p{
  margin:18px 0 0;color:#fff;
  font-size:clamp(14px,1.15vw,15px);line-height:1.7;max-width:52ch;
}
.lux-program-split .ps-reveal ul{
  list-style:none;margin:20px 0 0;padding:0;display:flex;flex-direction:column;gap:10px;
}
.lux-program-split .ps-reveal li{
  display:flex;gap:12px;align-items:flex-start;color:#fff;font-size:14px;line-height:1.6;
}
.lux-program-split .ps-reveal li::before{
  content:"";flex:none;width:5px;height:5px;background:var(--fe-blue);margin-top:8px;
}
.lux-program-split .ps-reveal .lux-actions{margin-top:26px}

/* The open state. Gated at the width where the panels are genuinely side by
   side; below it the panels stack and everything is open anyway (see below).
   :focus-within is not decoration — the button inside a closed panel is
   focusable, so without it a keyboard tab would send focus into a zero-height
   box the user cannot see. */
@media (min-width:900px){
  .lux-program-split .ps-panel:hover,
  .lux-program-split .ps-panel:focus-within{flex:1.45}
  /* The other panel yields. Keyed on the parent so the rule fires on the
     sibling that is NOT pointed at. */
  .lux-program-split:has(.ps-panel:hover) .ps-panel:not(:hover),
  .lux-program-split:has(.ps-panel:focus-within) .ps-panel:not(:focus-within){flex:.75}
  .lux-program-split .ps-panel:hover > img,
  .lux-program-split .ps-panel:focus-within > img{transform:scale(1.04)}
  .lux-program-split .ps-panel:hover .ps-scrim,
  .lux-program-split .ps-panel:focus-within .ps-scrim{--ps-top:.55}
  .lux-program-split .ps-panel:hover .ps-reveal,
  .lux-program-split .ps-panel:focus-within .ps-reveal{
    max-height:480px;opacity:1;transform:translateY(0);
  }
}
/* A wide TOUCH screen — a tablet in landscape — clears the 900px gate but can
   never satisfy :hover, which would leave both panels permanently shut and the
   copy permanently invisible. Open them and leave them open. */
@media (min-width:900px) and (hover:none){
  .lux-program-split .ps-reveal{max-height:none;opacity:1;transform:none}
  .lux-program-split .ps-scrim{--ps-top:.55}
}
/* Stacked. Hover has nowhere to go on a phone, so the panels are simply open,
   and the flex ratios are dropped — a "wider" panel means nothing in a column.
   min-height per panel rather than on the row, or the two would share 620px. */
@media (max-width:899.98px){
  .lux-program-split{flex-direction:column;min-height:0}
  .lux-program-split .ps-panel{flex:none;min-height:460px}
  .lux-program-split .ps-reveal{max-height:none;opacity:1;transform:none;transition:none}
  .lux-program-split .ps-scrim{--ps-top:.55}
  /* Back into the flow. Pinning the label to the corner works while the panel
     is a tall frame with a short stack of copy at its foot; stacked, the copy is
     always open and fills the panel, so an absolutely positioned label lands on
     top of the heading. Above it instead, which is where the label sits in
     every other component in this file. */
  .lux-program-split .ps-panel .lux-eyebrow{position:static;margin:0 0 12px}
}
/* The reveal is the component's whole point, so it still happens — what stops
   is the sliding, scaling and easing that carry it. */
@media (prefers-reduced-motion:reduce){
  .lux-program-split .ps-panel,
  .lux-program-split .ps-panel > img,
  .lux-program-split .ps-scrim,
  .lux-program-split .ps-reveal{transition:none}
  .lux-program-split .ps-panel:hover > img,
  .lux-program-split .ps-panel:focus-within > img{transform:none}
  .lux-program-split .ps-reveal{transform:none}
}

/* ---- Aircraft class callout ----------------------------------------------
   A short "what you fly" row: photo, class label, aircraft name. Deliberately
   lighter than .lux-snap-card's scroller — these are a fixed handful and
   should all be visible at once. */
.lux-aircraft-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:clamp(16px,2vw,26px)}
/* The bare auto-fit row is sized for the three-card fleet teasers on
   membership and jet-club. /our-fleet/ lists all six, and auto-fit lands them
   4+2 on a wide viewport — a ragged last row, with cards small enough that the
   photography stops doing any work. --3 pins three columns once there is room
   for them, so six read as two even rows; below 1000px it falls back to
   auto-fit and collapses 2-up then 1-up as before. */
@media (min-width:1000px){.lux-aircraft-row--3{grid-template-columns:repeat(3,1fr)}}
.lux-aircraft-card{display:flex;flex-direction:column;background:none;text-decoration:none}
.lux-aircraft-card img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;transition:transform .5s cubic-bezier(.22,1,.36,1)}
.lux-aircraft-card .a-body{padding:16px 0 0;display:flex;flex-direction:column;flex:1 0 auto}
/* Spec rows under a card's model name. Named rather than inline so the two
   fleet sections that use this pattern (membership, jet-club) can't drift. */
.lux-aircraft-card .lux-spec-list{margin-top:14px;margin-bottom:18px}
.lux-aircraft-card .a-class{margin:0 0 5px;font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;color:var(--fe-blue-600)}
.lux-aircraft-card h3{margin:0;font-family:var(--lux-font);font-weight:400;font-size:clamp(17px,1.5vw,20px);line-height:1.25;color:var(--fe-navy)}
/* Hover was a border-colour shift plus a drop shadow — both reinstate the box.
   The image push-in already reads as interactive; the title going sky is the
   affordance that replaces them. */
.lux-aircraft-card:hover h3,.lux-aircraft-card:focus-visible h3{color:var(--fe-blue-600)}
.lux-aircraft-card:hover img,.lux-aircraft-card:focus-visible img{transform:scale(1.04)}
/* The per-card CTA. A <span>, not an <a>: the whole card is already the
   anchor and anchors do not nest. It fills on card hover rather than its
   own, so the button lights from anywhere on the card — its padding is
   trimmed from the stock 17px/36px so it reads as the card's detail, not
   the section's. margin-top:auto (the card and .a-body are flex columns)
   bottom-aligns the row's buttons on /our-fleet/, where three-spec-row
   cards sit beside two-row ones; the spec list's bottom margin is the
   minimum gap on the tallest card, where auto resolves to 0. */
.lux-aircraft-card .a-cta{display:inline-block;align-self:flex-start;margin-top:auto;padding:12px 26px}
.lux-aircraft-card:hover .a-cta,.lux-aircraft-card:focus-visible .a-cta{background-color:var(--fe-navy);color:#fff}
@media (prefers-reduced-motion:reduce){
  .lux-aircraft-card img,.lux-aircraft-card h3{transition:none}
  .lux-aircraft-card:hover img,.lux-aircraft-card:focus-visible img{transform:none}
}

/* ---- Popular routes widget ------------------------------------------------
   Auto-rotating top-10 routes with sample Jet Club vs Fractional pricing per
   cabin class. Markup is built by js/lux-routes.js from a data table.

   Ported from a standalone build, with two deliberate changes:
   1. Its private palette and font token block is dropped — this file's :root
      already defines the palette, and the copy carried a different --fe-blue
      (#1B6FAE) than the site's (#299FCF). Small text on light uses
      --fe-blue-600, the accessible 5.5:1 blue, per the .lux-eyebrow note above.
   2. Display weights are 300, not the 600 the standalone used. The site sets
      headings and figures light (.lux-head h2, .lux-stat-number) and reserves
      600 for tiny letterspaced uppercase labels only — so the route name and
      the prices go light and the eyebrow/column heads stay at 600. */
.lux-routes{
  position:relative;width:100%;max-width:1440px;height:520px;margin:0 auto;
  overflow:hidden;background:var(--fe-paper);border:1px solid var(--fe-line);
  box-shadow:0 1px 3px rgba(0,40,80,.10),0 8px 24px rgba(0,40,80,.06);
  font-family:var(--lux-font);color:var(--fe-ink);-webkit-font-smoothing:antialiased;
}
.lux-routes-slide{position:absolute;inset:0;opacity:0;transition:opacity .7s ease;pointer-events:none}
.lux-routes-slide.is-active{opacity:1;pointer-events:auto;z-index:2}
.lux-routes-grid{display:grid;grid-template-columns:1fr 1fr;height:100%}
.lux-routes-copy{padding:clamp(32px,3.4vw,52px) clamp(28px,3.6vw,56px) clamp(28px,3vw,44px);display:flex;flex-direction:column}
/* Weight 300: this is the slide's display heading, so it follows
   .lux-head h2 rather than the standalone's semibold.
   margin-top:0 — the route name is the first thing in .lux-routes-copy now
   that the "Top routes · No. NN" eyebrow is gone, so the wrapper's own top
   padding sets the spacing and a margin here would double it. */
.lux-routes .r-route{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(24px,2.7vw,36px);line-height:1.12;letter-spacing:.01em;
  color:var(--fe-navy);margin:0;text-wrap:balance;
}
.lux-routes .r-arrow{color:var(--fe-blue);font-weight:300;padding:0 .12em}
.lux-routes .r-sub{font-size:14.5px;line-height:1.6;color:var(--fe-slate);margin:9px 0 0}
.lux-routes-table{margin-top:auto}
/* column-gap, not bare fr tracks: at 390px the class name ran straight into
   its price with no separation. */
.lux-routes-thead{display:grid;grid-template-columns:1.2fr 1fr 1fr;column-gap:clamp(12px,1.2vw,20px);padding-bottom:10px;border-bottom:1px solid var(--fe-navy)}
.lux-routes .r-th{font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:.18em;text-transform:uppercase}
.lux-routes .r-th--jc{color:var(--fe-navy)}
.lux-routes .r-th--fr{color:var(--fe-blue-600)}
.lux-routes-row{display:grid;grid-template-columns:1.2fr 1fr 1fr;column-gap:clamp(12px,1.2vw,20px);align-items:baseline;padding:15px 0;border-bottom:1px solid var(--fe-line)}
.lux-routes .r-cls{font-size:14.5px;font-weight:400;color:var(--fe-ink)}
/* tabular-nums so the two price columns line up digit-for-digit down the
   table — proportional figures made the light weight look ragged. */
.lux-routes .r-jc,.lux-routes .r-fr{font-family:var(--lux-font);font-weight:300;font-variant-numeric:tabular-nums}
.lux-routes .r-jc{font-size:clamp(20px,1.9vw,26px);color:var(--fe-navy);line-height:1.1}
.lux-routes .r-fr{font-size:clamp(15px,1.35vw,18px);color:var(--fe-blue-600);line-height:1.1}
.lux-routes .r-legal{font-size:12px;line-height:1.5;color:var(--fe-slate);margin:14px 0 0}
.lux-routes-photo{position:relative;background:linear-gradient(160deg,var(--fe-navy) 0%,var(--fe-blue) 100%)}
.lux-routes-photo img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
/* Scrim, photo slides only: the destination label sits centred over the image
   and several of these photographs are bright sky, where white type alone
   drops below contrast. Darkest at the centre band the text occupies. */
.lux-routes-photo.has-photo::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(0,25,50,.20) 0%,rgba(0,25,50,.50) 50%,rgba(0,25,50,.24) 100%);
}
/* The destination, set in light letterspaced caps. Weight 400, not 600 — same
   reason as the headings. Present on photo and gradient slides alike so the
   label never appears to move as the carousel cycles. */
.lux-routes-photo .r-place{
  position:absolute;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;
  font-family:var(--lux-font);font-size:15px;font-weight:400;letter-spacing:.22em;
  text-transform:uppercase;color:#fff;text-align:center;padding:24px;margin:0;
  text-shadow:0 1px 10px rgba(0,20,40,.5);
}
.lux-routes-progress{position:absolute;bottom:0;left:0;right:0;height:3px;background:var(--fe-line);z-index:5}
.lux-routes-fill{height:100%;width:0;background:var(--fe-blue)}
/* Two identical animations, alternated per slide: re-adding the same class
   would not restart the animation. */
.lux-routes-fill.run-a{animation:luxRoutesA var(--lux-routes-dwell,5s) linear forwards}
.lux-routes-fill.run-b{animation:luxRoutesB var(--lux-routes-dwell,5s) linear forwards}
@keyframes luxRoutesA{from{width:0}to{width:100%}}
@keyframes luxRoutesB{from{width:0}to{width:100%}}
@media (max-width:900px){
  .lux-routes{height:auto}
  .lux-routes-grid{grid-template-columns:1fr}
  .lux-routes-slide{position:relative;display:none}
  .lux-routes-slide.is-active{display:block}
  .lux-routes-photo{height:220px;order:-1}
}
/* No auto-advance under reduced motion (the JS also stops the timer); the
   progress bar would otherwise animate against a static slide. */
@media (prefers-reduced-motion:reduce){
  .lux-routes-slide{transition:none}
  .lux-routes-fill.run-a,.lux-routes-fill.run-b{animation:none;width:100%}
}

/* ---- HubSpot form skin ----------------------------------------------------
   Styles HubSpot's own generated markup (.hs-form / fieldset.form-columns-N /
   .hs-input / .legal-consent-container). Add .lux-hsform to the element the
   embed targets; everything below is scoped to it, so unskinned embeds
   elsewhere are unaffected.

   The unstyled embed had no max-width at all, so on a wide monitor each field
   stretched to ~1400px with borderless white inputs on a near-white ground —
   the fields read as gaps rather than fields. Fixed width, hairline boxes and
   a real vertical rhythm are what make it read as a form.

   HubSpot ships its own stylesheet, hence the handful of !important
   declarations: they are all overriding hs-form defaults, not this file. */
.lux-hsform{max-width:880px;margin:0 auto}
.lux-hsform .hs-form{
  background:var(--fe-paper);border:1px solid var(--fe-line);
  padding:clamp(26px,3.2vw,48px) clamp(22px,3vw,44px);
  font-family:var(--lux-font);
}
/* Scoped border-box reset, not decoration. On a normal page normalize.css has
   already set this globally, so it changes nothing — but HubSpot's iframe forms
   render in a bare about:blank document that loads no reset, where HubSpot's own
   width:100% is a *content* width and the padding above pushed the form ~50px
   past the frame, cutting the right-hand column off. */
.lux-hsform .hs-form,
.lux-hsform .hs-form *,
.lux-hsform .hs-form *::before,
.lux-hsform .hs-form *::after{box-sizing:border-box}
/* HubSpot's column fieldsets are float/width based; grid them instead so the
   gutters are even and they collapse cleanly on narrow screens. */
.lux-hsform .hs-form fieldset{max-width:none !important;width:100%;margin:0;padding:0;border:0}
.lux-hsform .hs-form fieldset.form-columns-1,
.lux-hsform .hs-form fieldset.form-columns-2,
.lux-hsform .hs-form fieldset.form-columns-3{
  display:grid;column-gap:clamp(16px,2vw,26px);row-gap:0;
}
.lux-hsform .hs-form fieldset.form-columns-2{grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr))}
.lux-hsform .hs-form fieldset.form-columns-3{grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr))}
.lux-hsform .hs-form fieldset .field{margin:0 0 clamp(18px,2vw,24px)}
/* HubSpot sets inline width:100% on its wrappers plus its own float widths */
.lux-hsform .hs-form .input{margin:0 !important}
.lux-hsform .hs-form .hs-form-field{width:auto !important;float:none !important}

/* Labels: the site's small-caps label voice, not HubSpot's body-text default */
.lux-hsform .hs-form label{
  display:block;margin:0 0 8px;
  font-family:var(--lux-font);font-size:11px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);
}
/* Not red: at 11px caps a red asterisk is the loudest thing in the form. */
.lux-hsform .hs-form .hs-form-required{color:var(--fe-blue-600);margin-left:3px}
.lux-hsform .hs-form .field > label{line-height:1.4}
/* Reserve two lines of label above every input, but only where the fields sit
   side by side. "Who are you currently flying with? (If Applicable)" wraps to
   two lines and pushed its input 16px below the select beside it. In one
   column there is no row to align to, so the reserve would just be dead space. */
@media (min-width:700px){
  .lux-hsform .hs-form fieldset.form-columns-2 .field > label{min-height:2.8em}
}

.lux-hsform .hs-form input[type=text],
.lux-hsform .hs-form input[type=email],
.lux-hsform .hs-form input[type=tel],
.lux-hsform .hs-form input[type=number],
.lux-hsform .hs-form textarea,
.lux-hsform .hs-form select{
  box-sizing:border-box;width:100% !important;
  padding:13px 15px;
  font-family:var(--lux-font);font-size:15px;line-height:1.4;color:var(--fe-ink);
  background:var(--fe-paper);border:1px solid var(--fe-line);border-radius:0;
  transition:border-color .2s ease,box-shadow .2s ease;
}
.lux-hsform .hs-form textarea{min-height:120px;resize:vertical}
.lux-hsform .hs-form input:focus,
.lux-hsform .hs-form textarea:focus,
.lux-hsform .hs-form select:focus{
  outline:0;border-color:var(--fe-navy);box-shadow:0 0 0 3px rgba(0,58,112,.12);
}
/* One chevron for every select, so the two selects match each other and the
   native Windows/macOS arrows do not both show up. */
.lux-hsform .hs-form select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  padding-right:40px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2317709A' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;background-size:16px 16px;
}
.lux-hsform .hs-form select.is-placeholder{color:var(--fe-slate)}

/* Checkbox rows (referral question, consent opt-in) */
.lux-hsform .hs-form .inputs-list{list-style:none;margin:0;padding:0}
/* HubSpot's own widths on these wrappers overflowed the card at 390px — the
   consent label measured 690px inside a 327px column and pushed the whole page
   into horizontal scroll. */
.lux-hsform .hs-form .inputs-list,
.lux-hsform .hs-form .hs-form-booleancheckbox,
.lux-hsform .hs-form .hs-form-booleancheckbox-display,
.lux-hsform .hs-form .legal-consent-container .input{max-width:100%;width:auto}
.lux-hsform .hs-form .hs-form-booleancheckbox label,
.lux-hsform .hs-form .hs-form-checkbox label{
  display:flex;align-items:flex-start;gap:11px;margin:0;
  font-size:13.5px;font-weight:400;letter-spacing:0;text-transform:none;
  line-height:1.55;color:var(--fe-ink);
}
/* min-width:0 so the text can wrap: a flex item defaults to min-width:auto,
   which refuses to shrink below its content and is what actually overflowed. */
.lux-hsform .hs-form .hs-form-booleancheckbox label > span,
.lux-hsform .hs-form .hs-form-checkbox label > span{min-width:0;flex:1 1 auto}
.lux-hsform .hs-form input[type=checkbox]{
  flex:none;width:17px;height:17px;margin:1px 0 0;accent-color:var(--fe-navy);
}
/* The referral question is a <legend>, so it needs the label voice explicitly */
.lux-hsform .hs-form .hs-field-desc,
.lux-hsform .hs-form legend{
  display:block;margin:0 0 9px;padding:0;
  font-family:var(--lux-font);font-size:11px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);
}
/* The referral checkbox's own <label> is EMPTY in the HubSpot form definition —
   the question text lives in the <legend> instead — so the box rendered on its
   own line looking like a stray tickbox. Laying the field out as a row binds it
   to its question without inventing label text that isn't in the form.
   Worth adding a checkbox label in HubSpot; this only makes it legible. */
.lux-hsform .hs-form .hs-fieldtype-booleancheckbox.field{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
}
/* width:auto is load-bearing — HubSpot sets width:100% on .hs-field-desc, which
   as a flex item ate the whole row and wrapped the checkbox onto the next line. */
.lux-hsform .hs-form .hs-fieldtype-booleancheckbox.field > legend,
.lux-hsform .hs-form .hs-fieldtype-booleancheckbox.field > .hs-field-desc{
  margin:0;width:auto !important;max-width:none;flex:0 1 auto;
}
.lux-hsform .hs-form .hs-fieldtype-booleancheckbox.field > .input{flex:none}

/* Consent block: a hairline-separated footnote, not a wall of body text */
.lux-hsform .hs-form .legal-consent-container{
  margin-top:clamp(8px,1.4vw,16px);padding-top:clamp(20px,2.4vw,28px);
  border-top:1px solid var(--fe-line);
}
.lux-hsform .hs-form .legal-consent-container .hs-richtext,
.lux-hsform .hs-form .legal-consent-container p{
  font-size:12px;line-height:1.65;color:var(--fe-slate);margin:0 0 14px;
}
.lux-hsform .hs-form .legal-consent-container a{color:var(--fe-blue-600);text-decoration:underline}

/* Submit: the site's CTA voice, and wide enough to close the form decisively */
.lux-hsform .hs-form .hs_submit{margin-top:clamp(22px,2.6vw,30px)}
.lux-hsform .hs-form .actions{margin:0;padding:0}
.lux-hsform .hs-form input[type=submit],
.lux-hsform .hs-form .hs-button{
  display:block;width:100%;max-width:320px;margin:0 auto;
  padding:16px 34px;border:1px solid var(--fe-navy);border-radius:0;
  background:var(--fe-navy);color:#fff;
  font-family:var(--lux-font);font-size:12px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;cursor:pointer;
  transition:background .2s ease,border-color .2s ease;
}
.lux-hsform .hs-form input[type=submit]:hover,
.lux-hsform .hs-form .hs-button:hover{background:var(--fe-navy-900);border-color:var(--fe-navy-900)}

/* Validation */
.lux-hsform .hs-form .hs-error-msgs{list-style:none;margin:7px 0 0;padding:0}
.lux-hsform .hs-form .hs-error-msg,
.lux-hsform .hs-form .hs-error-msgs label{
  font-size:12px;font-weight:400;letter-spacing:0;text-transform:none;color:var(--fe-error);
}
.lux-hsform .hs-form .hs-input.invalid{border-color:var(--fe-error)}
.lux-hsform .hs-form .hs-form__virality-link{display:none}
@media (prefers-reduced-motion:reduce){
  .lux-hsform .hs-form input,.lux-hsform .hs-form select,
  .lux-hsform .hs-form textarea,.lux-hsform .hs-form .hs-button{transition:none}
}

/* Where the skin sits inside .lux-form-card or .lux-panel, that wrapper already
   supplies the fill and the padding — leaving .hs-form's own card chrome on
   would draw a second box inside the first, with two lots of padding. */
.lux-form-card .lux-hsform,.lux-form-card.lux-hsform,
.lux-panel .lux-hsform,.lux-panel.lux-hsform{max-width:none}
.lux-form-card .lux-hsform .hs-form,.lux-form-card.lux-hsform .hs-form,
.lux-panel .lux-hsform .hs-form,.lux-panel.lux-hsform .hs-form{
  background:none;border:0;padding:0;
}
/* Same thing by hand, for cards this file doesn't know about — the jc25 form
   card on the Jet Club page has its own radius and shadow, and only wants the
   field styling out of the skin. Note --bare goes on the host card itself, which
   is why it must not say max-width:none: that cancelled the host's own cap
   (jet-card__form-block's 600px) and let the card stretch. It carries no
   geometry at all — the host keeps its box, the skin only dresses the fields. */
.lux-hsform--bare .hs-form{background:none;border:0;padding:0}

/* ---- Native form skin -----------------------------------------------------
   The same form as .lux-hsform above, for the Webflow-authored forms that were
   never moved to HubSpot (contact, join, referrals, privacy request, …). Those
   ship .w-input / .w-select / .w-button markup plus a per-page mix of Webflow
   classes — .updated__text-field here, .text-field-3 there — which is why the
   fields looked different on every page. Everything below matches the HubSpot
   skin value for value; the two are meant to be indistinguishable on screen.

   Add .lux-webform to the .w-form wrapper, not to the <form>: the card border
   belongs to the form, so a heading in the wrapper sits above the card the way
   "Discover flyExclusive" does on the homepage.

   Selectors carry an extra type or class over the Webflow originals they have
   to outrank (.updated__text-field.w-input, .new__cta.light-blue.w-button) —
   the counts are load-bearing, don't shorten them into ties. */
/* display/height are resets, not decoration: the Webflow wrappers this lands on
   (.new-full-page__form-block, .get-in-touch__form) are flex columns with
   align-items:center and height:100%, which shrink-wrapped the card and pulled
   it off the page's left edge. */
.lux-webform:not(.lux-webform--bare){display:block;height:auto;max-width:880px;margin:0 auto;text-align:left}
.lux-webform form{
  background:var(--fe-paper);border:1px solid var(--fe-line);
  padding:clamp(26px,3.2vw,48px) clamp(22px,3vw,44px);
  font-family:var(--lux-font);width:100%;margin:0;
  display:grid;grid-template-columns:1fr;
  column-gap:clamp(16px,2vw,26px);row-gap:clamp(18px,2vw,24px);
}
/* Two columns, stated rather than auto-fit: these forms put every field in one
   flat grid (HubSpot splits them into per-row fieldsets), so an auto-fit track
   list counted the fields and gave three columns at 880px. Two is what the
   homepage form shows. */
@media (min-width:640px){
  .lux-webform form{grid-template-columns:1fr 1fr}
}
/* A message field, a consent tick and the recaptcha slot all read as full-width
   rows; leaving them in a column made the form look half-empty beside them. */
.lux-webform form > div:has(textarea),
.lux-webform form > div:has(label.w-checkbox),
.lux-webform form > label.w-checkbox,
.lux-webform form > .w-embed,
.lux-webform form > .w-form-formrecaptcha{grid-column:1/-1}
/* The Webflow export leaves an empty .w-embed holding only a hidden input */
.lux-webform form > .w-embed{margin:0}

.lux-webform form label:not(.w-checkbox),
.lux-webform form .fieldlabel{
  display:block;margin:0 0 8px;
  font-family:var(--lux-font);font-size:11px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);
  line-height:1.4;
}
/* Reserve two lines of label above every input so side-by-side fields align on
   their boxes — "Which are you interested in?" wraps and its neighbour didn't.
   Only where the fields actually sit in a row; in one column it's dead space. */
@media (min-width:640px){
  .lux-webform form > div > label:not(.w-checkbox){min-height:2.8em}
}

.lux-webform form input.w-input,
.lux-webform form textarea.w-input,
.lux-webform form select.w-select{
  box-sizing:border-box;width:100%;height:auto;margin:0;
  padding:13px 15px;
  font-family:var(--lux-font);font-size:15px;line-height:1.4;color:var(--fe-ink);
  background:var(--fe-paper);border:1px solid var(--fe-line);border-radius:0;
  transition:border-color .2s ease,box-shadow .2s ease;
}
.lux-webform form textarea.w-input{min-height:120px;resize:vertical}
.lux-webform form input.w-input:focus,
.lux-webform form textarea.w-input:focus,
.lux-webform form select.w-select:focus{
  outline:0;border-color:var(--fe-navy);box-shadow:0 0 0 3px rgba(0,58,112,.12);
}
.lux-webform form input.w-input::placeholder,
.lux-webform form textarea.w-input::placeholder{color:var(--fe-slate)}
/* One chevron for every select, so they match each other and the native
   Windows/macOS arrow does not show up alongside it. */
.lux-webform form select.w-select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  padding-right:40px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2317709A' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;background-size:16px 16px;
}

/* Checkbox rows (consent opt-in, referral question) */
.lux-webform form label.w-checkbox{
  display:flex;align-items:flex-start;gap:11px;margin:0;padding:0;
  font-size:13.5px;font-weight:400;letter-spacing:0;text-transform:none;
  line-height:1.55;color:var(--fe-ink);
}
.lux-webform form label.w-checkbox .w-form-label{
  margin:0;min-width:0;flex:1 1 auto;
  font-size:13.5px;font-weight:400;letter-spacing:0;text-transform:none;
  line-height:1.55;color:var(--fe-ink);
}
.lux-webform form input[type=checkbox]{
  flex:none;width:17px;height:17px;margin:1px 0 0;padding:0;
  accent-color:var(--fe-navy);border-radius:0;
}

/* Submit: the site's CTA voice, centred and wide enough to close the form */
.lux-webform form input[type=submit],
.lux-webform form input[type=submit].w-button{
  grid-column:1/-1;
  display:block;width:100%;max-width:320px;margin:clamp(8px,1vw,14px) auto 0;
  padding:16px 34px;border:1px solid var(--fe-navy);border-radius:0;
  background:var(--fe-navy);color:#fff;
  font-family:var(--lux-font);font-size:12px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;cursor:pointer;
  transition:background .2s ease,border-color .2s ease;
}
.lux-webform form input[type=submit]:hover,
.lux-webform form input[type=submit].w-button:hover{
  background:var(--fe-navy-900);border-color:var(--fe-navy-900);
}

/* Webflow's own success/error panels, in the form's voice rather than the
   default green and red blocks. */
.lux-webform .w-form-done,
.lux-webform .w-form-fail{
  margin-top:14px;padding:16px 18px;border:1px solid var(--fe-line);
  background:var(--fe-surface-grey);
  font-family:var(--lux-font);font-size:13.5px;line-height:1.6;color:var(--fe-ink);
}
.lux-webform .w-form-fail{border-color:var(--fe-error);color:var(--fe-error)}

/* Same nesting rule as the HubSpot skin: no card inside a card. */
.lux-form-card .lux-webform,.lux-form-card.lux-webform,
.lux-panel .lux-webform,.lux-panel.lux-webform{max-width:none}
.lux-form-card .lux-webform form,.lux-form-card.lux-webform form,
.lux-panel .lux-webform form,.lux-panel.lux-webform form{
  background:none;border:0;padding:0;
}
/* By hand, for the cards this file doesn't know about: .jet-card__form-block
   (tinted, 22px radius) and the exit-intent popup already are the container.
   Carries no geometry — see the note on .lux-hsform--bare above. */
.lux-webform--bare form{background:none;border:0;padding:0}
@media (prefers-reduced-motion:reduce){
  .lux-webform form input,.lux-webform form select,
  .lux-webform form textarea{transition:none}
}

/* ---- Tick list ------------------------------------------------------------
   A standalone checklist for use inside prose, where .lux-feature-card's own
   ul rules are not in scope (that component brings a border and padding with
   it, which is wrong in the middle of a .lux-split copy column). */
.lux-ticklist{list-style:none;margin:22px 0 0;padding:0;display:grid;gap:11px}
.lux-ticklist li{display:flex;gap:11px;align-items:flex-start;font-size:14.5px;line-height:1.5;color:var(--fe-ink)}
.lux-ticklist li svg{flex:none;width:16px;height:16px;stroke:var(--fe-blue);fill:none;stroke-width:2.4;margin-top:3px}

/* ---- Aircraft profile band ------------------------------------------------
   The side-on profile artwork (cutout photo or navy silhouette) the site ships
   per aircraft, presented as the identifying figure on an aircraft page. Sized
   by max-width rather than height so the very different aspect ratios of the
   cutouts (730x170) and silhouettes (800x225) both sit correctly. */
.lux-profile{margin:0;text-align:center}
.lux-profile img{width:100%;max-width:760px;height:auto;margin:0 auto;display:block}
.lux-profile figcaption{
  font-family:var(--lux-font);font-size:11px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--fe-slate);
  margin-top:clamp(14px,1.8vw,22px);text-align:center;
}

/* ---- Fleet cross-links ----------------------------------------------------
   Deliberately typographic, not photo cards: not every aircraft in the fleet
   has its own photograph, and a card row where some tiles carried a real
   aircraft and others a stand-in would misrepresent the ones without. */
/* 300px floor, not 220px: there are six siblings, and a narrower floor gave
   five columns and a stranded sixth. This lands on 3x2 at full width. */
.lux-fleetlinks{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));gap:clamp(12px,1.4vw,18px)}
.lux-fleetlinks a{
  display:block;padding:20px 22px;background:var(--fe-paper);
  border:1px solid var(--fe-line);text-decoration:none;
  transition:border-color .3s ease,box-shadow .3s ease;
}
.lux-fleetlinks a:hover,.lux-fleetlinks a:focus-visible{border-color:var(--fe-blue-300);box-shadow:0 6px 22px rgba(0,40,80,.10)}
.lux-fleetlinks .f-class{margin:0 0 6px;font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;color:var(--fe-blue-600)}
.lux-fleetlinks .f-name{margin:0;font-family:var(--lux-font);font-weight:400;font-size:clamp(16px,1.4vw,19px);line-height:1.25;color:var(--fe-navy)}
@media (prefers-reduced-motion:reduce){.lux-fleetlinks a{transition:none}}

/* Modal (native dialog) */
.lux-modal{border:1px solid var(--fe-line);padding:0;width:min(420px,90vw);max-width:420px}
.lux-modal::backdrop{background:rgba(0,25,50,.55)}
.lux-modal .m-head{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;border-bottom:1px solid var(--fe-line)}
.lux-modal .m-head h3{margin:0;font-family:var(--lux-font);font-weight:400;font-size:18px;color:var(--fe-navy)}
.lux-modal .m-close{background:none;border:0;font-size:20px;line-height:1;color:var(--fe-slate);cursor:pointer}
.lux-modal .m-body{padding:22px 24px;font-size:13.5px;color:var(--fe-ink);line-height:1.7}
.lux-modal .m-foot{padding:16px 24px;border-top:1px solid var(--fe-line);display:flex;justify-content:flex-end;gap:10px}

/* Drawer (native dialog, slides from the right) */
.lux-drawer{border:0;padding:0;position:fixed;inset:0 0 0 auto;height:100vh;max-height:100vh;width:min(360px,88vw);margin:0;box-shadow:-16px 0 40px rgba(0,25,50,.2)}
.lux-drawer::backdrop{background:rgba(0,25,50,.45)}
.lux-drawer .m-head{display:flex;justify-content:space-between;align-items:center;padding:22px 24px;border-bottom:1px solid var(--fe-line)}
.lux-drawer .m-head h3{margin:0;font-family:var(--lux-font);font-weight:400;font-size:18px;color:var(--fe-navy)}
.lux-drawer .m-close{background:none;border:0;font-size:20px;color:var(--fe-slate);cursor:pointer}
.lux-drawer .m-body{padding:22px 24px;font-size:13.5px;color:var(--fe-ink);line-height:1.7}

/* Popover */
.lux-popover-wrap{position:relative;display:inline-block}
.lux-popover{position:absolute;top:calc(100% + 10px);left:50%;transform:translateX(-50%);background:#fff;border:1px solid var(--fe-line);box-shadow:0 16px 40px rgba(0,25,50,.14);width:230px;padding:16px 18px;text-align:left;font-size:12.5px;color:var(--fe-ink);z-index:5}
.lux-popover-wrap:not([open]) .lux-popover{display:none}
.lux-popover-wrap > summary{list-style:none;cursor:pointer}
.lux-popover-wrap > summary::-webkit-details-marker{display:none}

/* CTA band — padding matches .lux-section and the content is capped at the
   same 1180px as .lux-wrap, so it doesn't jog out of the page grid. */
.lux-cta-band{
  width:100%;background:var(--fe-navy-900);color:#fff;
  padding:clamp(36px,5vw,52px) clamp(20px,5vw,40px);
  display:flex;align-items:center;justify-content:center;
  gap:24px;column-gap:clamp(24px,6vw,80px);flex-wrap:wrap;text-align:left;
}
.lux-cta-band > *{flex:0 1 auto}
.lux-cta-band > div{flex:1 1 420px;max-width:760px}
/* color is set explicitly rather than inherited from the band: the legacy
   Webflow sheet colours bare h3 navy (#003a70), which beat inheritance and
   left this heading at ~1.2:1 against the navy band — invisible on every page
   that uses it. */
.lux-cta-band h3{margin:0 0 6px;font-family:var(--lux-font);font-weight:300;font-size:clamp(22px,2.6vw,28px);color:#fff}
.lux-cta-band p{margin:0;color:var(--fe-blue-200);font-size:14px}

/* Press / quote banner */
.lux-press-banner{width:100%;padding:56px 48px;text-align:center;background:var(--fe-canvas);border-top:1px solid var(--fe-line);border-bottom:1px solid var(--fe-line)}
.lux-press-banner blockquote{margin:0 auto 16px;max-width:640px;font-family:var(--lux-font);font-weight:300;font-size:clamp(20px,2.4vw,26px);line-height:1.5;color:var(--fe-navy);border:0;padding:0}
.lux-press-banner cite{font-style:normal;font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--fe-slate)}

/* Stat band (dark variant of lux-stat-row) */
.lux-stat-band{display:flex;width:100%;background:var(--fe-navy-900)}
.lux-stat-band .s{flex:1;padding:34px 16px;text-align:center;border-right:1px solid rgba(255,255,255,.15)}
.lux-stat-band .s:last-child{border-right:0}
.lux-stat-band .num{font-family:var(--lux-font);font-weight:300;font-size:34px;color:#fff;line-height:1.1;margin:0}
.lux-stat-band .lbl{font-family:var(--lux-font);font-size:10px;font-weight:600;letter-spacing:.24em;text-transform:uppercase;color:var(--fe-blue-300);margin:8px 0 0}

/* Split promo block */
/* A real grid gap does the job the copy column's 44px padding used to, and
   unlike one-sided padding it stays correct when --reverse flips the columns. */
.lux-split{display:grid;grid-template-columns:1fr 1fr;width:100%;align-items:stretch;gap:clamp(24px,3.5vw,56px)}
/* Fixed ratio, not height:100% — stretching to match a runaway copy column
   cover-cropped 3:2 aircraft renders into portrait slots and clipped wings. */
.lux-split img{width:100%;aspect-ratio:4/3;height:auto;align-self:center;object-fit:cover;display:block}
.lux-split .s-copy{padding:0;display:flex;flex-direction:column;justify-content:center;text-align:left}
.lux-split .s-copy h3{margin:0 0 12px;font-family:var(--lux-font);font-weight:300;font-size:clamp(20px,2.2vw,26px);color:var(--fe-navy)}
.lux-split .s-copy p{margin:0 0 18px;color:var(--fe-slate);font-size:14px;line-height:1.7}
/* --lg — a copy column set one step up from the 14px body size. For a split
   whose paragraph IS the section's argument rather than a caption beside a
   photograph (fractional.html #program: the ownership pitch plus the page's
   tax claim). Opt-in per instance, because the 14px default is right for the
   short supporting copy most splits carry. The tick rows move with it so the
   list still reads as part of the same block, and the 16px glyph is nudged a
   pixel down to stay optically centred on the taller line. */
.lux-split .s-copy.lux-copy--lg p{font-size:17px;line-height:1.65}
.lux-copy--lg .lux-ticklist{gap:13px}
.lux-copy--lg .lux-ticklist li{font-size:16px;line-height:1.55}
.lux-copy--lg .lux-ticklist li svg{margin-top:4px}
/* .lux-feature-card's list moves with --lg for the same reason .lux-ticklist
   does. Without this the card's rows stayed at 13.5px against a 17px paragraph,
   and its h4 stayed at 17px — the same size as the paragraph above it, so the
   list title stopped outranking the prose it follows. mro/avionics.html is the
   first page to pair --lg with this card. */
.lux-copy--lg .lux-feature-card h4{font-size:19px}
.lux-copy--lg .lux-feature-card li{font-size:16px;line-height:1.55}
.lux-copy--lg .lux-feature-card li svg{width:16px;height:16px;margin-top:4px}
@media (max-width:700px){
  .lux-split{grid-template-columns:1fr}
  .lux-split img{aspect-ratio:16/9}
  /* Alternating splits are laid out by source order, so a run of them read
     copy-first, image-first, copy-first once stacked. Pin one reading order
     for every split on mobile instead of reordering markup page by page. */
  .lux-split .s-copy{order:1}
  /* The media slot is not always an <img>: careers/corporate.html puts a
     .lux-embed player in it. Ordering only <img> left the embed at the flex
     default of order:0, so on mobile the video sat above the heading it
     illustrates. Every media child now takes the same slot as the photograph. */
  .lux-split > img,
  .lux-split > .lux-embed,
  .lux-split > figure{order:2}
}

/* ==========================================================================
   CAROUSELS & SLIDERS
   Only two engines here. (1) CSS scroll-snap — no JS at all, the browser
   does the paging; (2) a shared [data-lux-carousel] controller that either
   translates a flex track or crossfades stacked slides. Every visual variant
   below is styling on top of one of those two, so there is one place to fix
   a bug and one behavior for users to learn.
   ========================================================================== */

/* ---------- shared chrome: arrows, dots, counter, play/pause ---------- */
.lux-carousel-arrow{width:42px;height:42px;flex:none;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--fe-navy);background:#fff;color:var(--fe-navy);cursor:pointer;transition:all .3s ease}
.lux-carousel-arrow:hover:not(:disabled){background:var(--fe-navy);color:#fff}
.lux-carousel-arrow:disabled{border-color:var(--fe-line);color:var(--fe-line);cursor:default}
.lux-carousel-arrow svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8}
.lux-carousel-arrow--ondark{border-color:rgba(255,255,255,.55);background:transparent;color:#fff}
.lux-carousel-arrow--ondark:hover:not(:disabled){background:#fff;color:var(--fe-navy-900)}
.lux-carousel-arrow--ondark:disabled{border-color:rgba(255,255,255,.25);color:rgba(255,255,255,.35)}

.lux-carousel-dots{display:flex;align-items:center;gap:10px;list-style:none;margin:0;padding:0}
/* turbine pagination. These were hollow navy diamonds that filled in; the mark
   carries the state by colour now — light sky at rest, sky on hover, navy for
   the current slide. Border dropped: the art has its own silhouette, and a box
   around it read as a frame rather than a dot. */
.lux-carousel-dots button{width:12px;height:12px;padding:0;border:0;background:url("../images/turbine-lightsky.png") center/contain no-repeat;cursor:pointer;transition:opacity .25s ease}
.lux-carousel-dots button:hover{background-image:url("../images/turbine-sky.png")}
.lux-carousel-dots button[aria-current="true"]{background-image:url("../images/turbine-navy.png")}
.lux-carousel-dots--ondark button{background-image:url("../images/turbine-lightsky.png");opacity:.6}
.lux-carousel-dots--ondark button:hover{background-image:url("../images/turbine-white.png");opacity:1}
.lux-carousel-dots--ondark button[aria-current="true"]{background-image:url("../images/turbine-white.png");opacity:1}
/* --rule: hairline dashes instead of turbine marks, for components whose own
   detailing is hairlines (the testimonial rotator). The button is 20px tall so
   the hit target clears the 24px-with-spacing minimum even though the mark it
   draws is one pixel. */
.lux-carousel-dots--rule{gap:14px}
/* The :hover and [aria-current] variants are listed explicitly, not because the
   declarations differ, but to match the specificity of the turbine rules above:
   `.lux-carousel-dots button[aria-current="true"]` is (0,2,1) and beat a plain
   `.lux-carousel-dots--rule button` (0,1,1), so background-image:none lost and
   the active and hovered dots still painted a turbine — tiled at natural size
   from the top-left corner, because `background:none` DID win for size/position
   /repeat. These tie on specificity and win on order. Keep them after the
   --ondark turbine rules for the same reason. */
.lux-carousel-dots--rule button,
.lux-carousel-dots--rule button:hover,
.lux-carousel-dots--rule button[aria-current="true"]{
  width:26px;height:20px;position:relative;
  background:none;background-image:none;
}
.lux-carousel-dots--rule button::before{
  content:"";position:absolute;left:0;right:0;top:50%;height:1px;
  background:var(--fe-line);transition:background-color .3s ease;
}
.lux-carousel-dots--rule button:hover::before{background:var(--fe-blue-300)}
.lux-carousel-dots--rule button[aria-current="true"]::before{background:var(--fe-blue-400)}
.lux-carousel-dots--rule.lux-carousel-dots--ondark button::before{background:rgba(255,255,255,.3)}
.lux-carousel-dots--rule.lux-carousel-dots--ondark button:hover::before,
.lux-carousel-dots--rule.lux-carousel-dots--ondark button[aria-current="true"]::before{background:#fff}

.lux-carousel-count{font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:.2em;color:var(--fe-slate);white-space:nowrap}
.lux-carousel-count b{color:var(--fe-navy);font-weight:600}
.lux-carousel-count--ondark{color:rgba(255,255,255,.6)}
.lux-carousel-count--ondark b{color:#fff}

.lux-carousel-toggle{width:32px;height:32px;flex:none;display:inline-flex;align-items:center;justify-content:center;border:1px solid rgba(255,255,255,.55);background:transparent;color:#fff;cursor:pointer;transition:all .3s ease}
.lux-carousel-toggle:hover{background:#fff;color:var(--fe-navy-900)}
.lux-carousel-toggle svg{width:12px;height:12px;stroke:currentColor;fill:currentColor;stroke-width:0}
.lux-carousel-toggle .i-pause{display:none}
.lux-carousel-toggle.is-playing .i-pause{display:block}
.lux-carousel-toggle.is-playing .i-play{display:none}

/* ---------- engine 1: CSS scroll-snap rail (no JS) ---------- */
.lux-snap{display:flex;gap:18px;width:100%;overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;scroll-behavior:smooth;padding-bottom:16px;scrollbar-width:thin;scrollbar-color:var(--fe-navy) var(--fe-line)}
.lux-snap::-webkit-scrollbar{height:3px}
.lux-snap::-webkit-scrollbar-track{background:var(--fe-line)}
.lux-snap::-webkit-scrollbar-thumb{background:var(--fe-navy)}
.lux-snap > *{flex:0 0 clamp(200px,60%,250px);scroll-snap-align:start}
.lux-snap-card{background:none;text-align:left}
.lux-snap-card img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block}
.lux-snap-card .c-body{padding:13px 0 0}
.lux-snap-card h4{margin:0 0 3px;font-family:var(--lux-font);font-weight:400;font-size:16px;color:var(--fe-navy)}
.lux-snap-card p{margin:0;font-family:var(--lux-font);font-size:10.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--fe-slate)}
@media (prefers-reduced-motion:reduce){.lux-snap{scroll-behavior:auto}}

/* Peek rail — the snap scroller above plus a header row of arrows */
.lux-rail{width:100%}
.lux-rail-head{display:flex;align-items:flex-end;justify-content:space-between;gap:20px;margin-bottom:18px}
.lux-rail-head h3{margin:0;font-family:var(--lux-font);font-weight:300;font-size:clamp(19px,2.2vw,24px);color:var(--fe-navy)}
.lux-rail-nav{display:flex;gap:8px;flex:none}

/* ---------- engine 2a: translateX track ---------- */
.lux-slider{width:100%}
.lux-slider-viewport{width:100%;overflow:hidden}
.lux-slider-track{display:flex;transition:transform .6s cubic-bezier(.4,0,.2,1)}
.lux-slider-track > *{flex:0 0 100%;min-width:0}
.lux-slider figure{margin:0}
.lux-slider img{width:100%;aspect-ratio:16/9;object-fit:cover;display:block}
.lux-slider figcaption{font-family:var(--lux-font);font-size:12.5px;color:var(--fe-slate);padding:12px 2px 0;text-align:left}
.lux-slider-foot{display:flex;align-items:center;justify-content:space-between;gap:20px;padding-top:16px;border-top:1px solid var(--fe-line);margin-top:16px}
.lux-slider-foot .f-nav{display:flex;align-items:center;gap:8px}
@media (prefers-reduced-motion:reduce){.lux-slider-track{transition:none}}

/* ---------- engine 2b: crossfade stack ---------- */
.lux-fade{position:relative;width:100%}
.lux-fade-stage{position:relative;width:100%;aspect-ratio:16/9;overflow:hidden;background:var(--fe-navy-900)}
.lux-fade-slide{position:absolute;inset:0;opacity:0;visibility:hidden;transition:opacity .9s ease,visibility .9s ease}
.lux-fade-slide.is-active{opacity:1;visibility:visible}
.lux-fade-slide img{width:100%;height:100%;object-fit:cover;display:block}
.lux-fade-caption{position:absolute;left:0;right:0;bottom:0;padding:70px 40px 34px;text-align:left;background:linear-gradient(to top,rgba(0,39,77,.88),rgba(0,39,77,.35) 55%,rgba(0,39,77,0))}
.lux-fade-caption h3{margin:6px 0 0;font-family:var(--lux-font);font-weight:300;font-size:clamp(19px,2.6vw,30px);color:#fff}
.lux-fade-bar{position:absolute;right:28px;bottom:28px;z-index:2;display:flex;align-items:center;gap:16px}
@media (prefers-reduced-motion:reduce){.lux-fade-slide{transition:none}}
@media (max-width:700px){
  .lux-fade-caption{padding:60px 22px 62px}
  .lux-fade-bar{right:22px;bottom:20px}
}
/* Upright stage, for a crossfade that shares a .lux-split with a copy column.
   The default 16/9 stage is a letterbox strip once the column is half-width,
   and it left the copy beside it floating against dead space. Back to 4/3 when
   the split stacks and the stage has the full measure again. */
.lux-fade--portrait .lux-fade-stage{aspect-ratio:4/5}
@media (max-width:700px){.lux-fade--portrait .lux-fade-stage{aspect-ratio:4/3}}

/* Testimonial slider — track engine, centered copy, no photography */
.lux-quote-slider{width:100%;max-width:620px;background:var(--fe-canvas);border-top:1px solid var(--fe-line);border-bottom:1px solid var(--fe-line);padding:36px 34px 26px}
.lux-quote-slider blockquote{margin:0;padding:0 12px;border:0;text-align:center;font-family:var(--lux-font);font-weight:300;font-size:clamp(16px,2vw,20px);line-height:1.55;color:var(--fe-navy)}
.lux-quote-slider .q-attr{margin-top:16px;text-align:center;font-family:var(--lux-font);font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate)}
.lux-quote-slider .lux-slider-foot{justify-content:center;border-top:0;margin-top:20px;padding-top:0}

/* ---- Testimonial wall ----------------------------------------------------
   Every quote on the page at once. This exists because .lux-quote-slider is
   built on the shared .lux-slider-track engine, which is a flex row: all
   slides inherit the tallest slide's height. That is correct for the image
   sliders it was written for (uniform 16/9 stages) and wrong for quotes —
   jet-club's first testimonial runs ~90 words, so the other five each sat in
   a 620px box with ~330px of empty grey beneath them.

   No boxes. The first pass gave each quote a filled, outlined tile and it read
   as a grid of grey cards — busy, and against the house rule already stated on
   .lux-quote-card above: a quote, not a boxed quote. What separates the quotes
   here is a short hairline and a lot of air, nothing more. That also disposes
   of the ragged-bottom problem a card wall has: with no box edge, columns of
   unequal length just look like columns of type.

   Two columns, not three. At 1180px three columns set a ~355px measure, about
   40 characters — tight and choppy for a light 300 face. Two gives ~530px and
   roughly 60 characters, which is where this type wants to sit.

   CSS columns, not grid: grid rows would reintroduce the equal-height problem
   one row at a time. Columns lets a 90-word quote and a 15-word quote sit side
   by side, each only as tall as it needs. Reading order runs down column one,
   then column two. */
.lux-quote-wall{
  --lux-wall-gap:clamp(40px,5vw,72px);
  --lux-wall-row:clamp(38px,4vw,54px);
  columns:2;column-gap:var(--lux-wall-gap);
}
/* The margin is on the quote, not a row-gap, because column layout has none —
   the bottom margin is what separates stacked quotes. break-inside keeps one
   from being sliced across a column boundary. */
.lux-quote-tile{
  break-inside:avoid;-webkit-column-break-inside:avoid;
  margin:0 0 var(--lux-wall-row);
  text-align:left;
}
.lux-quote-tile blockquote{
  margin:0;padding:0;border:0;
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(16px,1.55vw,19px);line-height:1.7;
  color:var(--fe-navy);text-wrap:pretty;
}
/* A hairline opens each quote — not a ” glyph. The copy already carries curly
   quotes, so a display ” beside them is the same mark twice, and Galano's is a
   pair of thin slashes that reads as a stray double-prime at that size. With
   the boxes gone this rule is also what marks where one quote ends and the
   next begins. */
.lux-quote-tile blockquote::before{
  content:"";display:block;
  width:28px;height:1px;
  background:var(--fe-blue-400);
  margin-bottom:20px;
}
/* text-align is set, not inherited from the tile: the attribution is a
   <figcaption>, and Webflow's components.css centres every figcaption on the
   site with a bare element selector, which inheritance cannot outrank. */
.lux-quote-tile .q-attr{
  margin:14px 0 0;
  font-family:var(--lux-font);font-size:10.5px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);
  text-align:left;
}
/* On a navy ground only the ink changes — there was never a fill to invert. */
.lux-section--navy .lux-quote-tile blockquote{color:#fff}
.lux-section--navy .lux-quote-tile blockquote::before{background:var(--fe-blue-400)}
.lux-section--navy .lux-quote-tile .q-attr{color:var(--fe-blue-200)}

/* --even: for a set whose quotes are all about the same length. Masonry only
   pays off when the lengths differ; with near-equal quotes it just splits them
   down two columns and the reading order stops matching the source. Rows
   instead, so quote tops and attributions line up across each row. Use the
   masonry default whenever one quote is much longer than the others.
   Rows start at the left rather than centring: at two columns a lone trailing
   quote centred would sit at the 25% mark, a left-aligned block floating in
   the middle of nothing. Aligned under column one it just reads as the next
   line of the list. */
.lux-quote-wall--even{
  columns:auto;
  display:flex;flex-wrap:wrap;justify-content:flex-start;
  column-gap:var(--lux-wall-gap);row-gap:var(--lux-wall-row);
}
.lux-quote-wall--even .lux-quote-tile{
  margin:0;
  flex:0 1 calc((100% - var(--lux-wall-gap)) / 2);
  display:flex;flex-direction:column;
}
/* Quotes in a row are the same height, so the attributions only line up if the
   shorter ones push theirs down. padding-top keeps the 14px minimum gap that
   margin-top:auto gives away. */
.lux-quote-wall--even .lux-quote-tile .q-attr{margin-top:auto;padding-top:14px}

/* One column once two would each be under ~330px — below that the measure is
   worse than the extra scrolling. */
@media (max-width:760px){
  .lux-quote-wall{columns:1}
  .lux-quote-wall--even .lux-quote-tile{flex-basis:100%}
  .lux-quote-tile blockquote::before{margin-bottom:16px}
}

/* ---- Testimonial rotator -------------------------------------------------
   One quote at a time, dissolving. Same boxless .lux-quote-tile as the wall,
   set larger and centred because it is now the only thing on screen rather
   than one of six.

   Driven by the "fade" engine in js/lux-carousel.js with data-lux-autoplay
   ="auto", which measures each quote and gives it its own dwell instead of one
   delay for all of them — see the timing note there.

   Degrades to the wall. Without JS the stage is an ordinary block and all the
   quotes are in normal flow, so a reader with no JS gets the stacked list, not
   one quote and five invisible ones. lux-carousel.js adds .is-live. */
.lux-quote-rotator{
  width:100%;max-width:760px;margin-left:auto;margin-right:auto;
}
.lux-quote-rotator .lux-rotator-stage > [data-lux-slide]{margin:0 0 44px}
.lux-quote-rotator .lux-quote-tile{text-align:center}
.lux-quote-rotator blockquote{font-size:clamp(18px,1.9vw,23px);line-height:1.6}
.lux-quote-rotator blockquote::before{margin-left:auto;margin-right:auto;margin-bottom:24px}
.lux-quote-rotator .q-attr{text-align:center;margin-top:20px}

/* Height is animated because the quotes are wildly different lengths — a
   stage fixed to the tallest would leave the 15-word quotes floating in ~350px
   of nothing, which is the fault this whole section was rebuilt to fix. JS
   writes the pixel height; the transition is here. */
.lux-quote-rotator.is-live .lux-rotator-stage{
  position:relative;
  transition:height .5s cubic-bezier(.4,0,.2,1);
}
/* Dissolve through nothing, not a true crossfade: two blocks of text at 50%
   opacity on top of each other is unreadable mush. The outgoing quote fades
   out over .45s, and the incoming one waits that out before starting, so they
   barely overlap. The 6px rise is on the way in only — transform snaps back
   after the fade-out so the leaving quote never slides. */
.lux-quote-rotator.is-live .lux-rotator-stage > [data-lux-slide]{
  position:absolute;top:0;left:0;right:0;margin:0;
  opacity:0;transform:translateY(6px);
  transition:opacity .45s ease,transform 0s linear .45s;
}
.lux-quote-rotator.is-live .lux-rotator-stage > [data-lux-slide].is-active{
  opacity:1;transform:none;
  transition:opacity .7s ease .35s,transform .7s cubic-bezier(.4,0,.2,1) .35s;
}
.lux-rotator-foot{display:flex;justify-content:center;margin-top:clamp(26px,3vw,38px)}
/* No autoplay under reduced motion (lux-carousel.js declines to start it), so
   the dots become the only way through — the swap itself is instant. */
@media (prefers-reduced-motion:reduce){
  .lux-quote-rotator.is-live .lux-rotator-stage,
  .lux-quote-rotator.is-live .lux-rotator-stage > [data-lux-slide]{transition:none}
  .lux-quote-rotator.is-live .lux-rotator-stage > [data-lux-slide]{transform:none}
}

/* Filmstrip gallery — crossfade stage driven by thumbnail indicators */
.lux-filmstrip{width:100%}
.lux-filmstrip .lux-fade-stage{aspect-ratio:3/2}
.lux-filmstrip-thumbs{display:flex;justify-content:center;gap:10px;list-style:none;margin:10px 0 0;padding:0 0 6px;overflow-x:auto;scrollbar-width:thin;scrollbar-color:var(--fe-line) transparent}
/* The <li> is the flex item, so it carries the track sizing — putting
   flex:0 0 90px on the button leaves it shrink-to-fit and the strip
   renders at ragged sizes. */
.lux-filmstrip-thumbs li{flex:0 0 90px}
.lux-filmstrip-thumbs button{display:block;width:100%;padding:0;border:1px solid transparent;background:none;cursor:pointer;opacity:.45;transition:opacity .25s ease,border-color .25s ease}
.lux-filmstrip-thumbs button:hover{opacity:.85}
.lux-filmstrip-thumbs button[aria-current="true"]{opacity:1;border-color:var(--fe-navy)}
.lux-filmstrip-thumbs img{width:100%;aspect-ratio:3/2;object-fit:cover;display:block}

/* ---------- marquee ticker (CSS only, no engine) ---------- */
.lux-marquee{width:100%;overflow:hidden;padding:24px 0;border-top:1px solid var(--fe-line);border-bottom:1px solid var(--fe-line);-webkit-mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent);mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent)}
.lux-marquee-track{display:flex;width:max-content;animation:luxMarquee 30s linear infinite}
.lux-marquee:hover .lux-marquee-track,.lux-marquee:focus-within .lux-marquee-track{animation-play-state:paused}
/* Two identical halves, each padded by exactly one gap, so translating the
   track by -50% lands on a seamless loop point. */
.lux-marquee-group{display:flex;gap:54px;padding-right:54px}
.lux-marquee-group span{font-family:var(--lux-font);font-size:12.5px;font-weight:600;letter-spacing:.24em;text-transform:uppercase;color:var(--fe-slate);white-space:nowrap}
@keyframes luxMarquee{to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){
  .lux-marquee{-webkit-mask-image:none;mask-image:none}
  .lux-marquee-track{animation:none;width:100%;flex-wrap:wrap;justify-content:center}
  .lux-marquee-group{flex-wrap:wrap;justify-content:center;gap:20px 32px;padding-right:0}
  .lux-marquee-group + .lux-marquee-group{display:none}
}

/* ============================================================
   8 · PAGE SCAFFOLDING
   ------------------------------------------------------------
   Section/grid primitives the component library sits inside, so
   the redesigned pages share one vertical rhythm and one set of
   container widths instead of per-page Webflow leftovers.
   ============================================================ */
/* Review 2026-08-07 · 8 — "tighter spacing between modules", raised on the
   homepage and then again on jet-club and fractional. Was
   clamp(56px,7vw,104px). Every module on every page takes its vertical rhythm
   from this one token, so the fix belongs here rather than in per-page
   overrides: the complaint was as much that the gaps were UNEVEN as that they
   were large, and the unevenness came from pages patching individual joins.
   About a fifth off the top of the range, and the floor barely moves — the
   problem was 104px of air on a desktop between two related bands, not the
   56px a phone was getting. */
.lux-section{padding:clamp(52px,5.6vw,84px) clamp(20px,5vw,40px);background:var(--fe-paper)}
.lux-section--canvas{background:var(--fe-canvas)}
.lux-section--grey{background:var(--fe-surface-grey)}
.lux-section--navy{background:var(--fe-navy-900)}
.lux-section--tight{padding-top:clamp(36px,4vw,56px);padding-bottom:clamp(36px,4vw,56px)}
/* .home-header is fixed and reserves no space, which is right on the pages that
   open with a full-bleed .lux-hero for it to float over. A page that opens on
   content instead has to buy the clearance itself — the header runs to roughly
   84px and its scrim fades out 76px below that, so the first line of copy needs
   to start below both or it reads through the tint. */
.lux-section--clears-header{padding-top:clamp(112px,12vw,164px)}
.lux-section--flush{padding-left:0;padding-right:0}
.lux-section--bleed{padding:0}
/* Hairline separator for consecutive sections on the same ground. Lets a page
   run mostly on --fe-paper and still read as distinct chapters, instead of
   ping-ponging between --canvas and --grey to prove a section changed. Inset to
   .lux-wrap's 1180px so the rule tracks the content column, not the viewport. */
.lux-section--ruled{position:relative}
.lux-section--ruled::before{
  content:"";position:absolute;top:0;left:clamp(20px,5vw,40px);right:clamp(20px,5vw,40px);
  height:1px;background:var(--fe-line);
}
/* At 1260px the 1180px wrap plus its 40px gutters exactly fills the viewport,
   so switching the inset here is seamless rather than a visible jump. */
@media (min-width:1260px){
  .lux-section--ruled::before{left:calc((100% - 1180px) / 2);right:calc((100% - 1180px) / 2)}
}
.lux-wrap{max-width:1180px;margin:0 auto}
.lux-wrap--narrow{max-width:820px}
.lux-wrap--wide{max-width:1400px}

/* White card that hosts an embedded (HubSpot) form on a dark section */
/* Outline dropped; the padding stays because this sits on a navy section and
   the white fill is what separates it from the ground. */
.lux-form-card{background:var(--fe-paper);padding:clamp(26px,3.5vw,44px)}
.lux-form-card .hs-form,.lux-form-card form{margin:0}
/* The legacy Webflow wrapper centres and shrink-wraps its children, which
   centre-aligned the whole card against a left-set page. */
.lux-form-card .new-full-page__form-block{align-items:stretch;max-width:none;height:auto;margin-top:0}
.lux-form-card .f-head{font-family:var(--lux-font);font-weight:400;font-size:21px;color:var(--fe-navy);margin:0 0 8px;letter-spacing:.01em}
.lux-form-card .f-sub{font-family:var(--lux-font);font-size:13.5px;line-height:1.7;color:var(--fe-slate);margin:0 0 22px}

/* Section-leading splits and rails: when the component IS the section, its
   heading should be at h2 scale, not the h3 scale used inside a grid.
   h2 is listed alongside h3 because a split that IS the section often wants the
   real heading level too — on a page whose other sections are h2, an h3 here
   breaks the outline for no visual gain. Both render identically. */
/* h1 is here for the same reason as h2: on a biography page the opening split
   IS the page's headline, and the name has to be the h1 or the document has no
   top-level heading at all. */
.lux-split--lead .s-copy h1,
.lux-split--lead .s-copy h2,
.lux-split--lead .s-copy h3,
.lux-rail--lead .lux-rail-head h3{font-size:clamp(26px,3.4vw,40px);font-weight:300;line-height:1.15}
/* .s-copy h3 carries the family, weight and colour; an h2 in the same slot has
   to be told, or it inherits the legacy Webflow h2 instead. */
.lux-split .s-copy h1,
.lux-split .s-copy h2{margin:0 0 12px;font-family:var(--lux-font);font-weight:300;color:var(--fe-navy)}

/* A stepper that explains a sequence, not progress: numerals carry the accent,
   the connector rules stay neutral so it doesn't read as "100% complete". */
.lux-steps--static li::before{background:var(--fe-line)}
.lux-steps--static li .num{color:var(--fe-blue-600)}

/* Long service copy would otherwise turn a 3-up card grid into a wall of text */
.lux-prog-card--clamp p{display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden}

/* Panel: a padded region with no card semantics attached. The outline is gone,
   so on a paper ground this now reads as spacing rather than a container — use it
   on a tinted or navy section where the fill still separates it. */
.lux-panel{background:var(--fe-paper);padding:clamp(26px,3vw,36px)}
/* Kept as a no-op alias: .lux-feature-card is already bare, and pages still
   reference this modifier. */
.lux-feature-card--bare{border:0;padding:0;background:none}

/* Icon benefit card — icon, title, copy. The three-up "why this program"
   tile used on the program, service and maintenance pages. */
.lux-icon-card{
  border:1px solid var(--fe-line);background:var(--fe-paper);
  padding:clamp(26px,3vw,36px) clamp(22px,2.5vw,30px);text-align:center;
  display:flex;flex-direction:column;align-items:center;
}
.lux-icon-card img,.lux-icon-card svg{height:56px;width:auto;margin-bottom:22px;opacity:.85}
.lux-icon-card h3{
  font-family:var(--lux-font);font-weight:400;font-size:19px;
  color:var(--fe-navy);margin:0 0 12px;letter-spacing:.01em;
}
.lux-icon-card p{
  font-family:var(--lux-font);font-size:14.5px;line-height:1.7;
  color:var(--fe-slate);margin:0;
}
.lux-icon-card--left{text-align:left;align-items:flex-start}
.lux-icon-card .lux-num{color:var(--fe-blue);font-weight:300}

/* .lux-split is a two-column grid, so which side the copy lands on is decided
   by source order alone — put .s-copy first for copy-left. This modifier is
   only for flipping presentation without touching source order (e.g. when the
   copy must come first for screen readers but read right on desktop). */
@media (min-width:701px){
  .lux-split--reverse .s-copy{order:2}
  .lux-split--reverse > img{order:1}
}
/* .s-copy is a flex column, so a button stretches edge to edge unless told
   not to. Buttons size to their label. */
.lux-split .s-copy .new__cta,
.lux-split .s-copy .lux-link{align-self:flex-start}
/* A .lux-actions row is already a flex container, so its buttons sit left on
   their own — but the row itself is a flex-column child and would stretch. */
.lux-split .s-copy .lux-actions{align-self:flex-start}

/* Wider frame for a landscape source that the default 4/3 crop would gut —
   a subject standing beside an aircraft, a ramp, a skyline. 16/9 keeps the
   context that made the photograph worth using. */
.lux-split--wide img{aspect-ratio:16/9}
/* Pin a cover-cropped image to the foot of its frame. --wide renders a 4:3
   portrait into 16:9, and centred that takes the crop off both ends evenly,
   which on a standing subject lands the bottom edge on their collar. */
.lux-split img.lux-img-anchor-bottom{object-position:50% 100%}

/* A split that stacks at every width — copy leads, photograph sits under it.
   This is a modifier rather than hand-built markup because .s-copy's heading and
   pull-quote scales are scoped to .lux-split: lifted out of one, .lux-display-quote
   jumps to clamp(24px,3.6vw,42px) and starts arguing with the h2 beside it at 40px.
   Staying inside the split keeps the stepped-down quote size the section was
   designed around.
   The image drops to its intrinsic size instead of filling the column: these
   sources are 750-900px wide, and stretched across a 1180px .lux-wrap they both
   upscale and lose their top and bottom to --wide's 16/9 cover crop. width:auto
   reads the width/height attributes already on the tag, so there is no magic
   number here or in the markup. */
.lux-split--stacked{grid-template-columns:1fr}
.lux-split--stacked > img{
  width:auto;max-width:100%;height:auto;
  aspect-ratio:auto;align-self:start;justify-self:start;
}
/* Stacked splits side by side in a .lux-grid (index.html #corporate). Two
   corrections, both scoped to the grid case so single-column stacked splits
   keep the intrinsic-size behaviour above:
   — the intrinsic aspect-ratio:auto lets each column's photograph set its own
     height, and this pair's sources differ (2000×1293 vs 2000×1333), so the
     two modules' headings land at different heights. Pin one crop instead;
     3/2 is what both sources nearly are, so the cover crop is invisible.
   — the sibling margin below (.lux-split + .lux-split) is rhythm between
     full-width rows; grid gap already does that job here, and the margin
     pushes the second cell 40px below the first. */
.lux-grid > .lux-split--stacked > img{width:100%;aspect-ratio:3/2;object-fit:cover}
.lux-grid > .lux-split + .lux-split{margin-top:0}

/* The opposite problem: a studio headshot is the one photograph a bio page is
   guaranteed to have, and the default 4/3 crop takes the top of the head off.
   Portrait keeps the frame the photographer chose, and the image column gives
   up half the row so a 4:5 slab does not tower over its own copy. */
.lux-split--portrait{grid-template-columns:minmax(0,1fr) clamp(220px,26vw,340px)}
.lux-split--portrait img{aspect-ratio:4/5}
@media (max-width:700px){
  .lux-split--portrait{grid-template-columns:1fr}
  /* --wide's mobile rule flattens every split image to 16/9; a portrait must
     opt out of that or it loses the crop again at the narrowest width. */
  .lux-split--portrait img{aspect-ratio:4/5;max-width:320px}
}

/* App store badges — ghost buttons with a two-line label */
.lux-app-badges{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px}
.lux-app-badge{
  display:inline-flex;align-items:center;gap:12px;
  padding:11px 20px;border:1px solid var(--fe-navy);background:var(--fe-navy);
  color:#fff;text-decoration:none;transition:all .3s ease;
}
.lux-app-badge:hover{background:var(--fe-navy-900);border-color:var(--fe-navy-900)}
.lux-app-badge svg{flex:none;fill:#fff}
.lux-app-badge span{display:flex;flex-direction:column;line-height:1.15;text-align:left}
.lux-app-badge small{font-family:var(--lux-font);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--fe-blue-200)}
.lux-app-badge b{font-family:var(--lux-font);font-size:14px;font-weight:500;letter-spacing:.01em}

/* Large editorial pull-quote used to open a program page */
.lux-display-quote{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(24px,3.6vw,42px);line-height:1.22;letter-spacing:.01em;
  color:var(--fe-navy);margin:0 0 26px;
}
/* In a split's copy column the full scale collides with .lux-split--lead's h2
   (clamp(26px,3.4vw,40px)) and the section reads as two headlines arguing.
   Step it down so the heading stays the heading and the quote stays a quote. */
.lux-split .s-copy .lux-display-quote{
  font-size:clamp(21px,2.5vw,30px);line-height:1.3;margin:0;
}

/* ============================================================
   OPENING STATEMENT — the page's framing paragraph. Used by index /
   fractional / membership / seaplane / routes / safety-certification. On index
   and membership it sits between the hero and the first real section; on
   fractional / seaplane it moved below the first section (2026-08-07), so the
   hero runs straight into the program/advantage block and the statement
   follows it. It was on jet-club in that second position until 2026-08-11,
   when the unified ledger (section Z) took the whole middle of that page and
   the statement came off it. The seam
   treatment (hairline, top padding sized to clear a disc) was designed for
   the dark-hero join but reads correctly as a section break on paper too.

   Replaces .lux-section--tight > .lux-wrap--narrow.lux-text-center >
   .lux-display-quote, closed by a .lux-divider. Three things were wrong with
   that arrangement:

   1. The divider drew a horizontal rule under the page's first idea, so the
      statement read as a caption stranded between two large blocks. A
      vertical thread descending into the next section reads as continuation
      instead. index.html's own .hp-lead invented that thread; five pages
      want it, so it is generalised here and .hp-lead retired into this.
   2. The statement carried no internal hierarchy — two sentences set
      entirely at 42px, the qualifier shouting as loudly as the claim.
      __coda steps the tail clause down to slate. Same words in the same
      order: a typographic split, not a copy change.
   3. The hero join was a bare edge where dark footage meets white paper. It
      is articulated with the brand turbine on a paper disc sitting ON the
      seam, over the centre-bright hairline that .home-header--hq::after
      already uses for the same job. The ornament that used to close the
      block now opens it.

   .lux-display-quote is NOT deprecated: mro, mro/facilities and
   who-we-are/jim-segrave use it inside sections that are not page openings,
   where none of the above applies.
   ============================================================ */
.lux-statement{
  position:relative;
  /* Has to beat the hero, and tree order is not enough: the Webflow export
     carries .home-hero{z-index:9} (its line 6845), so on the homepage the
     hero is a positive-z-index stacking context and paints over every
     z-index:auto sibling after it — which is what the hairline and the disc
     below are. 10 is one step over the hero and far below the fixed header
     (1300), the menu panel (1220) and its backdrop (1205). */
  z-index:10;
  background:var(--fe-paper);
  /* Asymmetric on purpose. The top has to clear the disc (58px, half of it
     hanging into the hero). The bottom is deliberately short: the thread and
     its own margin already contribute ~100px, and the section below brings its
     own padding — pay full section padding here too and the thread ends in a
     dead gap instead of arriving somewhere. */
  padding:clamp(64px,7vw,104px) clamp(20px,5vw,40px) clamp(24px,3vw,40px);
}
/* The export caps the bare element (`p{max-width:900px}`, its line 248),
   which on centred copy sizes a box pinned to the container's left edge and
   centres the text inside the BOX. Reset, then state the measure each part
   actually wants. */
.lux-statement p{max-width:none}
.lux-statement__inner{max-width:880px;margin:0 auto;text-align:center}

/* The hairline along the join: brightest at the centre, falling to nothing at
   both gutters. Verbatim the device .home-header--hq::after uses for the
   scrolled bar's bottom edge, so the page already speaks it. */
.lux-statement::before{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;pointer-events:none;
  background:linear-gradient(90deg,
    rgba(41,159,207,0) 0%,rgba(41,159,207,.45) 22%,
    rgba(41,159,207,.9) 50%,rgba(41,159,207,.45) 78%,rgba(41,159,207,0) 100%);
}
/* The turbine at 22px for the same reason .lux-divider sets it there: the
   twelve blades are unreadable smaller. The disc is opaque paper so the mark
   stays legible over whatever the hero's last frame happens to be, and the
   ring gives it an edge against a light one. */
.lux-statement__mark{
  position:absolute;top:0;left:50%;transform:translate(-50%,-50%);
  width:58px;height:58px;border-radius:50%;
  background:var(--fe-paper) url("../images/turbine-navy.png") center/22px 22px no-repeat;
  box-shadow:0 0 0 1px rgba(41,159,207,.35);
}

/* Sized off .lux-display-quote, which is what this replaces. */
.lux-statement__quote{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(26px,3.7vw,44px);line-height:1.2;letter-spacing:.005em;
  color:var(--fe-navy);margin:0;text-wrap:balance;
}
/* Inside the quote, not after it: the two clauses are one sentence pair from
   the copy deck and screen readers should still read them as one paragraph. */
.lux-statement__coda{
  display:block;margin-top:.5em;
  font-size:clamp(17px,1.5vw,22px);line-height:1.5;letter-spacing:0;
  color:var(--fe-slate);
}
.lux-statement__prose p{
  margin:clamp(18px,2.4vw,26px) auto 0;max-width:62ch;
  font-size:16px;line-height:1.75;color:var(--fe-ink);
}
/* No page uses this any more: the homepage was the only one whose copy deck
   supplied a label, and on 2026-08-05 its statement (link included) moved into
   the programs module as .hp-statement. Kept because the component is the
   shared opening for four other pages and any of them may be given a labelled
   hand-off later; treatment matches .hp-panel__cta so the statement hands off
   in the voice the next section answers in. */
.lux-statement__cta{
  display:inline-flex;align-items:center;gap:.6em;
  margin:clamp(22px,3vw,32px) 0 0;
  font-family:var(--lux-font);font-size:10.5px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;
  color:var(--fe-blue-600);text-decoration:none;
  border-bottom:1px solid rgba(23,112,154,.35);padding-bottom:5px;
  transition:color .3s ease,border-color .3s ease;
}
.lux-statement__cta:hover,.lux-statement__cta:focus-visible{color:var(--fe-navy);border-color:var(--fe-navy)}
.lux-statement__cta svg{
  width:1.15em;height:1.15em;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
  transition:transform .45s cubic-bezier(.25,.1,.25,1);
}
.lux-statement__cta:hover svg,.lux-statement__cta:focus-visible svg{transform:translateX(4px)}
@media (prefers-reduced-motion:reduce){.lux-statement__cta svg{transition:none}}
/* Vertical, so it reads as continuation where the .lux-divider it replaces
   read as a full stop. Fades UP out of nothing and arrives at full accent on
   the section below, which is the direction of travel. */
.lux-statement__thread{
  width:1px;height:clamp(40px,6vh,64px);
  margin:clamp(24px,3.5vw,38px) auto 0;
  background:linear-gradient(180deg,rgba(41,159,207,0),var(--fe-blue));
}
@media (max-width:700px){
  /* 58px is a third of the statement's first line at this width and starts to
     read as a button rather than an ornament. */
  .lux-statement{padding-top:clamp(52px,13vw,72px)}
  .lux-statement__mark{width:46px;height:46px;background-size:18px 18px}
}

/* Fluid variants — the catalogue caps these for its preview grid, but on a
   real page they should fill their column. */
.lux-tier-card--fluid{max-width:none}
.lux-quote-card--fluid{max-width:none}
.lux-accordion--fluid,.lux-tabs--fluid,.lux-spec-list--fluid,.lux-timeline--fluid,.lux-timeline-chart--fluid,.lux-alert--fluid{max-width:none}
.lux-tier-pair{align-items:stretch}
.lux-tier-pair .lux-tier-card{display:flex;flex-direction:column}
.lux-tier-pair .lux-tier-card ul{flex:1}
.lux-tier-card .t-head h4{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.lux-tier-card .t-foot{padding:0 24px 24px}
.lux-tier-card.is-featured .t-head .lux-badge.is-solid{background:#fff;color:var(--fe-navy);border-color:#fff}

/* Stepper at section scale rather than the catalogue's compact preview */
.lux-steps--wide{max-width:none;gap:clamp(18px,3vw,40px)}
.lux-steps--wide li{font-size:13px;line-height:1.6;text-transform:none;letter-spacing:.01em;color:var(--fe-slate);font-weight:400;padding:0 clamp(6px,1.5vw,16px)}
.lux-steps--wide li .num{font-size:clamp(26px,3vw,34px);margin-bottom:8px}

/* Small layout helpers, so pages don't reach for inline styles */
.lux-align-center{align-items:center}
.lux-align-top{align-items:start}
.lux-center-block{margin-left:auto;margin-right:auto}
.lux-text-center{text-align:center}
.lux-text-left{text-align:left}
.lux-grid--gap-lg{gap:clamp(28px,4vw,56px)}
/* Stacked editorial splits space themselves rather than each carrying a margin */
.lux-split + .lux-split{margin-top:clamp(24px,3vw,40px)}
/* Section-scale gap between two blocks inside one .lux-wrap — a split followed
   by its prose, say. Named so pages don't reach for an inline margin. */
.lux-flow-lg{margin-top:clamp(28px,3.5vw,48px)}
/* --md is the step below, for a gap INSIDE one block: a credential row under the
   paragraph that names it, inside a .lux-split copy column. --lg was the only
   flow utility, so that case reached for it and got a section-scale 48px in a
   column, which reads as a break rather than a step and pads the column past its
   own photograph. Added 2026-08-11 for who-we-are/safety-certification #how. */
.lux-flow-md{margin-top:clamp(20px,2.2vw,30px)}
/* Reading-width caps for components the catalogue sizes for its preview grid */
.lux-accordion--wide{max-width:860px}
.lux-slider--wide{max-width:900px}
.lux-filmstrip--wide{max-width:860px}
.lux-prose--sm{font-size:14px;line-height:1.7}
.lux-prose--measure{max-width:66ch;margin-left:auto;margin-right:auto}
.lux-grid--gap-sm{gap:18px}
/* Taller crossfade for a full-bleed section rather than the catalogue's 16:9 */
.lux-fade--tall .lux-fade-stage{aspect-ratio:auto;min-height:clamp(420px,54vw,620px)}
.lux-timeline .lux-prose--sm{margin:6px 0 0}
.lux-actions--spaced{margin-top:28px}
.lux-mb-32{margin-bottom:32px}
.lux-head--tight{margin-bottom:28px}
.lux-card--pad{padding:clamp(26px,3vw,36px)}
.lux-feature-card--fluid{max-width:none}
/* Accreditation marks as a credentials wall on a light section. No tile behind
   them: the marks sit directly on the section ground, and what makes the five
   different artwork styles (round seals, wide wordmarks) read as one row is the
   uniform box the img itself occupies plus object-fit:contain, not a visible
   card edge. Two of the source PNGs shipped with an opaque white ground baked
   in and had to be keyed out to transparent for this to work — see
   images/cae-simuflite-alpha.png and images/flightsafety-alpha.png. */
.lux-safety-badges{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:clamp(12px,1.5vw,18px);
  align-items:stretch;
}
/* Each img still occupies an identical box — that uniform footprint plus
   object-fit:contain is what makes five mismatched artwork styles read as one
   row, and it survives the tile being gone. The padding is now only there to
   keep the marks off each other; it is lighter than the tiled version needed,
   since there is no border for the artwork to clear. */
.lux-safety-badges img{
  box-sizing:border-box;
  display:block;
  width:100%;
  height:clamp(92px,10vw,124px);
  padding:clamp(10px,1.2vw,14px) clamp(10px,1.4vw,16px);
  object-fit:contain;
  /* Desaturated at rest so the row is one calm unit, full colour on hover.
     No brightness lift: this artwork is dark, and the ground is now light.
     Higher rest opacity than the tiled version used: the near-white tile was
     lifting these dark marks off the grey ground, and without it .72 reads
     faded rather than calm. */
  filter:grayscale(1);
  opacity:.86;
  transition:opacity .3s ease,filter .3s ease;
}
.lux-safety-badges img:hover{opacity:1;filter:grayscale(0)}
/* Five marks into two columns leaves one orphan in the last row. Let it span
   instead, so the row reads as deliberate rather than short — object-fit:contain
   keeps the seal centred at its own size, it does not stretch.

   :nth-child(odd) is what makes that conditional, and it is a fix, not a
   flourish. The rule was written for a five-mark row, where the last child IS
   the orphan. The component's only remaining user is
   who-we-are/safety-certification #how, which carries two marks (the training
   providers), and there an unconditional span put CAE in half a row and
   FlightSafety across the full width beneath it at twice the size — which reads
   as a layout fault, because it is one. In a two-column grid the
   last child is only ever orphaned when its position is odd, so the count now
   decides: 2 marks pair off, 5 marks still span the fifth, and any future row
   is correct without another rule. */
@media (max-width:640px){
  .lux-safety-badges{grid-template-columns:repeat(2,minmax(0,1fr))}
  .lux-safety-badges img:last-child:nth-child(odd){grid-column:1 / -1}
}

/* The doc's accreditation claim, set as a figure line between the lede and the
   marks that prove it. Rules top and bottom rather than a box — it is a
   statement, not a card. */
.lux-safety-claim{
  max-width:62ch;
  /* Top margin, not bottom: this now sits BELOW the badge row as its caption,
     so the gap it owns is the one above it. */
  margin:clamp(28px,3.5vw,44px) auto 0;
  padding:clamp(20px,2.6vw,30px) 0;
  border-top:1px solid var(--fe-line);
  border-bottom:1px solid var(--fe-line);
  font-family:var(--lux-font);
  font-weight:300;
  font-size:clamp(17px,1.9vw,23px);
  line-height:1.55;
  text-align:center;
  color:var(--fe-navy);
}
.lux-safety-claim strong{font-weight:400;color:var(--fe-blue-600)}

/* Section header: eyebrow + light display heading + lede */
.lux-head{max-width:760px;margin:0 0 clamp(32px,4vw,52px)}
.lux-head--center{margin-left:auto;margin-right:auto;text-align:center}
.lux-head h2{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(26px,3.4vw,40px);line-height:1.15;
  color:var(--fe-navy);margin:0 0 16px;letter-spacing:.01em;
}
.lux-head p{
  font-family:var(--lux-font);font-size:clamp(15px,1.3vw,17px);
  line-height:1.75;color:var(--fe-slate);margin:0;
}
.lux-section--navy .lux-head h2{color:#fff}
.lux-section--navy .lux-head p{color:var(--fe-blue-200)}

/* One framing sentence between a heading and the body copy — a step above
   .lux-prose, a step below .lux-display-quote. .lux-hero-sub already does this
   job, but it is scoped to .lux-hero-copy, so a page that opens on content
   rather than a hero has nowhere to put it. The .s-copy variant is spelled out
   because .lux-split .s-copy p is three classes deep and outranks a bare one. */
.lux-lead,
.lux-split .s-copy .lux-lead{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(17px,1.6vw,20px);line-height:1.55;
  color:var(--fe-navy);margin:0 0 20px;max-width:46ch;
}

/* Body copy inside a redesigned section */
/* Capped measure: inside .lux-wrap--narrow this ran ~105 characters per line,
   well past the 45-75ch band, and pages were patching it inline at three
   different widths. */
.lux-prose{font-family:var(--lux-font);font-size:16px;line-height:1.8;color:var(--fe-ink);max-width:68ch}
.lux-text-center .lux-prose,.lux-head--center .lux-prose{margin-left:auto;margin-right:auto}
.lux-prose p{margin:0 0 18px}
.lux-prose p:last-child{margin-bottom:0}

/* Auto-fit grids — no media queries needed */
.lux-grid{display:grid;gap:clamp(18px,2.2vw,28px)}
.lux-grid--2{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.lux-grid--3{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.lux-grid--4{grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}

/* Action row under a section header or hero card */
.lux-actions{display:flex;flex-wrap:wrap;gap:14px;align-items:center}
.lux-actions--center{justify-content:center}
/* A CTA in an actions row sizes to its own label.
   width:auto is the load-bearing half: above 480px the Webflow sheet gives
   .new__cta.light-blue `width:30%`, which is only ever accidentally sensible —
   it is 30% of whatever contains it. Inside .lux-split .s-copy the actions row
   is align-self:flex-start, so it shrink-wraps, and 30% of that resolved to a
   114px box for a label needing 162px: "Request Info" wrapped onto two lines
   beside an unwrapped sibling link. (The same percentage is already undone
   below 480px further up this file, for the same reason.)
   flex-shrink:0 then stops the row's own free-space maths from re-squeezing it;
   flex-wrap still drops the button to its own line if the row will not fit.

   max-width is the floor under both: flex-wrap cannot help a single item that is
   itself wider than the row, so a CTA whose label is a full sentence sized to its
   unwrapped text and pushed straight through the right edge of the page. That is
   what index.html's "Find the aircraft that fits your trip" did on a phone: 419px
   of button in a 335px column, widening the document by 63px and giving the whole
   homepage a horizontal scroll. The label is the doc's own wording, so the fix
   belongs here rather than in the copy. Short labels never reach the cap; a long
   one now wraps inside the button instead of escaping it. */
.lux-actions > .new__cta{flex-shrink:0;width:auto;max-width:100%}
/* Webflow underlines every <a>; these components carry their own affordance.
   .new__cta is a button in every context, so it never wants an underline. */
a.new__cta,
.lux-actions a,
.lux-tier-card a,
.lux-feature-card a,
.lux-quote-card a,
.lux-prog-card,
.lux-snap-card,
a.lux-card,
.lux-carousel-count,
.lux-filmstrip-thumbs a{text-decoration:none}

/* Wider cards for full-bleed rails than the catalogue's compact default */
.lux-snap--wide > *{flex:0 0 clamp(260px,78vw,340px)}
.lux-snap--feature > *{flex:0 0 clamp(280px,86vw,420px)}

/* ---- Stat rows and steppers reflow by grid, not by breakpoint ----
   These were single un-wrapped flex rows: four cells at 380px leaves ~61px of
   content width, which overflows any label ("COMPANY-OWNED AIRCRAFT") and any
   wide numeral ("Part 145"). auto-fit handles every width, not just the two
   a media query would guess at. min-width:0 stops grid items refusing to
   shrink below their content. */
/* 190px floor, not 150: at a 335px row a 150px floor gave two ~143px cells,
   and a tracked caps label ("DOWNDRAFT BOOTHS", "AIRFRAME ACCOMMODATED") does
   not fit that, so its last word dropped to a line of its own. 190 sends
   phones to a single column and leaves desktop's four-across untouched. */
.lux-stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.lux-stat-row .lux-stat{min-width:0}
.lux-stat-band{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
.lux-stat-band .s{min-width:0}
/* .lux-metricset needs no entry here: it is auto-fit in its own base rule, with
   the reasoning at that rule. It shipped with a duplicate override on this line
   for one commit, which meant the base rule's repeat(3,1fr) never applied at any
   width — the .lux-prose--sm trap, source order rather than specificity. */
/* The vertical hairlines that used to be reinstated here are gone with the box
   (see the .lux-stat-row block above). They were drawn as a box-shadow on every
   cell — including the last, so a rule always hung off the row's right edge —
   inside an @supports(subgrid) test that was only ever a proxy for "a modern
   engine", never for "these two cells are actually adjacent".
   .lux-stat-band keeps its own splits: it is a solid navy bar, where an edge
   rule has a filled background behind it rather than open page. */
@supports (grid-template-columns:subgrid){
  /* :not(:last-child) — the old rule shadowed every cell, so the band carried a
     trailing rule too. Invisible against navy at the bar's own edge, but wrong
     for the same reason. */
  .lux-stat-band .s:not(:last-child){box-shadow:1px 0 0 rgba(255,255,255,.15)}
}
.lux-steps{flex-wrap:wrap;gap:22px 0}
.lux-steps li{min-width:0}
.lux-steps--wide li{flex:1 1 220px}
@media (max-width:560px){
  .lux-steps--wide li{flex:1 1 100%;display:flex;align-items:baseline;gap:14px;text-align:left}
  .lux-steps--wide li::before{display:none}
  .lux-steps--wide li .num{margin-bottom:0;flex:none;min-width:2.2em}
}

/* Four-item grids orphan their last card between ~950px and ~1030px, where
   auto-fit drops to three columns but the content still wants four. */
@media (min-width:900px){
  .lux-grid--4{grid-template-columns:repeat(4,1fr)}
}

/* Editorial image + caption block used across the program pages */
.lux-figure{margin:0}
.lux-figure img{width:100%;display:block;object-fit:cover}
.lux-figure figcaption{
  font-family:var(--lux-font);font-size:12px;letter-spacing:.04em;
  color:var(--fe-slate);padding:12px 2px 0;
}
.lux-media-tall img{aspect-ratio:4/5}
.lux-media-wide img{aspect-ratio:16/9}
.lux-media-square img{aspect-ratio:1/1}

/* Full-bleed lifestyle band with centred copy over a photograph */
.lux-band{position:relative;min-height:clamp(360px,48vw,560px);display:flex;align-items:center;justify-content:center;overflow:hidden}
.lux-band > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* Review 2026-08-07 · 80 — the band can take footage as well as a still. Same
   geometry as the <img> above, and the same reduced-motion swap the plain-video
   heroes use (.lux-hero-videoposter, section 8): these pages carry no script
   that could pause it, so the still has to take over in CSS.
   .lux-band-videoposter is inside .lux-band > img already, so it needs no
   positioning of its own — only the show/hide. */
.lux-band > video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.lux-band > .lux-band-videoposter{display:none}
@media (prefers-reduced-motion:reduce){
  .lux-band > video{display:none}
  .lux-band > .lux-band-videoposter{display:block}
}
/* Scrim keyed to where the copy actually sits (centred), not a uniform wash.
   A flat .lux-tint left white text at ~1.7:1 over bright frames like a sunset
   or a white-shirted subject; this holds ~4.6:1 on the worst of them. */
.lux-band::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    radial-gradient(ellipse 90% 70% at 50% 50%,rgba(0,25,50,.74) 0%,rgba(0,25,50,.52) 60%,rgba(0,25,50,.34) 100%),
    linear-gradient(180deg,rgba(0,25,50,.30) 0%,rgba(0,25,50,0) 45%,rgba(0,25,50,.40) 100%);
}
/* A band with no photograph behind it — the ground is painted flat and the
   scrim is dropped, since there is nothing left for it to hold down. Used where
   a review has asked for the frame to come out so the words carry the band. */
.lux-band--navy{background:var(--fe-navy)}
.lux-band--navy::after{display:none}

.lux-band-copy{position:relative;z-index:2;text-align:center;padding:clamp(32px,5vw,64px);max-width:760px}
.lux-band-copy h2{font-family:var(--lux-font);font-weight:300;font-size:clamp(24px,3.4vw,40px);line-height:1.2;color:#fff;margin:0 0 18px}
.lux-band-copy p{font-family:var(--lux-font);font-size:clamp(15px,1.3vw,17px);line-height:1.7;color:rgba(255,255,255,.94);margin:0 0 26px}

/* Hero card — glass panel over hero video/photography. Replaces the
   per-page inline-styled .hero-card blocks so every hero matches. */
.lux-hero-card{
  max-width:640px;padding:clamp(30px,4vw,56px) clamp(26px,4vw,56px);
  /* Deliberately NOT backdrop-filter: these panels sit over autoplaying
     hero video, where a live blur forces a full-frame composite every
     frame and visibly stalls the main thread. A flat scrim reads the
     same and costs nothing. */
  background:linear-gradient(135deg,rgba(0,25,50,.62),rgba(0,25,50,.42));
  border:1px solid rgba(255,255,255,.28);
  /* Webflow hero containers centre their text; these panels are left-set */
  text-align:left;
}
.lux-hero-card h1{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,5vw,56px);line-height:1.08;letter-spacing:.01em;
  color:#fff;margin:0 0 16px;
  text-shadow:0 1px 3px rgba(0,0,0,.45);
}
.lux-hero-card p{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(16px,1.6vw,21px);line-height:1.55;
  color:rgba(255,255,255,.92);margin:0 0 28px;
  text-shadow:0 1px 3px rgba(0,0,0,.4);
}
.lux-hero-card .lux-actions{margin-top:4px}
.lux-hero-card--plain{background:none;border:0;-webkit-backdrop-filter:none;backdrop-filter:none;padding-left:0;padding-right:0}
/* Mid-page promo panel: same shell, one step down the type scale so it does
   not compete with the page's actual hero. */
.lux-hero-card--secondary h2{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(26px,3.4vw,40px);line-height:1.1;letter-spacing:.01em;
  color:#fff;margin:0 0 16px;text-shadow:0 1px 3px rgba(0,0,0,.45);
}

/* Photo hero — full-bleed image, navy scrim, left-set copy. The standard
   page opener for the program, service and about pages. */
.lux-hero{position:relative;display:flex;align-items:flex-end;min-height:clamp(460px,62vh,720px);overflow:hidden;background:var(--fe-navy-900)}
.lux-hero > img,
.lux-hero > video,
.lux-hero > .w-background-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* Webflow's background-video atom sets its own min-height; the hero owns it here.
   background-image:none because .new-home__bg-video carries the *careers* hero
   photo from the Webflow stylesheet, which showed until the video painted —
   clearing it lets the inner <video>'s own poster through. */
.lux-hero > .w-background-video{min-height:0;background-image:none}
.lux-hero > .w-background-video video{width:100%;height:100%;object-fit:cover}
/* Poster still for a plain <video> hero. Hidden by default; it takes over only
   under prefers-reduced-motion, because these pages carry no JS that could
   pause the video the way the homepage hero's script does. */
.lux-hero > .lux-hero-videoposter{display:none}
@media (prefers-reduced-motion:reduce){
  .lux-hero > .lux-hero-video{display:none}
  .lux-hero > .lux-hero-videoposter{display:block}
}
/* Focal point for a hero whose subject is a person standing right of centre in
   a wide source. object-fit:cover defaults to the middle of the frame, which on
   a short-and-wide hero crops a standing figure off at the neck.
   Vertical: 20% keeps the head and its headroom inside the window at every
   height the hero clamp produces.
   Horizontal: only bites on narrow viewports, where cover crops sideways
   instead. 50% there would centre the subject under the copy; 28% pushes them
   to the right of the frame so the left-set text lands on background. */
.lux-hero--subject-right > img{object-position:50% 20%}
@media (max-width:767px){
  .lux-hero--subject-right > img{object-position:28% 20%}
}

/* Two-axis scrim: the vertical pass seats the nav and the copy block, the
   horizontal pass keeps left-set text legible over bright sky or ramp.
   The two passes MULTIPLY at the bottom-left, which is exactly where
   .lux-hero-copy sits — keep the stops low enough that the composite stays
   around 85% there (>7:1 for white) instead of burying the photograph. */
.lux-hero-scrim{
  position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(100deg,rgba(0,25,50,.62) 0%,rgba(0,25,50,.30) 46%,rgba(0,25,50,0) 76%),
    linear-gradient(180deg,rgba(0,25,50,.34) 0%,rgba(0,25,50,.10) 34%,rgba(0,25,50,.62) 100%);
}
/* Deeper stops, same two-pass shape, for a hero whose photograph is bright
   enough that the standard scrim leaves the headline around 3:1 — white sky
   over pale concrete is the case this exists for. Composite at the copy block
   lands near 92%, still short of burying the frame. */
.lux-hero-scrim--deep{
  background:
    linear-gradient(100deg,rgba(0,25,50,.78) 0%,rgba(0,25,50,.52) 46%,rgba(0,25,50,.24) 76%),
    linear-gradient(180deg,rgba(0,25,50,.50) 0%,rgba(0,25,50,.26) 34%,rgba(0,25,50,.74) 100%);
}

.lux-hero-inner{position:relative;z-index:2;width:100%;max-width:1180px;margin:0 auto;padding:clamp(40px,7vw,88px) clamp(20px,5vw,40px)}
/* 1000px, not 720: "Leaders in Aircraft Maintenance" needs ~930px at the 58px
   cap, and the old 720 dropped the last word onto a line of its own. The
   sub-copy below keeps the 720px measure — only the headline wants the room. */
.lux-hero-copy{max-width:1000px;text-align:left}
.lux-hero-copy > p,.lux-hero-copy .lux-hero-sub,.lux-hero-copy .lux-lead{max-width:720px}
/* h2 alongside h1: a .lux-hero used mid-page as a full-bleed video band must
   not emit a second <h1> (index.html #seaplane). Same type, same treatment —
   only the outline level differs. */
.lux-hero-copy h1,
.lux-hero-copy h2{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,5.2vw,58px);line-height:1.06;letter-spacing:.01em;
  color:#fff;margin:0 0 18px;text-shadow:0 2px 10px rgba(0,0,0,.35);
}
/* Emphasised word in a hero headline. The only italic cut we host is
   GalanoGrotesque-Italic.otf at weight 400, so the weight is stated rather than
   inherited from the Light 300 above — CSS matches style before weight, so this
   is the real italic face and not a synthesised oblique. Matches the treatment
   on .home-hero__title em (css/home-hero.css). */
.lux-hero-copy h1 em,
.lux-hero-copy h2 em{font-style:italic;font-weight:400}
.lux-hero-copy .lux-hero-sub{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(16px,1.7vw,22px);line-height:1.5;
  color:rgba(255,255,255,.9);margin:0 0 30px;max-width:620px;
  text-shadow:0 1px 6px rgba(0,0,0,.35);
}
/* The .lux-hero-nav anchored jump strip that used to live here is gone: the
   navy bar under the hero was dropped site-wide, so every page now runs
   straight from the hero into its first section. */
/* The global sky-blue focus ring is unreliable over arbitrary hero
   photography; pair a white ring with a dark halo so it reads on both. */
.lux-hero :focus-visible,
.lux-band :focus-visible{outline-color:#fff;box-shadow:0 0 0 4px rgba(0,25,50,.65)}

/* Program / service card — image, title, copy, action row. The one card
   shape shared by the program grids, MRO capabilities and service tiles. */
.lux-prog-card{
  display:flex;flex-direction:column;
  border:1px solid var(--fe-line);background:var(--fe-paper);
  text-decoration:none;transition:border-color .3s ease,box-shadow .3s ease;
}
.lux-prog-card:hover{border-color:var(--fe-navy);box-shadow:0 18px 40px rgba(0,25,50,.09)}
.lux-prog-card .lux-img-wrap{overflow:hidden}
.lux-prog-card .lux-img-wrap img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;transition:transform .5s ease}
.lux-prog-card:hover .lux-img-wrap img{transform:scale(1.04)}
.lux-prog-card .p-body{padding:22px 24px 20px;flex:1}
.lux-prog-card h3{
  font-family:var(--lux-font);font-weight:400;font-size:20px;
  color:var(--fe-navy);margin:0 0 10px;letter-spacing:.01em;
}
.lux-prog-card p{
  font-family:var(--lux-font);font-size:14px;line-height:1.7;
  color:var(--fe-slate);margin:0;
}
.lux-prog-card .p-action{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 24px;border-top:1px solid var(--fe-line);
  font-family:var(--lux-font);font-size:11px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--fe-navy);
}
.lux-prog-card .p-action span:last-child{color:var(--fe-blue);transition:transform .3s ease}
.lux-prog-card:hover .p-action span:last-child{transform:translateX(4px)}

/* ============================================================
   Background video in a .new-hero-section (the careers heroes)
   The Webflow stylesheet only gives .new-home__bg-video its absolute fill
   inside @media (max-width:767px). On desktop the wrapper therefore stays a
   position:relative flex item of .new-hero-section — which is display:flex,
   align-items:flex-end — and collapses to height 0, so the video never paints
   and the hero's background photo shows instead. Same shape of fix as
   .lux-hero > .w-background-video further up this file.
   background-image:none clears the careers hero photo that the Webflow rule
   puts on the wrapper, letting the inner <video>'s poster through.
   z-index:0 keeps it under .new-home-hero__content-container: that computes to
   z-index 1 here, and an equal value would let this later sibling paint over
   the headline.
   Deliberately keyed on .fe-video-scrim rather than .w-background-video: seven
   other pages (mro/painting-coating, mro/interior-refurbishment,
   mro/paint-upgrade-landing, where-we-fly and the -staging variants) put a
   .w-background-video in a .new-hero-section too and carry the same latent
   collapse. A bare .new-hero-section > .w-background-video would silently
   un-hide all of their hero videos as a side effect of this change.
   ============================================================ */
.new-hero-section > .fe-video-scrim{
  position:absolute;inset:0;width:100%;height:100%;min-height:0;
  z-index:0;background-image:none;
}
.new-hero-section > .fe-video-scrim > video{
  width:100%;height:100%;object-fit:cover;
}

/* The hero's own darkening gradient is painted on .new-hero-section itself, so
   the video above covers it and leaves the white h1 straight over the footage.
   This puts a scrim back — above the video, below the copy. Needed because the
   Raleigh clip opens on a bright daytime sky. */
.fe-video-scrim::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(0,0,0,.30) 0%,rgba(0,0,0,.20) 45%,rgba(0,0,0,.62) 100%);
}

/* ============================================================
   MRO GROUP (Jul 2026)
   Three small additions the mro/* rebuild needed. Each is generic
   enough to live in the library rather than on the page.
   ============================================================ */

/* A borrowed wordmark set above the hero headline — mro/starlink.html carries
   the Starlink logo. Sized against the h1 rather than running to its native
   1444px, and it inherits the hero's left alignment. */
.lux-hero-copy .lux-hero-logo{
  display:block;width:clamp(140px,17vw,210px);height:auto;
  margin:0 0 clamp(16px,2vw,24px);
}

/* Stepper items that carry a title line above their description. .lux-steps li
   sets font-weight:400 on the whole item, so a bare <strong> read as body copy;
   this promotes it to its own line in navy.
   The title and its description must be wrapped together in a .s-body span:
   below 640px .lux-steps--wide li becomes a flex ROW, and without the wrapper
   the <strong> and the description text become two sibling flex items and land
   side by side next to the number. Markup:
     <li><span class="num">01</span>
         <span class="s-body"><strong>Title</strong>Description</span></li> */
.lux-steps--wide li .s-body{display:block}
.lux-steps--wide li strong{
  display:block;font-weight:500;color:var(--fe-navy);margin-bottom:6px;
}
@media (max-width:640px){
  /* flex-start, not the inherited baseline: the number is ~26-34px against a
     13px title, and baseline alignment dropped the number below the title. */
  .lux-steps--wide li{align-items:flex-start}
  .lux-steps--wide li strong{margin-bottom:4px}
}

/* Responsive 16:9 box for third-party embeds (Matterport tours, players).
   Replaces the Webflow .w-iframe pattern of height="100%" on an iframe whose
   parent has no height, which collapsed the embed to zero. */
.lux-embed{
  position:relative;width:100%;aspect-ratio:16/9;
  background:var(--fe-navy-900);overflow:hidden;
}
.lux-embed iframe{
  position:absolute;inset:0;width:100%;height:100%;border:0;display:block;
}

/* Width guard for HubSpot's iframe-rendered forms.
   Roughly half our forms render inside <iframe class="hs-form-iframe">;
   js/lux-hsform-iframe.js already skins those and follows their height, but
   nothing owned their WIDTH. On mro/maintenance.html and
   mro/interior-refurbishment.html the wrapper still carried Webflow's
   .code-embed-3 / .code-embed-4, which set min-width:850px / 800px. min-width
   beats max-width, so below ~900px the form pushed past the viewport and the
   whole page scrolled sideways. Those classes are gone from the markup; this
   is the backstop, so re-introducing one cannot bring the horizontal scroll
   back with it. Scoped to .lux-form-card rather than every .lux-hsform: the
   HubSpot embeds outside that panel sit in other containers and are not part
   of this pass. */
.lux-form-card .lux-hsform,
.lux-form-card .hbspt-form,
.lux-form-card .hubspot-form-parent{
  min-width:0 !important;max-width:100% !important;
}
.lux-form-card iframe.hs-form-iframe{
  width:100% !important;max-width:100% !important;
}

/* Section headings can take the same one-phrase italic emphasis the heroes use
   (.lux-hero-copy h1 em). Without this the <em> falls back to the browser
   default at the heading's own weight 300, which reads thin and accidental
   rather than as the deliberate accent the hero gives it. */
.lux-head h2 em,
.lux-split .s-copy h2 em,
.lux-split .s-copy h3 em{font-style:italic;font-weight:400}

/* ---- Client offer pages (rockco, tolleson) --------------------------------
   .rocko-offer_container is a flex COLUMN with align-items:center, so its
   children size to max-content on the cross axis instead of filling it. The
   embedded rate table sets min-width:760px, which made the embed 1085px wide
   inside a 338px column — centred, so it hung ~340px off both edges and the
   page scrolled sideways on every phone.

   Stretching the embed back to the column width lets .fx-scroll's
   overflow-x:auto do the job it was already written for: the table then
   scrolls inside its own box, which is what the "Swipe to see all rates"
   hint next to it has always promised. Only the embed is stretched, so the
   headings and copy above it keep their centring. */
.rocko-offer_container > .w-embed{align-self:stretch;min-width:0}

/* ---- Trip request panel ---------------------------------------------------
   The full-bleed navy quote panel on membership.html, in the slot the
   sample-routes carousel used to hold. Three stages — trip builder, contact
   form, confirmation — driven by js/lux-quote.js; this block owns the look of
   all three.

   Was an instant-quote comparison until 2026-08-11; the price-card rules
   (.lux-quote-cards / .lux-quote-card--pick) went with it, since the figures
   they styled were illustrative and never moved with the route. .lux-quote-card
   itself is NOT defined here — it is the pull-quote component up at line ~1527
   and is still in use elsewhere, so do not grep-and-delete it on the strength
   of the name.

   Ported from the "Immersive quote page" design bundle, which was authored as
   a standalone full-viewport page. Two deliberate departures from it:
   1. No logo lockup and no min-height:100vh. It lands mid-page here, under
      the site header, so a second logo and a full-screen height would read as
      a second page rather than a section.
   2. The design's inline styles are lifted into classes and its private
      colour literals swapped for the tokens above (rgba(0,39,77,.62) is
      --fe-navy-900 at .62 either way, but --fe-blue-600 replaces its hard
      #1B6FAE for the same reason the routes widget above does).

   Fields are deliberately light-on-navy: the global rule at the top of this
   file already gives every bare input a white ground and a hairline, so only
   geometry is set here. */
.lux-quote{position:relative;background:var(--fe-navy-900);overflow:hidden}
/* [hidden] is a UA rule on the element, so any class below that sets a display
   (.lux-quote-result is a flex column) outranks it and the stage renders even
   while hidden. This restores it at class-plus-attribute specificity, which
   beats every rule in this block. */
.lux-quote [hidden]{display:none}
.lux-quote > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
/* Scrim: lightest across the middle band so the photograph still reads behind
   the form, heaviest at the foot where the price cards and the legal line sit. */
.lux-quote::after{
  content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(0,25,50,.55) 0%,rgba(0,25,50,.35) 45%,rgba(0,25,50,.82) 100%);
}
.lux-quote-inner{
  position:relative;z-index:2;max-width:1180px;margin:0 auto;
  padding:clamp(44px,5vw,56px) clamp(20px,4vw,64px) clamp(52px,6vw,72px);
  display:flex;flex-direction:column;gap:clamp(24px,3vw,36px);
}
.lux-quote-head{max-width:680px}
.lux-quote-head h2{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,3.6vw,46px);line-height:1.08;letter-spacing:.01em;
  color:#fff;margin:0 0 12px;text-wrap:balance;
}
.lux-quote-head h2 em{font-style:italic;font-weight:400}
.lux-quote-head p{font-weight:300;font-size:clamp(15px,1.4vw,17px);line-height:1.55;color:rgba(255,255,255,.88);margin:0}

/* ---- stage 1 · the trip form ---- */
.lux-quote-form{
  background:rgba(0,39,77,.62);border:1px solid rgba(255,255,255,.35);
  padding:clamp(20px,2.4vw,24px) clamp(20px,2.8vw,28px);
  display:flex;flex-direction:column;gap:18px;
}
.lux-quote-modes{display:flex;gap:22px;flex-wrap:wrap;border:0;padding:0;margin:0}
.lux-quote-modes legend{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.lux-quote-modes label{display:flex;align-items:center;gap:8px;font-size:12.5px;color:#fff;cursor:pointer}
.lux-quote-modes input{accent-color:#fff}
.lux-quote-fields{display:flex;gap:14px;align-items:flex-end;flex-wrap:wrap}
.lux-quote-field{display:flex;flex-direction:column;gap:6px;flex:1;min-width:150px}
/* From/To carry longer values than the dates, so they get the wider track. */
.lux-quote-field--wide{flex:1.2;min-width:180px}
.lux-quote-field span{
  font-size:10.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(255,255,255,.8);
}
.lux-quote-field input,
.lux-quote-field select{padding:11px 13px;font-size:14px;width:100%}
.lux-quote-form .new__cta{white-space:nowrap}
.lux-quote-field[hidden]{display:none}
/* Dates and times are narrower than a city name and shouldn't share the
   flex:1 the text fields get, or a four-field row gives half its width to
   two date pickers. */
.lux-quote-field--time{flex:.7;min-width:118px}
/* Passengers rides in the leg row beside Time, not once in the footer, so it
   takes the same narrow track. */
.lux-quote-field--pax{flex:.7;min-width:118px}

/* ---- airport typeahead (js/lux-airport.js) ----
   The list is absolutely positioned against the field's own <label>, which is
   the flex item, so it stays glued to its input when the leg row wraps. It is
   deliberately opaque and light-on-white rather than following the panel's
   navy: this is a menu, and a translucent menu over a photograph of an
   aeroplane is unreadable at the exact moment it matters. */
.lux-ap-wrap{position:relative}
.lux-ap-list{
  position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;
  margin:0;padding:4px 0;list-style:none;
  background:#fff;border:1px solid var(--fe-line);
  box-shadow:0 18px 40px rgba(0,25,50,.28);
  max-height:264px;overflow-y:auto;text-align:left;
}
.lux-ap-list[hidden]{display:none}
.lux-ap-item{
  display:flex;flex-direction:column;gap:2px;
  padding:8px 14px;cursor:pointer;
}
.lux-ap-item.is-active,
.lux-ap-item:hover{background:var(--fe-canvas)}
/* Two-class selectors, and every inherited property restated.
   These <span>s sit inside the field's <label>, so `.lux-quote-field span`
   above (0,1,1) outranks a bare `.lux-ap-name` (0,1,0) and was painting the
   whole menu in the FIELD LABEL's style: white, uppercase, 10.5px, letter-
   spaced — i.e. white text on the white menu, invisible, with the list still
   scrollable behind it. Raising to (0,2,0) wins, but the inherited transform,
   spacing and weight have to be undone explicitly too. */
.lux-ap-item .lux-ap-name{
  font-size:13.5px;font-weight:400;letter-spacing:0;text-transform:none;
  color:var(--fe-navy);line-height:1.3;
}
/* The code first, then the place: someone scanning for "KTEB" is scanning a
   column of codes, and indenting it behind the city would defeat that. */
.lux-ap-item .lux-ap-place{
  font-size:11.5px;font-weight:400;letter-spacing:0;text-transform:none;
  color:var(--fe-slate);line-height:1.3;
}

/* ---- the legs ----
   One row per leg, rebuilt by js/lux-quote.js on every mode change. The rows
   are separated by a rule rather than boxed: on a multi-leg trip six boxed
   rows inside the already-bordered form read as a table of cards. */
.lux-quote-legs{display:flex;flex-direction:column;gap:16px}
.lux-quote-leg{display:flex;gap:14px;align-items:flex-end;flex-wrap:wrap}
.lux-quote-leg + .lux-quote-leg{border-top:1px solid rgba(255,255,255,.22);padding-top:16px}
/* The number sits on the field row's baseline, not the row's top, so it lines
   up with the inputs rather than with the labels above them. */
.lux-quote-leg-no{
  flex:0 0 auto;width:24px;height:41px;display:flex;align-items:center;
  font-size:12px;font-weight:600;color:rgba(255,255,255,.7);
  font-variant-numeric:tabular-nums;
}
/* The return leg states its route instead of asking for it again, so the row
   leads with a sentence where the others lead with two text fields. */
.lux-quote-leg-back{
  flex:1 1 100%;margin:0;font-size:12.5px;color:rgba(255,255,255,.8);
}
.lux-quote-leg--ret{align-items:flex-end}
.lux-quote-legdel{
  flex:0 0 auto;width:41px;height:41px;padding:0;
  background:none;border:1px solid rgba(255,255,255,.35);color:#fff;
  font-size:19px;line-height:1;cursor:pointer;
  transition:background .2s ease,border-color .2s ease;
}
.lux-quote-legdel:hover{background:rgba(255,255,255,.14);border-color:#fff}
.lux-quote-legs-actions{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin:0;
}
.lux-quote-legadd{
  background:none;border:1px solid rgba(255,255,255,.55);color:#fff;
  padding:9px 16px;font-size:12.5px;letter-spacing:.04em;cursor:pointer;
  transition:background .2s ease,border-color .2s ease;
}
.lux-quote-legadd:hover:not(:disabled){background:rgba(255,255,255,.14);border-color:#fff}
.lux-quote-legadd:disabled{opacity:.45;cursor:default}
.lux-quote-legs-note{font-size:12px;color:rgba(255,255,255,.7);flex:1;min-width:180px}
/* The foot row is now only the submit — passengers moved into the leg rows —
   so it sits at the end rather than stretching across. */
.lux-quote-fields--foot{justify-content:flex-end}

/* ---- stage 2 · who to send it to ---- */
.lux-quote-gate{max-width:640px;margin:0 auto;text-align:center;padding:clamp(28px,3.4vw,40px) clamp(24px,3.6vw,48px)}
.lux-quote-gate .g-eyebrow{
  margin:0 0 8px;font-size:10.5px;font-weight:600;letter-spacing:.28em;
  text-transform:uppercase;color:rgba(255,255,255,.85);
}
.lux-quote-gate h3{font-family:var(--lux-font);font-weight:300;font-size:clamp(22px,2.2vw,26px);letter-spacing:.01em;color:#fff;margin:0 0 10px}
.lux-quote-gate .g-sub{margin:0 0 24px;font-size:13.5px;line-height:1.7;color:rgba(255,255,255,.8)}
.lux-quote-err{margin:14px 0 0;font-size:12.5px;color:#F2B8B5}
/* The way back to the trip. A link, not a button-looking control: the only
   thing on this stage that should read as the primary action is HubSpot's own
   submit. */
.lux-quote-edit{margin:0 0 22px}
.lux-quote-editbtn{
  background:none;border:0;padding:0;cursor:pointer;
  font-size:12.5px;color:rgba(255,255,255,.85);
  text-decoration:underline;text-underline-offset:3px;
}
.lux-quote-editbtn:hover{color:#fff}
/* HubSpot's form lands on navy here, and .lux-hsform--bare means it draws no
   card of its own, so its labels need the panel's light-on-dark treatment.
   Left-aligned against the stage's centred heading, because a form whose
   labels are centred over its inputs is unreadable at a glance. */
.lux-quote-gate .lux-hsform{margin-top:4px;text-align:left}
.lux-quote-gate .lux-hsform label,
.lux-quote-gate .lux-hsform .hs-form-field > label{color:rgba(255,255,255,.85)}
/* .lux-framed-box's ground is rgba(0,39,77,.25) — enough behind the three
   inputs it was written for, nowhere near enough behind a ten-field form with
   a paragraph of consent text sitting over a photograph of an aeroplane. The
   trip form above uses .62; this stage is taller and carries the small print,
   so it goes further still. */
.lux-quote-gate{background:rgba(0,25,50,.88)}
/* HubSpot's consent block is authored for a light card and ships near-black.
   Unstyled it is invisible here — and it is the one paragraph on the panel
   that is a legal disclosure, so it cannot be left to fade into the photo. */
.lux-quote-gate .legal-consent-container,
.lux-quote-gate .legal-consent-container p,
.lux-quote-gate .legal-consent-container span,
.lux-quote-gate .hs-richtext,
.lux-quote-gate .hs-richtext p{color:rgba(255,255,255,.78)}
.lux-quote-gate .legal-consent-container a,
.lux-quote-gate .hs-richtext a{color:#fff;text-decoration:underline}
/* The Master form serves the Caravan pages too, so it carries their two
   route selects. They are optional and mean nothing on a membership quote —
   two dead "Please Select" dropdowns in the middle of the form. Hidden, not
   removed: the field has to keep existing for the 27 other pages. */
.lux-quote-gate .hs_caravan_from,
.lux-quote-gate .hs_caravan_destination{display:none}

/* ---- stage 3 · the confirmation ---- */
.lux-quote-done{display:flex;flex-direction:column;gap:14px;max-width:640px;margin:0 auto;text-align:center}
.lux-quote-done h3{font-family:var(--lux-font);font-weight:300;font-size:clamp(22px,2.4vw,28px);color:#fff;margin:0}
.lux-quote-doneline{margin:6px 0 0;font-size:13px;color:rgba(255,255,255,.75)}
/* <pre> because the itinerary is built with real newlines — one line per leg,
   in order, which is also exactly what the CRM field receives. Its own font
   stack is reset to the page's: a monospace block would read as debug output. */
.lux-quote-itin{
  margin:0;padding:18px 20px;
  background:rgba(0,39,77,.62);border:1px solid rgba(255,255,255,.35);
  font-family:inherit;font-size:14px;line-height:1.75;color:#fff;
  white-space:pre-wrap;text-align:left;overflow-x:auto;
}
.lux-quote-sent{margin:0;color:#fff;font-size:14px;display:flex;align-items:center;gap:10px}
.lux-quote-done .lux-quote-sent{justify-content:center}
.lux-quote-done .lux-quote-legal{margin-inline:auto;text-align:center}
.lux-quote-done a{color:#fff;text-decoration:underline}
.lux-quote-sent::before{
  content:'';flex:0 0 auto;width:16px;height:16px;
  background:url("../images/turbine-white.png") center/contain no-repeat;
}
.lux-quote-legal{margin:0;font-size:11.5px;line-height:1.7;color:rgba(255,255,255,.6);max-width:820px}

@media (max-width:900px){
  /* The submit is the last flex item on a row of fields; once the fields wrap
     to one per line it should span rather than sit stranded at 50%. */
  .lux-quote-form .new__cta{width:100%;text-align:center}
  .lux-quote-fields--foot{gap:18px}
  /* Stacked one per line, except Time and Passengers: both are narrow, and
     pairing them keeps a leg to four lines instead of five. Date takes its own
     line rather than pairing with Time, or Passengers is the one left stranded
     full-width on a line of its own — which is what a 40% basis alone gives,
     because Date's 150px min plus Time still fits 371px and pushes it over. */
  .lux-quote-leg .lux-quote-field{flex:1 1 100%}
  .lux-quote-leg .lux-quote-field--time,
  .lux-quote-leg .lux-quote-field--pax{flex:1 1 40%;min-width:0}
  /* Stacked, the leg number would take a whole line to itself and the delete
     button would land under the last field rather than beside the row it
     removes. Both move onto the row's own header line. */
  .lux-quote-leg{position:relative;padding-top:4px}
  .lux-quote-leg-no{height:auto;width:auto}
  .lux-quote-legdel{position:absolute;top:0;right:0;width:34px;height:34px;font-size:16px}
  /* The return row needs no rule of its own — it is a leg row and stacks by
     the same two above. */
}
/* iOS zooms the page in on focus for any control under 16px, and never zooms
   back out — it leaves the visitor mid-form on a page wider than the screen.
   Only the mobile breakpoint needs it; the desktop 14px is deliberate. */
@media (max-width:640px){
  .lux-quote-field input,
  .lux-quote-field select{font-size:16px}
}
/* Focus rings on this panel follow .lux-band's — the blue default disappears
   against the navy. */
.lux-quote :focus-visible{outline-color:#fff;box-shadow:0 0 0 4px rgba(0,25,50,.65)}

/* ------------------------------------------------------------------
   Email-gated download on a .lux-band — js/lux-gate.js
   ------------------------------------------------------------------
   Deliberately almost no new CSS: the gate reuses .lux-quote-gate,
   .lux-quote-gate-row, .lux-quote-err, .lux-quote-sent and .lux-framed-box
   from the quote panel above, so the two gates on membership.html are the
   same object rather than two things that resemble each other. What follows
   is only what the band context needs. */

/* .lux-actions and .lux-quote-gate-row both set a display, which outranks the
   UA rule on [hidden], so a hidden stage would render anyway. Restore it at
   class-plus-attribute specificity — same fix as .lux-quote [hidden] above. */
.lux-band [hidden]{display:none}
/* .lux-band-copy already caps the measure at 760px and centres the column, so
   the gate drops the 640px cap it needs when it sits in the full-width quote
   panel, and tightens the padding to suit the shorter band. */
.lux-band-copy .lux-quote-gate{max-width:none;padding:clamp(22px,2.8vw,30px) clamp(20px,3vw,34px)}
/* .lux-band-copy p carries a 26px bottom margin for the gap above the CTA;
   inside the gate box the paragraphs set their own rhythm. */
.lux-band-copy .lux-quote-gate p{margin-bottom:0}
.lux-band-copy .lux-quote-gate .g-sub{margin:0 0 20px}
/* The sent line is a two-item flex row (turbine mark + text) and centres as a
   row, not as text — .lux-quote-gate's text-align does not reach it. */
.lux-band-copy .lux-quote-sent{justify-content:center;text-align:left}
.lux-band-copy .lux-quote-sent + .lux-actions{margin-top:20px}

/* ------------------------------------------------------------------
   .lux-job-* lives in css/job-openings.css, not here.
   Those components are used only by job-openings.html and
   job-openings/*.html, which are GENERATED by
   tools/build_job_openings.py — keeping them out of this file means a
   job-listing tweak does not force a `luxury.css?v=` bump across every
   hand-maintained page. They still depend on this file's tokens, so
   luxury.css must load first. (Comment only: no cache bump needed.)
   ------------------------------------------------------------------ */

/* ============================================================
   N · DISCOVER STEP FLOW  (.fx-discover)
   ------------------------------------------------------------
   One-question-at-a-time front end for the homepage HubSpot form
   (portal 22283886 / form fd6f42bb…). The real HubSpot <form> still
   mounts in #hs-form-homepage and is still what validates and
   submits — it is parked off-screen by .fx-hs-vault below and this
   component mirrors every answer into it. So the CRM fields, the
   utm_* hidden inputs, hs_context and the reCAPTCHA proxy path are
   all untouched; only the UI in front of them is new.

   Geometry follows .lux-hsform deliberately (square corners, 13/15px
   inputs, navy focus ring, 11px .16em uppercase labels) so the flow
   reads as the same form family as every other page.
   ------------------------------------------------------------ */

/* The live HubSpot form. Off-screen rather than display:none — a
   display:none'd required control cannot be focused, which breaks
   both native validation and HubSpot's own "scroll to the bad field"
   behaviour. Kept 1px and clipped so it still lays out and validates. */
.fx-hs-vault{
  position:absolute !important;
  width:1px;height:1px;
  margin:-1px;padding:0;border:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);
  white-space:nowrap;
}

/* Every panel below is toggled with the `hidden` attribute, and most of them
   carry a display:flex class rule — a class beats the UA's [hidden]{display:none}
   on specificity, so without this they would never actually hide. */
.fx-discover[hidden],
.fx-discover [hidden]{display:none !important}

.fx-discover{
  width:100%;max-width:680px;margin:0 auto;
  background:var(--fe-paper);
  border:1px solid var(--fe-line);
  box-shadow:0 4px 24px rgba(0,0,0,.04);
  overflow:hidden;
  font-family:var(--lux-font);
  text-align:left;
}

/* Progress rail */
.fx-discover__rail{height:2px;background:var(--fe-surface-grey)}
.fx-discover__bar{
  height:2px;width:0;background:var(--fe-navy);
  transition:width .5s cubic-bezier(.16,1,.3,1);
}

.fx-discover__body{
  padding:44px 48px 36px;
  min-height:400px;
  display:flex;flex-direction:column;
}
.fx-discover__live{display:flex;flex-direction:column;flex:1}

/* Header: title left, "Step n of m" right */
.fx-discover__head{
  display:flex;align-items:baseline;justify-content:space-between;
  gap:16px;margin-bottom:26px;
}
.fx-discover__brand{
  font-family:var(--lux-font) !important;
  font-weight:200;font-size:26px;letter-spacing:.02em;
  color:var(--fe-navy);margin:0;line-height:1.1;
}
.fx-discover__counter{
  flex:none;
  font-size:11px;font-weight:600;line-height:1;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);
}
/* Only the homepage lets the flow print its own "Discover flyExclusive" — every
   other page already has a heading above the form, so there the counter is the
   whole header row.
   Review 2026-08-07 · 13 — it used to sit flush right, where it read as a stray
   label floating off the end of the sub. Left-aligned it stacks under the title
   and sub and joins the column the rest of the flow already sits in. */
.fx-discover__head--counter-only{justify-content:flex-start}

.fx-discover__q{
  font-family:var(--lux-font) !important;
  font-weight:400;font-size:20px;line-height:1.4;
  color:var(--fe-navy);
  /* margin-top:auto is load-bearing, not spacing. The body is a fixed height so
     the card (or, in the split band, the photograph beside it) does not resize
     step to step, and the nav already sits on margin-top:auto — with only that
     one auto margin, ALL the free space on a short step piled into a single gap
     between the last field and the button, which is what made a two-input step
     read as a mostly-empty panel. Two auto margins in a flex column share the
     free space equally, so the question block sits optically centred and the
     button stays pinned where it is on every other step. */
  margin:auto 0 6px;
}
.fx-discover__sub{
  font-weight:300;font-size:14px;line-height:1.7;
  color:var(--fe-slate);margin:0 0 26px;max-width:48ch;
}
.fx-discover__sub:empty{margin:0 0 20px}

/* Field grid — two text inputs sit side by side, selects go full width */
.fx-discover__fields{display:flex;flex-wrap:wrap;gap:20px}
.fx-discover__field{
  display:flex;flex-direction:column;gap:8px;
  flex:1 1 220px;min-width:0;
}
.fx-discover__field--wide{flex:1 1 100%}
.fx-discover__label{
  font-size:11px;font-weight:600;line-height:1;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);
}
.fx-discover__input{
  box-sizing:border-box;width:100%;min-width:0;
  padding:13px 15px;
  font-family:var(--lux-font);font-size:15px;font-weight:300;line-height:1.4;
  color:var(--fe-ink);background:var(--fe-paper);
  border:1px solid var(--fe-line);border-radius:0;
  transition:border-color .2s ease,box-shadow .2s ease;
}
.fx-discover__input::placeholder{color:var(--fe-slate);opacity:.65}
.fx-discover__input:focus{
  outline:0;border-color:var(--fe-navy);box-shadow:0 0 0 3px rgba(0,58,112,.12);
}
.fx-discover__input.is-invalid{border-color:var(--fe-error)}
/* Same single chevron as .lux-hsform's selects, so the long "how did you hear
   about us" list matches the inputs either side of it instead of showing the
   native Windows/macOS arrow. */
select.fx-discover__input{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  padding-right:40px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2317709A' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;background-size:16px 16px;
}

/* Choice buttons stand in for HubSpot's <select>. The value written back to
   the real select is the option's own value, never this label.

   A grid, not a column. One button per row is what made the choice steps the
   tallest in the flow — the four-option "what brings you to flyExclusive"
   measured 464px against 281px for a two-input step, and the fixed body height
   below has to clear the tallest step, so that one list was setting the height
   of every step on every page. auto-fit means the same rule gives two columns
   in the navy panel, two in the light card, and one on a phone, with no
   per-context override. 220px is picked to make that two and not three: at
   180px the 620px-wide light card fits three tracks and a five-option list
   breaks 3 + 2, which reads as a chip row rather than a list of answers. It is
   also comfortably wider than the longest label any of the 14 forms carries
   ("Fractional Ownership"). */
.fx-discover__choices{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:8px;width:100%;
}
.fx-discover__choice{
  text-align:left;
  padding:14px 18px;
  font-family:var(--lux-font);font-size:15px;font-weight:400;line-height:1.4;
  color:var(--fe-ink);background:var(--fe-paper);
  border:1px solid var(--fe-line);border-radius:0;
  transition:border-color .2s ease,background-color .2s ease,color .2s ease;
}
.fx-discover__choice:hover{border-color:var(--fe-navy)}
.fx-discover__choice[aria-pressed="true"]{
  background:var(--fe-navy);border-color:var(--fe-navy);color:#fff;
}

/* Consent step */
.fx-discover__consent{
  display:flex;flex-direction:column;gap:16px;
  border-top:1px solid var(--fe-line);padding-top:22px;
}
.fx-discover__legal{
  font-weight:300;font-size:12px;line-height:1.65;color:var(--fe-slate);margin:0;
}
.fx-discover__check{
  display:flex;gap:11px;align-items:flex-start;cursor:pointer;
  font-weight:300;font-size:13px;line-height:1.6;color:var(--fe-ink);
}
.fx-discover__check input[type=checkbox]{
  flex:none;width:17px;height:17px;margin:2px 0 0;accent-color:var(--fe-navy);
}
.fx-discover__check > span{min-width:0;flex:1 1 auto}

/* Errors surfaced from HubSpot's own validator */
.fx-discover__error{
  margin:18px 0 0;padding:11px 14px;
  background:rgba(178,59,59,.06);border-left:2px solid var(--fe-error);
  font-size:13px;font-weight:400;line-height:1.55;color:var(--fe-error);
}
.fx-discover__error[hidden]{display:none}

/* Footer nav — Back on the left, primary on the right */
.fx-discover__nav{
  display:flex;align-items:center;gap:16px;
  margin-top:auto;padding-top:34px;
}
.fx-discover__back{
  border:0;background:transparent;padding:0;
  font-size:11px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--fe-slate);
  transition:color .2s ease;
}
.fx-discover__back:hover{color:var(--fe-navy)}
.fx-discover__next{
  margin-left:auto;border:0;border-radius:0;
  padding:15px 46px;
  background:var(--fe-navy);color:#fff;
  font-family:var(--lux-font);
  font-size:12px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  transition:background-color .3s ease,opacity .3s ease;
}
.fx-discover__next:hover:not([disabled]){background:var(--fe-navy-900)}
.fx-discover__next[disabled]{opacity:.4;cursor:not-allowed}
.fx-discover__next.is-busy{opacity:.6;cursor:progress}

/* Thank-you panel */
.fx-discover__done{
  display:flex;flex-direction:column;justify-content:center;
  flex:1;padding:30px 0;
}
.fx-discover__done h2{
  font-family:var(--lux-font) !important;
  font-weight:200;font-size:32px;line-height:1.15;
  color:var(--fe-navy);margin:0 0 12px;
}
.fx-discover__done p{
  font-weight:300;font-size:15px;line-height:1.7;
  color:var(--fe-slate);margin:0;max-width:46ch;
}

/* Where the flow lands inside a container that is already a card, that wrapper
   owns the paper, the border and the padding — same call as the .lux-hsform
   rule above. Six our-fleet pages sit in .lux-form-card and fractional/explore
   sits in .jet-card__form-block; without this the visitor sees a card in a card
   and roughly 90px of stacked padding.
   Note this drops chrome only. It must NOT touch max-width: the rule targets
   .fx-discover as a descendant, and the host card is what caps the width. */
.lux-form-card .fx-discover,
.jet-card__form-block .fx-discover{
  background:none;border:0;box-shadow:none;max-width:none;
}
.lux-form-card .fx-discover__body,
.jet-card__form-block .fx-discover__body{padding:0;min-height:340px}
/* The rail is the card's own top edge in that context, so it would read as a
   stray line floating inside the padding. */
.lux-form-card .fx-discover__rail,
.jet-card__form-block .fx-discover__rail{margin-bottom:24px}

@media screen and (max-width:767px){
  .fx-discover__body{padding:32px 24px 28px;min-height:360px}
  .fx-discover__head{margin-bottom:20px}
  .fx-discover__brand{font-size:22px}
  .fx-discover__q{font-size:18px}
  /* Single column: two 220px-basis inputs would otherwise wrap unevenly */
  .fx-discover__field{flex:1 1 100%}
  .fx-discover__next{padding:15px 32px;flex:1 1 auto;margin-left:auto}
  .fx-discover__done h2{font-size:26px}
  .lux-form-card .fx-discover__body,
  .jet-card__form-block .fx-discover__body{padding:0;min-height:300px}
}

/* The step flow replaces the stock embed on the homepage, so the old
   .lux-hsform max-width no longer needs to reserve 880px there. */

/* ============================================================
   O · LATEST NEWS  (.lux-news)
   ------------------------------------------------------------
   Homepage newsroom module: one featured article laid out large,
   then three more recent ones. js/home-news.js fills it from the
   same store /news/ reads, so nothing here hard-codes content.

   Deliberately its own component rather than a reuse of
   .fex-news-card from css/news.css: that sheet is 1350 lines of
   index, filter and article-page styling written against the
   news pages' own cascade, and the homepage does not load it.
   The proportions below follow it closely so the two still read
   as one family.
   ------------------------------------------------------------ */

/* The section ships hidden and home-news.js reveals it once it has
   articles, so a store failure leaves no empty band. A class rule
   would beat the UA's [hidden], hence the explicit override. */
.lux-news[hidden]{display:none !important}

.lux-news__body{display:block}

/* Shared bits ------------------------------------------------ */
.lux-news__tag{
  position:absolute;left:0;bottom:0;
  margin:0;padding:7px 12px;
  background:rgba(0,39,77,.86);
  font-family:var(--lux-font);font-weight:600;font-size:10px;
  letter-spacing:.18em;text-transform:uppercase;color:#fff;
}
.lux-news__date{
  display:block;margin:0 0 8px;
  font-family:var(--lux-font);font-weight:400;font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-slate);
}
.lux-news__excerpt{
  display:block;margin:0 0 18px;
  font-family:var(--lux-font);font-weight:300;font-size:14.5px;line-height:1.75;
  color:var(--fe-ink);max-width:52ch;
}
.lux-news__more{
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--lux-font);font-weight:600;font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--fe-navy);
}
.lux-news__more svg{
  width:16px;height:16px;flex:none;
  fill:none;stroke:currentColor;stroke-width:1.6;
  transition:transform .4s cubic-bezier(.2,.7,.3,1);
}
.lux-news__lead:hover .lux-news__more svg{transform:translateX(4px)}

/* Featured lead ---------------------------------------------- */
.lux-news__lead{
  display:grid;
  grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  gap:clamp(24px,3vw,48px);
  align-items:center;
  text-decoration:none;
  padding-bottom:clamp(28px,3vw,44px);
  margin-bottom:clamp(28px,3vw,44px);
  border-bottom:1px solid var(--fe-line);
}
.lux-news__lead-media,
.lux-news__card-media{
  position:relative;display:block;overflow:hidden;
  background:var(--fe-surface-blue);
}
.lux-news__lead-media img,
.lux-news__card-media img{
  display:block;width:100%;height:auto;
  aspect-ratio:3/2;object-fit:cover;
  transition:transform .7s cubic-bezier(.2,.7,.3,1);
}
.lux-news__lead:hover .lux-news__lead-media img,
.lux-news__card:hover .lux-news__card-media img{transform:scale(1.04)}

.lux-news__lead-copy{display:block;min-width:0}
.lux-news__eyebrow{
  display:block;margin:0 0 14px;
  font-family:var(--lux-font);font-weight:600;font-size:10px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--fe-blue-600);
}
/* The headline is the point of the module, so it carries real size
   rather than the 17px the grid cards use. */
.lux-news__lead-title{
  display:block;margin:0 0 14px;
  font-family:var(--lux-font) !important;
  font-weight:300;font-size:clamp(24px,2.5vw,34px);line-height:1.2;
  letter-spacing:.01em;color:var(--fe-navy);
  text-wrap:balance;
}
.lux-news__lead:hover .lux-news__lead-title{color:var(--fe-blue-600)}

/* Three recent ----------------------------------------------- */
.lux-news__grid{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(20px,2.4vw,32px);
}
.lux-news__card{display:flex;flex-direction:column;min-width:0;text-decoration:none}
.lux-news__card-media{margin:0 0 14px}
.lux-news__card-copy{display:flex;flex-direction:column;flex:1 1 auto;min-width:0}
.lux-news__card-title{
  display:block;margin:0;
  font-family:var(--lux-font) !important;
  font-weight:500;font-size:17px;line-height:1.32;
  letter-spacing:.01em;color:var(--fe-navy);
  text-wrap:balance;
}
.lux-news__card:hover .lux-news__card-title{color:var(--fe-blue-600)}

/* .lux-actions carries no top margin of its own, so the newsroom button
   otherwise butts straight onto the card row — and being centred, it reads as
   part of the middle card rather than as the section's own action. */
.lux-news .lux-actions{margin-top:clamp(30px,3.4vw,48px)}

@media screen and (max-width:900px){
  /* Photo over copy: at this width the two-up lead squeezes the
     headline into a column narrower than the excerpt beside it. */
  .lux-news__lead{grid-template-columns:1fr;gap:20px}
  .lux-news__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  /* Three into two leaves an orphan; it spans so the row stays even. */
  .lux-news__grid > .lux-news__card:nth-child(3){grid-column:1 / -1}
  .lux-news__grid > .lux-news__card:nth-child(3) .lux-news__card-media img{aspect-ratio:21/9}
}
@media screen and (max-width:600px){
  .lux-news__grid{grid-template-columns:1fr}
  .lux-news__grid > .lux-news__card:nth-child(3){grid-column:auto}
  .lux-news__grid > .lux-news__card:nth-child(3) .lux-news__card-media img{aspect-ratio:3/2}
}

/* ============================================================
   P · SPLIT FORM PANEL  (.lux-splitform)
   ------------------------------------------------------------
   Full-bleed lead capture: photography edge-to-edge on the left,
   the form on a deep navy panel on the right. Built to host the
   step flow in section N — .fx-discover mounts itself as the
   previous sibling of its .lux-hsform host, so the host lives in
   .lux-splitform__inner and the flow lands inside the panel with
   no extra markup.

   The panel is the only dark form surface on the site, so every
   override below exists because a light-ground default would be
   unreadable on navy. Two specificity traps to respect when
   editing:

   - the global field rule in section 2 carries five :not()s, i.e.
     (0,5,1). A single-class rule cannot repaint a field. The field
     rules here repeat that chain rather than reach for !important.
   - h1[class] / h2[class] in section 1 pins headings to navy at
     (0,1,1), which is why the title rules are written as
     .lux-splitform h2[class].
   - the jc25 pages carry their own low-specificity reset in a page
     <style> that lands after this file: `.jc25 :where(p){color:
     inherit;font:inherit;max-width:none}` at (0,1,0). It is meant
     to sit under single-class component rules, and does — but only
     for components declared in that same page block. Rules here
     load earlier, so a bare .lux-splitform__sub would lose its
     size, weight, colour and measure to it and nothing else. Hence
     the text rules are written as `.lux-splitform p.<class>`.

   Everything here is CSS: no script, no font, no iframe, and one
   lazily-loaded photograph.
   ------------------------------------------------------------ */

.lux-splitform{
  position:relative;
  /* Every native control in this band sits on navy — see the note on the option
     list below. This is what makes the platform draw them dark to match. */
  color-scheme:dark;
  display:grid;
  grid-template-columns:minmax(0,.88fr) minmax(0,1fr);
  align-items:stretch;
  background:linear-gradient(155deg,#00335F 0%,var(--fe-navy-900) 55%,#001A34 100%);
  overflow:hidden;
  /* The footer that follows is a lighter navy (#003A70) and butts straight up
     against this band, so without a hairline the two dark fields read as one
     muddy mass with a seam in the middle of it. The top edge needs the same
     treatment on the our-fleet pages, where .lux-cta-band (--fe-navy-900) sits
     directly above; against a light section above it simply reads as a rule. */
  border-top:1px solid rgba(255,255,255,.12);
  border-bottom:1px solid rgba(255,255,255,.12);
  /* deep-linked from the sticky CTA and #Jet-Club-Form-Section */
  scroll-margin-top:96px;
}
/* The legacy #Jet-Club-Form-Section deep-link anchor is an empty <a> at the top
   of the section, i.e. the grid's first child — left in flow it claims track 1
   and pushes the panel onto a second row. Absolute takes it out of the grid
   without costing it its job as a jump target. */
.lux-splitform > a[aria-hidden="true"]{
  position:absolute;top:0;left:0;width:0;height:0;overflow:hidden;
}

/* --lede — the band IS the top of the page (request-info.html), instead of the
   closing band under a hero. Three consequences:

   - .home-header is position:fixed and reserves no space, and on a page that
     does not open with something matching resolveHero() in js/home-hero.js the
     header pins .is-scrolled from load, i.e. the solid bar is over the band from
     the first paint. The padding buys its clearance, and it sits on the SECTION
     rather than the panel so the photograph starts below the bar as well —
     hiding the top of the image behind an opaque bar is just a worse crop. The
     band's own gradient fills the reserved strip and reads as continuous with
     the bar's navy.
   - the title is now the page's h1, and it is the largest mark on the screen, so
     the type steps back up (see the title rule further down). The step DOWN in
     the base rule exists to fit a band that already has a hero above it in the
     same screen; this band has none.
   - no border-top: there is nothing above it to be separated from.

   The clamp is measured, not guessed. The bar is 104px tall on a phone and
   grows to 122px, all of that growth in its own padding —
   clamp(1rem,2.2vw,1.75rem), which stops moving at 1273px wide — over a 48px
   logo row and a 40/46px quicklink strip. So the FLOOR has to clear 122, not
   the phone's 104: 10vw only overtakes the floor at 1220px, which is about
   where the bar has finished growing. Same shape as .lux-section--clears-header,
   which solves this for a light section and needs a bigger number because there
   the header is a scrim with a 76px fade rather than a bar with an edge. */
.lux-splitform--lede{
  padding-top:clamp(122px,10vw,146px);
  border-top:0;
}

/* Depth without an asset: one cool wash off the top-right corner so the
   panel is not a flat block of navy behind white text. */
.lux-splitform__panel::before{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 90% at 88% 0%,rgba(41,159,207,.20) 0%,rgba(41,159,207,0) 62%);
}

/* Both tracks are minmax(0,…) above, but a grid *item* still has an automatic
   min-width of min-content, so one unbreakable token (a long word, a URL, a
   heading joined by &nbsp;) sizes the column to itself and pushes the band past
   the viewport. min-width:0 here plus break-word on the copy below is what makes
   the band's width depend on the viewport alone, at every breakpoint. */
.lux-splitform__media,
.lux-splitform__panel{min-width:0}

/* ---- MEDIA SIDE ------------------------------------------- */
/* 440, not 520: the panel is the taller track at every desktop width, so this
   only ever mattered as a floor — and at 520 it was a floor above the height the
   compacted panel now settles at on a laptop, i.e. it would have been the thing
   keeping the band from fitting one screen. */
/* Review 2026-08-07 · 10 — the photo stopped dead at the panel edge and the
   seam read as a drawn vertical line. The ::after blend below only reached .62
   alpha, so the image was still fully visible right up to the cut.
   Masking the whole media cell (image AND its scrim) dissolves that edge into
   whatever is behind it — here the section's own 155deg gradient — so the two
   halves match by construction instead of by a hand-picked colour that would
   drift the moment the band gradient changed. Cancelled below 1024px, where the
   band stacks and the photo is full-width: a right-edge fade there would eat the
   side of the picture for no reason. */
.lux-splitform__media{position:relative;overflow:hidden;min-height:440px;
  -webkit-mask-image:linear-gradient(90deg,#000 0%,#000 56%,rgba(0,0,0,0) 100%);
          mask-image:linear-gradient(90deg,#000 0%,#000 56%,rgba(0,0,0,0) 100%);
}
.lux-splitform__media img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;object-position:50% 56%;
}
/* Two scrims in one layer: the first grounds the overlay copy, the second
   blends the photo's right edge into the panel so the split reads as a
   single surface rather than two boxes butted together.
   On ::after deliberately — an ::before on the same element paints *under*
   the positioned <img>, which is the trap the newsroom cards hit. */
.lux-splitform__media::after{
  content:'';position:absolute;inset:0;
  background:
    linear-gradient(180deg,rgba(0,26,52,.20) 0%,rgba(0,26,52,0) 34%,rgba(0,26,52,.55) 72%,rgba(0,26,52,.86) 100%),
    linear-gradient(90deg,rgba(0,39,77,0) 58%,rgba(0,39,77,.62) 100%);
}
.lux-splitform__media-copy{
  position:absolute;z-index:2;left:0;right:0;bottom:0;
  padding:clamp(28px,3vw,52px);
  display:flex;flex-direction:column;gap:clamp(14px,1.6vw,20px);
}
.lux-splitform p.lux-splitform__kicker{
  margin:0;
  font-family:var(--lux-font);font-weight:600;font-size:11px;
  letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.82);
}
.lux-splitform p.lux-splitform__line{
  margin:0;max-width:22ch;
  font-family:var(--lux-font);font-weight:200;
  font-size:clamp(24px,2.5vw,36px);line-height:1.14;letter-spacing:.005em;
  color:#fff;text-wrap:balance;overflow-wrap:break-word;
}
/* The overlay carried a row of pill chips (.lux-splitform__proof) under the
   line. Removed on 2026-08-05 — on photography they read as UI stuck to the
   image, and they were the first thing to collide with the copy once the media
   band goes short on a phone. The claims they carried are all still made in the
   page body above. */

/* ---- PANEL SIDE ------------------------------------------- */
/* The block padding is measured against the VIEWPORT HEIGHT, not the width,
   and that is the whole point of it: the brief for this band is that the entire
   module is visible on a normal laptop without scrolling, and the panel's own
   padding was the second-largest item in its height budget (126px of the 821px
   the band measured at 1366×700). vw knows nothing about the constraint —
   a 1366-wide laptop and a 1366-wide slice of a 4K monitor got identical
   padding. 3.4vh gives 24px on a 700px-tall viewport and 49px at 1440, so the
   air comes back on the screens that have room for it. Inline padding stays on
   vw, where vw is the right axis. */
.lux-splitform__panel{
  position:relative;
  display:flex;flex-direction:column;justify-content:center;
  padding:clamp(22px,3.4vh,52px) clamp(26px,4.2vw,82px);
}
.lux-splitform__inner{position:relative;z-index:1;width:100%;max-width:620px;margin:0 auto}
.lux-splitform p.lux-splitform__eyebrow{
  margin:0 0 10px;
  font-family:var(--lux-font);font-weight:600;font-size:11px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--fe-blue-300);
}
/* h1 is in the list for --lede below, where the band is the top of the page and
   its title is therefore the page's h1. h1[class] in section 1 pins headings to
   navy at (0,1,1), so it has to be named here explicitly like the others. */
.lux-splitform h1[class],
.lux-splitform h2[class],
.lux-splitform h3[class]{color:#fff}
/* Was clamp(27px,2.9vw,40px). Stepped down because at laptop widths this title
   runs to two lines and each line costs ~34px of a band that has to fit in one
   screen; 2.2vw keeps it two lines but 22px shorter, and it is still the
   largest thing in the panel. */
.lux-splitform h1.lux-splitform__title,
.lux-splitform h2.lux-splitform__title{
  margin:0 0 10px;
  font-family:var(--lux-font);font-weight:200;
  font-size:clamp(22px,2vw,31px);line-height:1.12;letter-spacing:.005em;
  text-wrap:balance;overflow-wrap:break-word;
}
/* --lede's title is the page's h1 and has no hero above it competing for the
   screen, so it takes the size back. It has to sit AFTER the rule above rather
   than beside the modifier's own block: both selectors are (0,2,1), so source
   order is the only thing deciding it, and up there the base rule won.
   The ceiling is set against .lux-splitform__line — the statement over the
   photograph — which tops out at 36px. The h1 has to be the larger of the two
   or the page reads as though the photo caption is the headline. */
.lux-splitform--lede h1.lux-splitform__title{
  margin-bottom:12px;
  font-size:clamp(27px,2.9vw,44px);
}
/* Review 2026-08-07 · 12 — "…connect you with a Private Aviation Expert."
   broke onto a second line on every form. The measure was the cause, not the
   space: 46ch resolves to about 333px here and the sentence sets at roughly
   470px. .lux-splitform__inner already caps the column at 620px, which is the
   measure control that matters, so the second cap only ever forced the wrap.
   Longer subs (request-info, the our-fleet pages) still wrap against 620px. */
.lux-splitform p.lux-splitform__sub{
  margin:0;max-width:none;
  font-family:var(--lux-font);font-weight:300;font-size:14.5px;line-height:1.55;
  color:var(--fe-blue-200);
}
.lux-splitform p.lux-splitform__foot{
  margin:16px 0 0;padding-top:14px;
  border-top:1px solid rgba(255,255,255,.16);
  display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 20px;
  font-family:var(--lux-font);font-weight:300;font-size:12.5px;line-height:1.6;
  color:var(--fe-blue-200);
}
.lux-splitform__foot a{
  color:#fff;font-weight:600;text-decoration:none;
  border-bottom:1px solid rgba(255,255,255,.45);
  transition:border-color .2s ease;
}
.lux-splitform__foot a:hover{border-bottom-color:#fff}

/* ---- THE STEP FLOW, ON NAVY -------------------------------- */
/* The HubSpot embed is a light card: vaulted at 1px when the flow mounts, and
   the visible form when it does not (JS off, or the embed script blocked). Put
   it back on the light scheme — the global field rule sets its inputs white but
   never sets their text colour, so under the section's dark scheme the fallback
   would render white-on-white. */
.lux-splitform .lux-hsform{color-scheme:light}

.lux-splitform .fx-discover{
  background:none;border:0;box-shadow:none;
  max-width:none;margin:0;overflow:visible;
}
.lux-splitform .fx-discover__rail{height:1px;background:rgba(255,255,255,.18);margin-top:16px}
.lux-splitform .fx-discover__bar{height:1px;background:var(--fe-blue)}
/* min-height is the tallest step, measured across the HubSpot forms this band
   hosts, not a guess. Sizing the body to the longest step keeps the section —
   and therefore the photograph beside it — one fixed height for the whole flow
   instead of growing and shrinking step to step.

   It was 500px, set by the choice steps when their options were one per row
   (464px for four options, 496px where a list runs a line longer). Those are
   now a two-column grid (section N), which drops them under the consent step —
   HubSpot's own message-frequency paragraph plus the checkbox row, the one step
   whose height is other people's copy. Everything else in the flow's rhythm was
   then tightened (head, sub, nav, consent and legal below) to bring that step
   down to 345px at 1280–1366 and 328px at 1440 and up, and 361 is the worse of
   those plus this body's own 16px padding-top: the smallest number that still
   never moves the photograph.

   The input is a WIDTH, not a height — the narrower the panel, the more lines
   the consent paragraph wraps to. Hence the 1024–1279 bump below rather than a
   single bigger number for everyone. Re-measure at 1024, 1280 and 1440 if a
   portal edit ever lengthens that paragraph. */
.lux-splitform .fx-discover__body{padding:16px 0 0;min-height:338px}
/* Narrow desktop: the same paragraph wraps one line further (362px), and the
   band is over one screen at this width regardless, so it takes the taller pin
   rather than dragging every wider screen up with it. */
@media (min-width:1024px) and (max-width:1279px){
  /* 373, not the 338 above: at this width the two-input steps stack their
     fields into two rows (357px) and overtake the consent step, so THEY set the
     pin here. */
  .lux-splitform .fx-discover__body{min-height:373px}
}
/* How the leftover space on a short step is distributed is section N's job now
   (see the margin note on .fx-discover__q) — it applies to the light-card
   pages too, which had the same single-gap problem at a smaller scale. */
.lux-splitform .fx-discover__head{margin-bottom:14px}
/* The rest of this group is the same compaction: every value here was larger
   and is now the smallest that keeps the step legible, because the band has a
   one-screen budget and the flow is the largest item in it. */
.lux-splitform .fx-discover__nav{padding-top:22px}
.lux-splitform .fx-discover__next{padding:13px 38px}
.lux-splitform .fx-discover__consent{padding-top:14px;gap:12px}
.lux-splitform .fx-discover__brand{color:#fff}
.lux-splitform .fx-discover__counter{color:var(--fe-blue-300)}
.lux-splitform .fx-discover__q{color:#fff;font-weight:300;font-size:21px}
/* The flow's <p> elements need their size and weight restated, not just their
   colour: the jc25 reset's `font:inherit` (see the note at the top of this
   section) outranks section N's own single-class rules on these pages, so a
   colour-only override would leave 16px/400 body text behind. */
.lux-splitform .fx-discover__sub{color:var(--fe-blue-200);font-size:14px;font-weight:300;line-height:1.6;margin-bottom:16px}
.lux-splitform .fx-discover__error{font-size:13px;font-weight:400;line-height:1.55}
/* 11.5/1.5, not 12/1.65. This paragraph is HubSpot's own consent wording and
   none of it may be cut or hidden, so the only lever on the tallest step in the
   flow is how tightly it sets. It is still 11.5px on a dark ground at
   AA-passing contrast (--fe-blue-200 on the panel), and it is disclosure text,
   not reading copy. */
.lux-splitform .fx-discover__legal{font-size:11.5px;font-weight:300;line-height:1.5}
.lux-splitform .fx-discover__done p{font-size:15px;font-weight:300;line-height:1.7}
.lux-splitform .fx-discover__label{color:var(--fe-blue-300)}
.lux-splitform .fx-discover__fields{gap:20px}

/* Underline fields. The :not() chain matches section 2's global field rule so
   this wins on specificity rather than on !important. */
.lux-splitform input.fx-discover__input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=image]),
.lux-splitform select.fx-discover__input,
.lux-splitform textarea.fx-discover__input{
  min-height:52px;padding:13px 2px;
  font-size:16px;font-weight:300;   /* 16px: anything smaller zooms iOS on focus */
  color:#fff;background-color:transparent;
  border:0;border-bottom:1px solid rgba(255,255,255,.42);
}
.lux-splitform .fx-discover__input::placeholder{color:rgba(255,255,255,.5);opacity:1}
.lux-splitform input.fx-discover__input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=image]):focus,
.lux-splitform select.fx-discover__input:focus,
.lux-splitform textarea.fx-discover__input:focus{
  border-bottom-color:var(--fe-blue);
  /* thickens the rule; a ring would float free of an underline field */
  box-shadow:0 1px 0 0 var(--fe-blue);
}
.lux-splitform input.fx-discover__input.is-invalid:not([type=checkbox]):not([type=radio]),
.lux-splitform select.fx-discover__input.is-invalid{border-bottom-color:#F6A9A0}
/* Light chevron: the navy one from section N would be invisible here */
.lux-splitform select.fx-discover__input{
  padding-right:34px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239CC4DE' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-position:right 4px center;
}
/* The open option list is drawn by the platform, not by this stylesheet. With a
   transparent field Chrome falls back to a white popup with a system-blue
   highlight row — the one piece of chrome in this panel that ignores the
   design. color-scheme:dark on the section switches every native surface here
   (option list, its scrollbar, the consent checkbox, Chrome's autofill) to the
   platform's dark rendering; the option colours below cover the browsers that
   paint from the option rather than the scheme. */
.lux-splitform select.fx-discover__input option{
  background-color:var(--fe-navy-900);color:#fff;
}
.lux-splitform select.fx-discover__input option:disabled{color:rgba(255,255,255,.5)}

/* Autofill is the other place the browser overrules the panel: Chrome paints a
   light fill behind autofilled fields with a UA !important that nothing but an
   inset shadow can cover, which on navy lands as a pale blue block mid-form.
   This form asks for name, email and phone with autocomplete attributes, so it
   is the common path, not an edge case. */
.lux-splitform input.fx-discover__input:-webkit-autofill,
.lux-splitform input.fx-discover__input:-webkit-autofill:hover,
.lux-splitform input.fx-discover__input:-webkit-autofill:focus{
  -webkit-text-fill-color:#fff;
  -webkit-box-shadow:0 0 0 60px #002346 inset;
  caret-color:#fff;
}

/* Answer chips */
.lux-splitform .fx-discover__choices{gap:10px}
.lux-splitform .fx-discover__choice{
  padding:15px 22px;border-radius:999px;
  font-size:15px;font-weight:300;color:#fff;
  background:rgba(255,255,255,.05);
  border:1px solid rgba(255,255,255,.42);
}
.lux-splitform .fx-discover__choice:hover{border-color:#fff;background:rgba(255,255,255,.12)}
/* Not pure #fff: a large flat white fill on deep navy halates at the edges and
   reads as a cut-out. Cooling it ~3% keeps the contrast (12.9:1) and loses the
   hard edge. Same reason the primary button below is off-white. */
.lux-splitform .fx-discover__choice[aria-pressed="true"]{
  background:#EFF4F8;border-color:#EFF4F8;color:var(--fe-navy-900);font-weight:500;
}

/* Consent + errors */
.lux-splitform .fx-discover__consent{border-top-color:rgba(255,255,255,.16)}
.lux-splitform .fx-discover__legal{color:var(--fe-blue-200)}
.lux-splitform .fx-discover__legal a,
.lux-splitform .fx-discover__check a{color:#fff;text-decoration:underline}
.lux-splitform .fx-discover__check{color:rgba(255,255,255,.92)}
.lux-splitform .fx-discover__check input[type=checkbox]{accent-color:var(--fe-blue)}
.lux-splitform .fx-discover__error{
  background:rgba(246,169,160,.10);
  border-left-color:#F6A9A0;color:#F6A9A0;
}

/* Nav */
.lux-splitform .fx-discover__nav{padding-top:32px}
.lux-splitform .fx-discover__back{color:rgba(255,255,255,.62)}
.lux-splitform .fx-discover__back:hover{color:#fff}
.lux-splitform .fx-discover__next{
  padding:17px 52px 17px 34px;border-radius:999px;
  color:var(--fe-navy-900);
  background-color:#EFF4F8;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300274D' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13M13 6l6 6-6 6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 22px center;background-size:15px 15px;
  transition:background-color .25s ease,color .25s ease,opacity .25s ease;
}
.lux-splitform .fx-discover__next:hover:not([disabled]){background-color:var(--fe-blue-200)}
.lux-splitform .fx-discover__next[disabled]{opacity:.45}

/* Thank-you */
.lux-splitform .fx-discover__done h2{color:#fff}
.lux-splitform .fx-discover__done p{color:var(--fe-blue-200)}

/* ---- RESPONSIVE ------------------------------------------- */
@media screen and (max-width:1023px){
  .lux-splitform{grid-template-columns:minmax(0,1fr)}
  /* Stacked: the photo is full-width and the panel is below it, so the
     right-edge fade added for the desktop seam has nothing to blend into. */
  .lux-splitform__media{-webkit-mask-image:none;mask-image:none}
  /* A height, deliberately, not aspect-ratio. `aspect-ratio` plus a `max-height`
     cap resolves by shrinking the *width*: on a landscape phone the cap bound
     first and a 797px-wide row rendered a 293px-wide photo, with the overlay
     copy — sized for the full width — overflowing the box and getting clipped
     against .lux-splitform__media's own overflow:hidden. The <img> is
     object-fit:cover, so a plain height crops the photo instead of resizing its
     frame, and the frame always fills the column. */
  .lux-splitform__media{min-height:0;height:clamp(220px,58vw,460px)}
  .lux-splitform__media img{object-position:50% 60%}
  .lux-splitform p.lux-splitform__line{font-size:clamp(22px,4.4vw,30px);max-width:26ch}
  .lux-splitform__panel{padding:clamp(38px,6vw,56px) clamp(24px,5vw,48px)}
}
/* Landscape phones and other short viewports: 58vw of a wide-but-short screen
   is most of the screen, so the band gets a fixed short height and the overlay
   is re-set to fit inside it. */
@media screen and (max-width:1023px) and (max-height:520px){
  .lux-splitform__media{height:190px}
  .lux-splitform__media-copy{padding:18px 20px;gap:8px}
  .lux-splitform p.lux-splitform__line{font-size:19px;max-width:34ch}
  /* The 500px floor exists to hold the photograph beside the form at one height;
     stacked on a 375px-tall screen it only adds scroll, so this matches the
     phone rule and lets the steps size themselves. */
  .lux-splitform .fx-discover__body{min-height:352px}
}
@media screen and (max-width:767px){
  .lux-splitform__panel{padding:36px 22px 44px}
  .lux-splitform .fx-discover__body{padding:26px 0 0;min-height:352px}
  .lux-splitform .fx-discover__rail{margin-top:28px}
  .lux-splitform .fx-discover__q{font-size:19px}
  .lux-splitform .fx-discover__next{flex:1 1 auto;padding:16px 48px 16px 28px}
  .lux-splitform p.lux-splitform__foot{font-size:12px}
}
@media (prefers-reduced-motion:reduce){
  .lux-splitform .fx-discover__next,
  .lux-splitform .fx-discover__choice,
  .lux-splitform__foot a{transition:none}
}

/* ============================================================
   Q · WEB CONTENT REFRESH — 2026-08-05
   ------------------------------------------------------------
   Four small extensions added for WebContentRefresh_JS.docx. Each one is a
   modifier on an existing component rather than a new component: the refresh
   asked for shapes the library nearly had, and the near-misses are noted per
   rule below. Nothing here restyles an existing selector.
   ============================================================ */

/* ---- heading levels in two card components -------------------------------
   .lux-feature-card and .lux-tier-card both style their title as `h4` by
   element (luxury.css sections 5 and 6). That was fine while both only ever
   appeared under an h3, but the refresh puts each of them directly under a
   section h2 — .lux-feature-card--figure under #services on about.html, and
   .lux-tier-card under #program on jet-club.html — which skipped a level and
   broke the document outline (WCAG 1.3.1).

   (The jet-club tier pair was replaced by .lux-ledger on 2026-08-11; the
   .lux-tier-card rules below stay because design-library.html still catalogues
   the component and the same outline problem applies wherever it is used next.)

   So the markup uses h3 and these two selectors accept it. h4 is kept alongside
   so nothing that already ships an h4 changes. No visual difference: same
   declarations, and the `h1[class],h2[class],h3[class],h4[class]` rule at the
   top of this file cannot interfere because these headings carry no class. */
.lux-feature-card h3{margin:0 0 14px;font-family:var(--lux-font);font-weight:400;font-size:17px;color:var(--fe-navy)}
.lux-tier-card .t-head h3{
  margin:0 0 6px;font-family:var(--lux-font);font-weight:400;font-size:19px;color:var(--fe-navy);
  display:flex;flex-wrap:wrap;align-items:center;gap:10px;
}
.lux-tier-card.is-featured .t-head h3{color:#fff}

/* Cover-crop focus for a portrait source in a landscape frame. The seaplane
   "Bring What Matters" panel uses the one photograph in the repo that shows
   luggage aboard the Caravan — a 2:3 portrait with the bag at the bottom, which
   .lux-program-panel's centred 16/10 cover crop removed entirely. Was an inline
   style; CLAUDE.md is explicit that the component library is the architecture,
   and a crop decision is presentation. */
.lux-media-focus-low{object-position:50% 88%}

/* .t-note — the parenthetical qualifier the refresh hangs off a tier's deposit
   figure ("(competitive entry pricing across the industry!)"). It is neither the
   price nor a bullet, and set at .t-price's 26px it competed with the figure it
   was qualifying. Slate at 13px so the deposit stays the number you read.
   Lives in .t-head, after .t-price. */
.lux-tier-card .t-note{
  font-family:var(--lux-font);font-size:13px;line-height:1.55;
  color:var(--fe-slate);margin:6px 0 0;
}
.lux-tier-card.is-featured .t-note{color:var(--fe-blue-200)}

/* --figure — .lux-feature-card carrying a display figure above its title, for
   the "[NUMBER]+ Flight Control / Member Services / Pilots" trio. Not
   .lux-stat-row: those cells are a figure and a letterspaced label with no room
   for the sentence each of these three carries. Not .lux-icon-card either — the
   figure IS the ornament here, so a second mark above it would be one too many.
   The accent rule is .lux-stat::before's, so the two components' figures read as
   one family across the site. */
.lux-feature-card--figure::before{
  content:'';display:block;width:26px;height:2px;background:var(--fe-blue);
  margin:0 0 clamp(15px,1.5vw,20px);
}
.lux-feature-card--figure .lux-stat-number{margin:0 0 10px;text-align:left}

/* --2col — .lux-ticklist as a two-column block. The list is a single-column
   grid by design (it sits in a .lux-split's copy column, where one column is
   the only option). The refresh's "Benefits Overview" is four short labels
   standing on their own across a full .lux-wrap, where one column leaves a
   1180px row holding four words. auto-fit rather than a fixed 2, so it collapses
   to one column on a phone without a second media query. */
.lux-ticklist--2col{grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));column-gap:clamp(20px,2.6vw,40px)}

/* Deep-linked sections must clear the fixed header. The refresh gives both
   program-page heroes a second CTA that jumps to #program, and the homepage
   statement a link to #programs — and .home-header is position:fixed and
   reserves no space, so an anchor jump put the section's heading UNDER the
   header bar every time. .lux-splitform already carried exactly this fix for
   #Jet-Club-Form-Section (scroll-margin-top:96px, ~84px of header plus a little
   air); this generalises the same value to the section components.

   Costs nothing anywhere else: scroll-margin has no effect on layout and no
   effect on an element that is not the target of a scroll. So it also silently
   fixes every pre-existing anchor on the site (#faq, #benefits, #form, #shares,
   #aircraft and the rest), which all had the same problem. */
.lux-section,.lux-band,.lux-hero,.lux-quote{scroll-margin-top:96px}

/* --evenheads — line the LEADS of a .lux-program-panel row up with each other.
   The panels already pin their feet (.p-fit and .lux-actions both take
   margin-top:auto); this is the same concern at the top of the block. In the
   seaplane three-up, "Depart from Land or Water" wraps to two lines while its
   two neighbours run to one, so all three body paragraphs started on different
   baselines and the row read as three unrelated cards rather than one comparison.

   min-height in em, not px, so it tracks the h3's own clamp()ed size instead of
   assuming a viewport: 2 lines at the component's line-height of 1.12, plus its
   16px bottom margin left alone.

   A modifier rather than a change to .lux-program-panel h3, because the other
   rows built on this component (fractional's three aircraft, membership's
   Jet Club / Fractional pair) are already balanced and reserving a second line
   for them would only add a gap. */
.lux-grid--evenheads .lux-program-panel h3{min-height:2.24em}
@media (max-width:900px){
  /* One column, so nothing is beside anything and a reserved second line is
     just dead space under a single-line heading. */
  .lux-grid--evenheads .lux-program-panel h3{min-height:0}
}
/* MEASURED, so nobody has to re-derive it. The obvious worry with a hard 900px
   release is that .lux-grid--3 is repeat(auto-fit,minmax(280px,1fr)) and reflows
   intrinsically, so the two thresholds cannot be kept in sync — at 930-960px the
   grid is already 2 columns while the reserve is still on, leaving the third
   panel alone on row 2 reserving a line it does not need.

   That band was measured on seaplane.html (930 / 960 / 1024 / 1100px). It is
   real and it is a net GAIN, not the dead space it looks like: at 930px panels 1
   and 2 share row 1, panel 1's heading wraps to two lines and panel 2's does not,
   so without the reserve that visible pair misaligns. The cost is one line of
   space under the orphan on row 2; the benefit is the row the visitor is actually
   comparing. Below 900px it is one column and the reserve is released.

   Also checked, because a 2-line reserve against a clamp()ed heading could
   under-reserve: the h3 is 2 lines at every width from 930 to 1100 (54 -> 64px
   against a 54.2 -> 64.1px reserve), so it never needs a third. The 3-column
   flip sits near 962px and is decided by ~2px of container width, which is why
   this is documented rather than tuned — do not move the 900px threshold to
   chase it. If this ever needs to be exact, grid-template-rows:subgrid is the
   mechanism, but it would have to be threaded through .p-body as well, since the
   heading is not a direct child of the panel. */

/* --name — a hero sub-headline that is a PERSON'S NAME rather than a sentence.
   The founder page's refresh makes the headline the vision statement and demotes
   "Jim Segrave" to the line beneath it, with the role under that. At the stock
   .lux-hero-sub size and 30px bottom margin the name read as a caption and its
   own job title floated away from it. Larger, tighter, and full white, so the
   name/role pair reads as one identification block under the headline.
   Set on .lux-hero-copy to match the specificity of the rule it overrides. */
.lux-hero-copy .lux-hero-sub--name{
  font-size:clamp(20px,2.2vw,28px);line-height:1.25;
  color:#fff;margin:0 0 10px;letter-spacing:.01em;
}

/* A link inside a display quote. The homepage's closing founder invitation is
   one paragraph whose first sentence is the link, so the anchor has to sit at
   42px inside navy copy without becoming the loudest thing in the block. It
   keeps the quote's own weight and colour and is marked by a hairline underline
   that fills in on hover — the Webflow export's global <a> colour would
   otherwise repaint it mid-sentence.

   The underline is a 35%-opacity navy, NOT --fe-blue. At 42px a bright sky-blue
   rule running the width of a two-line sentence was the loudest thing in the
   section and read as a highlighter stroke. It cannot become colour-only either:
   navy and blue-600 are too close in luminance to carry a link on hue alone
   (WCAG 1.4.1), so the line has to stay — it just has to stop shouting. */
.lux-display-quote a{
  color:inherit;text-decoration:none;
  border-bottom:1px solid rgba(0,58,112,.35);
  transition:border-color .3s ease,color .3s ease;
}
.lux-display-quote a:hover,
.lux-display-quote a:focus-visible{color:var(--fe-blue-600);border-color:var(--fe-blue-600)}

/* ---- .lux-routes: pause control, and the no-JS case ----------------------
   .lux-routes auto-advances every 5 seconds (js/lux-routes.js, DWELL_SECONDS).
   Moving content that runs longer than 5s needs a pause mechanism to satisfy
   WCAG 2.2.2, and the widget shipped without one that anybody could reach: the
   script pauses on mouseenter and on focusin, but every element it builds is a
   <p>, so there is nothing focusable inside it and focusin could never fire.
   Touch and keyboard users had no way to stop it. prefers-reduced-motion is
   honoured by the script, which helps some people and does not discharge 2.2.2.

   So the widget now carries a real toggle button. Placed bottom-right over the
   photo half, which is either a scrimmed photograph or the navy/blue gradient
   fallback — dark either way, so the white-on-transparent treatment
   .lux-carousel-toggle already defines is correct here and is reused rather than
   restyled. z-index clears .lux-routes-slide.is-active (2) and sits under
   .lux-routes-progress (5).

   The no-JS case is no longer :empty. The button lives inside the container, so
   :empty would never match once the markup carries it — and hiding the widget
   alone left its section heading ("We'll meet you where you are.") standing over
   nothing. The section itself is now `hidden` in the markup and revealed by the
   script once slides exist, which is the pattern .lux-news on the homepage
   already uses, and it also removes the 520px box materialising after first
   paint as a CLS hit. */
.lux-routes-toggle{
  position:absolute;right:20px;bottom:18px;z-index:4;
}
@media (max-width:900px){
  /* The photo band moves to the top and shrinks to 220px on mobile, so the
     bottom-right corner is over the copy column's white ground, where a white
     button on transparent is invisible. Move it onto the photo band. */
  .lux-routes-toggle{top:18px;right:14px;bottom:auto}
}

/* Partner mark inside a .lux-band's centred copy — the AeroAngel logo above the
   "Life-Saving Flights" headline. The band's copy column is text-align:center,
   so the image only needs a block context and a cap; the mark is white-safe
   artwork on a scrimmed photograph.

   230px, not the 190px first tried: at 190 the mark read as a small credit line
   rather than as the partner whose name makes the claim credible, and it is the
   only object in the frame it sits on. */
.lux-band-logo{display:block;width:auto;max-width:230px;height:auto;margin:0 auto 24px}
@media (max-width:700px){
  .lux-band-logo{max-width:170px;margin-bottom:18px}
}

/* ---- .lux-band--subject — a band whose photograph has someone in it ---------
   The stock .lux-band centres its copy and puts the darkest part of the scrim
   at 50%/50%, which is right when the frame is scenery: the copy sits on the
   quietest part of the picture and nothing is lost behind it. It is wrong the
   moment the picture has a subject, because the subject is almost always
   centred too — so the copy lands on exactly the thing the photograph was
   chosen for.

   That is what happened when the home page's AeroAngel band took a photograph
   of a child walking to the airstairs: she rendered directly under the "Learn
   More" button, under the darkest point of the radial scrim, and the band read
   as an empty ramp at sunset. This modifier moves the copy off her rather than
   moving her off the page.

   Copy to the right, subject to the left. Not the reverse: the child in this
   frame walks left-to-right toward the aircraft, so leaving her on the left
   means she is walking INTO the copy rather than out of the frame.

   object-position:100% 100% — bottom-right — is doing more work than it looks.
   Horizontally, right-aligning the crop is what makes the clearance survive a
   narrow window: the band is ~3:1 and the source is 3.11:1, so which part of
   the frame is dropped changes fast with viewport width. Centred, the subject
   drifted back under the copy everywhere below ~1400px. Right-aligned, the
   discarded strip is the empty foreground ramp on the left and she stays put.
   Vertically it only bites past ~1750px, where min-height's 560px cap makes the
   band shorter than the scaled image: centred there, the crop took her legs off
   at the shin. Bottom-aligning spends that crop on sky instead.

   The scrim is rebuilt to match — the radial moved to 76% and a left-to-right
   linear added, so the dark weight follows the copy and the left third of the
   frame stays open. Contrast over the copy is unchanged; it is the same
   treatment, re-aimed.

   margin-right: the clamp() is right up to ~1625px, but because the scrim's
   ellipse is percentage-based (76%) and the margin is capped at 80px, an
   ultrawide monitor carries the copy past the dark weight and out to the
   screen edge. The max() second term keeps the copy's horizontal centre on
   the 76% line instead: 24vw - 310px (half the 620px block). It overtakes the
   clamp exactly where 24vw - 310px = 80px, so laptop widths are pixel-for-
   pixel unchanged. */
.lux-band--subject{justify-content:flex-end}
.lux-band--subject .lux-band-copy{max-width:620px;margin-right:max(clamp(20px,5vw,80px),24vw - 310px)}
.lux-band--subject > img{object-position:100% 100%}
.lux-band--subject::after{
  background:
    radial-gradient(ellipse 62% 88% at 76% 50%,rgba(0,25,50,.78) 0%,rgba(0,25,50,.55) 58%,rgba(0,25,50,.20) 100%),
    linear-gradient(90deg,rgba(0,25,50,0) 30%,rgba(0,25,50,.42) 100%);
}

/* Below ~900px there is no "beside": the copy needs the full width, so nothing
   can sit next to it. The subject moves BELOW the copy instead — the band grows
   to 600px, the copy sets to the top, and the crop bottom-aligns so the lower
   third of the band is the subject, clear of the type. 600px is the measured
   fit: the copy block runs ~340px at 390px wide, and at 600 the child clears it
   head-to-toe. Shorter and the button sits on her again.

   The scrim flips with the layout — an ellipse at 20% down, weighted to the top
   where the copy now is, and a vertical wash instead of a horizontal one. */
@media (max-width:900px){
  .lux-band--subject{justify-content:center;align-items:flex-start;min-height:600px}
  .lux-band--subject .lux-band-copy{max-width:760px;margin-right:0;padding-bottom:0}
  .lux-band--subject > img{object-position:44% bottom}
  .lux-band--subject::after{
    background:
      radial-gradient(ellipse 110% 46% at 50% 20%,rgba(0,25,50,.84) 0%,rgba(0,25,50,.60) 60%,rgba(0,25,50,.22) 100%),
      linear-gradient(180deg,rgba(0,25,50,.58) 0%,rgba(0,25,50,.14) 52%,rgba(0,25,50,.34) 100%);
  }
}

/* --overlogo — an eyebrow that labels a .lux-band-logo sitting below it
   ("Our Featured Partner" above the AeroAngel mark on the home page).

   It exists because .lux-band-copy p sets body-copy size and margin at 0,1,1,
   which outranks the single-class .lux-eyebrow: the label rendered at 17px with
   the eyebrow's 5.44px tracking, measuring 632px wide against a 230px logo, so
   the label shouted over the mark it introduces. Written as p.lux-eyebrow--*
   (0,2,1) to win that fight by class count rather than with !important, and
   scoped to this modifier so the band eyebrows already shipped on charter,
   fractional, jet-club, mro, about and the fleet pages keep their current
   size — restoring those is a separate, deliberate change. */
p.lux-eyebrow--overlogo{font-size:12px;line-height:1.4;margin:0 0 18px}

/* ---- .is-entry — the light counterpart to .is-featured's head band ---------
   In a .lux-tier-pair, .is-featured fills its .t-head navy with 22/24 padding
   while the sibling head keeps the stock treatment: no fill, no inset, a
   hairline underneath. Side by side that is not two tiers, it is one card and
   one column of loose text — the heads start at the same y but the type sits
   24px further left, the band measures 116px against 145px, and only one of
   them looks like a thing you can compare.

   So .is-entry gives the other head the same object at a lighter value: canvas
   fill, hairline box, same type sizes (the h3/.t-price/.t-note rules are shared
   and untouched). The two heads now read as one component in two states.

   Padding is 21/24/22, not 22/24, because the box is bordered on all four sides
   and .is-featured is bordered only on the bottom. 1+21+content+22+1 equals
   22+content+22+1, so both bands measure identically off the same content — and
   the content matches too, now that Entry also carries a badge on its h3 line.
   Adjust these together or the pair drifts by a pixel. */
.lux-tier-card.is-entry .t-head{
  background:var(--fe-canvas);
  border:1px solid var(--fe-line);
  padding:21px 24px 22px;
}
/* The badge inverts with the band. .is-featured flips .is-solid to white-on-navy
   (rule above); on the light band the stock navy-on-white .is-solid is already
   right, so this needs no rule — it is noted here so the pair is not "fixed"
   later by adding one. */

/* ---- .lux-share — the hours-to-share calculator (fractional.html #shares) ---
   Two halves of one sentence: on the left the input (how many hours you fly a
   year), on the right the answer as a navy card (what share of an aircraft that
   is). The share ladder is linear — 50 hours is 6.25%, and every extra 25 hours
   is another 3.125% — so a slider states the whole product in one gesture where
   the prose could only state one rung of it.

   Read-only fallback: with JS off the markup still renders a correct, static
   100-hour / 12.5% answer. Nothing here is hidden by default and the two
   position-dependent values (--lux-share-pos on the input, the inline width on
   .lux-share__fill) are seeded in the HTML to match value="100". Keep those
   three numbers in step if the default hours ever change. */
.lux-share{display:grid;gap:clamp(34px,4.5vw,64px);align-items:center}
@media (min-width:900px){.lux-share{grid-template-columns:1fr 1fr}}

.lux-share__label{
  font-size:11px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;
  color:var(--fe-slate);margin:0 0 14px;
}
/* Review 2026-08-07 · 68 — label left, live value right, on one baseline.
   The row owns the 14px the label used to carry itself; leaving it on the label
   would push the two apart by that much and break the baseline. */
.lux-share__labelrow{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  margin:0 0 14px;
}
.lux-share__labelrow .lux-share__label{margin:0}
/* Reads as a value, not as another label: same navy and weight as the card's
   percentage, sized to sit under the section heading rather than compete. */
.lux-share__value{
  margin:0;flex:none;
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(20px,1.9vw,26px);line-height:1;
  color:var(--fe-navy);font-variant-numeric:tabular-nums;
}
.lux-share__scale{
  display:flex;justify-content:space-between;margin-top:10px;
  font-size:12px;color:var(--fe-slate);
}

/* The slider. Native range widgets disagree across engines about track height,
   thumb size and whether the filled portion is drawn at all, so all three are
   authored here rather than left to accent-color. Blink/WebKit get the fill as a
   hard-stop gradient on the track driven by --lux-share-pos (JS writes it);
   Firefox has ::-moz-range-progress and needs no variable. */
.lux-share__range{
  -webkit-appearance:none;appearance:none;
  display:block;width:100%;height:22px;margin:0;padding:0;
  background:transparent;border:0;cursor:pointer;
}
.lux-share__range::-webkit-slider-runnable-track{
  height:3px;border:0;
  background:linear-gradient(to right,
    var(--fe-navy-900) 0 var(--lux-share-pos,14.29%),
    var(--fe-line) var(--lux-share-pos,14.29%) 100%);
}
.lux-share__range::-moz-range-track{height:3px;border:0;background:var(--fe-line)}
.lux-share__range::-moz-range-progress{height:3px;border:0;background:var(--fe-navy-900)}
/* margin-top is (track 3px - thumb 16px) / 2. Adjust both together or the thumb
   stops sitting on the track in Blink. */
.lux-share__range::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:16px;height:16px;margin-top:-6.5px;border:0;border-radius:0;
  background:var(--fe-navy-900);
  box-shadow:0 0 0 0 rgba(0,39,77,.12);
  transition:box-shadow .18s ease;
}
.lux-share__range::-moz-range-thumb{
  width:16px;height:16px;border:0;border-radius:0;
  background:var(--fe-navy-900);
}
.lux-share__range:hover::-webkit-slider-thumb,
.lux-share__range:active::-webkit-slider-thumb{box-shadow:0 0 0 6px rgba(0,39,77,.12)}
@media (prefers-reduced-motion:reduce){
  .lux-share__range::-webkit-slider-thumb{transition:none}
}
/* The global input:focus rule paints a 1px box-shadow ring, which on a slider
   frames the whole 100%-wide control. Killed here; the site-wide :focus-visible
   outline still marks keyboard focus. */
.lux-share__range:focus{box-shadow:none}

.lux-share__card{background:var(--fe-navy-900);padding:clamp(34px,4vw,52px) clamp(28px,3.5vw,48px)}
.lux-share__pct{
  font-weight:300;font-size:clamp(46px,6vw,64px);line-height:1;
  color:#fff;margin:0;font-variant-numeric:tabular-nums;
}
.lux-share__detail{font-size:14px;line-height:1.6;color:var(--fe-blue-200);margin:12px 0 30px}
.lux-share__note{font-size:13px;line-height:1.7;color:var(--fe-blue-200);margin:26px 0 0}

/* The meter is the whole aircraft, ticked into sixteenths — one tick per 6.25%,
   which is exactly the smallest share sold. So the fill is not an abstract
   progress bar: it is a count of minimum shares. It tops out near half the
   width by design, because the largest share on the slider is half an aircraft;
   the empty remainder is the part you are explicitly not buying. */
.lux-share__meter{
  position:relative;height:12px;
  background-color:rgba(255,255,255,.12);
  background-image:repeating-linear-gradient(90deg,
    rgba(255,255,255,.28) 0 1px,transparent 1px 6.25%);
}
.lux-share__fill{
  position:absolute;top:0;bottom:0;left:0;
  background:var(--fe-blue);transition:width .2s ease;
}
@media (prefers-reduced-motion:reduce){.lux-share__fill{transition:none}}

/* ============================================================
   R · SPLIT BENEFIT LIST  (.lux-splitlist)
   ------------------------------------------------------------
   UNUSED as of 2026-08-11. Its only page was jet-club.html, whose
   "Benefits Overview" band was absorbed into .lux-ledger (section
   Z). Kept rather than deleted because the arrangement is a
   generic one — a ruled label list against a full-bleed photo —
   and it is the light sibling of .lux-splitform, which four pages
   do use. If it is still unreferenced at the next sweep, delete it
   along with images/jc-benefits-cl350*.jpg.

   Photography edge-to-edge on one half, a ruled list of short
   benefit labels on the other. The light-ground sibling of
   .lux-splitform in section P — same full-bleed two-track shape,
   same media handling — but the panel is paper, not navy, and it
   carries a list instead of a form.

   Why a component and not .lux-split: .lux-split lives inside a
   .lux-wrap and sets its image an aspect-ratio, so the photo is a
   framed 4:3 block sitting in a gutter. This band's photo is a
   surface that runs to the viewport edge and takes its height from
   the copy beside it, which is a cover crop in a grid track — the
   .lux-splitform arrangement, not the .lux-split one.

   Why not .lux-ticklist for the rows: a ticklist is a run of 14.5px
   lines set close, read as a group. These are four 19px statements
   on hairlines with 22px of air above and below each — a table of
   contents, read one at a time. Different rhythm, different rule.

   Specificity, the same three traps section P documents:
   - the h2 carries NO class, so `h1[class],h2[class]` in section 1
     cannot reach it and a bare descendant rule is enough.
   - the jc25 pages' `.jc25 :where(p)` reset (0,1,0) lands after this
     file, so every paragraph rule here is written `p.<class>` to
     clear it. The band is currently used outside that wrapper, but
     the cost of being safe is one element selector.
   - the Webflow export's bare `p{max-width:900px}` is why the lead
     sets its own measure rather than inheriting one.
   ------------------------------------------------------------ */

.lux-splitlist{
  display:grid;
  grid-template-columns:1fr 1fr;
  align-items:stretch;
  background:var(--fe-paper);
  /* A floor, not a height: past four rows the copy column is the
     taller track and sets the band. At four it is not, and without
     this the photo collapses to ~440px and the band reads as a
     wide strip rather than a surface. */
  min-height:640px;
  overflow:hidden;
}
/* Grid items default to a min-content minimum width, so one long
   unbreakable label would size its track to itself and push the band
   past the viewport. Same guard as .lux-splitform. */
.lux-splitlist__media,
.lux-splitlist__panel{min-width:0}

/* ---- MEDIA SIDE ------------------------------------------- */
.lux-splitlist__media{position:relative;overflow:hidden}
.lux-splitlist__media img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
}
/* One raking wash off the top-left so the photo has a direction into
   the copy and its bright sky does not sit at full strength against
   white. On ::after, not ::before — an ::before on the same element
   paints under the positioned <img>. */
.lux-splitlist__media::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(115deg,rgba(0,39,77,.42) 0%,rgba(0,39,77,.08) 60%);
}

/* ---- COPY SIDE -------------------------------------------- */
.lux-splitlist__panel{
  padding:clamp(56px,5vw,88px) clamp(48px,5vw,80px);
  display:flex;flex-direction:column;justify-content:center;
}
/* The measure cap, and the reason there is an __inner at all — same job and
   same figure as .lux-splitform__inner. Without it the hairline rows run the
   full half-viewport, which on a 3440px display is a 1550px rule under four
   words. Centred in the track so the copy stays optically opposite the photo
   rather than hard against the seam. */
.lux-splitlist__inner{width:100%;max-width:620px;margin:0 auto}
.lux-splitlist p.lux-splitlist__eyebrow{
  margin:0 0 18px;
  font-family:var(--lux-font);font-weight:600;font-size:12px;
  letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;
  color:var(--fe-blue-600);
}
.lux-splitlist__panel h2{
  margin:0 0 14px;
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,3.2vw,40px);line-height:1.12;letter-spacing:.01em;
  color:var(--fe-navy-900);text-wrap:balance;
}
.lux-splitlist p.lux-splitlist__lead{
  margin:0 0 40px;max-width:46ch;
  font-family:var(--lux-font);font-size:16.5px;line-height:1.75;
  color:var(--fe-slate);text-wrap:pretty;
}

/* ---- THE LIST --------------------------------------------- */
/* Hairline above every row plus one below the last, so the run is a
   closed block rather than four lines trailing off. */
.lux-splitlist__rows{list-style:none;margin:0;padding:0}
.lux-splitlist__rows li{
  display:flex;gap:20px;align-items:center;
  /* The Webflow export ships a bare `li{margin:4px 0 4px 36px}`. Zeroing the
     ul's padding is not enough: the 36px is on the ITEM, so the hairlines
     started 36px right of the heading they belong under, and the 4px vertical
     margins opened a gap between every rule and the next. */
  margin:0;
  padding:22px 0;
  border-top:1px solid var(--fe-line);
  font-family:var(--lux-font);font-weight:400;
  font-size:19px;line-height:1.4;color:var(--fe-ink);
  overflow-wrap:break-word;
}
.lux-splitlist__rows li:last-child{border-bottom:1px solid var(--fe-line)}
/* The flyExclusive mark as the bullet. An 80px source at 22px, so it
   stays sharp at 2x/3x; alt="" because it is ornament, and the row's
   text is the whole content. */
.lux-splitlist__rows img{
  flex:none;width:22px;height:22px;object-fit:contain;
}

.lux-splitlist__cta{margin-top:36px}

/* ---- NARROW ----------------------------------------------- */
/* 900px, not the library's usual 860: the copy column's own padding
   (up to 80px a side) plus a 19px row is what runs out of width here,
   and it does so before the shared breakpoint. */
@media (max-width:900px){
  .lux-splitlist{grid-template-columns:1fr;min-height:0}
  /* Nothing above sizes the photo once it is no longer a track in a
     stretched row, so it needs an explicit band height. */
  .lux-splitlist__media{min-height:320px}
  .lux-splitlist__rows li{font-size:17px;gap:16px;padding:18px 0}
}

/* ============================================================
   Timeline hero — .lux-timeline-panorama (th-*)
   The company history as the page's HERO: a full-viewport horizontal
   accordion of milestone photograph panels. Exactly one panel is open —
   full photograph, display-size year, title, prose — and the rest
   collapse to slivers labelled by a vertical year. Pointer hover opens a
   panel (the CSS below is enough for that); js/lux-timeline-panorama.js adds
   what hover cannot express — the last hovered panel KEEPS .is-open when
   the pointer leaves, tap moves it on touch screens, and keyboard focus
   moves it too. Without JS the component still works as a pure hover
   accordion resting on the hard-coded .is-open panel.

   Interaction is hover/tap, deliberately NOT scroll: this replaces the
   scroll-pinned stepped mode of .lux-timeline-split on about.html, where
   eight milestones cost eight steps of pinned scrolling to read. Here the
   whole history is one glance and any milestone is one hover away.

   Below 860px the same accordion turns vertical: closed panels become
   year-labelled bands and the open one expands between them. All copy is
   in the DOM and only visually collapsed (opacity), so screen readers
   read the full history regardless of which panel is open. */
.lux-timeline-panorama{
  position:relative;
  display:flex;flex-direction:column;
  min-height:100vh;min-height:100svh;
  background:var(--fe-navy-900);
  overflow:hidden;
}

/* ---- Drifting sky — .th-sky ------------------------------------------
   SHARED. Written for the About timeline and now also the homepage's
   .fx-why band, hence the :is() on every selector in this block. Both
   scopes are a single class, so the specificity is unchanged from the
   panorama-only version it replaced. Everything else prefixed .th- stays
   scoped to .lux-timeline-panorama — those are that component's own
   layout, and only the weather is portable.

   Adding a third user means: give it position:relative, put the
   .th-sky markup first inside it, and set the three --a/--b/--c `top`
   values for that band's height (see the .fx-why overrides).

   The navy band above the panels was flat ground. This puts weather in
   it: three cloud layers crossing left over ~3.5-5 minutes, so the
   backdrop is alive without ever asking to be watched. Same art and the
   same near-imperceptible pace as the flight-time evaluator at
   apps.flyexclusive.com/flighttimes, retuned for a dark sky.

   The clouds run the FULL height of the section, not just the head band.
   The panels are opaque photographs, so a cloud reaching them simply
   slides behind the strip — the top edge of the panels reads as a
   horizon, which is why no bottom fade is needed.

   Tinting: the source PNGs are white cumulus painted for a pale daylit
   sky, and white-on-navy reads as smoke. So the PNG is used as a MASK
   over a blue gradient fill instead of as an image — top-lit pale blue
   falling to a deeper navy-blue underside, which is how cloud reads at
   altitude. @supports keeps the plain-image version for anything without
   mask support; there the clouds are simply white and slightly dimmer.

   Cost: three composited layers translating on the GPU. The blur and the
   mask sit on the inner <i>, which never changes, so the expensive
   raster happens once and the animation only moves the finished layer. */
:is(.lux-timeline-panorama,.fx-why) .th-sky{
  position:absolute;inset:0;z-index:0;
  overflow:hidden;pointer-events:none;
  /* Nothing inside affects layout or paints outside — lets the browser
     skip the whole subtree when the hero is off screen. */
  contain:strict;
}
/* Atmosphere: the band lifts very slightly toward the horizon, the way
   sky does just above a cloud deck. Sits under the clouds. */
:is(.lux-timeline-panorama,.fx-why) .th-sky::before{
  content:"";position:absolute;inset:0;
  background:radial-gradient(120% 62% at 50% 6%, rgba(96,146,201,.22), rgba(96,146,201,0) 70%);
}
:is(.lux-timeline-panorama,.fx-why) .th-cloud{
  position:absolute;left:0;
  will-change:transform;
  /* One shared pass for every cloud: enter just off the right edge,
     leave fully past the left. Percentages in the end state resolve
     against the cloud's OWN width, so one keyframe fits all three sizes.
     Negative delays below start each one mid-crossing, spread across the
     viewport, so the first paint is already a composed sky. */
  animation:th-cloud-drift linear infinite;
}
:is(.lux-timeline-panorama,.fx-why) .th-cloud>i{
  display:block;width:100%;height:100%;
  background:var(--th-cloud) center/contain no-repeat;
  /* A hair of blur is what stops a 1x cut-out from showing its edge
     against flat navy. Static, so it rasterises once. */
  filter:blur(1.2px);
  /* Independent of the drift because the parent owns translateX; a slow
     alternating rise and fall keeps the clouds from reading as decals. */
  animation:th-cloud-bob ease-in-out infinite alternate;
}
@supports ((-webkit-mask-image:url("#")) or (mask-image:url("#"))){
  :is(.lux-timeline-panorama,.fx-why) .th-cloud>i{
    background:linear-gradient(180deg,rgba(214,232,250,.95) 0%,rgba(150,186,224,.72) 46%,rgba(84,124,172,.5) 100%);
    -webkit-mask:var(--th-cloud) center/contain no-repeat;
    mask:var(--th-cloud) center/contain no-repeat;
  }
}
/* Three sizes, three heights, three speeds with no common factor, so the
   arrangement never repeats within a visit. aspect-ratio carries each
   PNG's own proportions, so only the width needs stating. */
:is(.lux-timeline-panorama,.fx-why) .th-cloud--a{
  --th-cloud:url("../images/luxury/lux-cloud-a.png");
  top:9vh;width:clamp(300px,42vw,700px);aspect-ratio:694/216;opacity:.17;
  animation-duration:210s;animation-delay:-58s;
}
:is(.lux-timeline-panorama,.fx-why) .th-cloud--b{
  --th-cloud:url("../images/luxury/lux-cloud-b.png");
  top:5vh;width:clamp(150px,17vw,280px);aspect-ratio:266/140;opacity:.13;
  animation-duration:260s;animation-delay:-120s;
}
:is(.lux-timeline-panorama,.fx-why) .th-cloud--c{
  --th-cloud:url("../images/luxury/lux-cloud-c.png");
  top:16vh;width:clamp(340px,52vw,860px);aspect-ratio:847/315;opacity:.2;
  animation-duration:300s;animation-delay:-192s;
}
:is(.lux-timeline-panorama,.fx-why) .th-cloud--a>i{animation-duration:23s}
:is(.lux-timeline-panorama,.fx-why) .th-cloud--b>i{animation-duration:31s}
:is(.lux-timeline-panorama,.fx-why) .th-cloud--c>i{animation-duration:27s}
@keyframes th-cloud-drift{
  from{transform:translate3d(105vw,0,0)}
  to{transform:translate3d(-100%,0,0)}
}
@keyframes th-cloud-bob{
  from{transform:translate3d(0,-7px,0)}
  to{transform:translate3d(0,7px,0)}
}
/* The head, panels and rail all sit above the sky. Only the head needs
   it visually — the panels are opaque — but stating it on all three
   keeps the stacking order explicit rather than positional. */
.lux-timeline-panorama .th-head,
.lux-timeline-panorama .th-panels,
.lux-timeline-panorama .th-rail{position:relative;z-index:1}

/* Top padding pays for the fixed transparent header (~76-100px). */
.lux-timeline-panorama .th-head{
  padding:clamp(96px,14vh,140px) clamp(20px,4vw,44px) clamp(18px,3vh,30px);
  text-align:center;
}
/* .lux-eyebrow is a constrained-width block; without auto margins its
   centred TEXT sits in a left-pinned box under the centred heading. */
.lux-timeline-panorama .th-head .lux-eyebrow{margin-left:auto;margin-right:auto}
.lux-timeline-panorama .th-head h1{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,4.4vw,52px);line-height:1.08;letter-spacing:.01em;
  color:#fff;margin:0;text-wrap:balance;
}
.lux-timeline-panorama .th-sub{
  font-family:var(--lux-font);font-weight:400;
  font-size:clamp(14px,1.25vw,17px);line-height:1.55;
  color:var(--fe-blue-200);
  max-width:60ch;margin:10px auto 0;
}
.lux-timeline-panorama .th-panels{
  list-style:none;margin:0;
  /* no bottom inset of its own — the .th-rail strip below carries it;
     the <860px block restores it where the rail is hidden */
  padding:0 clamp(12px,2vw,24px);
  display:flex;gap:5px;
  flex:1;min-height:0;
}
/* margin:0 beats the Webflow export's bare li{margin:4px 0 4px 36px}. */
.lux-timeline-panorama .th-panels>li{
  position:relative;overflow:hidden;
  flex:1 1 0;min-width:0;margin:0;
  cursor:pointer;
  /* Free here (already relative + overflow:hidden) and keeps each panel's
     0.7s flex relayout from invalidating layout outside itself. */
  contain:layout paint;
  transition:flex-grow .7s cubic-bezier(.22,1,.36,1);
}
/* The panel expanding is the focus indicator, which shows nothing when the
   focused panel is ALREADY the open one — always true of the first Tab stop.
   Inset ring because overflow:hidden clips an outset one. */
.lux-timeline-panorama .th-panels>li:focus-visible{outline:2px solid var(--fe-blue-300);outline-offset:-3px}
/* One shared expansion figure. 4.6 gives the open panel ~540px on a
   1440px screen — room for the 46ch prose column — while seven closed
   panels keep ~120px each, enough for their photograph to read.

   ---- Why :hover is quarantined to :not(.th-js) ------------------------
   The script stamps .th-js on the root. Where it ran, .is-open is the
   ONLY thing that moves geometry; where it did not, bare :hover is.
   Having both live at once is what made the progress rail lie: a panel
   expanded by :hover alone is one the rail cannot follow (the rail has
   no hover state of its own — it mirrors .is-open), so any moment the
   two triggers disagree, the markers sit off their panels' centres. The
   two known disagreements were the scroll guard below (which suppresses
   the JS open but could not suppress :hover, and the pointer then rests
   there indefinitely without re-firing mouseenter) and panels sliding
   under a stationary cursor generally. One driver, no lie. */
.lux-timeline-panorama .th-panels>li.is-open,
.lux-timeline-panorama .th-panels>li:focus-visible{flex-grow:4.6}
.lux-timeline-panorama:not(.th-js) .th-panels>li:hover{flex-grow:4.6}
/* While some OTHER panel is hovered, the resting open one gives its
   space back, so the no-JS fallback reads as an accordion rather than
   two panels fighting. Not needed with JS — open() moves .is-open off
   the old panel itself.
   :has(>li:hover), NOT .th-panels:hover: the list's own hover is also
   true over its flex gaps and bottom padding, where no panel is hovered
   — there the rule would collapse all eight panels while the open one's
   copy stayed visible and got clipped mid-word. */
.lux-timeline-panorama:not(.th-js) .th-panels:has(>li:hover)>li.is-open:not(:hover):not(:focus-visible){flex-grow:1}
.lux-timeline-panorama .th-panels img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;
  transition:transform .7s cubic-bezier(.22,1,.36,1);
}
.lux-timeline-panorama .th-panels>li.is-open img{transform:scale(1.02)}
/* Legibility gradient, always on; the closed veil sits on top of it. */
.lux-timeline-panorama .th-scrim{
  position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(0,25,50,.28) 0%,rgba(0,25,50,.12) 40%,rgba(0,25,50,.72) 82%,rgba(0,25,50,.86) 100%);
}
/* Closed panels sit behind an extra navy veil so the open photograph is
   the one carrying colour. A pseudo-element, not a filter: filters on
   eight 100vh images are a paint cost hover would pay every frame. */
.lux-timeline-panorama .th-panels>li::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:rgba(0,39,77,.48);
  transition:opacity .55s ease;
}
.lux-timeline-panorama .th-panels>li.is-open::after,
.lux-timeline-panorama .th-panels>li:focus-visible::after{opacity:0}
.lux-timeline-panorama:not(.th-js) .th-panels>li:hover::after{opacity:0}
/* Closed label: the year set vertically, reading bottom-to-top, pinned
   to the foot of the sliver. */
.lux-timeline-panorama .th-tab{
  position:absolute;left:50%;bottom:20px;transform:translateX(-50%) rotate(180deg);
  writing-mode:vertical-rl;
  font-family:var(--lux-font);font-weight:400;
  /* line-height pinned: the export's bare p rule sets 200%, a 30px-thick
     line box that would drift the year off-centre if the sliver narrowed. */
  font-size:15px;line-height:1;letter-spacing:.14em;
  color:rgba(255,255,255,.92);
  margin:0;z-index:2;
  transition:opacity .35s ease;
}
.lux-timeline-panorama .th-panels>li.is-open .th-tab,
.lux-timeline-panorama .th-panels>li:focus-visible .th-tab{opacity:0}
.lux-timeline-panorama:not(.th-js) .th-panels>li:hover .th-tab{opacity:0}
/* Open copy. Fixed width so the text does NOT rewrap while the panel
   animates — it is clipped by the panel while closed and revealed whole. */
.lux-timeline-panorama .th-copy{
  position:absolute;left:0;bottom:0;z-index:2;
  width:clamp(300px,32vw,470px);max-width:none;
  padding:clamp(18px,2.2vw,32px);
  opacity:0;transform:translateY(14px);
  transition:opacity .3s ease,transform .55s cubic-bezier(.22,1,.36,1);
}
.lux-timeline-panorama .th-panels>li.is-open .th-copy,
.lux-timeline-panorama .th-panels>li:focus-visible .th-copy,
.lux-timeline-panorama:not(.th-js) .th-panels>li:hover .th-copy{
  opacity:1;transform:none;
  transition:opacity .4s ease .18s,transform .6s cubic-bezier(.22,1,.36,1) .12s;
}
.lux-timeline-panorama .th-year{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(40px,4vw,62px);line-height:1;letter-spacing:.01em;
  color:#fff;margin:0 0 10px;
}
.lux-timeline-panorama .th-title{
  font-family:var(--lux-font);font-weight:400;
  font-size:clamp(16px,1.4vw,19px);line-height:1.35;
  color:#fff;margin:0 0 8px;max-width:34ch;
}
.lux-timeline-panorama .th-body{
  font-family:var(--lux-font);font-weight:400;
  font-size:13.5px;line-height:1.65;
  color:rgba(255,255,255,.85);margin:0;max-width:46ch;
}
/* "Today" carries the same current-milestone accent the rail timelines
   use — the sky blue that marks now. */
.lux-timeline-panorama .th-panels>li.is-current .th-tab,
.lux-timeline-panorama .th-panels>li.is-current .th-year{color:var(--fe-blue-300)}
/* ---- Progress rail ---------------------------------------------------
   The horizontal counterpart of the split timeline's centre rail: a
   hairline under the panels through one turbine marker per milestone,
   blue up to the open milestone and quiet past it. The cells carry the
   panels' EXACT flex values and transition, so each marker rides the
   centre of its panel while the accordion animates — no measurement, no
   rAF chasing, which the vertical rail needed for the same job.
   js/lux-timeline-panorama.js mirrors .is-open onto the cells and lets
   them open their panel on hover/click; without JS the rail rests on the
   hard-coded open panel. aria-hidden in the markup — it restates the
   panel list — so it is deliberately not focusable. */
.lux-timeline-panorama .th-rail{
  list-style:none;
  display:flex;gap:5px;
  margin:0;
  padding:2px clamp(12px,2vw,24px) clamp(10px,1.8vh,18px);
}
.lux-timeline-panorama .th-rail>li{
  position:relative;
  flex:1 1 0;min-width:0;margin:0;
  height:36px;
  cursor:pointer;
  transition:flex-grow .7s cubic-bezier(.22,1,.36,1);
}
.lux-timeline-panorama .th-rail>li.is-open{flex-grow:4.6}
/* The line, drawn as one segment either side of each marker. Left
   segments start 5px early so the flex gaps never show as holes; the
   span is trimmed to first-marker → last-marker like the vertical rail
   (no hairline hanging past the end turbines). */
.lux-timeline-panorama .th-rail>li::before,
.lux-timeline-panorama .th-rail>li::after{
  content:"";position:absolute;top:50%;height:1px;margin-top:-.5px;
  background:var(--fe-blue);
  /* The fill boundary crosses cells while the panels are still gliding;
     without this it snaps a step ahead of the geometry. */
  transition:background-color .35s ease;
}
/* The rail mirrors .is-open and has no hover state of its own, so with
   no JS to move .is-open it would sit on the first milestone while the
   panels hover-expand around it — pointing at the wrong one. It is
   decorative; absent beats wrong. (The script is deferred, so .th-js
   lands before first paint and this never flashes.) */
.lux-timeline-panorama:not(.th-js) .th-rail{display:none}
.lux-timeline-panorama .th-rail>li::before{left:-5px;right:50%}
.lux-timeline-panorama .th-rail>li::after{left:50%;right:0}
.lux-timeline-panorama .th-rail>li:first-child::before,
.lux-timeline-panorama .th-rail>li:last-child::after{display:none}
/* Everything past the open milestone goes quiet: its own right half,
   and both halves of every later cell. */
.lux-timeline-panorama .th-rail>li.is-open::after,
.lux-timeline-panorama .th-rail>li.is-open~li::before,
.lux-timeline-panorama .th-rail>li.is-open~li::after{background:rgba(255,255,255,.25)}
/* Turbine marker, same art as the vertical rails. The disc behind it is
   navy-900 — the hero's own ground — masking the line where it would
   show through the turbine's open centre (the paper disc trick from
   .lux-timeline-split, in this component's colour). */
.lux-timeline-panorama .th-mark{
  position:absolute;left:50%;top:50%;z-index:2;
  width:18px;height:18px;margin:-9px 0 0 -9px;border-radius:50%;
  background:var(--fe-navy-900) url("../images/turbine-sky.png") center/contain no-repeat;
  transition:transform .7s cubic-bezier(.22,1,.36,1);
}
.lux-timeline-panorama .th-rail>li:hover .th-mark{transform:scale(1.2)}
.lux-timeline-panorama .th-rail>li.is-open .th-mark{transform:scale(1.4)}
/* Today keeps the current-milestone ring. outline follows border-radius,
   so it draws as a circle around the disc. */
.lux-timeline-panorama .th-rail>li.is-current .th-mark{
  outline:1px solid var(--fe-blue-300);outline-offset:3px;
}

@media (prefers-reduced-motion:reduce){
  .lux-timeline-panorama .th-panels>li,
  .lux-timeline-panorama .th-panels img,
  .lux-timeline-panorama .th-panels>li::after,
  .lux-timeline-panorama .th-tab,
  .lux-timeline-panorama .th-copy,
  .lux-timeline-panorama .th-rail>li,
  .lux-timeline-panorama .th-mark{transition:none}
  .lux-timeline-panorama .th-panels>li.is-open img{transform:none}
  /* paused, not none: a paused animation still resolves its negative
     delay, so the clouds freeze exactly where they would have been —
     the composed sky stays, only the motion goes. animation:none would
     drop all three back onto the left edge in a heap. */
  :is(.lux-timeline-panorama,.fx-why) .th-cloud,
  :is(.lux-timeline-panorama,.fx-why) .th-cloud>i{animation-play-state:paused}
}

/* Vertical accordion. Closed panels become year bands; the open one
   expands between them. The year tab returns to horizontal and the copy
   spans the full panel width. */
@media (max-width:860px){
  .lux-timeline-panorama .th-head{padding-top:clamp(84px,13vh,110px)}
  /* The vertical accordion leaves a shorter band, so the clouds move up
     and shrink to stay inside it. b is dropped rather than squeezed —
     three clouds in a 150px band is congestion, not weather. */
  :is(.lux-timeline-panorama,.fx-why) .th-cloud--a{top:5vh;width:min(78vw,420px);opacity:.15}
  :is(.lux-timeline-panorama,.fx-why) .th-cloud--b{display:none}
  :is(.lux-timeline-panorama,.fx-why) .th-cloud--c{top:12vh;width:min(96vw,520px);opacity:.18}
  /* No rail in the vertical accordion: the year bands ARE the index
     there, and a horizontal axis has nothing left to measure. */
  .lux-timeline-panorama .th-rail{display:none}
  .lux-timeline-panorama .th-panels{flex-direction:column;gap:4px;padding-bottom:clamp(12px,2vw,24px)}
  .lux-timeline-panorama .th-panels>li{min-height:44px}
  /* Same one-driver rule as the desktop block: bare :hover expands only
     where no script is moving .is-open. It matters on touch too — hover
     emulation sticks to the last tapped element, so an ungated rule can
     leave a panel expanded that .is-open no longer points at. */
  .lux-timeline-panorama .th-panels>li.is-open,
  .lux-timeline-panorama .th-panels>li:focus-visible{flex-grow:6.5;min-height:230px}
  .lux-timeline-panorama:not(.th-js) .th-panels>li:hover{flex-grow:6.5;min-height:230px}
  .lux-timeline-panorama .th-tab{
    left:18px;bottom:auto;top:50%;
    transform:translateY(-50%);
    writing-mode:horizontal-tb;
    font-size:14px;
  }
  .lux-timeline-panorama .th-copy{
    width:100%;padding:16px 18px;
  }
  .lux-timeline-panorama .th-year{font-size:clamp(30px,8vw,40px);margin-bottom:6px}
  .lux-timeline-panorama .th-title{font-size:15px;margin-bottom:6px}
  .lux-timeline-panorama .th-body{font-size:12.5px;line-height:1.6;max-width:none}
}

/* ============================================================
   S · NUMBERED VALUE SET  (.lux-valueset)
   ------------------------------------------------------------
   A short, fixed set of principles, numbered, with the first one
   given the width of the page and the rest paired off below it.
   Built for the five CORE values on about.html.

   Why not .lux-grid--3 of .lux-icon-card, which it replaces: those
   six equal cells said the five values and the community page were
   six interchangeable things. They are not — "Safety First" is the
   value the section's own lead sentence is about, and the community
   link is a footnote to the fifth value, not a sixth value. This
   component says that with layout: item 01 full width above the
   rule, the other four in pairs, the link inline in 05's sentence.

   The list is an <ol> because the numbers are content, not ornament.
   The visible 01/02/… are aria-hidden — the list already conveys
   order and a screen reader would otherwise say it twice.

   Two Webflow-export traps are reset below rather than worked
   around; both are on bare elements, so nothing warns you:
     ol{padding-left:40px}  and  li{margin:4px 0 4px 36px}
   ------------------------------------------------------------ */

.lux-valueset{display:block}

/* ---- HEADER ----------------------------------------------- */
/* Heading left, lead right, baselines aligned at the bottom — the
   lead is a caption to the heading, not a subtitle under it, which
   is what lets the numbered list start higher up the page. */
.lux-valueset__head{
  display:grid;grid-template-columns:1fr 1fr;
  gap:24px clamp(32px,5vw,72px);
  align-items:end;
  margin-bottom:clamp(36px,4vw,56px);
}
.lux-valueset__head > div{display:flex;flex-direction:column;gap:18px}
.lux-valueset__head h2{
  margin:0;
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,3.6vw,44px);line-height:1.12;letter-spacing:.01em;
  color:var(--fe-navy-900);text-wrap:balance;
}
.lux-valueset__head h2 em{font-style:italic;font-weight:400}
.lux-valueset p.lux-valueset__lead{
  margin:0;max-width:52ch;
  font-family:var(--lux-font);font-size:16px;line-height:1.75;
  color:var(--fe-slate);text-wrap:pretty;
}

/* ---- THE LIST --------------------------------------------- */
.lux-valueset__list{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:1fr 1fr;
  column-gap:clamp(32px,5vw,72px);
}
.lux-valueset__item{
  /* margin:0 kills the export's bare li{margin:4px 0 4px 36px} — the
     36px is on the ITEM, so zeroing the list's padding does not
     reach it and every row would sit indented off the heading. */
  margin:0;
  padding:40px 0;
  display:flex;flex-direction:column;gap:12px;
  border-bottom:1px solid var(--fe-line);
}
/* Item 01 takes the full measure and hangs its number in a column of
   its own, so the rule above it reads as the top of the set. */
.lux-valueset__item--lead{
  grid-column:1 / -1;
  display:grid;grid-template-columns:88px 1fr;gap:8px 24px;
  border-top:1px solid var(--fe-line);
}
/* The closing rule belongs under the last ROW, not the last item.
   -n+2 is the bottom pair, which is correct for the five values this
   holds; a sixth would need this rethought rather than extended. */
.lux-valueset__item:nth-last-child(-n+2){border-bottom:0}

/* ---- NUMBER ------------------------------------------------ */
/* The supplied design set the flyExclusive mark beside each number.
   Dropped 2026-08-06: five copies of the turbine down one column read
   as an ornament repeated, not a mark, and the numbers are already
   the thing that indexes the set. The number is now the whole of it. */
.lux-valueset__n{
  display:block;
  font-family:var(--lux-font);font-weight:300;font-size:28px;line-height:1;
  color:var(--fe-blue);
}
/* On the lead item the number spans both text rows in its own column,
   so align-self:start is what keeps it level with the h3 rather than
   centred against the whole two-row block. */
.lux-valueset__item--lead .lux-valueset__n{
  grid-row:span 2;align-self:start;
  font-size:34px;
}

/* ---- TEXT -------------------------------------------------- */
.lux-valueset__item h3{
  margin:0;
  font-family:var(--lux-font);font-weight:400;font-size:20px;line-height:1.3;
  color:var(--fe-navy-900);
}
.lux-valueset__item--lead h3{font-size:clamp(21px,2.2vw,24px)}
.lux-valueset p.lux-valueset__body{
  margin:0;max-width:none;
  font-family:var(--lux-font);font-size:15px;line-height:1.75;
  color:var(--fe-slate);text-wrap:pretty;
}
.lux-valueset__item--lead p.lux-valueset__body{font-size:16px;max-width:64ch}
/* The one inline link in the set. Underlined on hover only, so the
   sentence it closes is not broken by a rule through it. */
.lux-valueset__body a{
  color:var(--fe-blue-600);text-decoration:none;
  border-bottom:1px solid transparent;transition:border-color .25s ease;
}
.lux-valueset__body a:hover{color:var(--fe-navy-900);border-bottom-color:currentColor}

/* ---- NARROW ------------------------------------------------ */
@media (max-width:860px){
  .lux-valueset__head{grid-template-columns:1fr;align-items:start}
  .lux-valueset__list{grid-template-columns:1fr}
  /* One column means one item per row, so the bottom-pair rule above
     is now wrong by one — every item closes its own row except the
     last. Restoring it needs the same :nth-last-child specificity
     (0,2,0) to undo, not a bare class: a media query changes nothing
     about which rule wins. */
  .lux-valueset__item{padding:30px 0}
  .lux-valueset__item:nth-last-child(-n+2){border-bottom:1px solid var(--fe-line)}
  .lux-valueset__item:last-child{border-bottom:0}
  /* The lead item's 88px number column costs a quarter of a phone's
     measure for two glyphs; stacked it reads the same. */
  .lux-valueset__item--lead{display:flex;flex-direction:column;gap:12px}
  .lux-valueset__item--lead .lux-valueset__n{font-size:30px}
}

/* ============================================================
   SAFETY CREDENTIALS — stat-led (about.html #safety)
   Added 2026-08-06 to the supplied design. Replaces the light
   .lux-safety treatment on About: the 5% figure becomes the
   headline rather than a caption under the marks, and the five
   accreditations are demoted to a hairline-divided rail beneath it.
   .lux-safety / .lux-safety-badges / .lux-safety-claim stay in this
   file untouched — index.html still uses all three.

   Colours come from the existing on-dark pair rather than new
   tokens: --fe-blue-300 is what .lux-eyebrow--ondark already sets,
   and --fe-blue-200 is what .lux-section--navy .lux-head p already
   sets. Dividers use rgba(255,255,255,.16), the house
   hairline-on-navy value (see .lux-splitform).
   ============================================================ */
.lux-safety-stat{
  background:var(--fe-navy-900);
  padding:clamp(64px,7vw,96px) clamp(20px,5vw,72px);
}
/* Narrower than the 1180px house wrap: the figure is enormous, and at
   full width the lede beside it stretched past a comfortable measure. */
.lux-safety-stat .lux-wrap{max-width:1036px}

/* The figure and the copy are one sentence, so they share a row and are
   optically centred on each other rather than top-aligned. */
.lux-safety-stat__lead{
  display:grid;grid-template-columns:auto 1fr;
  gap:clamp(36px,5vw,72px);align-items:center;
  margin-bottom:clamp(40px,5vw,64px);
}
.lux-safety-stat__figure{
  font-family:var(--lux-font);
  font-weight:300;font-size:clamp(120px,17vw,240px);
  line-height:.9;letter-spacing:-.01em;
  color:var(--fe-blue);
}
/* (0,1,1), the same specificity as the h1[class],h2[class] navy rule near
   the top of this file, so this wins on order — it must stay after it. */
.lux-safety-stat h2{
  font-family:var(--lux-font);
  font-weight:300;font-size:clamp(28px,3.4vw,40px);line-height:1.12;
  letter-spacing:.01em;color:#fff;margin:0 0 16px;max-width:520px;
}
.lux-safety-stat__lede{
  font-family:var(--lux-font);
  font-size:clamp(15px,1.3vw,17px);line-height:1.75;
  color:var(--fe-blue-200);margin:0;max-width:480px;
}
/* Same one-phrase italic accent the headings and heroes take
   (see .lux-head h2 em) — 300 alone reads thin and accidental. */
.lux-safety-stat h2 em,
.lux-safety-stat__lede em{font-style:italic;font-weight:400}

/* ---- Credential rail --------------------------------------------------
   Five hairline-divided columns, each a mark over its name. */
.lux-safety-stat__rail{
  display:grid;grid-template-columns:repeat(5,1fr);
  border-top:1px solid rgba(255,255,255,.16);
  list-style:none;margin:0;padding:0;
}
/* margin:0 is load-bearing, not tidying. The Webflow sheet carries a bare
   `li{margin:4px 0 4px 36px}` (line ~277), which indents every column 36px
   inside its own grid track — measured: the 207px tracks gave 171px columns,
   so the plates capped at 122px instead of 150px and the rail's hairline
   dividers no longer met the content. The same rule's font-size:14px and
   font-weight:300 are overridden on .lux-safety-stat__name below. */
.lux-safety-stat__cert{
  margin:0;
  padding:28px 24px 0;
  border-right:1px solid rgba(255,255,255,.16);
}
.lux-safety-stat__cert:first-child{padding-left:0}
.lux-safety-stat__cert:last-child{padding-right:0;border-right:0}

/* The plate is a box, not a ground: transparent since 2026-08-06, so the
   marks sit directly on the navy rather than in five white cards.

   What the white ground was solving is still real, and is now solved per
   mark instead of for all five at once. Measured mean luminance of the
   opaque pixels, against a ground of ~33:

     ARG/US        140  silver seal, its dark type sits on its own silver
     Wyvern        134  a badge — the artwork carries its own light panel
     IS-BAO        106  mid-blue disc, all-white type inside it
     FlightSafety   71  blue wordmark  -> 2.3:1. reversed, see --reverse
     CAE SimuFlite  27  black wordmark -> invisible. reversed, see --reverse

   The three seals keep their own colour: they carry their text INSIDE the
   mark, so flattening them to white silhouettes (which is what --reverse
   does) would turn them into featureless discs. The two that are pure
   wordmarks lose nothing to it — a white lockup is the reversed treatment
   both brands publish for dark grounds, and the form is untouched.

   Note the Wyvern mark still shows a pale panel. That panel is baked into
   the badge artwork, not drawn here, and it is what the mark IS; the only
   way to lose it is to display a different mark.

   All five plates are one identical box. That uniform footprint plus
   object-fit:contain is what makes a 3.5:1 wordmark and a 1:1 seal read as
   one row — the same reasoning as .lux-safety-badges, which this replaces
   on About. The seals leave white to either side; that is the cost of the
   uniform box and it is the right trade.

   max-width, not a bare 100%: the flush first and last columns have wider
   content boxes than the middle three, so without a cap their two plates
   would be the odd ones out. 150px is the narrowest of the five columns at
   the 1036px wrap.

   The 150x90 box is measured, not guessed. The five marks run from 0.94:1
   (Wyvern) to 3.95:1 (FlightSafety), and one box has to serve both: the
   width is set by the widest wordmark needing to stay legible (at 126px of
   content "SimuFlite" is still readable; below ~110px it is not), and the
   height is then set so the square seals are not lost in it. At a 62px-tall
   plate the seals rendered 44px in a 126px-wide box and read as small marks
   adrift on white cards; 72px of content height brings them up to 72px, so
   both the seals and the wordmarks use most of the box they are given. */
.lux-safety-stat__plate{
  width:100%;max-width:150px;
  height:clamp(76px,7.4vw,90px);
  margin-bottom:16px;
  padding:9px 12px;
  background:transparent;
  display:flex;align-items:center;justify-content:center;
}
.lux-safety-stat__plate img{
  width:100%;height:100%;
  object-fit:contain;object-position:center;
}
/* Reversed to white: the two dark WORDMARKS only (see the note above).
   brightness(0) comes first so the source colour cannot survive as a tint —
   invert(1) on its own turns CAE's blue arrow orange. Neither step touches
   alpha, so the lockup keeps exactly the shape it had. */
.lux-safety-stat__plate--reverse img{filter:brightness(0) invert(1)}
/* Its own class, not `.lux-safety-stat__cert span`: that selector is (0,1,1)
   and would outrank .lux-safety-stat__plate (0,1,0) on the plate's own span,
   overriding its display:flex and handing it the label's type styles. */
.lux-safety-stat__name{
  display:block;font-family:var(--lux-font);
  font-size:13px;font-weight:500;letter-spacing:.14em;
  text-transform:uppercase;color:#fff;line-height:1.5;
}
/* The rail's labels are the bottom of the block, so the CTA needs more
   air under them than .lux-actions--spaced's 28px gives. */
.lux-safety-stat .lux-actions{margin-top:clamp(36px,4vw,52px)}

@media (max-width:900px){
  .lux-safety-stat__lead{grid-template-columns:1fr;gap:28px}
  .lux-safety-stat__rail{grid-template-columns:repeat(2,1fr)}
  .lux-safety-stat__cert{padding:24px 20px 0}
  .lux-safety-stat__cert:nth-child(2n){border-right:0;padding-right:0}
  .lux-safety-stat__cert:nth-child(2n+1){padding-left:0}
  /* Five into two columns leaves an orphan; let it span, as
     .lux-safety-badges already does at its own breakpoint. */
  .lux-safety-stat__cert:last-child{grid-column:1 / -1;border-right:0}
}

/* ============================================================
   PERSONALISED PROPOSAL SECTION  (.lux-proposal)
   ------------------------------------------------------------
   jet-club.html and fractional.html. Added 2026-08-06; rebuilt
   twice the same day — first to put the "How It Works" rail where
   the photograph had been, then light instead of navy.

   Two columns inside the normal .lux-wrap: the step flow on the
   left, the three steps of the process on the right. No
   photograph, and no .lux-splitform: that component is the
   full-bleed navy band, and every form rule in section P is
   scoped to it. On a light ground the flow needs none of them —
   section N's own treatment (paper card, hairline, bordered
   fields, navy chips) is the light half of the same component,
   and it is what the our-fleet pages already use.

   Both pages still close on a navy .lux-splitform, so this
   section reads as a distinct step rather than a second copy of
   the page's closing band.

   --canvas on both pages, with the flow's white card sitting on
   it: the card needs a ground it can lift off, and on paper the
   section would run into the module above it. On Jet Club the
   section BELOW is also --canvas, which is why #member-services
   now carries .lux-section--ruled.
   ------------------------------------------------------------ */
.lux-proposal__grid{
  display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:clamp(32px,4vw,64px);
  align-items:start;
}
.lux-proposal__form{min-width:0}
/* The flow is a card in its own right (section N) — paper, hairline, soft
   shadow — so this column adds nothing but the width. max-width:none: section N
   caps the card at 680px for a centred single-column page, and in a column that
   cap would leave a gap on the right at wide viewports. */
.lux-proposal .fx-discover{max-width:none}
/* Measured against the tallest step of THIS flow (the consent step) at 1280,
   1100 and 375, plus the card's own 44px padding-top. Section N's 400px is set
   for the HubSpot-derived flows, which ask more questions per step; a fixed
   height still matters here so the card does not resize under the visitor as
   they answer, and so it stays level with the rail beside it. */
.lux-proposal .fx-discover__body{min-height:424px}
/* Stacked, nothing sits beside the card for it to stay level with, and the
   consent step measures 523px on a 375px screen — pinning to that would have
   left up to 230px of empty card on every shorter step. This drops back to the
   360px floor section N sets for a phone, i.e. what the flow does on every other
   page. It has to be restated rather than left to section N: the desktop rule
   above carries two classes and would outrank it at any width. */
@media (max-width:900px){
  .lux-proposal .fx-discover__body{min-height:360px}
}
.lux-proposal p.lux-proposal__foot{
  margin:18px 0 0;
  font-family:var(--lux-font);font-weight:300;font-size:13px;line-height:1.6;
  color:var(--fe-slate);
}
.lux-proposal__foot a{
  color:var(--fe-navy);font-weight:600;text-decoration:none;
  border-bottom:1px solid rgba(0,58,112,.35);
  transition:border-color .2s ease;
}
.lux-proposal__foot a:hover{border-bottom-color:var(--fe-navy)}

.lux-proposal__aside{min-width:0;padding-top:clamp(4px,1vw,12px)}
.lux-proposal p.lux-proposal__aside-title{
  margin:0 0 clamp(22px,2.6vw,32px);
  font-family:var(--lux-font);font-weight:600;font-size:11px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--fe-blue-600);
}

@media (max-width:900px){
  /* Stacked, the rail is what follows the form rather than a column beside it. */
  .lux-proposal__grid{grid-template-columns:minmax(0,1fr);gap:clamp(36px,6vw,52px)}
  .lux-proposal__aside{padding-top:0}
}

/* ---- SLIDER QUESTIONS -------------------------------------- */
/* Two questions in the proposal flow are ranges (trips a year, average trip
   time) rather than lists: the answers are quantities with no natural bucket
   boundaries, and a chip row would have invented them.

   Geometry deliberately matches .lux-share__range, the hours-to-share slider on
   fractional.html — 3px track, 16px square thumb, and the filled portion drawn
   from a custom property because engines disagree about whether they draw one at
   all. --fx-pos is written by the script on every input event.

   No :not() chain needed to win against the global field rule the way the
   .lux-splitform inputs do: that rule already excludes [type=range] (see the
   note in section 2, which was written for .lux-share__range). */
.fx-discover__field--range{gap:0}
.fx-discover__readout{
  display:block;margin:6px 0 2px;
  font-family:var(--lux-font);font-weight:200;
  font-size:clamp(28px,2.6vw,36px);line-height:1.1;
  color:var(--fe-navy);font-variant-numeric:tabular-nums;
}
.fx-discover__range{
  -webkit-appearance:none;appearance:none;
  display:block;width:100%;height:26px;margin:0;padding:0;
  background:transparent;border:0;cursor:pointer;
}
.fx-discover__range::-webkit-slider-runnable-track{
  height:3px;border:0;
  background:linear-gradient(to right,
    var(--fe-navy) 0 var(--fx-pos,50%),
    var(--fe-line) var(--fx-pos,50%) 100%);
}
.fx-discover__range::-moz-range-track{height:3px;border:0;background:var(--fe-line)}
.fx-discover__range::-moz-range-progress{height:3px;border:0;background:var(--fe-navy)}
/* margin-top is (track 3px - thumb 16px) / 2. Adjust both together or the thumb
   stops sitting on the track in Blink. */
.fx-discover__range::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:16px;height:16px;margin-top:-6.5px;border:0;border-radius:0;
  background:var(--fe-navy);
  box-shadow:0 0 0 0 rgba(0,58,112,.12);
  transition:box-shadow .18s ease;
}
.fx-discover__range::-moz-range-thumb{
  width:16px;height:16px;border:0;border-radius:0;background:var(--fe-navy);
}
.fx-discover__range:hover::-webkit-slider-thumb,
.fx-discover__range:active::-webkit-slider-thumb{box-shadow:0 0 0 7px rgba(0,58,112,.12)}
/* The global input:focus rule paints a 1px box-shadow ring, which on a slider
   frames the whole 100%-wide control. Killed here; the site-wide :focus-visible
   outline still marks keyboard focus. Same call as .lux-share__range. */
.fx-discover__range:focus{box-shadow:none}
.fx-discover__scale{
  display:flex;justify-content:space-between;margin-top:8px;
  font-family:var(--lux-font);font-weight:300;font-size:12px;
  color:var(--fe-slate);
}
@media (prefers-reduced-motion:reduce){
  .fx-discover__range::-webkit-slider-thumb{transition:none}
}

/* ============================================================
   HOW IT WORKS RAIL  (.lux-howsteps)
   ------------------------------------------------------------
   The three steps between the proposal form and a proposal in the
   member's hands, to the supplied design: an icon plate on a
   softer mat, the step number ghosted beside it, a dashed
   connector with a joint, and a title plus copy.

   The design arrived as a three-across row under the form. It
   lives in the column beside the form instead, so the sequence
   runs DOWN: the plates form a vertical rail, each step's copy is
   indented into its own column, and the dashed line runs down the
   rail where nothing can collide with it. Three-across in a
   half-width column would have left each step about 38 characters
   of measure.

   Two departures from the mock: the section heading is an
   uppercase eyebrow rather than the mock's heavy near-black
   display line (Light 300 display type is the house rule, and the
   section already prints a title), and the copy is sentence case,
   not title case.

   Not .lux-steps--wide, the site's existing stepper: that one is
   centred, numerals-only and hangs its items off a 2px rule above
   them.
   ------------------------------------------------------------ */
.lux-howsteps{
  --how-plate:clamp(52px,4.6vw,62px);   /* icon plate, square */
  --how-mat:10px;                       /* mat padding around the plate */
  --how-gap:clamp(20px,2.2vw,30px);     /* between steps; the joint sits in it */
  --how-mat-bg:#E4EAF1;                 /* set for --canvas, the only ground used */
  list-style:none;margin:0;padding:0;
  display:flex;flex-direction:column;gap:var(--how-gap);
}
.lux-howsteps__step{
  position:relative;min-width:0;
  display:grid;grid-template-columns:auto minmax(0,1fr);
  column-gap:clamp(14px,1.5vw,20px);
  /* Not the default stretch: the mat is the plate's own frame, and a grid item
     stretched to the row height turned it into a tall pill running down behind
     the copy — which also put its rounded bottom on top of the rail. */
  align-items:start;
}
/* The rail. Runs from the bottom of this step's mat to the top of the next
   one's, i.e. through the gap — hence the negative bottom. Centred on the mat,
   which is the plate plus its padding on both sides. */
.lux-howsteps__step:not(:last-child)::before{
  content:"";position:absolute;z-index:0;
  left:calc(var(--how-plate) / 2 + var(--how-mat) - .5px);
  top:calc(var(--how-plate) + var(--how-mat) * 2);
  bottom:calc(-1 * var(--how-gap));
  border-left:1px dashed #C4D0DC;
}
/* The joint, in the middle of the gap between two steps. Positioned off the
   bottom edge rather than at a percentage of the step's height: the steps differ
   in height (their copy runs to two lines or three) and a percentage would put
   the dot somewhere different on each one. */
.lux-howsteps__step:not(:last-child)::after{
  content:"";position:absolute;z-index:1;
  left:calc(var(--how-plate) / 2 + var(--how-mat) - 4.5px);
  bottom:calc(-1 * var(--how-gap) / 2 - 4.5px);
  width:9px;height:9px;border-radius:50%;
  background:var(--fe-navy-900);
}
.lux-howsteps__mat{
  position:relative;z-index:1;
  padding:var(--how-mat);border-radius:22px;
  background:var(--how-mat-bg);
}
.lux-howsteps__plate{
  display:flex;align-items:center;justify-content:center;
  width:var(--how-plate);height:var(--how-plate);
  border-radius:14px;
  background:var(--fe-paper);border:1px solid var(--fe-line);
  box-shadow:0 6px 18px rgba(11,31,42,.06);
}
.lux-howsteps__icon{
  width:calc(var(--how-plate) * .52);height:calc(var(--how-plate) * .52);
  fill:none;stroke:var(--fe-navy);stroke-width:1.4;
  stroke-linecap:round;stroke-linejoin:round;
}
.lux-howsteps__body{min-width:0;padding-top:2px}
/* Ghosted numeral. Kept large — it is the piece of the supplied design that
   carries the sequence visually — but moved above the title, where the column is
   free, instead of beside the plate, where it would sit on the rail. */
.lux-howsteps__num{
  display:block;
  font-family:var(--lux-font);font-weight:200;
  font-size:clamp(26px,2.4vw,34px);line-height:1;letter-spacing:-.01em;
  color:#D3DDE8;
}
/* Two classes plus the type: h1/h2/h3 in section 1 pin headings to navy at
   (0,1,1), so a single-class ancestor rule could not set the size. */
.lux-proposal .lux-howsteps__step h3{
  margin:6px 0 8px;
  font-family:var(--lux-font);font-weight:400;
  font-size:clamp(16px,1.4vw,18.5px);line-height:1.3;letter-spacing:.005em;
  color:var(--fe-navy);text-wrap:balance;
}
/* The jc25 pages carry `:where(p){font:inherit;color:inherit;max-width:none}`
   in a page <style> that loads after this file. It is (0,1,0), so a two-class
   selector clears it — but everything it would reset has to be restated here,
   not only the colour. */
.lux-proposal .lux-howsteps__step p{
  margin:0;max-width:46ch;
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(13.5px,1.05vw,14.5px);line-height:1.7;
  color:var(--fe-slate);
}

@media screen and (max-width:600px){
  /* Smaller plate and numeral so the copy column keeps a readable measure on a
     320px screen; the rail's maths is all driven off these two values. */
  .lux-howsteps{--how-plate:46px;--how-mat:8px}
  .lux-howsteps__num{font-size:24px}
  .lux-proposal .lux-howsteps__step p{max-width:none}
}

/* ============================================================
   FOUNDER PAGE GROUP (Aug 2026)
   Three additions the who-we-are/jim-segrave.html redesign needed.
   Each is a modifier on a component that already exists rather than a
   new component, so nothing here is page-private.
   ============================================================ */

/* ---- Plate hero -----------------------------------------------------------
   .lux-hero sets align-items:flex-end, so every hero on the site drops its
   copy bottom-left over the photograph. This modifier lifts it to the vertical
   centre and pairs it with a .lux-framed-box: on a page whose subject is one
   person the frame reads as a plate carrying the name, where a bottom-left
   caption read as a label on the photograph.

   LEFT-SET, not centred. The design centres the plate, which put it straight
   over the subject — in jim-segrave.jpg he stands across 48-62% of the frame,
   so a centred 820px plate covered him from the chest down. He is the reason
   the photograph is on the page. The plate is capped at 640px against the
   page's 1180px measure instead, which lands it on the clean stretch of
   fuselage to his left and leaves him in the open.

   Taller than the base hero (780px against clamp(460px,62vh,720px)) because
   the plate needs air above and below it. The asymmetric vertical padding is
   the fixed header — a plate on the geometric centre sits visually low once
   the header floats over it, so the extra top padding lifts it onto the
   optical centre. */
.lux-hero--plate{
  align-items:center;
  min-height:clamp(560px,86vh,780px);
}
/* A flat wash, not .lux-hero-scrim. The scrim is a corner gradient that fades
   out towards the top-right, and this plate sits mid-left with the subject
   lit behind it. */
.lux-hero--plate .lux-tint{background:rgba(0,25,50,.42)}
.lux-hero--plate .lux-hero-inner{
  padding:clamp(96px,12vh,120px) clamp(20px,5vw,40px) clamp(56px,8vh,80px);
}
.lux-hero--plate .lux-framed-box{
  max-width:640px;
  padding:clamp(32px,3.4vw,52px) clamp(28px,3.4vw,56px);
  /* Below 768px the plate takes the whole column and the cap never applies —
     there the subject is kept in frame by --subject-right's 28% crop instead. */
  /* Stronger than .lux-framed-box's own rgba(0,39,77,.25). That value is for a
     dark ground; the fuselage this plate now sits on is bright white, where the
     .25 fill plus the hero tint left 12px eyebrow text at ~3.9:1. This holds
     ~7:1 on the brightest part of the frame. */
  background:rgba(0,25,50,.55);
}
/* .lux-hero-copy is 1000px wide by default; inside the plate it is the plate
   that sets the measure. Text stays left-set, as the house heroes are. */
.lux-hero--plate .lux-hero-copy{max-width:none}
/* Below the 58px ceiling the full-width heroes take: this headline is measured
   against the 640px plate it sits inside, not against the viewport. */
.lux-hero--plate .lux-hero-copy h1{
  font-size:clamp(30px,2.9vw,42px);line-height:1.12;margin:0 0 12px;
}
.lux-hero--plate .lux-hero-copy .lux-eyebrow{margin:0 0 16px}
.lux-hero--plate .lux-hero-copy .lux-hero-sub{margin-bottom:26px}
/* The cap that actually keeps the subject clear, and why it is not a round
   number. jim-segrave.jpg is 900x490 (1.84) and every desktop viewport is wider
   than that ratio, so object-fit:cover scales to the frame's WIDTH and crops
   height only — there is no horizontal overflow for object-position to shift.
   The subject therefore sits at a FIXED fraction of the frame however wide it
   gets: his left edge is 430/900 = 47.8% across.

   The plate's own left edge is not fixed, though: it rides the 1180px wrap, so
   it starts at (100vw - 1180)/2 + 40 above 1180px and at 40px below it. Setting
   the right edge to land at 46vw and solving for the width in each regime gives
   ~480px on the wrap and 46vw - 44px off it. A single flat cap cannot satisfy
   both — 640px clears him at 1280 and covers his face at 1920.

   If the photograph is ever replaced, re-measure the subject's left edge as a
   fraction of the source width and put it in place of the 46vw. */
@media (min-width:768px){
  .lux-hero--plate .lux-framed-box{max-width:min(480px,calc(46vw - 44px))}
}

/* ---- Stat band reflow steps -----------------------------------------------
   .lux-stat-band reflows by auto-fit on a 200px floor, which with the four
   stats this page carries steps 4 -> 3 -> 2 -> 1. The 3-column step is the
   problem: the fourth stat lands alone on a row at a third of the width, which
   reads as a broken cell rather than as a stat. Measured at 768px it put
   "2015 / flyExclusive Founded" by itself with two thirds of the row empty.

   So the middle of the range is pinned to 2x2 and the phone to one column,
   leaving auto-fit to give four across from 1024px up. This is the exception
   the "reflow by grid, not by breakpoint" note above allows for: the band is a
   fixed four-cell row, not an arbitrary-length list, so the steps are knowable
   rather than guessed at.
   Dividers are dropped at the wrap edge of each step; the component's own
   :last-child rule only knows about a single row. */
@media (max-width:1023px){
  .lux-stat-band{grid-template-columns:repeat(2,minmax(0,1fr))}
  .lux-stat-band .s:nth-child(2n){border-right:0}
}
@media (max-width:479px){
  .lux-stat-band{grid-template-columns:minmax(0,1fr)}
  .lux-stat-band .s{border-right:0}
}

/* ---- Quote band -----------------------------------------------------------
   .lux-band with a quotation instead of a headline-and-CTA. Deliberately the
   band and not a flat .lux-tint over the photograph: .lux-band::after is a
   radial scrim built for exactly this frame (see its note above — a flat tint
   left white text at ~1.7:1 over a sunset, the scrim holds ~4.6:1), and the
   only photograph this page has for the slot is lux-horizon-sunset.

   Markup: <section class="lux-band lux-band--quote"> img,
           .lux-band-copy > .lux-band-mark, blockquote, .lux-eyebrow */
.lux-band--quote{min-height:clamp(420px,52vw,560px)}
.lux-band--quote .lux-band-copy{max-width:880px}
/* Review 2026-08-07 · 94 — the quotation sat on the optical centre of the
   photograph and got lost in it; set at the foot it reads as something the
   speaker is saying from inside the frame rather than a caption laid over a
   landscape.
   The scrim has to move with it. .lux-band::after is built around a radial
   centred at 50% 50%, i.e. it grounds the middle and thins towards the edges —
   exactly backwards once the text is at the bottom. This replaces it with a
   single vertical ramp that is lightest where the photograph should be legible
   and heaviest under the type. */
.lux-band--quote{align-items:flex-end}
/* ...but only when there IS a photograph. On --navy the frame is gone, and
   flex-end pinned a 405px copy box to the foot of a 560px band: 156px of dead
   navy above the turbine mark and none under the attribution, which reads as a
   rendering fault rather than as air. Measured on mro/maintenance.html;
   who-we-are/jim-segrave.html carries the same class trio and the same sag, so
   this corrects both. */
.lux-band--quote.lux-band--navy{align-items:center}
.lux-band--quote::after{
  background:linear-gradient(180deg,
    rgba(0,25,50,.20) 0%,
    rgba(0,25,50,0) 30%,
    rgba(0,25,50,.58) 64%,
    rgba(0,25,50,.88) 100%);
}
/* The turbine mark, set above the quotation. Not a typographic quote glyph:
   the mark is the one already used for this job on dark grounds
   (.lux-divider--ondark span). */
.lux-band-mark{display:block;width:26px;height:auto;margin:0 auto 26px}
/* border:0/padding:0 because the UA and the Webflow export both give
   blockquote a rule and an indent, and this one is centred. */
.lux-band--quote blockquote{
  margin:0 0 22px;padding:0;border:0;
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(20px,2vw,28px);line-height:1.55;color:#fff;
  text-wrap:pretty;
}
.lux-band--quote .lux-eyebrow{margin:0}

/* .lux-split .s-copy .lux-display-quote is margin:0, which was written for a
   pull-quote that CLOSES the column — every earlier use had nothing after it.
   #culture on the founder page now runs body copy under the quote, and with no
   margin the quote and the first paragraph collide. Scoped to the case that
   needs it so the closing-quote uses are untouched. */
.lux-split .s-copy .lux-display-quote:not(:last-child){margin:18px 0 24px}

/* ---- Ruled column notes ---------------------------------------------------
   Three or four short paragraphs set as columns, each capped with a hairline.
   For material that is a set of parallel facts rather than an argument that
   runs in order — stacked as .lux-prose it read as one long passage and the
   reader lost which point was which.
   Children are plain <div>s so a column can hold more than one paragraph. */
.lux-colnotes{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:clamp(28px,3.5vw,56px);
}
.lux-colnotes > div{border-top:1px solid var(--fe-line);padding-top:22px}
.lux-colnotes p{
  font-family:var(--lux-font);font-weight:300;
  font-size:14.5px;line-height:1.75;color:var(--fe-ink);margin:0 0 14px;
}
.lux-colnotes p:last-child{margin-bottom:0}

/* ---- Accordion answers that carry a list ----------------------------------
   fractional.html's "how do shares work?" answer is the first FAQ answer on the
   site whose approved copy ends in a list (the four share sizes). Two traps, both
   on bare elements, so nothing warns you — the same pair the .lux-valueset note
   above documents:
     ul{font-size:18px;padding-left:0}  and  li{margin:4px 0 4px 36px;font-size:14px}
   Left alone, the list rendered at 14px, indented 36px, with the bullet outside
   the box instead of in the gutter.

   The sizes are stated rather than inherited, and that is deliberate. It looks
   like these should be font-size:inherit off .lux-accordion .a-body (13.5px),
   but no FAQ answer on this site actually renders at 13.5px: a bare
   p{font-size:16px;line-height:1.7} further up THIS file matches the <p> inside
   the answer directly, and a directly-matching rule always beats an inherited
   value whatever the specificity. So every answer is 16px/27.2px and .a-body's
   13.5px only ever applied to text not wrapped in a <p>. inherit here would have
   made the bullets 13.5px directly under a 16px paragraph in the same answer.

   Matching the paragraph is the narrow fix. The wider one — deciding whether
   answers are 13.5px or 16px and making .a-body mean it — changes every FAQ on
   the site and is not a copy-drop decision. */
.lux-accordion .a-body ul{
  list-style:disc;margin:10px 0 0;padding-left:18px;
  font-size:16px;line-height:1.7;
}
.lux-accordion .a-body li{
  margin:0 0 4px;padding-left:0;font-size:16px;line-height:1.7;
}
.lux-accordion .a-body li:last-child{margin-bottom:0}

/* ---- .lux-partner-mark — a partner's logo on paper -------------------------
   The counterpart to .lux-band-logo above, which only works inside a
   .lux-band's centred copy over a scrimmed photograph. A partnership page has
   to show the mark on white too, in its "about the partner" section, where the
   mark is the thing that makes the rest of the section credible: it is the
   partner's own identity, not our description of them.

   Capped on WIDTH only, with height:auto and no box. Partner artwork arrives at
   whatever aspect its owner chose — the AeroAngel primary is 1481x759, close to
   2:1 — and a fixed frame would letterbox a wide mark or crop a square one. A
   width cap scales any of them to roughly the same optical weight.

   200px rather than .lux-band-logo's 230: on paper the mark sits above a
   heading instead of alone in a photograph, so it has to read as the partner's
   signature beside the type rather than compete with it.

   --center for a centred .lux-head; the bare class is left-set for a split's
   copy column. */
.lux-partner-mark{display:block;width:auto;max-width:200px;height:auto;margin:0 0 26px}
.lux-partner-mark--center{margin-left:auto;margin-right:auto}
@media (max-width:700px){
  .lux-partner-mark{max-width:160px;margin-bottom:20px}
}

/* ---- .lux-sourcenote — where a figure came from ----------------------------
   A partnership page carries two kinds of number: ours, and the partner's own.
   The partner's have to say whose they are and when they were read, because we
   do not control them and a stale third-party statistic presented as a
   flyExclusive claim is the worst failure this page has available to it. Our
   own cumulative figures need the same treatment for the same reason.

   Deliberately quieter than .lux-stat-label so it annotates the row above
   without joining it.

   Not .lux-prose--sm: that modifier is declared BEFORE .lux-prose's own
   font-size in this sheet, so on source order every --sm on the site silently
   renders at the base 16px. --ondark for a note under a navy .lux-stat-band.

   max-width and BOTH auto margins are load-bearing, not taste. The Webflow
   export carries a bare `p{max-width:900px}` with no margin, so a <p> dropped
   straight into a 1180px .lux-wrap is a 900px box hard against the left edge —
   text-align:center then centres the words inside THAT box, landing them 140px
   left of the column they are annotating. It looks like a bug in the stat row
   above it, and nothing in the markup hints at the cause. Stating the measure
   here overrides the bare rule and the auto margins re-centre the box. */
.lux-sourcenote{
  font-family:var(--lux-font);font-weight:300;font-size:12.5px;line-height:1.6;
  color:var(--fe-slate);margin:18px auto 0;max-width:70ch;text-align:center;
}
.lux-sourcenote--ondark{color:var(--fe-blue-200)}

/* ============================================================
   Y · WHY FLYEXCLUSIVE  (.fx-why)
   ------------------------------------------------------------
   Homepage, directly under the hero: three ledger rows answering
   the claim the hero makes. Supplied as a self-contained
   block with its styles in a page <style>; moved here because
   component CSS lives in this file, not in the page (see
   design-library.html).

   Ground is the drifting sky shared with the About timeline —
   .th-sky above — rather than the photograph the supplied version
   carried. Two reasons that matters beyond taste: the hero directly
   above is video, so a second full-bleed photograph immediately
   under it gave the top of the page three competing images in a
   row; and the sky is ~40KB of PNG that About already ships,
   against a 2000px JPEG this band would have loaded on its own.

   The rows are a 2-column grid — heading, body — which is what
   makes them read as a ledger rather than as three cards. The
   hairline is on the row's top edge so the last row's foot is the
   CTA's rule, and the section closes on one line rather than two.
   ------------------------------------------------------------ */
.fx-why{position:relative;background:var(--fe-navy-900);overflow:hidden}

/* ---- The join with the hero ------------------------------------------
   This band butts straight against the homepage's full-bleed video hero —
   there is no paper section between them any more (see the retired
   .lux-statement note in index.html). The hero's scrim ends on this band's
   own #00274D so the two surfaces are the same colour where they touch,
   but that was still showing a hard line, because the band's top edge was
   not #00274D: the shared .th-sky::before atmosphere glow peaked at 6% of
   the band, which put ~22% of a pale blue in the first pixels under the
   seam. Same colour on one side, a lift on the other, is still an edge.

   Two changes fix it, and they only work together:

   1. The glow's centre drops from 6% to 34%, so the lift happens inside
      the band instead of on its boundary. Scoped to .fx-why — the About
      panorama keeps 6%, since its top edge is the top of the page and has
      nothing above it to blend with.
   2. This ::before lays the hero's exact ending colour over the top of the
      band and fades it out over ~260px. Whatever the sky does underneath,
      the first pixel below the seam is now the same value as the last
      pixel above it, and the ramp away from it is gradual.

   The result is a soft dark trough centred ON the join rather than a bar
   sitting above it. Above z-index 0 (.th-sky) and below the DOM-later
   z-index 1 (.fx-why__wrap), so it dims the clouds, never the copy.
   Paired with the bottom stops of .home-hero__scrim in home-hero.css —
   if you retune one, retune the other. */
.fx-why .th-sky::before{
  background:radial-gradient(120% 62% at 50% 34%, rgba(96,146,201,.22), rgba(96,146,201,0) 70%);
}
.fx-why::before{
  content:"";position:absolute;left:0;right:0;top:0;
  height:clamp(160px,20vh,280px);
  z-index:1;pointer-events:none;
  /* Every stop is the same rgb as --fe-navy-900, so this is a pure
     opacity ramp — a fade to a different hue would grey the sky out. */
  background:linear-gradient(to bottom,
    rgba(0,39,77,1) 0%,
    rgba(0,39,77,.74) 34%,
    rgba(0,39,77,.34) 66%,
    rgba(0,39,77,0) 100%);
}
/* Sits over the sky, under nothing. The rows need no ground of their
   own — the clouds run at .13–.2 opacity and the type is white. */
.fx-why__wrap{
  position:relative;z-index:1;
  max-width:1180px;margin:0 auto;
  padding:clamp(56px,6vw,92px) clamp(20px,4vw,48px);
}
.fx-why__eyebrow{display:flex;align-items:center;gap:16px;margin-bottom:clamp(32px,3.6vw,52px)}
.fx-why__eyebrow img{width:20px;height:20px;flex:none}
/* --onsky rather than the inline colour the supplied block carried:
   .lux-eyebrow's own colour is set for paper. */
.fx-why .lux-eyebrow--onsky{color:#7FC4E3;margin:0}
/* The 01/02/03 ordinal column was dropped 2026-08-07 at the client's
   request; the heading now takes the row's display weight instead, one
   scale up from where it sat beside the numeral. Two columns, not
   three — the heading's own column absorbs the numeral's 140px. */
.fx-why__row{
  display:grid;grid-template-columns:minmax(0,480px) 1fr;
  gap:clamp(24px,3vw,56px);align-items:start;
  border-top:1px solid rgba(255,255,255,.18);
  padding:clamp(28px,3vw,42px) 0;
}
.fx-why__row h3{
  font-family:var(--lux-font);font-weight:300;
  font-size:clamp(30px,3.2vw,44px);line-height:1.15;letter-spacing:.01em;
  color:#fff;margin:0;text-wrap:balance;
}
.fx-why__row p{
  font-family:var(--lux-font);font-size:16px;line-height:1.8;
  color:var(--fe-blue-200);margin:0;max-width:52ch;text-wrap:pretty;
}
.fx-why__foot{
  display:flex;justify-content:center;
  border-top:1px solid rgba(255,255,255,.18);
  padding-top:clamp(28px,3vw,42px);
}
.fx-why__cta{
  display:inline-flex;align-items:center;
  border:2px solid #fff;color:#fff;padding:15px 38px;
  font-family:var(--lux-font);font-weight:500;font-size:14px;
  letter-spacing:.14em;text-transform:uppercase;text-decoration:none;
  transition:background-color .25s ease,color .25s ease;
}
.fx-why__cta:hover{background:#fff;color:var(--fe-navy)}

/* Cloud placement for THIS band. The panorama's own values are in vh,
   which is right for a full-viewport hero and wrong here: this band is
   roughly 520-700px tall, so on a short laptop 16vh puts a cloud near
   its foot and on a 4K monitor the same rule puts all three in the top
   sliver. Percentages resolve against the band, so the spread holds at
   any viewport. Sizes and speeds are inherited untouched. */
.fx-why .th-cloud--a{top:8%}
.fx-why .th-cloud--b{top:44%}
.fx-why .th-cloud--c{top:62%}

@media (max-width:991px){
  .fx-why__row{grid-template-columns:1fr;gap:14px}
  /* The band gets taller here (the rows stack), so the two outer clouds
     move apart to keep the spread even. Only `top` is restated — the
     shared max-width:860px rules above still set width and opacity, and
     they drop cloud B entirely below 860px. These land later in the file
     at the same specificity, so they win where the two overlap. */
  .fx-why .th-cloud--a{top:5%}
  .fx-why .th-cloud--c{top:58%}
}
@media (max-width:479px){
  .fx-why__foot{justify-content:stretch}
  .fx-why__cta{width:100%;justify-content:center}
}

/* ============================================================
   Z · PROGRAM LEDGER  (.lux-ledger)
   ------------------------------------------------------------
   Supplied 2026-08-11 as "Jet Club Program - Unified Ledger".
   Replaces THREE bands on jet-club.html — the .lux-tier-pair
   cards, the .lux-statement between them, and the .lux-splitlist
   "Benefits Overview" — with one section, and the merge is the
   point rather than a saving: the two tier cards repeated five of
   their six bullets verbatim, and the four splitlist rows were
   also shared by both tiers. So eight of the page's claims were
   printed twice or three times over ~1600px of scroll, and the
   only thing that actually differed between the tiers — 330 days
   against 365 — was the last line of a six-item list.

   This inverts that. The membership's terms are stated ONCE, as a
   two-column run of hairline rows (the ledger), and the deposit
   choice is a single three-cell band under it whose two right
   cells hold nothing but what is different. The tier pair's
   "Competitive entry pricing across the industry!" notes and the
   "Best entry" badge are not carried: with the prices side by side
   in one row, a badge on the cheaper one and the same sentence
   under both are noise.

   No photograph. The splitlist's Challenger 350 is dropped with
   the band — the page opens on a full-bleed video hero and the
   .lux-splitform at its foot carries its own imagery, so this
   middle section is where the page is allowed to be quiet.
   images/jc-benefits-cl350*.jpg are now unreferenced but kept.

   Built on the page scaffolding rather than as a standalone band:
   .lux-section + .lux-wrap + .lux-head, so it takes the site's
   shared vertical rhythm and container width. Only the ledger
   rows, the deposit band and the foot are new.

   The mock sets its lead in --fe-ink; kept at .lux-head p's
   --fe-slate instead, because every other section head on this
   page and the eight around it sets its lead in slate, and one
   darker lead reads as a mistake rather than as emphasis.

   Specificity, the traps this file's other components document:
   - the eyebrow is a <div>, not a <p>. .lux-head p (0,1,1) sets
     margin:0 and a 15-17px clamp, and it OUTRANKS .lux-eyebrow
     (0,1,0) — as a <p> the eyebrow silently rendered at lead size
     with no gap under it.
   - the h2 carries no class, so `h1[class],h2[class]` in section 1
     cannot reach it and .lux-head h2 governs.
   - every paragraph rule is written `p.<class>` to clear the jc25
     pages' `.jc25 :where(p)` reset, which lands after this file.
   ------------------------------------------------------------ */

.lux-ledger .lux-head{max-width:660px}

/* ---- THE LEDGER ------------------------------------------- */
/* Two lists, not one list in two columns. The split is meaningful:
   the left four are the terms of the deposit (fees, surcharges,
   fleet access, connectivity) and the right four are what the
   membership gives you regardless of which deposit you choose. A
   single <ul> flowing row-wise would interleave the two groups, and
   grid-auto-flow:column would keep them but put the grouping in the
   CSS instead of in the markup, where a screen reader can hear it.

   The rows share one set of row tracks via subgrid, and that is
   load-bearing rather than tidiness. As two independent lists the
   columns size their own rows, so the one row that wraps to two
   lines ("No taxi time…") pushed every hairline below it in the
   left column 25px out of step with its opposite number, and the
   two closing rules ended 10px apart. Four rules that nearly line
   up read as a mistake in a component whose whole idea is a ruled
   ledger. With subgrid each of the four rows is as tall as the
   taller of its two cells and all five rules are continuous across
   the gap.

   The `repeat(4,auto)` couples this to FOUR rows per column. Add a
   fifth to either list and it lands in an implicit track that the
   subgrid does not share, so it will sit correctly but stop
   aligning — extend this number with the content. Pre-subgrid
   browsers (Chrome <117, Safari <16) get exactly that same
   degradation for every row, which is the arrangement this
   component shipped with, so the fallback needs no rules. */
.lux-ledger__cols{
  display:grid;grid-template-columns:1fr 1fr;
  grid-template-rows:repeat(4,auto);
  column-gap:clamp(40px,5.5vw,80px);
  margin-top:clamp(40px,4.4vw,64px);
}
.lux-ledger__rows{
  list-style:none;margin:0;padding:0;min-width:0;
  display:grid;grid-row:1 / -1;grid-template-rows:subgrid;
}
/* Hairline above every row plus one under the last, so each column
   closes as a block. The Webflow export ships a bare
   `li{margin:4px 0 4px 36px}` — the 36px indent is on the ITEM, so
   zeroing the ul's padding is not enough to get the rules to line
   up under the heading. */
.lux-ledger__rows li{
  display:flex;gap:16px;align-items:baseline;
  margin:0;padding:20px 0;
  border-top:1px solid var(--fe-line);
  font-family:var(--lux-font);font-weight:400;
  font-size:16px;line-height:1.6;color:var(--fe-ink);
  overflow-wrap:break-word;
}
.lux-ledger__rows li:last-child{border-bottom:1px solid var(--fe-line)}
/* baseline alignment, not center: rows wrap to two lines from about
   1100px down, and one of the eight wraps even at full width, so a
   centred mark on those floats halfway down the row while its
   single-line neighbours sit on the text. Baseline tracks the first
   line everywhere instead. An image's baseline is its bottom edge,
   which sits it a shade high against the type — the 2px is the
   correction. An 80px source at 14px; small, because it is a bullet
   here, not the 20px divider mark. */
.lux-ledger__rows img{
  flex:none;width:14px;height:14px;object-fit:contain;
  position:relative;top:2px;
}

/* ---- THE DEPOSIT BAND ------------------------------------- */
/* One outer hairline box with internal vertical rules, so the three
   cells read as one object. The label cell is fixed-width and
   tinted; the two tier cells share what is left equally, which
   keeps the two prices at the same optical distance from the label. */
.lux-ledger__deposit{
  margin-top:clamp(40px,4vw,56px);
  border:1px solid var(--fe-line);
  display:grid;grid-template-columns:220px 1fr 1fr;
  align-items:stretch;
}
.lux-ledger__deposit > *{min-width:0}
.lux-ledger__label{
  display:flex;align-items:center;
  padding:24px clamp(22px,2.4vw,32px);
  background:var(--fe-canvas);
  font-family:var(--lux-font);font-weight:600;font-size:12px;
  letter-spacing:var(--lux-track-eyebrow);text-transform:uppercase;
  color:var(--fe-slate);
}
.lux-ledger__tier{
  padding:24px clamp(22px,2.4vw,32px);
  border-left:1px solid var(--fe-line);
}
.lux-ledger__tier h3{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  margin:0;font-family:var(--lux-font);font-weight:500;
  font-size:15px;line-height:1.4;letter-spacing:0;
  color:var(--fe-navy-900);
}
.lux-ledger__price{font-weight:300;font-size:22px}
/* The differentiator, as a flag rather than the tier pair's solid
   badge: "$200k" is already the loudest thing in its cell and a
   filled chip beside it made the cell shout twice. */
.lux-ledger__flag{
  font-weight:600;font-size:11px;
  letter-spacing:.2em;text-transform:uppercase;
  color:var(--fe-blue-600);
}
.lux-ledger p.lux-ledger__note{
  margin:6px 0 0;
  font-family:var(--lux-font);font-size:14px;line-height:1.6;
  color:var(--fe-slate);
}

.lux-ledger__foot{text-align:center;margin-top:clamp(34px,3.4vw,48px)}

/* ---- NARROW ----------------------------------------------- */
/* 860px is the library's shared breakpoint and the right one here:
   what runs out first is the deposit band's 220px label track
   against two priced cells, and that happens at about the same
   width as the two ledger columns. */
@media (max-width:860px){
  /* One column, and the shared row tracks have to go with it: both
     lists claim `grid-row:1/-1`, so leaving four tracks in place
     would stack them ON each other in the same single column. */
  .lux-ledger__cols{grid-template-columns:1fr;grid-template-rows:none;column-gap:0}
  .lux-ledger__rows{grid-row:auto;grid-template-rows:none}
  /* Stacked, the first list's closing hairline lands on the second's
     opening one and paints 2px. The first list gives its up. */
  .lux-ledger__cols > .lux-ledger__rows:first-child li:last-child{border-bottom:0}
  .lux-ledger__deposit{grid-template-columns:1fr}
  /* The vertical rules become horizontal ones — same hairlines,
     turned with the stack, so the band is still one box. */
  .lux-ledger__tier{border-left:0;border-top:1px solid var(--fe-line)}
}
