/* ==========================================================================
   FLIGHTPROOF BRAND LAYER — one design system for the whole site
   --------------------------------------------------------------------------
   Why this file exists (2026-10-22, owner: "country pages, main page and
   partner page are not harmonic in design and responsiveness"):

   The three page families each grew their own skin and drifted apart.

     family          sheet(s)                  body face    display face   figures
     -----------------------------------------------------------------------
     homepage        styles.css + instrument   DM Sans      Outfit         IBM Plex Mono
     country guide   instrument.css            Outfit(!)    Outfit         JetBrains Mono
     partner portal  inline styles only        DM Sans      Outfit         ui-monospace

   The drift was not in the palettes — those are all the brand's navy/amber.
   The drift was in the three things a visitor can actually see:

   1. TYPE. The two biggest families loaded NO webfont at all. The country
      guides asked for "Outfit" and "DM Sans" in CSS and got the system
      fallback instead, so 2,281 pages rendered in Segoe UI next to a
      marketing site rendered in Outfit. The mono face differed too: IBM
      Plex Mono on the homepage, JetBrains Mono on the guides, ui-monospace
      on the partner page — and 83 locale homepages carried a BROKEN font
      URL (`css2?IBM+Plex+Mono…`, no `family=`, so Google served nothing).
   2. THE PROOF STRIP. Three surfaces say the same three facts — tickets
      sold, delivery time, coverage — in three different grammars: an
      uppercase mono micro-row on the homepage, a 3-cell card grid on the
      guides, a navy bar on the partner page. Same facts, three voices.
   3. THE BUTTON. A 50px-radius pill on the legacy homepage hero, a
      0px-radius hard block on the guides, a 10px soft-shadow block on the
      partner page. The guide's own buy button (10px) and the homepage's
      band button (10px) agreed; everything around them did not.
      Render proof (2026-10-22, 1280px) counted six action radii on one
      guide page alone — 12px (band CTA), 14px (in-article CTA), 4px (the
      stub's buy button), 6px (the Pass button), 10px (the destination
      picker's buy), plus the homepage's 6px rescue button — and the
      modal's pay button in the UA's Arial. All of them are in section 3
      now, at 12px, in the display face.

   This file is the seam. It does NOT repaint the families: the homepage's
   ticket band and the guides' paper ticket stay theirs. It makes the TYPE
   identical, gives the proof strip one grammar, gives the buttons one
   grammar, and sets a shared responsive floor.

   Rules for this file:
     * Namespace is --fpb-* (FlightProof Brand). The --fp-* namespace is
       already taken by per-page tokens (--fp-sans, --fp-ink, --fp-amber on
       the locale homes) — never collide with it.
     * Palette values are the e-ticket email's (ADR 0001): navy #1a1a2e,
       amber #FFE66D, paper #ece8df. No new colours without an ADR.
     * It loads LAST, after styles.css and instrument.css, so it can settle
       the disagreements between them — see scripts/add-brand-layer.cjs.
     * It is SELF-SUFFICIENT: every custom property it READS is defined in
       this file. It may not lean on --sans / --mono / --i-* from the other
       sheets, because a page can load this file without them.
   ========================================================================== */

:root {
  /* The pages without instrument.css (10 of 2,938) still need the light
     declaration, or their native controls follow the OS dark preference while
     the page stays white. See the note at the top of instrument.css. */
  color-scheme: light;

  /* ── palette (from the e-ticket email — ADR 0001) ────────────────────── */
  --fpb-ink: #1a1a2e;
  --fpb-amber: #FFE66D;
  --fpb-paper: #ece8df;
  --fpb-card: #ffffff;
  --fpb-edge: rgba(255, 255, 255, .22);   /* edges on a DARK surface */
  --fpb-edge-light: #e2ddcf;              /* edges on a LIGHT surface */
  --fpb-dash: #d7d2c2;
  --fpb-dim: #67624f;
  --fpb-grey: #6a6555;
  --fpb-ok: #22c55e;

  /* ── type: three roles, one stack, site-wide ──────────────────────────── */
  /* Display: Outfit. Text: DM Sans. Figures: JetBrains Mono.
     The Noto names are not decoration — they are how the Bengali, Devanagari,
     Thai, Arabic and CJK pages keep a designed face instead of dropping to
     a system font mid-sentence. */
  --fpb-display: "Outfit", "Segoe UI", system-ui, -apple-system, "Noto Sans",
                 "Noto Sans Devanagari", "Noto Sans Bengali", "Noto Sans Thai",
                 "Noto Sans Arabic", "Noto Sans CJK SC", sans-serif;
  --fpb-sans: "DM Sans", "Segoe UI", system-ui, -apple-system, "Noto Sans",
              "Noto Sans Devanagari", "Noto Sans Bengali", "Noto Sans Thai",
              "Noto Sans Arabic", "Noto Sans CJK SC", sans-serif;
  --fpb-mono: "JetBrains Mono", ui-monospace, Consolas, "Courier New", monospace;

  /* ── fluid scale (the "responsive" half of the harmony) ───────────────── */
  --fpb-fs-xs: clamp(11.5px, 0.36vw + 10.6px, 13px);
  --fpb-fs-sm: clamp(13px, 0.3vw + 12.2px, 14.5px);
  --fpb-fs-body: clamp(14.5px, 0.25vw + 13.8px, 16px);
  --fpb-fs-lead: clamp(15.5px, 0.42vw + 14.4px, 18px);
  --fpb-fs-h3: clamp(16px, 0.5vw + 14.6px, 19px);
  --fpb-fs-h2: clamp(21px, 1.1vw + 17.6px, 28px);
  --fpb-fs-h1: clamp(27px, 2.1vw + 20.3px, 40px);

  --fpb-gap: clamp(10px, 1.1vw, 16px);
  --fpb-gap-lg: clamp(16px, 2vw, 28px);
  --fpb-pad: clamp(16px, 2.4vw, 30px);
  --fpb-r-sm: 10px;
  --fpb-r-md: 12px;
  --fpb-r-lg: 18px;
  --fpb-shadow: 0 18px 44px -18px rgba(26, 26, 46, .45);
}

/* ==========================================================================
   1. TYPE HARMONY — one stack, three roles
   --------------------------------------------------------------------------
   The families each named their own faces, so the same word rendered in
   three different ones. This file does not rewrite the rules that use the
   families' own tokens (that would be 2,000+ pages' worth of churn); it
   assigns the ROLES at the source:

     body copy  → DM Sans   (text face, one size, one line-height)
     headings   → Outfit    (display face)
     figures    → JetBrains Mono, tabular (the PNR, the price, the count)

   Two mechanisms, because the families disagree about where the family is
   named:

   a) The legacy token names. The instrument layer and the homepage sheet
      ask for --sans, --i-sans, --mono, --i-mono and --mono-font. Those are
      remapped here, so every rule that already asks for one of those names
      gets the brand's answer with no markup change and no new class.
      NOTE: the instrument layer REDEFINES --sans and --mono on .inst, so on
      the guides the remap below is shadowed — that is exactly why (b)
      exists.
   b) The elements themselves. The body face and the heading face are set
      here, so they win whatever the family does with its own tokens.
   ========================================================================== */

:root {
  --sans: var(--fpb-sans);
  --i-sans: var(--fpb-display);
  --mono: var(--fpb-mono);
  --i-mono: var(--fpb-mono);
  --mono-font: var(--fpb-mono);
}

/* The `!important` on the body rule is deliberate. Two reasons:

   1. The 43 locale homepages and the widget carry
      `body{font-family:Inter,'DM Sans',…!important}` — Inter is a face the
      site NEVER requests, so on a machine that happens to have it installed
      those pages would render in Inter while every other page renders in
      DM Sans. That is the same drift the owner is looking at, one step
      removed.
   2. The guides set the body face with a `font:` shorthand on .inst, which
      is a normal declaration; this one is important, so it wins the family
      while leaving the shorthand's size and line-height alone.

   The per-locale rules in styles.css (`html[lang="zh"] body{…!important}`
   and friends) out-specify this one, so the CJK / Arabic / Bengali body
   faces keep their native stack. The guide body therefore becomes DM Sans
   — the same text face as the homepage — instead of Outfit, which is a
   display face and was never meant to carry a screen of copy. */
body {
  font-family: var(--fpb-sans) !important;
}

/* The instrument layer sets the body face on .inst / .inst-map with a
   shorthand; this is the same statement for the case where .inst is not the
   body element (the guide's ticket shell is <body class="inst">, but the
   map shell is not). */
.inst, .inst-map {
  font-family: var(--fpb-sans) !important;
}

/* The UA default nobody asked for. Chrome's UA stylesheet gives every
   <button>, <input>, <select> and <textarea> `font: 400 13.33px Arial` — a
   face the site never requests and never wanted. Form controls do NOT
   inherit the body face, so the brand's text face has to be handed to them
   explicitly. Measured on /countries/thailand.html before this rule: NINE
   controls in Arial, including the booking modal's pay button ("Get the
   ticket"), its close ×, the consent checkbox and the PNR copy button —
   the money path, in the one face that appears nowhere else.
   The action buttons are then lifted to the display face by section 3;
   this rule is the floor for everything else. */
button,
input,
select,
textarea,
option {
  font-family: inherit;
}

/* Headings, everywhere, are the display face. The rule is deliberately
   un-specific (0,0,1): it only reaches the headings that never named a
   family. Any heading that DOES name one keeps it — including the
   per-locale CJK rules, which are !important and win outright. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--fpb-display);
}

.inst h1, .inst h2, .inst h3, .inst h4,
.inst .nav .brand, .inst .doc-head h1, .inst .band .kick,
.fp-inst h1, .fp-inst h2, .fp-inst h3, .fp-inst h4,
.hero h1, .hero h2, .hero .kick, .wrap h2 {
  font-family: var(--fpb-display);
}

/* ==========================================================================
   2. THE PROOF STRIP — one grammar, three surfaces
   --------------------------------------------------------------------------
   The homepage band, the guide header and the partner bar all answer the
   same question ("can I trust this, how fast, how much") with the same
   three facts. The containers stay theirs — a row in the band, a card grid
   on the guide, a navy bar on the partner page — but the TYPE inside them
   is now identical:

     the FIGURE is a number or a code, so it is set in JetBrains Mono with
       tabular figures: $7, 21,412, <60s, 18 / 19 all line up;
     the LABEL is words, so it is set in DM Sans, sentence case, muted;
     the FIGURE outranks the LABEL in size and weight, always.

   The old treatment — uppercase, letter-spaced, 10-11px mono micro-type —
   was the same "instrument readout" idea executed as decoration. It is
   dropped: the markup already says "Airports 440" in sentence case, and
   uppercasing it made the reader decode it. On the guides the labels are
   full sentences ("delivered to your inbox in under 60 seconds"), which in
   uppercase is both hard to read and needlessly wide.
   ========================================================================== */

/* ── homepage + locale-home band readout (a row) ────────────────────────── */
.inst-readout,
.inst-band .inst-readout {
  font-family: var(--fpb-sans);
  font-size: var(--fpb-fs-xs);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0;
  text-transform: none;
  gap: 6px 22px;
}
.inst-readout b,
.inst-band .inst-readout b {
  font-family: var(--fpb-mono);
  font-size: 1.05em;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--fpb-amber);
}

/* ── country-guide readout (3-cell strip) ──────────────────────────────── */
.inst .readout {
  font-family: var(--fpb-sans);
  font-size: var(--fpb-fs-xs);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}
.inst .readout .rsv {
  font-family: var(--fpb-mono);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--fpb-amber);
}
.inst .readout .rsl {
  font-family: var(--fpb-sans);
  font-size: var(--fpb-fs-xs);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0;
  text-transform: none;
}

/* ── partner portal bar ─────────────────────────────────────────────────── */
.strip .wrap {
  font-family: var(--fpb-sans);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}
.strip .wrap span b {
  font-family: var(--fpb-mono);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--fpb-amber);
}

/* ==========================================================================
   3. BUTTON GRAMMAR — one shape language
   --------------------------------------------------------------------------
   A hard offset shadow (a printed ticket, not a glow), a 1px lift on hover,
   a press back down, a 3px focus ring, and a 48px minimum touch target.
   The RADIUS of the action buttons is unified at 12px, because that is the
   one place the families disagree at a glance (4px / 6px / 10px / 12px /
   14px / 50px). 12px is the ticket language of ADR 0001: the booking
   modal's pay button and the partner portal's buttons were already 12px,
   and the legacy 50px pills are the pre-instrument marketing look.

   The nav pill keeps its own shape — it is chrome, not a call to action,
   and a nav chip that matches a hero button is a nav chip nobody can find.

   THE THREE FAMILIES OF CORNER, so the next agent does not re-litigate it:

     ACTION  12px  (--fpb-r-md) — every button and link whose job is to DO
             something: buy, pick, pay, send, open a tool. One shape, one
             token, one rule. This is the only corner the site owns.

     CHIP    its own — a small filter, a legend key, a country tag, a chat
             suggestion. A chip is read first and pressed second, so it may
             be a pill (the map legend) or a small plate (the country tags).
             Chips are never mistaken for the action: they are smaller,
             lighter and set in a row.

     CHROME  its own — the nav pill, the nav ticket stub, the round icon
             buttons, the language menu, the cards and sheets around the
             content. Chrome is furniture: it recedes, and it must not be
             mistaken for the thing you are supposed to press.
   ========================================================================== */

.inst-buy-first,
.inst .doc-btn,
.booking-pay-btn,
.btn,
.btn-primary,
.btn-secondary,
.trip-cta,
.hero-card-btn,
.booking-cta-btn,
.inst-dest-buy,
.inst .pass-btn,
.inst button.buy,
.inst .stub button.buy,
.cta-btn,
.inst-earn-cta a,
body .fp-rescue-cta {
  border-radius: var(--fpb-r-md);
  font-family: var(--fpb-display);
  font-weight: 800;
  min-height: 48px;
  transition: transform .12s ease, box-shadow .12s ease;
}
.inst-buy-first:hover,
.inst .doc-btn:hover,
.btn:hover,
.btn-primary:hover,
.btn-secondary:hover,
.trip-cta:hover,
.hero-card-btn:hover,
.booking-cta-btn:hover,
.inst-dest-buy:hover,
.inst .pass-btn:hover,
.inst button.buy:hover,
.inst .stub button.buy:hover,
.cta-btn:hover,
.inst-earn-cta a:hover,
body .fp-rescue-cta:hover {
  transform: translate(-1px, -1px);
}
.inst-buy-first:active,
.inst .doc-btn:active,
.btn:active,
.btn-primary:active,
.btn-secondary:active,
.trip-cta:active,
.hero-card-btn:active,
.booking-cta-btn:active,
.inst-dest-buy:active,
.inst .pass-btn:active,
.inst button.buy:active,
.inst .stub button.buy:active,
.cta-btn:active,
.inst-earn-cta a:active,
body .fp-rescue-cta:active {
  transform: translate(1px, 1px);
}
.inst-buy-first:focus-visible,
.inst .doc-btn:focus-visible,
.booking-pay-btn:focus-visible,
.btn:focus-visible,
.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.inst-dest-buy:focus-visible,
.inst .pass-btn:focus-visible,
.inst button.buy:focus-visible,
.inst .stub button.buy:focus-visible,
.cta-btn:focus-visible,
.inst-earn-cta a:focus-visible,
body .fp-rescue-cta:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: 3px;
}

/* The ONE place this file needs !important, and it is scoped to a single
   property of a single class. The guide's in-article CTA carries its radius
   as an INLINE style — `border-radius:14px`, baked into 2,800+ pages — and an
   inline declaration outranks every stylesheet rule, so without this the
   guide page would still show three different action-button radii (12px /
   14px / 4px) sitting next to each other. The other two radii are fixed by
   the rules above; this one cannot be reached any other way.

   The homepage's rescue button needed the opposite trick: its rule lives in
   a <style> block in the BODY of public/index.html, i.e. after this file in
   document order, so an equal-specificity rule here would lose. `body
   .fp-rescue-cta` out-specifies it (0,1,1 vs 0,1,0) and needs no
   !important. */
.cta-btn {
  border-radius: var(--fpb-r-md) !important;
}

/* The action radius, extended to the action classes the families brought
   with them. They are listed here — and NOT in the block above — because
   that block also sets the display face, the 800 weight and a 48px touch
   target, which is right for a page-level plate and wrong for a compact
   control (the fare box's "grab this fare", the route error's "try again",
   the map popup's CTA). This block only sets the CORNER.

   The selectors carry a `body` prefix where the rule that used to win was
   injected at runtime: public/js/app-core-en.js and public/js/fp-ai-chat.js
   append their <style> to document.head AFTER this sheet, so an
   equal-specificity rule here would lose. `body .x` out-specifies their
   `.x`, and the sources were fixed too — this is the pin that survives a
   cached script.

   The two ID-scoped rules keep the ID, because an ID outranks a class: the
   booking modal's own button and the map popup's back button are named by
   id, and a class selector here would simply lose to them.

   The two `fp-pay` rules carry !important because the rules they replace
   did too (999px on the amber pay button, 2px on the crypto one). They are
   the MONEY PATH: the two buttons that take the payment must not disagree
   with each other, and they must not disagree with the page they sit on. */
.booking-modal .booking-pay-btn,
.booking-modal .btn-primary,
.booking-modal .btn-secondary,
#bookingModal #bookingForm button[type="button"],
#bookingModal #fp-pos-cta,
.booking-pnr-copy,
.fp-v1-buy,
.fp-pay-btn,
.popup-cta,
#fpMapModal .fp-map-pop-back,
.fp-tools-grid a,
#fp-buybar .bb-btn,
.inst-stub .fp-issue-btn,
.inst .routeerr button,
body .fpchat-buycta button,
body .fpchat-ask,
body .ai-buy-cta button,
body .fp-fh-cta,
body .fp-guide {
  border-radius: var(--fpb-r-md);
}
body .fp-v1-show button[class*="fp-pay"],
body .fp-ns .fp-v1-show button[class*="fp-pay"] {
  border-radius: var(--fpb-r-md) !important;
}

/* The homepage's footer inspiration cards (the inspiration grid under the
   map). Their two CTAs are styled by a <style> block that lives in the
   BODY of public/index.html — AFTER this file in document order — so their
   radius cannot be reached from here: an equal-specificity rule in the head
   loses to a later rule in the body. The radius is therefore fixed at the
   source (public/index.html), and this rule supplies only what that block
   does not set: the display face for the quiet "Country guide" link and a
   44px touch target for both (they sit two-up in a footer card, where the
   48px of a page-level button would break the card's rhythm). */
body footer.apf .fp-ir-buy,
body footer.apf .fp-ir-guide {
  font-family: var(--fpb-display);
  font-weight: 800;
  min-height: 44px;
}

/* The nav ticket stub, on both families that have one. At desktop it is 4px
   on the guide (the ticket-stub card in .inst .nav) and 4px on the homepage
   strip; below 620px the homepage's stub grows to 8px (it takes a full row
   of its own) while the guide's stayed 4px. Two nav bars, one role, two
   radii. The mobile stub is 8px everywhere now. */
@media (max-width: 620px) {
  .inst .nav .nav-cta,
  .inst-strip nav a.inst-strip-cta {
    border-radius: 8px;
  }
}

/* The partner portal's action button: same radius, same weight, same press,
   and the same hard-shadow hover the ticket language uses. */
.btn-pink:hover {
  transform: translate(-2px, -2px);
  box-shadow: 6px 6px 0 rgba(26, 26, 46, .55);
}
.btn:active { transform: translate(0, 0); }

/* ==========================================================================
   4. SHARED PRIMITIVES
   --------------------------------------------------------------------------
   The vocabulary a page uses when it needs something new. Deliberately few,
   deliberately boring: a kicker, a heading, a lede, a card, a trust row. A
   page that joins the layer inherits the system instead of inventing
   another one.
   ========================================================================== */

.fpb-kicker {
  font-family: var(--fpb-display);
  font-size: var(--fpb-fs-xs);
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fpb-dim);
  margin: 0 0 .35em;
}

.fpb-h2 {
  font-family: var(--fpb-display);
  font-size: var(--fpb-fs-h2);
  font-weight: 900;
  line-height: 1.14;
  letter-spacing: -.015em;
  color: var(--fpb-ink);
  margin: 0 0 .4em;
}

.fpb-lede {
  font-size: var(--fpb-fs-lead);
  line-height: 1.6;
  color: var(--fpb-dim);
  max-width: 68ch;
  margin: 0 0 var(--fpb-gap-lg);
}

.fpb-card {
  background: var(--fpb-card);
  border: 1px solid var(--fpb-edge-light);
  border-radius: var(--fpb-r-md);
  padding: var(--fpb-pad);
  box-shadow: 0 10px 30px -20px rgba(26, 26, 46, .35);
}

/* Trust row — the proof points (price, speed, coverage). One component, so
   the same three numbers are said the same way everywhere. */
.fpb-trust {
  display: flex;
  flex-wrap: wrap;
  gap: var(--fpb-gap);
  align-items: stretch;
  margin: 0;
  padding: 0;
  list-style: none;
}
.fpb-trust__item {
  flex: 1 1 180px;
  min-width: 0;
  background: var(--fpb-card);
  border: 1px solid var(--fpb-edge-light);
  border-radius: var(--fpb-r-sm);
  padding: 12px 14px;
}
.fpb-trust__value {
  display: block;
  font-family: var(--fpb-mono);
  font-size: var(--fpb-fs-h3);
  font-weight: 800;
  line-height: 1.1;
  color: var(--fpb-ink);
  font-variant-numeric: tabular-nums;
}
.fpb-trust__label {
  display: block;
  margin-top: 4px;
  font-size: var(--fpb-fs-xs);
  font-weight: 600;
  line-height: 1.4;
  color: var(--fpb-dim);
}

/* ==========================================================================
   5. RESPONSIVE FLOOR
   --------------------------------------------------------------------------
   The families disagreed about what "responsive" meant: the homepage leaned
   on 85 inline media queries, the guides on instrument.css, the partner
   page on two. Below the floor the type and the touch targets adapt, and
   no family is allowed to overflow sideways.
   ========================================================================== */

@media (max-width: 720px) {
  .fpb-trust { gap: 8px; }
  .fpb-trust__item { flex: 1 1 calc(50% - 4px); }
  .inst-buy-first,
  .inst .doc-btn,
  .booking-pay-btn,
  .btn-primary,
  .btn-secondary,
  .inst button.buy,
  .inst .stub button.buy { width: 100%; }
}

@media (max-width: 420px) {
  .fpb-trust__item { flex: 1 1 100%; }
  .inst .readout { grid-template-columns: 1fr; }
  .inst .readout .rscell { min-height: 44px; }
}

/* A long URL or a long country name must not push the page sideways. The
   guide family sets this on its own content column; the layer sets it for
   the families that did not. */
.inst .doc-body, .inst .doc-head, .inst .band, .wrap { overflow-wrap: break-word; }

/* ==========================================================================
   6. MOTION + PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .inst-buy-first, .inst .doc-btn, .btn, .booking-pay-btn, .btn-primary,
  .btn-secondary, .trip-cta, .hero-card-btn, .booking-cta-btn,
  .inst-dest-buy, .inst .pass-btn, .inst button.buy, .inst .stub button.buy,
  .cta-btn, .fp-rescue-cta,
  .inst-buy-first:hover, .inst .doc-btn:hover, .btn:hover, .btn-primary:hover,
  .btn-secondary:hover, .trip-cta:hover, .hero-card-btn:hover,
  .booking-cta-btn:hover, .inst-dest-buy:hover, .inst .pass-btn:hover,
  .inst button.buy:hover, .inst .stub button.buy:hover, .cta-btn:hover,
  .fp-rescue-cta:hover {
    transition: none;
    transform: none;
  }
}

@media print {
  .inst-buy-first, .inst .doc-btn, .btn, .booking-pay-btn { border-color: #000; }
}
