/* ==========================================================================
   BOOKALLO — bkx, THE VISUAL SHELL
   A NEW namespace, built to the approved reference set, not a patch over the
   old one. Nothing in this file extends janet_home.css or bk_hero.css; the
   homepage stops loading both and is rebuilt out of these components.

   WHAT IS PRESERVED, AND WHY IT LOOKS LIKE INHERITANCE BUT IS NOT
   ---------------------------------------------------------------
   Every id and class the running product QUERIES survives, because the search,
   the fares, the hotel band and the attribution path are driven by name from
   janet_home.js, janet_deals_strip.js and operator/price_refresh.js. So the
   markup keeps `#jn-form`, `#jn-dest`, `#jn-out`, `#jn-back`, `#jn-pax`,
   `#jn-go`, `#jn-go-label`, `#jn-err`, `.jn-tab[data-mode]`, and
   two children, `#jn-rows`, `#jn-deals`, `#jn-lowcost`, `#jn-hotels`,
   `#jn-freshness`, and the `data-dest` option list the price engine scans.
   Those are the PRODUCT. Everything around them - the layout, the material,
   the depth, the type, the light - is new.

   WHERE THE REFERENCE AND THE TRUTH RULE DISAGREE
   -----------------------------------------------
   The references print "10M+ Happy Travelers", "4.9 Average Rating", "120+
   Destinations", and fares for Santorini, the Maldives and Bali. This product
   holds none of those: no review corpus, no traveller count, and ten
   destinations with measured fares to European cities. Printing them would be
   the exact failure this codebase has a rule against, and the brief that
   commissioned this work says FAKE_DATA=FORBIDDEN in the same breath as it
   names the references.

   So the reference is followed as a VISUAL system - the stat block's rhythm,
   its position, its weight - and filled with claims this site already stands
   behind, plus one number the build can count. The design is the reference's.
   The facts are ours.

   01 tokens          05 the rail          09 planner
   02 shell + nav     06 the globe         10 closing + footer
   03 hero scene      07 measured fares    11 responsive
   04 search console  08 hotels            12 reduced motion
   ========================================================================== */


/* == 01 · TOKENS ========================================================== */

:where(.bkx) {
  /* ---- Ground. Midnight, not grey: the references are lit scenes in a dark
     room, and a #14161A "dark UI" grey reads as a dashboard the moment a
     photograph sits next to it. ---- */
  --x-void:    #04070C;
  --x-deep:    #070B13;
  --x-raised:  #0C1119;
  --x-line:    rgba(240, 236, 226, .10);
  --x-line-2:  rgba(240, 236, 226, .18);

  /* ---- Champagne. Three steps: the light, the metal, the wash. ---- */
  --x-gold:      #E3BE79;
  --x-gold-deep: #C9A24A;
  --x-gold-wash: rgba(227, 190, 121, .12);
  --x-gold-edge: rgba(227, 190, 121, .42);
  --x-on-gold:   #10131A;   /* NEVER #fff on champagne - 1.6:1 */

  /* ---- Warm white. Cool white on a warm sunset frame reads as a screenshot
     of a different site pasted on top. ---- */
  --x-ink:   #F5F1E8;
  --x-ink-2: #C3C6CC;
  --x-ink-3: #8E939C;

  /* ---- Smoked glass. The console and every floating panel are the same
     material at three densities, so the product reads as one object family. ---- */
  --x-glass:   linear-gradient(157deg, rgba(14, 19, 28, .78), rgba(6, 9, 15, .88));
  --x-glass-2: linear-gradient(157deg, rgba(18, 24, 34, .86), rgba(8, 11, 18, .93));
  --x-blur: blur(22px) saturate(150%);

  /* ---- Depth. Shadows are long and soft; a tight shadow reads as a sticker. ---- */
  --x-e1: 0 2px 10px rgba(0, 0, 0, .5);
  --x-e2: 0 18px 44px -20px rgba(0, 0, 0, .86);
  --x-e3: 0 34px 80px -30px rgba(0, 0, 0, .94);
  --x-e4: 0 54px 120px -40px rgba(0, 0, 0, .98);
  --x-glow: 0 18px 50px -20px rgba(227, 190, 121, .40);

  --x-r:    16px;
  --x-r-lg: 22px;
  --x-r-pill: 999px;

  --x-ease:   cubic-bezier(.22, 1, .36, 1);
  --x-ease-2: cubic-bezier(.16, 1, .3, 1);

  /* ---- The frame. Wide, because the references are cinema: a 1180px column
     in a 2560px window is a 2013 website with a lot of unused screen. ---- */
  --x-max: min(1680px, 92vw);
  --x-gut: clamp(20px, 4vw, 64px);

  color: var(--x-ink);
  background: var(--x-void);
}


/* == 02 · SHELL + NAV ===================================================== */

html.bkx-html, body.bkx-body {
  background: var(--x-void);
  color: var(--x-ink);
}
body.bkx-body { margin: 0; overflow-x: hidden; }

.bkx a { color: inherit; }
.bkx img { display: block; max-inline-size: 100%; }
.bkx ::selection { background: var(--x-gold); color: var(--x-on-gold); }

/* Focus is one visible ring for the whole shell, and it is never removed. */
.bkx :focus-visible {
  outline: 2px solid var(--x-gold);
  outline-offset: 3px;
  border-radius: 4px;
}

.bkx-wrap { inline-size: var(--x-max); margin-inline: auto; }

/* --- nav ---------------------------------------------------------------
 * Transparent over the hero, and it takes on ground only once the page has
 * left it. The state is set by bkx.js from the same frame that drives the
 * scroll camera, so there is one authority for "where are we".
 */
/*
 * FRAGMENT TARGETS.
 *
 * Measured 2026-09-09 by scripts/internal_link_audit.js: 186 links in the
 * built site pointed at homepage fragments that did not exist. A fragment is
 * never sent to the server, so /#deal and / are the SAME REQUEST, and every
 * HTTP route sweep reported 200 for a link that did nothing at all.
 *
 * Two rules make the restored targets usable:
 *
 *   .bkx-anchor   an ALIAS. One element carries one id, and two navigations
 *                 legitimately name the same band (#prices from the injected
 *                 header, #deal from the footer). A zero-size span is the
 *                 alias; it adds no box, no gap and no focus stop.
 *   scroll-padding-block-start  the nav is position:fixed, so without this the
 *                 browser scrolls the heading to y=0 and the bar covers it.
 *                 The mobile dock already claimed the -end side for the same
 *                 reason.
 */
.bkx-anchor {
  display: block;
  block-size: 0;
  inline-size: 0;
  overflow: hidden;
}
html { scroll-padding-block-start: var(--x-nav-h, 82px); }

.bkx-nav {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 44px);
  padding: clamp(14px, 1.6vw, 22px) var(--x-gut);
  transition: background-color .45s var(--x-ease), backdrop-filter .45s var(--x-ease),
              border-color .45s var(--x-ease), padding .45s var(--x-ease);
  border-block-end: 1px solid transparent;
}
.bkx-nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* .74 → .84 at the top and .16 → .34 at the fold of the tint: the nav's
     own labels ("Talk to EL", cream) measured 4.42:1 against the hero photo
     showing through. Still a translucent bar over the picture, a shade deeper. */
  background: linear-gradient(180deg, rgba(4, 7, 12, .84), rgba(4, 7, 12, .34) 62%, transparent);
  transition: opacity .45s var(--x-ease);
}
.bkx-nav.is-solid {
  background: rgba(4, 7, 12, .86);
  -webkit-backdrop-filter: var(--x-blur);
  backdrop-filter: var(--x-blur);
  border-block-end-color: var(--x-line);
  padding-block: clamp(10px, 1.1vw, 14px);
}
.bkx-nav.is-solid::before { opacity: 0; }

.bkx-brand { display: flex; align-items: center; gap: .6rem; text-decoration: none; flex: none; }
.bkx-brand__mark {
  display: grid;
  place-items: center;
  inline-size: 34px; block-size: 34px;
  border-radius: 10px;
  background: linear-gradient(150deg, var(--x-gold), var(--x-gold-deep));
  color: var(--x-on-gold);
  font-weight: 700;
  font-size: 1.05rem;
  line-height: 1;
  box-shadow: var(--x-glow);
}
.bkx-brand__name {
  font-size: clamp(1rem, .9vw + .7rem, 1.25rem);
  letter-spacing: .18em;
  font-weight: 600;
  color: var(--x-ink);
}

.bkx-nav__links {
  display: flex;
  align-items: center;
  gap: clamp(14px, 1.8vw, 30px);
  margin-inline-end: auto;
  /* so the compact search can claim room instead of pushing the nav wider
     than the viewport once it appears */
  min-inline-size: 0;
}
.bkx-nav__links a {
  position: relative;
  font-size: .93rem;
  letter-spacing: .01em;
  color: var(--x-ink-2);
  text-decoration: none;
  padding-block: 6px;
  transition: color .25s var(--x-ease);
}
.bkx-nav__links a::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  inline-size: 0;
  block-size: 1px;
  background: var(--x-gold);
  transition: inline-size .3s var(--x-ease);
}
.bkx-nav__links a:hover { color: var(--x-ink); }
.bkx-nav__links a:hover::after { inline-size: 100%; }

.bkx-nav__acts { display: flex; align-items: center; gap: 10px; flex: none; }
.bkx-icon {
  display: grid;
  place-items: center;
  inline-size: 38px; block-size: 38px;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-line-2);
  background: rgba(255, 255, 255, .03);
  color: var(--x-ink-2);
  text-decoration: none;
  transition: border-color .25s var(--x-ease), color .25s var(--x-ease),
              background-color .25s var(--x-ease), transform .25s var(--x-ease);
}
.bkx-icon:hover { border-color: var(--x-gold-edge); color: var(--x-gold); transform: translateY(-1px); }
.bkx-icon svg { inline-size: 17px; block-size: 17px; }
/*
 * The EL pill is a ROW. It inherited `display: grid` from .bkx-icon, which
 * stacked the mark over the label, and the label then hung below a 44px pill
 * (measured live 2026-09-16: label at y 56-74 under a pill ending at 68).
 */
.bkx-icon--el {
  display: inline-flex; align-items: center; justify-content: center;
  padding-block: 0; padding-inline: 8px 14px; inline-size: auto; gap: 8px;
  white-space: nowrap;
}
.bkx-icon--el > span:last-child { font-size: .84rem; line-height: 1; }
/* The pill's mark: a gold sparkle in a quiet disc — a symbol, never a face. */
.bkx-icon--el .bkx-ai {
  display: grid; place-items: center;
  inline-size: 28px; block-size: 28px; flex: none;
  border-radius: 50%;
  color: var(--x-gold);
  background: radial-gradient(circle at 32% 28%, rgba(227, 190, 121, .26), rgba(227, 190, 121, .06) 72%);
  box-shadow: inset 0 0 0 1px var(--x-gold-edge);
}
.bkx-icon--el .bkx-ai svg { inline-size: 16px; block-size: 16px; fill: currentColor; }
.bkx-icon--el:hover .bkx-ai { background: var(--x-gold-wash); }

.bkx-burger { display: none; }


/* == 03 · HERO SCENE ====================================================== */

/*
 * FIVE LAYERS, and each one is a real element at a real distance:
 *   sky      the graded horizon wash
 *   world    the destination photograph
 *   haze     atmosphere between the world and the interface
 *   ui       headline, console, stats
 *   float    the destination panel that sits in front of everything
 *
 * The camera is `--x-cam-*`, written once a frame by bkx.js from the pointer
 * and the scroll position, and INHERITED by the layers - so one write moves
 * the whole scene and every layer decides how much of it applies to itself.
 */
.bkx-hero {
  position: relative;
  min-block-size: 94svh;
  display: grid;
  place-items: center;
  isolation: isolate;
  overflow: hidden;
  --x-cam-x: 0;
  --x-cam-y: 0;
  --x-cam-z: 0;
}

.bkx-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transform: translate3d(
    calc(var(--x-cam-x) * var(--x-depth, 0px)),
    calc(var(--x-cam-y) * var(--x-depth, 0px) + var(--x-scroll, 0px)),
    0) scale(var(--x-zoom, 1));
}
/* MICRO-PARALLAX (owner, 2026-09-06: "the user should notice the depth
   subconsciously, not consciously see the objects moving"). `--x-depth` is
   the FULL pointer travel of a layer, edge to edge: the sky 1px, the
   photograph 2px, the near foreground 4px. Depth is carried by the
   perspective, the Z placement, the overlap and the light - not by motion. */
.bkx-layer--sky   { --x-depth: 1px;  z-index: 0; }
.bkx-layer--world { --x-depth: 2px;  z-index: 1; }
.bkx-layer--haze  { --x-depth: 4px;  z-index: 2; }

.bkx-hero__pic {
  position: absolute;
  inset: -6%;
  inline-size: 112%;
  block-size: 112%;
  /*
   * THE BLOCK OVERSCAN IS IN VIEWPORT UNITS, NOT A PERCENTAGE OF THE HERO
   * (2026-09-18). `inset: -6%` put the picture's top at -6% of the hero's
   * HEIGHT, so every change to anything in the hero — the origin fields
   * mounting, the hot-deals strip filling, a font swap re-wrapping the
   * sub-line — moved a full-viewport image. Measured on production at 390
   * with 4x CPU: CLS 0.21, all of it this element (0.163 when the fields
   * grew 15px -> 84px, 0.046 when the sub-line re-wrapped). The camera
   * travels 2px with the pointer and the scroll push-in only moves it DOWN,
   * so the top needs a fixed margin, not one that breathes with the content.
   * The inline overscan stays a percentage: the width does not move.
   */
  inset: -6svh -6%;
  block-size: calc(100% + 12svh);
  /*
   * THE OVERSCAN WAS BEING CANCELLED, and the parallax then exposed the
   * ground behind it. Measured at 1440 on the English homepage: the picture
   * sat at left -86 (the 6% offset, correctly applied) and was 1440 wide
   * rather than 1612 — an 86px black band down the right edge of the hero.
   *
   * The base sheet publishes a global `img { max-inline-size: 100% }`, which
   * is right for every photograph in an article and wrong for the one image
   * on the page that is DELIBERATELY bigger than its frame so the camera has
   * somewhere to travel.
   */
  object-fit: cover;
  object-position: center 52%;
}
/*
 * Two classes, because `.bkx img { max-inline-size: 100% }` is two and a
 * single-class override loses to it wherever it sits in the file. That cap is
 * right for every photograph in an article and wrong for the one image on the
 * page that is deliberately bigger than its frame so the camera has somewhere
 * to travel.
 */
.bkx .bkx-hero__pic { max-inline-size: none; max-block-size: none; }

/* The grade. The reference frames are dark at the edges and lit in the middle,
   with the ground carrying the interface. Three gradients, each priced for what
   it does alone - stacked opaque scrims are how a photograph disappears. */
.bkx-hero__grade {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(4, 7, 12, .86) 0%, rgba(4, 7, 12, .34) 22%,
                            rgba(4, 7, 12, .52) 62%, rgba(4, 7, 12, .90) 100%),
    radial-gradient(112% 74% at 50% 40%, rgba(4, 7, 12, .06) 22%, rgba(4, 7, 12, .82) 100%);
}

/* Atmosphere: two very slow warm/cool lights, and a horizon sheen that crosses
   the frame once every twenty seconds. No canvas, no particles - a dust field
   behind a search box is a game. */
.bkx-hero__haze {
  position: absolute;
  inset: -10%;
  inset: -10svh -10%; /* fixed block overscan, as .bkx-hero__pic above */
  opacity: .8;
  background:
    radial-gradient(42% 46% at 26% 30%, rgba(240, 196, 128, .16), transparent 70%),
    radial-gradient(46% 42% at 78% 62%, rgba(120, 158, 208, .12), transparent 72%);
}
@keyframes bkx-haze { 0%,100% { translate: 0 0; scale: 1; } 50% { translate: 2.2% -1.4%; scale: 1.07; } }
/* Was a 28s drift. The hero is still at idle now (owner, 2026-09-06); the
   two lights stay where they are painted. */
html.js .bkx-hero__haze { animation: none; }

.bkx-hero__sheen {
  position: absolute;
  inset: 0;
  opacity: .5;
  background: linear-gradient(102deg, transparent 42%, rgba(255, 244, 222, .10) 50%, transparent 58%);
  background-size: 280% 100%;
}
@keyframes bkx-sheen { from { background-position: 160% 0; } to { background-position: -70% 0; } }
/* Was a 22s sweep across the frame. Static now, for the same reason. */
html.js .bkx-hero__sheen { animation: none; background-position: 66.7% 0; }
/* Where the still streak lands: the band sits at 50% of a 280%-wide image,
   so background-position p puts it at (1.4 - 1.8p) of the frame - 66.7%
   is the FREE side of the Hebrew hero (x ~20%), 33.3% the free side of the
   English one (x ~80%). At 40% it lay across the headline column and the
   live contrast probe measured the sub-line at 4.50:1, on the floor. On a
   phone the type spans the frame, so the streak is simply not drawn. */
.bkx-hero:dir(ltr) .bkx-hero__sheen { background-position: 33.3% 0; }
@media (max-width: 900px) { .bkx-hero__sheen { opacity: 0; } }

.bkx-hero__body {
  position: relative;
  z-index: 5;
  inline-size: var(--x-max);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-block: clamp(88px, 11vh, 132px) clamp(26px, 4vh, 48px);
  transform: translate3d(0, var(--x-ui-y, 0px), 0) scale(var(--x-ui-s, 1));
  opacity: var(--x-ui-o, 1);
}

/* Full width; the MEASURE is capped on the lines that need one. */
.bkx-hero__say { inline-size: 100%; text-align: center; }

.bkx-hero__eyebrow {
  display: block;
  font-size: .72rem;
  letter-spacing: .34em;
  text-transform: uppercase;
  /* A lighter champagne than the accent: 11.5px gold over the hero photograph
     measured 4.43:1 at one width (release gate, 2026-09-07). The tint is the
     accent's own highlight stop, so it still reads as the same gold. */
  color: #EED3A0;
  margin-block-end: 1.1rem;
}
/*
 * The display face is Frank Ruhl Libre, which the page ALREADY loads for
 * Hebrew and which carries a full Latin serif. One font request for both
 * languages, and the same headline weight in each - a second display family
 * for English would be two brands.
 */
.bkx-h1 {
  font-family: "Frank Ruhl Libre", Georgia, "Times New Roman", serif;
  font-weight: 500;
  font-size: clamp(2.4rem, 4.4vw + .6rem, 5.2rem);
  line-height: 1.02;
  letter-spacing: -.02em;
  margin: 0 auto;
  max-inline-size: 18ch;
  text-wrap: balance;
  text-shadow: 0 4px 40px rgba(0, 0, 0, .7);
}
.bkx-h1 em {
  display: block;
  font-style: normal;
  color: var(--x-gold);
}
.bkx-hero__sub {
  margin: 1rem auto 0;
  max-inline-size: 46ch;
  font-size: clamp(.95rem, .4vw + .84rem, 1.08rem);
  line-height: 1.55;
  color: var(--x-ink-2);
  text-shadow: 0 2px 18px rgba(0, 0, 0, .8);
}

/* --- the trust block ---------------------------------------------------
 * The reference's stat block, filled with facts rather than invented ones.
 * The count is written by the build from the destinations that actually have
 * a page; the other two are commitments this site already makes everywhere.
 */
.bkx-stats {
  position: absolute;
  z-index: 6;
  inset-block-start: 46%;
  inset-inline-start: var(--x-gut);
  display: grid;
  gap: clamp(14px, 2vh, 26px);
  margin: 0;
  padding: 0;
  list-style: none;
  /* Narrow on purpose. This block is three short claims, and giving it the
     fare panel's width would take the room the console needs. */
  max-inline-size: 176px;
}
.bkx-stats li { display: block; }
.bkx-stats b {
  display: block;
  font-family: "Frank Ruhl Libre", Georgia, serif;
  font-size: clamp(1.5rem, 1.4vw + 1rem, 2.1rem);
  font-weight: 500;
  line-height: 1.05;
  color: var(--x-ink);
}
.bkx-stats span {
  display: block;
  font-size: .78rem;
  line-height: 1.4;
  color: var(--x-ink-3);
  margin-block-start: .2rem;
}

/* --- scroll cue --------------------------------------------------------- */
.bkx-cue {
  position: absolute;
  z-index: 6;
  inset-block-end: clamp(18px, 3vh, 34px);
  left: 50%;                     /* physical, like the translate (RTL centring, 2026-09-12) */
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: .6rem;
  font-size: .72rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  /* --x-ink-3 over the hero's lower haze measured 4.34:1 (release gate). One
     step up the ink scale; the cue is still the quietest thing on the screen. */
  color: var(--x-ink-2);
  background: none;
  border: 0;
  cursor: pointer;
}
.bkx-cue__ring {
  display: grid; place-items: center;
  inline-size: 30px; block-size: 30px;
  border-radius: 50%;
  border: 1px solid var(--x-line-2);
}
@keyframes bkx-cue { 0%,100% { transform: translateY(0); opacity: .6; } 50% { transform: translateY(4px); opacity: 1; } }
/* The cue used to bob every 2.4s - the one thing in the hero that never
   stopped. It points; it does not need to wave. */
html.js .bkx-cue__ring svg { animation: none; inline-size: 12px; block-size: 12px; }


/* == 04 · SEARCH CONSOLE ================================================== */

/*
 * The control deck. It is the largest object in the frame and the one thing
 * the page exists to be used through, so every effect here gets out of the way
 * the moment somebody touches it: the rest angle flattens on hover, on
 * focus-within and on every coarse pointer.
 */
.bkx-console {
  position: relative;
  z-index: 7;
  inline-size: 100%;
  max-inline-size: min(920px, 100%);
  margin-block-start: clamp(26px, 4vh, 46px);
  border-radius: var(--x-r-lg);
  border: 1px solid var(--x-line-2);
  background: var(--x-glass);
  -webkit-backdrop-filter: var(--x-blur);
  backdrop-filter: var(--x-blur);
  box-shadow: var(--x-e4), 0 0 0 1px rgba(227, 190, 121, .08);
  transform: perspective(1600px) rotateX(var(--x-deck, 5deg));
  transform-origin: 50% 100%;
  transition: transform .6s var(--x-ease-2), box-shadow .6s var(--x-ease-2);
}
html.js .bkx-console:hover,
html.js .bkx-console:focus-within { --x-deck: 0deg; }
@media (hover: none), (pointer: coarse) { .bkx-console { --x-deck: 0deg; } }

.bkx-console::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline: 15%;
  block-size: 1px;
  background: linear-gradient(90deg, transparent, rgba(227, 190, 121, .8), transparent);
}
/* The light it stands in. Clipped short - a full mirror image is a 2009 effect. */
.bkx-console::after {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  inset-inline: 8%;
  block-size: 52px;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(227, 190, 121, .18), transparent 76%);
  filter: blur(10px);
}

/* --- tabs --------------------------------------------------------------- */
.bkx-tabs {
  position: relative;
  display: flex;
  gap: 2px;
  padding: 8px 8px 0;
  border-block-end: 1px solid var(--x-line);
  /*
   * The console has a 22px corner; the glide behind the active tab is a
   * square-shouldered box sitting flush against the top edge, so at the
   * leading corner it poked OUT of the panel and the selected tab read as a
   * chip stuck onto the outside of it. Clipping the tab row to the same
   * radius keeps the highlight inside the object it belongs to; the console
   * itself stays unclipped so its reflection below is not cut off.
   */
  border-radius: var(--x-r-lg) var(--x-r-lg) 0 0;
  overflow: hidden;
}
.bkx-tab {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .74rem 1.15rem;
  border: 0;
  background: none;
  color: var(--x-ink-3);
  font: inherit;
  font-size: .9rem;
  border-radius: 12px 12px 0 0;
  cursor: pointer;
  text-decoration: none;
  transition: color .28s var(--x-ease);
  min-block-size: 44px;
}
.bkx-tab svg { inline-size: 17px; block-size: 17px; transition: transform .28s var(--x-ease), filter .28s var(--x-ease); }
.bkx-tab:hover { color: var(--x-ink-2); }
.bkx-tab[aria-selected="true"] { color: var(--x-ink); }
.bkx-tab[aria-selected="true"] svg {
  color: var(--x-gold);
  transform: translateY(-1px) scale(1.06);
  filter: drop-shadow(0 0 8px rgba(227, 190, 121, .6));
}
/* One light that GLIDES between tabs, rather than a border that reappears. */
.bkx-tabs__glide {
  position: absolute;
  z-index: 0;
  inset-block: 8px 0;
  inset-inline-start: 0;
  inline-size: var(--x-tab-w, 0px);
  transform: translate3d(var(--x-tab-x, 0px), 0, 0);
  border-radius: 12px 12px 0 0;
  background: linear-gradient(180deg, rgba(227, 190, 121, .20), rgba(227, 190, 121, .04));
  box-shadow: inset 0 0 0 1px rgba(227, 190, 121, .24);
  opacity: var(--x-tab-o, 0);
  transition: transform .32s var(--x-ease), inline-size .32s var(--x-ease), opacity .2s linear;
  pointer-events: none;
}

/* --- fields ------------------------------------------------------------- */
/* Not five equal columns. A dd/mm/yyyy control needs about 130px of usable
   width and clipped to "/mm/yyyy" at an even fifth, and the passengers cell is
   two words, so it can give room back.

   The origin cell used to be listed here as "a fixed string" and took the
   narrowest column on the deck. It is a searchable field over 3,787 airports
   now, so it takes the same width as the destination: a city typed into a
   column sized for "TLV" is ellipsised while it is being typed. */
.bkx-form {
  display: grid;
  grid-template-columns:
    minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.2fr) minmax(0, 1.2fr) minmax(0, .8fr) auto;
  align-items: stretch;
}
.bkx-field {
  position: relative;
  display: block;
  padding: .5rem .85rem .45rem;
  border-inline-start: 1px solid var(--x-line);
  transition: background-color .28s var(--x-ease), box-shadow .28s var(--x-ease);
  min-inline-size: 0;
}
.bkx-field:first-child { border-inline-start: 0; }
.bkx-field:focus-within { background: rgba(227, 190, 121, .05); box-shadow: inset 0 -2px 0 var(--x-gold); }
.bkx-field > span {
  display: block;
  font-size: .65rem;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--x-ink-3);
  margin-block-end: .3rem;
}
.bkx-field input,
.bkx-field select {
  /*
   * 50px, for a 44px TARGET, and the difference is the console's rest angle.
   *
   * The deck sits at rotateX(5deg), which foreshortens everything standing on
   * it: a control computing 46px measured 42px on screen, and the touch-target
   * sweep measures the RENDERED box - which is the one a thumb lands on. So the
   * height is chosen against the transform rather than against the number in
   * the specification: 50 * (42/46) = 45.6.
   *
   * border-box as well, because the base sheet sizes form controls on the
   * content box and a 44px minimum came out 40 once its own padding was
   * subtracted. Two separate reasons, both measured, neither visible in the
   * declared value.
   *
   * The alternative was to flatten the deck, which is the one thing about this
   * hero the reference is most specific about.
   */
  box-sizing: border-box;
  inline-size: 100%;
  border: 0;
  background: none;
  color: var(--x-ink);
  font: inherit;
  font-size: .98rem;
  padding: 0;
  min-block-size: 50px;
}
.bkx-field select { appearance: none; cursor: pointer; }
.bkx-field input::placeholder { color: var(--x-ink-3); }
.bkx-field input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(.8) sepia(1) saturate(2) hue-rotate(2deg); cursor: pointer; }
.bkx-field option { background: var(--x-raised); color: var(--x-ink); }

.bkx-go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  margin: 8px;
  padding-inline: clamp(1.2rem, 2vw, 2rem);
  min-block-size: 52px;
  border: 0;
  border-radius: 14px;
  background: linear-gradient(160deg, var(--x-gold), var(--x-gold-deep));
  color: var(--x-on-gold);
  font: inherit;
  font-weight: 700;
  font-size: .98rem;
  cursor: pointer;
  box-shadow: var(--x-glow);
  transition: transform .2s var(--x-ease), box-shadow .2s var(--x-ease), filter .2s var(--x-ease);
  white-space: nowrap;
}
.bkx-go:hover { transform: translateY(-2px); box-shadow: 0 22px 60px -20px rgba(227, 190, 121, .6); filter: brightness(1.04); }
.bkx-go:active { transform: translateY(1px) scale(.99); }
.bkx-go svg { inline-size: 17px; block-size: 17px; }

.bkx-err {
  grid-column: 1 / -1;
  margin: 0;
  padding: 0 1.1rem .7rem;
  color: #FFB4A2;
  font-size: .85rem;
  min-block-size: 0;
}
.bkx-err:empty { display: none; }
#jf-hint { color: var(--x-ink-3); }

/* --- the compact form of the same object -------------------------------- */
.bkx-sticky {
  /* A CHILD OF THE HEADER. See the mount comment in bkx.js: as a
     position:fixed overlay this pill printed itself on top of the globe, the
     coverflow and the planner, which is the "floating controls detached /
     debug-like" P0 verbatim. In the flow of the nav it can only ever sit
     beside the links, so there is nothing left for it to cover. */
  display: flex;
  align-items: center;
  flex: 0 1 auto;
  min-inline-size: 0;
  pointer-events: none;
  transform: translate3d(0, -6px, 0);
  opacity: 0;
  transition: transform .4s var(--x-ease), opacity .28s linear;
}
.bkx-sticky.is-on { transform: none; opacity: 1; }
.bkx-sticky[hidden] { display: none; }
.bkx-sticky__btn {
  pointer-events: auto;
  /* Sized to its CONTENT. Before the reader has chosen anything the bar holds
     four words, and a fixed 760px pill around them reads as an empty search
     field somebody left floating over the page rather than as a compact
     control. It grows as the summary does. */
  inline-size: auto;
  max-inline-size: min(360px, 30vw);
  min-block-size: 44px;
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .55rem 1rem;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-line-2);
  background: rgba(8, 11, 18, .92);
  -webkit-backdrop-filter: var(--x-blur);
  backdrop-filter: var(--x-blur);
  box-shadow: var(--x-e2);
  color: var(--x-ink);
  font: inherit;
  font-size: .92rem;
  text-align: start;
  cursor: pointer;
}
.bkx-sticky__btn:hover { border-color: var(--x-gold-edge); }
.bkx-sticky__ico {
  display: grid; place-items: center;
  inline-size: 32px; block-size: 32px; flex: none;
  border-radius: 50%;
  background: var(--x-gold);
  color: var(--x-on-gold);
}
.bkx-sticky__ico svg { inline-size: 16px; block-size: 16px; }
.bkx-sticky__vals { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* == SCENES · shared frame ================================================ */

.bkx-scene {
  position: relative;
  padding-block: clamp(56px, 7vh, 104px);
  isolation: isolate;
}
.bkx-scene--tight { padding-block: clamp(48px, 6vh, 90px); }

/* The ground between scenes is never flat black: a long soft wash keeps the
   page reading as one continuous room rather than stacked panels. */
.bkx-scene::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(80% 60% at 50% 0%, rgba(18, 26, 40, .55), transparent 70%);
}

.bkx-head { inline-size: var(--x-max); margin-inline: auto; margin-block-end: clamp(26px, 4vh, 48px); }
.bkx-head--row { display: flex; align-items: flex-end; justify-content: space-between; gap: 2rem; flex-wrap: wrap; }
.bkx-h2 {
  font-family: "Frank Ruhl Libre", Georgia, serif;
  font-weight: 500;
  font-size: clamp(1.75rem, 2.3vw + .6rem, 3.1rem);
  line-height: 1.06;
  letter-spacing: -.018em;
  margin: 0;
}
.bkx-h2 em { font-style: normal; color: var(--x-gold); }
.bkx-lede { margin: .6rem 0 0; color: var(--x-ink-3); font-size: clamp(.9rem, .4vw + .8rem, 1.02rem); max-inline-size: 60ch; }

.bkx-arrows { display: flex; gap: 10px; flex: none; }
.bkx-arrow {
  display: grid; place-items: center;
  inline-size: 44px; block-size: 44px;
  border-radius: 50%;
  border: 1px solid var(--x-line-2);
  background: rgba(255, 255, 255, .03);
  color: var(--x-ink-2);
  cursor: pointer;
  transition: transform .25s var(--x-ease), border-color .25s var(--x-ease), color .25s var(--x-ease);
}
.bkx-arrow:hover { border-color: var(--x-gold-edge); color: var(--x-gold); transform: translateY(-2px); }
.bkx-arrow:active { transform: translateY(1px) scale(.96); }
.bkx-arrow svg { inline-size: 18px; block-size: 18px; }


/* == 05 · THE 3D RAIL ===================================================== */

/*
 * A curved rail, not a slider. The scroller stays a scroller - momentum,
 * two-finger swipe, Home/End, the scrollbar and back-restore all keep working -
 * and every card is placed on the curve from ONE number: its signed distance
 * from the centre of the viewport, written per frame by bkx.js.
 *
 * The rotation is deliberately large (up to 34deg) because the brief is
 * explicit that a 2-degree tilt is not 3D. At this angle the neighbours read
 * as physically turned away, which is what the reference shows.
 */
.bkx-rail {
  position: relative;
  perspective: 1500px;
  perspective-origin: 50% 46%;
}
.bkx-rail__track {
  display: flex;
  gap: clamp(14px, 1.6vw, 26px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-block: clamp(22px, 3vh, 40px);
  padding-inline: calc(50% - min(150px, 31vw));
  scrollbar-width: none;
  transform-style: preserve-3d;
}
.bkx-rail__track::-webkit-scrollbar { display: none; }

.bkx-card {
  --d: 0;    /* signed distance from centre, -1.6..1.6 */
  --ad: 0;   /* its absolute value                      */
  position: relative;
  flex: 0 0 auto;
  inline-size: min(300px, 62vw);
  aspect-ratio: 3 / 4.1;
  border-radius: var(--x-r-lg);
  overflow: hidden;
  scroll-snap-align: center;
  text-decoration: none;
  transform-origin: 50% 62%;
  transform:
    translate3d(0, calc(var(--ad) * 16px), calc(var(--ad) * -190px))
    rotateY(calc(var(--d) * -34deg))
    scale(calc(1 - var(--ad) * .04));
  transition: transform .16s linear, box-shadow .3s var(--x-ease), border-color .3s var(--x-ease);
  border: 1px solid var(--x-line);
  background: var(--x-raised);
  box-shadow: var(--x-e2);
}
.bkx-card__pic {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  transition: transform .6s var(--x-ease), filter .4s var(--x-ease);
  filter: brightness(calc(1 - var(--ad) * .30)) saturate(calc(1 - var(--ad) * .26));
}
.bkx-card:hover .bkx-card__pic { transform: scale(1.05); }
.bkx-card__veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(4, 7, 12, .12) 0%, rgba(4, 7, 12, .05) 40%, rgba(4, 7, 12, .90) 100%);
}
.bkx-card__body { position: absolute; inset-block-end: 0; inset-inline: 0; padding: 1.1rem 1.15rem 1.25rem; }
.bkx-card__where { display: block; font-size: 1.16rem; font-weight: 600; line-height: 1.2; }
.bkx-card__country { display: block; font-size: .78rem; color: var(--x-ink-2); margin-block-start: .1rem; }
.bkx-card__from { display: block; font-size: .68rem; letter-spacing: .14em; text-transform: uppercase; color: var(--x-ink-3); margin-block-start: .7rem; }
.bkx-card__price { display: block; font-size: 1.45rem; font-weight: 700; color: var(--x-gold); line-height: 1.1; font-variant-numeric: tabular-nums; }
/* --x-ink-3 on the guide cards' darkened photographs measured 4.1–4.5:1 at
   1280 once the instrument could see grey-on-dark glyphs; one step up. */
.bkx-card__note { display: block; font-size: .68rem; color: var(--x-ink-2); margin-block-start: .25rem; line-height: 1.4; }

/* The card at the centre is the primary object: upright, forward, lit, and
   given the champagne edge so it reads as CHOSEN rather than merely nearest. */
.bkx-card[data-centre] {
  z-index: 3;
  border-color: var(--x-gold-edge);
  box-shadow: var(--x-e3), 0 0 0 1px rgba(227, 190, 121, .34), var(--x-glow);
}
.bkx-card[data-centre] .bkx-card__pic { filter: none; }

/* The platform the rail stands on, and its reflection. */
.bkx-rail__floor {
  position: absolute;
  inset-block-end: 8%;
  /*
   * PHYSICAL left, because `translate` is physical. With `inset-inline-start:
   * 50%` the Hebrew page resolved it to `right: 50%`, and the -50% translate
   * then carried the floor a further half-width LEFT: 930px past the edge of
   * the body (body.scrollWidth 2370 on a 1440 viewport). When the coverflow
   * clipped it, Chrome scored the vanished overflow as `main` moving — CLS
   * 0.74 on the live desktop homepage (measured 2026-09-12). Centred the same
   * way in both directions now.
   */
  left: 50%;
  translate: -50% 0;
  inline-size: min(1100px, 88vw);
  block-size: 42%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(58% 52% at 50% 100%, rgba(227, 190, 121, .22), rgba(227, 190, 121, .04) 46%, transparent 74%);
}

.bkx-dots { display: flex; justify-content: center; gap: 8px; margin-block-start: clamp(12px, 2vh, 22px); }
/* The deck's control row: prev, the dots the engine writes, next — one group,
   centred under the deck it drives. Inside this row the dots carry no top
   margin of their own; the row owns the spacing. */
.bkx-railctl {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(12px, 1.6vw, 24px);
  margin-block-start: clamp(16px, 2.2vh, 28px);
}
.bkx-railctl .bkx-dots { margin-block-start: 0; }
/* Two 44px arrows plus twelve dots at a touch-sized gap is ~380px of row, and
   at 360px the arrows sat at x -9 and 369 — outside a body that clips overflow
   (measured 2026-09-12). On a phone that narrow the rail is swiped; the dots
   are decorative (aria-hidden) and step aside so both arrows stay reachable. */
@media (max-width: 400px) {
  .bkx-railctl { gap: 10px; }
  .bkx-railctl .bkx-dots { display: none; }
  .bkx-railctl .bkx-arrow { flex: 0 0 44px; }
}
.bkx-dots button {
  inline-size: 7px; block-size: 7px; padding: 0;
  border: 0; border-radius: 50%;
  background: var(--x-line-2);
  cursor: pointer;
  transition: inline-size .3s var(--x-ease), background-color .3s var(--x-ease);
}
.bkx-dots button[aria-current="true"] { inline-size: 26px; border-radius: 4px; background: var(--x-gold); }


/* == 06 · THE GLOBE ======================================================= */

.bkx-globe {
  position: relative;
  inline-size: var(--x-max);
  margin-inline: auto;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) minmax(0, 300px);
  gap: clamp(18px, 3vw, 44px);
  align-items: center;
}
.bkx-globe__rail { display: grid; gap: 6px; align-content: center; }
.bkx-globe__rail a {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .6rem .9rem;
  border-radius: var(--x-r-pill);
  border: 1px solid transparent;
  color: var(--x-ink-3);
  text-decoration: none;
  font-size: .88rem;
  white-space: nowrap;
  transition: color .25s var(--x-ease), border-color .25s var(--x-ease), background-color .25s var(--x-ease);
}
.bkx-globe__rail a:hover { color: var(--x-ink); border-color: var(--x-line-2); background: rgba(255,255,255,.03); }
.bkx-globe__rail svg { inline-size: 17px; block-size: 17px; color: var(--x-gold); flex: none; }

.bkx-globe__stage {
  position: relative;
  aspect-ratio: 1 / 1;
  max-block-size: min(66vh, 620px);
  margin-inline: auto;
  inline-size: 100%;
}
.bkx-globe__stage canvas { display: block; inline-size: 100%; block-size: 100%; cursor: grab; }
.bkx-globe__stage.is-dragging canvas { cursor: grabbing; }
/* The atmosphere behind it, in CSS, so the scene has a halo before the
   texture has loaded and still has one if WebGL never starts. */
.bkx-globe__stage::before {
  content: "";
  position: absolute;
  inset: 6%;
  border-radius: 50%;
  z-index: -1;
  background: radial-gradient(circle at 50% 50%, rgba(70, 120, 190, .20), rgba(70, 120, 190, .05) 58%, transparent 72%);
  filter: blur(18px);
}

/*
 * THE FALLBACK IS A PHOTOGRAPH OF THE SCENE, NOT A DESCRIPTION OF ONE.
 *
 * This comment used to promise "a real, lit picture of the world with the
 * same routes drawn on it" over two radial gradients: a dark navy disc with
 * four gold dots. That disc is what every reader without WebGL saw, what a
 * reader saw for as long as a 1.6MB map took to arrive, and what a reader who
 * pressed Back saw for good. It is the "dark, empty central object" the owner
 * reported. The gradients are kept underneath as the last resort; on top of
 * them sits a real frame of the WebGL scene, rendered once by
 * scripts/build_globe_static.js from the same Natural Earth raster the live
 * sphere is mapped with, so the still and the live globe are the same object.
 */
.bkx-globe__fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background:
    url(/assets/earth/globe_static_720.webp) center / cover no-repeat,
    radial-gradient(circle at 38% 32%, rgba(58, 96, 150, .55), transparent 58%),
    radial-gradient(circle at 50% 50%, #0B1A2E 0%, #060C16 62%, transparent 72%);
  box-shadow: inset 0 0 90px rgba(0, 0, 0, .8), 0 0 90px -30px rgba(70, 120, 190, .5);
}
.bkx-globe__fallback::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(2px 2px at 30% 44%, var(--x-gold), transparent 60%),
    radial-gradient(2px 2px at 58% 36%, var(--x-gold), transparent 60%),
    radial-gradient(2px 2px at 66% 58%, var(--x-gold), transparent 60%),
    radial-gradient(3px 3px at 47% 52%, #FFF0CE, transparent 60%);
}

.bkx-globe__panel {
  border-radius: var(--x-r-lg);
  border: 1px solid var(--x-line-2);
  background: var(--x-glass-2);
  -webkit-backdrop-filter: var(--x-blur);
  backdrop-filter: var(--x-blur);
  box-shadow: var(--x-e3);
  overflow: hidden;
}
.bkx-globe__panel img { inline-size: 100%; block-size: 150px; object-fit: cover; }
.bkx-globe__panel-body { padding: 1rem 1.1rem 1.15rem; }
.bkx-globe__panel h3 { margin: 0; font-size: 1.15rem; font-weight: 600; }
.bkx-globe__panel p { margin: .15rem 0 0; font-size: .8rem; color: var(--x-ink-3); }
.bkx-globe__panel .bkx-price { display: block; margin-block-start: .7rem; font-size: 1.4rem; font-weight: 700; color: var(--x-gold); font-variant-numeric: tabular-nums; }
.bkx-globe__panel .bkx-note { display: block; font-size: .7rem; color: var(--x-ink-3); margin-block-start: .2rem; }
.bkx-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  margin-block-start: .9rem;
  inline-size: 100%;
  min-block-size: 44px;
  border-radius: var(--x-r-pill);
  background: linear-gradient(160deg, var(--x-gold), var(--x-gold-deep));
  color: var(--x-on-gold);
  font-weight: 700;
  font-size: .92rem;
  text-decoration: none;
  border: 0;
  cursor: pointer;
  transition: transform .2s var(--x-ease), box-shadow .2s var(--x-ease);
}
/*
 * THE CASCADE, NOT THE TOKEN. `.bkx-cta` says `--x-on-gold`, and every
 * <a class="bkx-cta"> painted CREAM on the gold gradient — 1.76:1, measured on
 * the globe's "לחיפוש טיסות" by the release gate. `.bkx a { color: inherit }`
 * is one class and one type, `.bkx-cta` is one class, and the more specific
 * rule wins whatever order they are written in. The <button> variant never
 * suffered because it is not an <a>. Same specificity trap as the EL monogram
 * in .claude/rules/bookallo-character.md, one more time.
 */
.bkx a.bkx-cta:not(.bkx-cta--ghost) { color: var(--x-on-gold); }
.bkx-cta:hover { transform: translateY(-2px); box-shadow: var(--x-glow); }
.bkx-cta--ghost {
  background: none;
  color: var(--x-ink);
  border: 1px solid var(--x-line-2);
}
.bkx-cta--ghost:hover { border-color: var(--x-gold-edge); color: var(--x-gold); box-shadow: none; }


/* == 07 · MEASURED FARES ================================================== */

.bkx-fares { inline-size: var(--x-max); margin-inline: auto; }
.bkx-freshness {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 1.4rem;
  padding: .45rem .9rem;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-line);
  background: rgba(255, 255, 255, .03);
  font-size: .8rem;
  color: var(--x-ink-2);
}
.bkx-freshness svg { inline-size: 15px; block-size: 15px; color: var(--x-gold); }

/* Each fare is a layered panel, not a table row: a hairline, a photograph, the
   city, the window, the figure and the observation that produced it. */
.bkx-fare {
  display: grid;
  grid-template-columns: 64px minmax(0, 1.2fr) minmax(0, 1fr) auto auto;
  align-items: center;
  gap: clamp(10px, 1.4vw, 22px);
  padding: .8rem 1rem;
  border-radius: var(--x-r);
  border: 1px solid var(--x-line);
  background: linear-gradient(140deg, rgba(16, 22, 32, .7), rgba(7, 11, 18, .82));
  text-decoration: none;
  transition: transform .3s var(--x-ease), border-color .3s var(--x-ease), box-shadow .3s var(--x-ease);
}
.bkx-fare + .bkx-fare { margin-block-start: 10px; }
.bkx-fare:hover {
  transform: translateY(-2px);
  border-color: var(--x-gold-edge);
  box-shadow: var(--x-e2);
}
.bkx-fare__pic { inline-size: 64px; block-size: 64px; border-radius: 12px; object-fit: cover; }
.bkx-fare__where b { display: block; font-size: 1.02rem; font-weight: 600; }
.bkx-fare__where span { display: block; font-size: .78rem; color: var(--x-ink-3); }
.bkx-fare__when b { display: block; font-size: .9rem; font-variant-numeric: tabular-nums; }
.bkx-fare__when small { display: block; font-size: .7rem; color: var(--x-ink-3); }
.bkx-fare__price { text-align: end; }
.bkx-fare__price b { font-size: 1.3rem; font-weight: 700; color: var(--x-gold); font-variant-numeric: tabular-nums; }
.bkx-fare__price span { display: block; font-size: .72rem; color: var(--x-ink-3); }
.bkx-fare__go { color: var(--x-ink-3); }


/* == 08 · HOTELS ========================================================== */

.bkx-hotels { inline-size: var(--x-max); margin-inline: auto; }
.bkx-hotels__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: clamp(14px, 1.6vw, 22px);
}
.bkx-hotel {
  position: relative;
  display: block;
  border-radius: var(--x-r-lg);
  overflow: hidden;
  aspect-ratio: 3 / 4;
  border: 1px solid var(--x-line);
  text-decoration: none;
  background: var(--x-raised);
  transition: transform .4s var(--x-ease), border-color .3s var(--x-ease), box-shadow .4s var(--x-ease);
}
.bkx-hotel:hover { transform: translateY(-8px); border-color: var(--x-gold-edge); box-shadow: var(--x-e3); }
.bkx-hotel img { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; object-fit: cover; transition: transform .7s var(--x-ease); }
.bkx-hotel:hover img { transform: scale(1.06); }
.bkx-hotel__veil { position: absolute; inset: 0; background: linear-gradient(180deg, transparent 34%, rgba(4, 7, 12, .92) 100%); }
.bkx-hotel__body { position: absolute; inset-block-end: 0; inset-inline: 0; padding: 1rem 1.1rem 1.15rem; }


/* == 09 · PLANNER ========================================================= */

.bkx-plan {
  inline-size: var(--x-max);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr) minmax(0, 320px);
  gap: clamp(18px, 2.6vw, 40px);
  align-items: center;
}
.bkx-steps { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; counter-reset: bkx-step; }
.bkx-steps li {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .6rem .5rem;
  color: var(--x-ink-3);
  font-size: .92rem;
  transition: color .5s var(--x-ease);
}
.bkx-steps li::before {
  counter-increment: bkx-step;
  content: counter(bkx-step);
  display: grid; place-items: center;
  inline-size: 30px; block-size: 30px; flex: none;
  border-radius: 50%;
  border: 1px solid var(--x-line-2);
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
  transition: background-color .5s var(--x-ease), color .5s var(--x-ease), border-color .5s var(--x-ease);
}
.bkx-steps li.is-on { color: var(--x-ink); }
.bkx-steps li.is-on::before {
  background: linear-gradient(160deg, var(--x-gold), var(--x-gold-deep));
  color: var(--x-on-gold);
  border-color: transparent;
}

.bkx-plan__stage { position: relative; aspect-ratio: 16 / 11; border-radius: var(--x-r-lg); overflow: hidden; border: 1px solid var(--x-line); }
.bkx-plan__stage img { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; object-fit: cover; }
.bkx-plan__stage::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(4,7,12,.32), rgba(4,7,12,.72)); }

/* The markers the trip assembles out of. Each one appears when its step does,
   and each one carries a REAL figure or no figure at all. */
.bkx-pin {
  position: absolute;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .75rem;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-line-2);
  background: rgba(8, 11, 18, .86);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: var(--x-e2);
  font-size: .84rem;
  opacity: 0;
  transform: translate3d(0, 10px, 0) scale(.94);
  transition: opacity .55s var(--x-ease), transform .55s var(--x-ease);
}
.bkx-pin.is-on { opacity: 1; transform: none; }
.bkx-pin svg { inline-size: 15px; block-size: 15px; color: var(--x-gold); }
.bkx-pin b { color: var(--x-gold); font-variant-numeric: tabular-nums; }

.bkx-plan__card {
  border-radius: var(--x-r-lg);
  border: 1px solid var(--x-line-2);
  background: var(--x-glass-2);
  -webkit-backdrop-filter: var(--x-blur);
  backdrop-filter: var(--x-blur);
  box-shadow: var(--x-e3);
  padding: 1.2rem 1.25rem 1.35rem;
}
.bkx-plan__card h3 { margin: 0 0 .1rem; font-size: 1.1rem; font-weight: 600; }
.bkx-plan__card > p { margin: 0 0 1rem; font-size: .82rem; color: var(--x-ink-3); }
.bkx-ledger { margin: 0; display: grid; gap: .5rem; }
.bkx-ledger div { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; font-size: .88rem; }
.bkx-ledger dt { color: var(--x-ink-2); margin: 0; }
.bkx-ledger dd { margin: 0; font-variant-numeric: tabular-nums; }
.bkx-ledger dd.is-empty { color: var(--x-ink-3); font-size: .8rem; }
.bkx-meter { block-size: 3px; border-radius: 2px; background: var(--x-line); margin-block: 1rem .3rem; overflow: hidden; }
.bkx-meter i { display: block; block-size: 100%; inline-size: var(--x-meter, 0%); background: linear-gradient(90deg, var(--x-gold-deep), var(--x-gold)); transition: inline-size 1.1s var(--x-ease); }


/* == 10 · CLOSING + FOOTER ================================================ */

.bkx-closing {
  position: relative;
  min-block-size: 76vh;
  display: grid;
  place-items: center;
  text-align: center;
  overflow: hidden;
  isolation: isolate;
}
.bkx-closing img { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; object-fit: cover; z-index: -2; }
.bkx-closing::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* .45 at the centre left the small gold mark under the headline on a photo
     measured at 2.9:1 and 3.4:1 (1920). The centre holds .62 now — the
     photograph still shows through — and the edges are as dark as before. */
  background: radial-gradient(90% 70% at 50% 50%, rgba(4, 7, 12, .62), rgba(4, 7, 12, .96) 78%);
}
.bkx-closing__mark { display: grid; justify-items: center; gap: .5rem; margin-block-start: 2rem; }
.bkx-closing__mark span { font-size: .68rem; letter-spacing: .38em; text-transform: uppercase; color: var(--x-gold); }

.bkx-foot { border-block-start: 1px solid var(--x-line); background: var(--x-deep); }
.bkx-foot__in {
  inline-size: var(--x-max);
  margin-inline: auto;
  padding-block: clamp(40px, 6vh, 72px);
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 48px);
}
.bkx-foot__h { margin: 0 0 .8rem; font-size: .72rem; letter-spacing: .2em; text-transform: uppercase; color: var(--x-ink-3); }
.bkx-foot ul { margin: 0; padding: 0; list-style: none; display: grid; gap: .5rem; }
.bkx-foot a { color: var(--x-ink-2); text-decoration: none; font-size: .9rem; transition: color .25s var(--x-ease); }
.bkx-foot a:hover { color: var(--x-gold); }
.bkx-foot__legal {
  inline-size: var(--x-max);
  margin-inline: auto;
  padding-block: 1.2rem 2rem;
  border-block-start: 1px solid var(--x-line);
  font-size: .78rem;
  color: var(--x-ink-3);
  display: flex; flex-wrap: wrap; gap: .8rem 1.6rem; align-items: center; justify-content: space-between;
}


/* == RENDERER MARKUP ======================================================
 *
 * `janet_deals_strip.js` and `janet_home.js` emit their own class names, and
 * they must NOT have to learn a second vocabulary to be styled — a renderer
 * that has to know about the shell is a renderer that breaks the next time the
 * shell changes. So the shell dresses what they already write.
 *
 * Everything below is scoped under `.bkx`, so the same renderers keep their
 * old appearance on any page still running the previous system.
 */

/* --- a fare card on the rail (#jn-deals, #jn-lowcost) ------------------- */
.bkx .jn-deals__track {
  display: flex;
  gap: clamp(14px, 1.6vw, 26px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-block: clamp(22px, 3vh, 40px);
  padding-inline: calc(50% - min(144px, 31vw));
  scrollbar-width: none;
}
.bkx .jn-deals__track::-webkit-scrollbar { display: none; }

.bkx .jn-deal {
  position: relative;
  flex: 0 0 auto;
  inline-size: min(288px, 62vw);
  min-block-size: 340px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 1.1rem 1.15rem 1.25rem;
  border-radius: var(--x-r-lg);
  border: 1px solid var(--x-line);
  background: var(--x-raised);
  overflow: hidden;
  text-decoration: none;
  scroll-snap-align: center;
  box-shadow: var(--x-e2);
}
.bkx .jn-deal__img {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center;
  transition: transform .7s var(--x-ease), filter .4s var(--x-ease);
  filter: brightness(calc(1 - var(--ad, 0) * .30)) saturate(calc(1 - var(--ad, 0) * .26));
}
.bkx .jn-deal:hover .jn-deal__img { transform: scale(1.05); }
.bkx .jn-deal[data-centre] .jn-deal__img { filter: none; }
.bkx .jn-deal__plate {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: grid;
  place-items: center;
  padding: 1rem;
  text-align: center;
  font-family: "Frank Ruhl Libre", Georgia, serif;
  font-size: 1.4rem;
  color: var(--x-ink-3);
  background: linear-gradient(150deg, #101823, #070B12);
}
.bkx .jn-deal::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(4,7,12,.10) 0%, rgba(4,7,12,.06) 38%, rgba(4,7,12,.93) 100%);
}
.bkx .jn-deal__body { position: relative; z-index: 2; display: grid; gap: .12rem; }
.bkx .jn-deal__where { font-size: 1.14rem; font-weight: 600; line-height: 1.2; }
.bkx .jn-deal__when { font-size: .78rem; color: var(--x-ink-2); direction: ltr; unicode-bidi: isolate; }
.bkx .jn-deal__price { display: flex; align-items: baseline; gap: .18rem; margin-block-start: .5rem; }
.bkx .jn-deal__price b { font-size: 1.62rem; font-weight: 700; color: var(--x-gold); line-height: 1; font-variant-numeric: tabular-nums; }
.bkx .jn-deal__price span { font-size: .95rem; color: var(--x-gold); }
.bkx .jn-deal__unit,
.bkx .jn-deal__src { font-size: .72rem; color: var(--x-ink-3); }
.bkx .jn-deal__obs { font-size: .68rem; color: var(--x-ink-3); line-height: 1.4; margin-block-start: .18rem; }
.bkx .jn-deal__label {
  display: inline-block;
  margin-block-start: .4rem;
  padding: .18rem .55rem;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-gold-edge);
  background: var(--x-gold-wash);
  color: var(--x-gold);
  font-size: .68rem;
}
/* The hot-deal deck card (bkx_hot_deals_core.railCardHTML). A fare observed
   in another currency keeps that currency in gold; the shekel figure beside
   it is an approximation and is set like one — smaller, muted, marked ≈. */
.bkx .jn-deal__approx { font-size: .8rem; color: var(--x-ink-3); margin-inline-start: .4rem; font-variant-numeric: tabular-nums; }
/* The one word a card may add to its evidence line — "דיל חזק" — printed by
   the core only when the fare was re-checked and sits at or under 75% of its
   route's recent median over at least eight observations. Same size as the
   line it sits in, the fare's gold, no pill, no icon: a fact, not a sticker. */
.bkx .jn-deal__badge { color: var(--x-gold); font-weight: 600; }
/* The card says where its click goes. Same gold as the fare, an arrow that
   points the reading direction, nothing that looks like a second button. */
.bkx .jn-deal__cta {
  display: inline-flex; align-items: center; gap: .3rem;
  margin-block-start: .6rem;
  font-size: .8rem; font-weight: 600; letter-spacing: .01em;
  color: var(--x-gold);
}
.bkx .jn-deal__cta::after { content: "\2190"; font-size: .95em; }
html[lang^="en"] .bkx .jn-deal__cta::after { content: "\2192"; }
.bkx .jn-deal__claim { font-size: .8rem; color: var(--x-ink); font-weight: 600; }

/* --- a measured row (#jn-rows) ------------------------------------------ */
.bkx .jn-rows { display: grid; gap: 10px; }
.bkx .jn-row-item {
  display: grid;
  grid-template-columns: 56px minmax(0, 1.1fr) minmax(0, 1fr) auto auto;
  align-items: center;
  gap: clamp(10px, 1.4vw, 22px);
  padding: .8rem 1rem;
  border-radius: var(--x-r);
  border: 1px solid var(--x-line);
  background: linear-gradient(140deg, rgba(16, 22, 32, .70), rgba(7, 11, 18, .82));
  text-decoration: none;
  transition: transform .3s var(--x-ease), border-color .3s var(--x-ease), box-shadow .3s var(--x-ease);
}
.bkx .jn-row-item:hover { transform: translateY(-2px); border-color: var(--x-gold-edge); box-shadow: var(--x-e2); }
.bkx .jn-row-item__pic { inline-size: 56px; block-size: 56px; border-radius: 12px; object-fit: cover; background: rgba(255,255,255,.04); }
.bkx .jn-row-item__where b { display: block; font-size: 1rem; font-weight: 600; }
.bkx .jn-row-item__where span { display: block; font-size: .76rem; color: var(--x-ink-3); }
.bkx .jn-row-item__when { font-size: .8rem; color: var(--x-ink-2); }
/*
 * FIVE TRACKS DO NOT FIT ON A PHONE.
 *
 * .jn-row-item is `56px minmax(0,1.1fr) minmax(0,1fr) auto auto`. At 390px,
 * once the thumbnail, two auto tracks and four gaps are taken out, the name
 * column resolves to about 30px — and a country label needs 33-34. Measured on
 * the built page: "הונגריה" scrollWidth 33 / clientWidth 30, "קפריסין" 34 / 30.
 * Three or four pixels, which is the last letter of the word.
 *
 * It reported no horizontal overflow, because a squeeze INSIDE a grid never
 * widens the document. Only comparing each leaf's scrollWidth to its own
 * clientWidth finds it.
 *
 * The row keeps its parts and its order; below 560px the trailing cells simply
 * take the second line instead of stealing width from the name. Nothing above
 * that width changes.
 */
@media (max-width: 560px) {
  .bkx .jn-row-item {
    grid-template-columns: 56px minmax(0, 1fr) auto;
    row-gap: .45rem;
  }
  .bkx .jn-row-item__when { grid-column: 2 / -1; }
}
.bkx .jn-row-item__when b { font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate; display: inline-block; }
.bkx .jn-row__at { color: var(--x-ink-3); font-size: .7rem; }
.bkx .jn-row-item__price { text-align: end; }
.bkx .jn-row-item__price b { font-size: 1.24rem; font-weight: 700; color: var(--x-gold); font-variant-numeric: tabular-nums; }
.bkx .jn-row-item__price span { display: block; font-size: .72rem; color: var(--x-ink-3); }
.bkx .jn-row-item__claim { font-size: .84rem; color: var(--x-ink); font-weight: 600; }
.bkx .jn-row-item__go { color: var(--x-ink-3); }
.bkx .jn-tag {
  display: inline-block;
  padding: .12rem .5rem;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-line-2);
  font-size: .68rem;
  color: var(--x-ink-2);
}
.bkx .jn-tag--live { border-color: var(--x-gold-edge); color: var(--x-gold); background: var(--x-gold-wash); }

/* --- a hotel (#jn-hotels) ----------------------------------------------- */
.bkx .jn-hotels__grid {
  display: flex;
  gap: clamp(14px, 1.6vw, 22px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-block: clamp(22px, 3vh, 40px);
  padding-inline: calc(50% - min(150px, 33vw));
  scrollbar-width: none;
}
.bkx .jn-hotels__grid::-webkit-scrollbar { display: none; }
.bkx .jn-hot {
  position: relative;
  flex: 0 0 auto;
  inline-size: min(300px, 66vw);
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-block-size: 400px;
  padding: 1rem 1.1rem 1.15rem;
  border-radius: var(--x-r-lg);
  border: 1px solid var(--x-line);
  background: var(--x-raised);
  overflow: hidden;
  text-decoration: none;
  transition: transform .4s var(--x-ease), border-color .3s var(--x-ease), box-shadow .4s var(--x-ease);
}
.bkx .jn-hot:hover { transform: translateY(-8px); border-color: var(--x-gold-edge); box-shadow: var(--x-e3); }
.bkx .jn-hot__img { position: absolute; inset: 0; z-index: 0; background-size: cover; background-position: center; transition: transform .7s var(--x-ease); }
.bkx .jn-hot:hover .jn-hot__img { transform: scale(1.06); }
.bkx .jn-hot::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(4,7,12,.10) 0%, rgba(4,7,12,.34) 34%, rgba(4,7,12,.97) 78%);
}
.bkx .jn-hot__body { position: relative; z-index: 2; display: grid; gap: .12rem; min-inline-size: 0; }
/* The meta line (score · stars · where) is Latin landmark names inside Hebrew
   text. Unstyled it was one inline run wider than the card: measured
   2026-09-12 at 390px, "Plaça Catalunya" was cut to "aya" and the stay dates
   below lost their first digits. It wraps now, and the place keeps its own
   direction. */
.bkx .jn-hot__meta { display: flex; flex-wrap: wrap; align-items: center; gap: .15rem .45rem; min-inline-size: 0; font-size: .76rem; color: var(--x-ink-3); }
.bkx .jn-hot__score { font-weight: 700; color: var(--x-ink); }
.bkx .jn-hot__area { flex-basis: 100%; min-inline-size: 0; overflow-wrap: anywhere; unicode-bidi: plaintext; }
.bkx .jn-hot__when { font-size: .76rem; color: var(--x-ink-3); font-variant-numeric: tabular-nums; }
.bkx .jn-hot__name { font-size: 1.05rem; font-weight: 600; line-height: 1.25; }
.bkx .jn-hot__where, .bkx .jn-hot__perks, .bkx .jn-hot__obs { font-size: .76rem; color: var(--x-ink-3); }
/* Two lines, then an ellipsis. A provider address is arbitrary length and a
   card that grows to fit the longest one in the set sizes every other card
   against a hotel nobody is looking at. */
.bkx .jn-hot__where { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.bkx .jn-hot__name { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.bkx .jn-hot__price { margin-block-start: .5rem; font-size: 1.3rem; font-weight: 700; color: var(--x-gold); font-variant-numeric: tabular-nums; }

/* --- the quiet states the renderers fall back to ------------------------ */
.bkx .jn-note { color: var(--x-ink-3); font-size: .88rem; margin: 0; }
.bkx .jn-note a { color: var(--x-gold); }



/* == PAGE FURNITURE THE SHELL OWNS NOW ====================================
 * These were in janet_home.css, which this page no longer loads. They are
 * re-authored here rather than imported, because importing one rule out of
 * a sheet means loading the whole sheet and re-opening the trench war the
 * head of index.html describes.
 */

/* The skip link. It exists for exactly one reader and it must be visible to
   them the instant it takes focus. */
.bkx .skip {
  position: absolute;
  inset-block-start: -100px;
  inset-inline-start: 12px;
  z-index: 200;
  padding: .7rem 1.1rem;
  border-radius: var(--x-r-pill);
  background: var(--x-gold);
  color: var(--x-on-gold);
  font-weight: 600;
  text-decoration: none;
  transition: inset-block-start .2s var(--x-ease);
}
.bkx .skip:focus { inset-block-start: 12px; }

/* The mobile menu. A layered sheet under the nav, not a cheap drawer. */
.bkx .mnav {
  position: fixed;
  z-index: 89;
  inset-block-start: var(--x-nav-h, 66px);
  inset-inline: 0;
  display: grid;
  gap: 2px;
  padding: 14px var(--x-gut) 20px;
  background: rgba(6, 9, 15, .96);
  -webkit-backdrop-filter: var(--x-blur);
  backdrop-filter: var(--x-blur);
  border-block-end: 1px solid var(--x-line);
  box-shadow: var(--x-e3);
}
.bkx .mnav[hidden] { display: none; }
.bkx .mnav a {
  padding: .85rem .4rem;
  min-block-size: 44px;
  display: flex;
  align-items: center;
  color: var(--x-ink);
  text-decoration: none;
  border-block-end: 1px solid var(--x-line);
}
.bkx .mnav a:last-child { border-block-end: 0; }

/* The read-only origin cell. It states a fact about the search rather than
   offering a control that changes nothing. */
.bkx-field__static { font-weight: 400; font-size: .98rem; color: var(--x-ink); }

/* --- the globe panel, same principle ---------------------------------- */
.bkx-globe__panel .bk-panel__pic {
  inline-size: 100%;
  block-size: 150px;
  object-fit: cover;
  background: rgba(255, 255, 255, .04);
}
.bkx-globe__panel .bk-panel__price--claim {
  font-size: .88rem;
  font-weight: 600;
  color: var(--x-ink);
  line-height: 1.35;
}
/* The idle copy stands down the moment a real measured destination arrives.
   Two panels showing at once would be the product talking over itself. */
.bkx-globe__panel #jn-shot2:not([hidden]) ~ [data-bkx-globe-idle] { display: none; }


/* == THE ENGLISH PAGE'S OWN CONTROLS ======================================
 * A language switcher and a currency select the Hebrew homepage does not
 * have. They are the English page's product, not decoration, so they get
 * shell material rather than being dropped to make the two pages match.
 */
.bkx-langs {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-line-2);
  background: rgba(255, 255, 255, .03);
}
.bkx-langs a,
.bkx-langs span {
  padding: .38rem .7rem;
  border-radius: var(--x-r-pill);
  font-size: .84rem;
  /* --x-ink-3 over the hero photograph, through the nav's translucent tint,
     measured 2.9–3.2:1 on the English homepage (release gate, 2026-09-07). */
  color: var(--x-ink-2);
  text-decoration: none;
  white-space: nowrap;
  transition: color .25s var(--x-ease), background-color .25s var(--x-ease);
}
.bkx-langs a:hover { color: var(--x-ink); background: rgba(255, 255, 255, .05); }
.bkx-langs [aria-current="true"] {
  background: linear-gradient(160deg, var(--x-gold), var(--x-gold-deep));
  color: var(--x-on-gold);
  font-weight: 600;
}

.bkx-cur { display: flex; align-items: center; gap: .5rem; font-size: .8rem; color: var(--x-ink-2); }  /* 3.7:1 as --x-ink-3 over the hero */
.bkx-cur select {
  /* 38px measured 52x38 by the release gate's TAP_TARGET rule (WCAG 2.5.5,
     44px) on the English homepage; the language pills beside it are 44. */
  min-block-size: 44px;
  padding-inline: .8rem;
  border-radius: var(--x-r-pill);
  border: 1px solid var(--x-line-2);
  background: rgba(255, 255, 255, .03);
  color: var(--x-ink);
  font: inherit;
  font-size: .84rem;
  cursor: pointer;
}
.bkx-cur option { background: var(--x-raised); color: var(--x-ink); }

/* Three commitments, side by side. Not a rail: these are statements, and a
   statement the reader has to drag into view is one they will not read. */
.bkx-trio {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: clamp(14px, 1.6vw, 22px);
}
.bkx-trio .bkx-plan__card p { margin: 0; font-size: .9rem; line-height: 1.6; color: var(--x-ink-2); }

.bkx-foot__blurb { margin-block-start: .9rem; max-inline-size: 34ch; }
.bkx-closing .bkx-h1 { max-inline-size: 16ch; margin-inline: auto; }
.bkx-closing__mark .bkx-brand__name { font-size: 1.4rem; }

/* At the narrow end the header cannot hold five languages and a currency
   select beside the brand. They move into the mobile menu's territory. */
@media (max-width: 1180px) {
  .bkx-langs, .bkx-cur { display: none; }
}


/* == TOUCH TARGETS ========================================================
 * 44px in BOTH dimensions on every control the sweep can reach, and the
 * sweep is the authority here rather than a judgement about which of these a
 * thumb will realistically land on. Measured before this block:
 * .skip 102x43 (one pixel short), .bkx-brand 118x34, .bkx-icon--el 77x40,
 * and every primary nav link 33x31.
 *
 * Height is bought with padding, never with a fixed block-size: a fixed
 * height on a link whose label wraps at 390px clips the second line.
 */
.bkx .skip { min-block-size: 44px; display: inline-flex; align-items: center; }
.bkx-brand { min-block-size: 44px; }
.bkx-icon { inline-size: 44px; block-size: 44px; }
.bkx-icon--el { inline-size: auto; min-inline-size: 44px; }
.bkx-nav__links a { min-block-size: 44px; display: inline-flex; align-items: center; padding-inline: 2px; }
.bkx-globe__rail a { min-block-size: 44px; }
.bkx-cue { min-block-size: 44px; }
.bkx-foot a { display: inline-flex; align-items: center; min-block-size: 44px; }
.bkx-foot__legal a { min-block-size: 44px; display: inline-flex; align-items: center; }
.bkx-langs a, .bkx-langs span { min-block-size: 38px; display: inline-flex; align-items: center; }
.bkx-arrow { inline-size: 44px; block-size: 44px; }

/* == SCENE REVEALS ========================================================
 * Behind `html.js`, and the class is added by bkx.js rather than written into
 * the markup. Both halves matter: with no JS these rules do not exist AND
 * there is no attribute to hide anything, so a page whose script failed and a
 * crawler that runs none both see the whole document.
 */
html.js .bkx-rise {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity .9s var(--x-ease-2), transform .9s var(--x-ease-2);
}
html.js .bkx-rise.bkx-in { opacity: 1; transform: none; }


/* == 11 · RESPONSIVE ====================================================== */

@media (max-width: 1180px) {
  .bkx-globe { grid-template-columns: minmax(0, 1fr); }
  .bkx-globe__rail { grid-auto-flow: column; justify-content: center; overflow-x: auto; }
  .bkx-globe__panel { max-inline-size: 420px; margin-inline: auto; }
  .bkx-plan { grid-template-columns: minmax(0, 1fr); }
  .bkx-steps { grid-auto-flow: column; overflow-x: auto; padding-block-end: 6px; }
  .bkx-steps li { white-space: nowrap; }
  .bkx-stats { position: static; inline-size: auto; max-inline-size: none; transform: none; }
  /* Once the claims sit statically at the foot of the hero, the scroll cue —
     absolutely placed at that same foot — lands on them: measured at 768,
     "הספק" under the cue's own box (release gate, 2026-09-08). The console
     and the claims already fill the first screen here; the cue goes. */
  .bkx-cue { display: none; }
}

@media (max-width: 1080px) {
  .bkx-form { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .bkx-go { grid-column: 1 / -1; }
  .bkx-field:nth-child(3n + 1) { border-inline-start: 0; }
  .bkx-field:nth-child(n + 4) { border-block-start: 1px solid var(--x-line); }
}
@media (max-width: 900px) {
  .bkx-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bkx-field:nth-child(3n + 1) { border-inline-start: 1px solid var(--x-line); }
  .bkx-field:nth-child(odd) { border-inline-start: 0; }
  .bkx-field:nth-child(n + 3) { border-block-start: 1px solid var(--x-line); }
}

@media (max-width: 860px) {
  .bkx-nav__links { display: none; }
  .bkx-burger {
    display: grid; place-items: center; gap: 4px;
    inline-size: 44px; block-size: 44px;
    border-radius: var(--x-r-pill);
    border: 1px solid var(--x-line-2);
    background: rgba(255,255,255,.03);
    cursor: pointer;
  }
  .bkx-burger span { display: block; inline-size: 16px; block-size: 1.5px; background: var(--x-ink); border-radius: 2px; }
  .bkx-nav__acts { margin-inline-start: auto; }
  .bkx-fare { grid-template-columns: 52px minmax(0, 1fr) auto; row-gap: .4rem; }
  .bkx-fare__when { grid-column: 2 / -1; }
  .bkx-fare__go { display: none; }
  .bkx-foot__in { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .bkx-hero { min-block-size: auto; }
  .bkx-hero__body { padding-block: clamp(88px, 16vh, 130px) clamp(24px, 5vh, 40px); }
  .bkx-hero__say { max-inline-size: 100%; }
  .bkx-console { transform: none; margin-block-start: 22px; }
  .bkx-console::after { display: none; }
  .bkx-form { grid-template-columns: minmax(0, 1fr); }
  .bkx-field { border-inline-start: 0; border-block-start: 1px solid var(--x-line); }
  .bkx-field:first-child { border-block-start: 0; }
  .bkx-tabs { overflow-x: auto; scrollbar-width: none; }
  .bkx-tabs::-webkit-scrollbar { display: none; }
  .bkx-stats { grid-auto-flow: column; justify-content: space-between; max-inline-size: none; margin-block-start: 26px; }
  .bkx-stats b { font-size: 1.2rem; }
  .bkx-cue { display: none; }
  .bkx-card { inline-size: min(268px, 74vw); }
  .bkx-rail__track { padding-inline: max(16px, calc(50vw - min(134px, 37vw))); }
  .bkx-foot__in { grid-template-columns: minmax(0, 1fr); }
  /*
   * THE BOTTOM BAR RESERVES ITS OWN SPACE.
   *
   * It is position:fixed, so it floats over whatever is beneath it — and
   * measured 2026-09-05 at 430x932 it sat at 868-920 with the globe panel's
   * "discover this destination" button at 844-888: twenty pixels of a primary
   * call to action underneath a control the reader cannot move. At 390 the same
   * two elements missed each other, which is the tell that this is a scroll
   * position and not a layout, and therefore not fixable by nudging either one.
   *
   * --x-dock is the height the bar occupies including its offset and the
   * device's own safe area. Padding the page by it means content can always be
   * scrolled clear of the bar, and scroll-padding means the browser's own
   * scrollIntoView never parks something under it either. Both are needed: the
   * first fixes where scrolling can REACH, the second fixes where it STOPS.
   */
  :where(.bkx) { --x-dock: calc(52px + 12px + 14px + env(safe-area-inset-bottom, 0px)); }
  /* The SCROLLING ELEMENT is <html>, not the .bkx body. scroll-padding on the
     body is inert — the browser reads it from the scrollport, and putting it
     on the wrong element is a rule that looks applied and does nothing. */
  html { scroll-padding-block-end: var(--x-dock); }
  body.bkx { padding-block-end: var(--x-dock); }

  .bkx-sticky {
    position: fixed;
    z-index: 88;
    inset-block-start: auto;
    inset-block-end: calc(12px + env(safe-area-inset-bottom, 0px));
    inset-inline: 0;
    justify-content: center;
    padding-inline: var(--x-gut);
    transform: translate3d(0, 180%, 0);
  }
  .bkx-sticky__btn { max-inline-size: min(560px, 100%); min-block-size: 48px; }
  /* Beats .is-on, which sets transform:none — two classes to its one. */
  .bkx-sticky.is-on.is-tucked { transform: translate3d(0, 180%, 0); }
}

/* 4K and ultrawide: the FRAME grows. A 1180px column in the middle of a 3840px
   black field is a 1440px design with margins, which is the failure the brief
   names by name. */
@media (min-width: 2200px) {
  :where(.bkx) { --x-max: min(2040px, 88vw); }
  .bkx-card { inline-size: 340px; }
  .bkx-console { inline-size: min(1180px, 100%); }
}
@media (min-width: 3000px) {
  :where(.bkx) { --x-max: min(2560px, 84vw); }
  .bkx-card { inline-size: 400px; }
  .bkx-console { inline-size: min(1360px, 100%); }
  .bkx-globe__stage { max-block-size: min(66vh, 860px); }
}


/* == 12 · REDUCED MOTION ================================================== */

/*
 * Movement goes. Content, state, depth and every affordance stay. A
 * reduced-motion reader still gets the layered scene, the lit centre card and
 * every hover and focus state - the layers simply do not travel.
 */
@media (prefers-reduced-motion: reduce) {
  html.js .bkx-hero__haze,
  html.js .bkx-hero__sheen,
  html.js .bkx-cue__ring svg { animation: none !important; }
  .bkx-layer, .bkx-hero__body { transform: none !important; }
  .bkx-console { transform: none !important; transition: none !important; }
  .bkx-console::after { display: none; }
  .bkx-rail__track { scroll-behavior: auto; }
  .bkx-card {
    transform: none !important;
    transition: none !important;
  }
  .bkx-card__pic { filter: none !important; transition: none !important; }
  .bkx-pin { opacity: 1 !important; transform: none !important; transition: none !important; }
  .bkx-meter i { transition: none !important; }
  .bkx-sticky { transition: opacity .2s linear; transform: none; }
  .bkx-sticky.is-on { transform: none; }
  .bkx-hotel:hover, .bkx-fare:hover, .bkx-go:hover, .bkx-cta:hover, .bkx-arrow:hover { transform: none; }
  .bkx-hotel:hover img, .bkx-card:hover .bkx-card__pic { transform: none; }
}

/* == P0 · THE HERO COMPOSITION ============================================
 *
 * WHAT WAS WRONG, from the owner's own screenshot rather than from taste:
 * the headline was CENTRED and set at up to 5.2rem across 18ch, so it landed
 * on top of the Parthenon — the one thing the photograph is of. Two side
 * blocks were pinned at 46% height on both edges (three claims on one side, a
 * fare card on the other), squeezing the console between them and competing
 * with the headline for the same horizontal band. The scrim was flat, so the
 * picture was equally dark under the type and away from it.
 *
 * The approved references do none of that. The headline sits on the READING
 * EDGE in a column of its own; the photograph's subject keeps the other half
 * of the frame; the grade is DIRECTIONAL, heavy behind the type and clear over
 * the subject; and the standing claims run along the bottom of the frame
 * instead of floating at mid height.
 *
 * All of it is logical properties, so the mirror is the Hebrew composition and
 * not a second set of rules that can drift from the first.
 */
.bkx-hero__body {
  align-items: flex-start;
  padding-block: clamp(104px, 14vh, 168px) clamp(96px, 13vh, 150px);
}
.bkx-hero__say {
  inline-size: 100%;
  text-align: start;
  max-inline-size: min(660px, 54%);
}
.bkx-h1 {
  margin-inline: 0;
  /* 15ch broke the Hebrew headline onto four lines at 1440. The approved
     reference sets its display in TWO, and three is the most this copy can be
     without the block starting to read as a paragraph. */
  max-inline-size: 19ch;
  font-size: clamp(2.2rem, 3.1vw + .45rem, 4rem);
  text-wrap: balance;
}
.bkx-hero__sub {
  margin-inline: 0;
  max-inline-size: 42ch;
}
/* The console is a panel on the same column, not a bar centred in the frame. */
.bkx-console { margin-inline: 0; }
@media (min-width: 1280px) {
  /*
   * The clearance subtraction is GONE, and this rule is what removed it.
   * A `--x-side` variable once reserved room for two panels pinned at mid
   * height on both edges. The claims moved to the bottom band and the fare
   * card was removed outright, so both the variable and the subtraction went
   * with them rather than leaving a 476px hole reserved for nothing.
   */
  /*
   * WIDER, because the lane these numbers reserved is empty now.
   *
   * 54% and 66% were measured against a fare card pinned to the far edge at
   * mid height. The owner removed that card, so the corridor they kept clear
   * holds nothing, and a hero that stops two thirds of the way across for no
   * visible reason is the "empty strange space" the same instruction asks not
   * to be left with.
   *
   * Not full-bleed: the photograph is the other half of this composition and
   * type running edge to edge would cover the thing it is set over.
   */
  .bkx .bkx-hero__say { max-inline-size: min(760px, 62%); }
  .bkx .bkx-console { max-inline-size: min(1020px, 78%); }
}

/*
 * THE GRADE IS DIRECTIONAL, AND IT IS TUNED TO A PARTICULAR PHOTOGRAPH.
 *
 * A flat scrim is the only kind that cannot serve both jobs at once: legible
 * type needs a dark ground, and a cinematic photograph needs to be visible.
 * The reading edge gets the weight; the far half keeps the picture. The bottom
 * band stays for the claims row, and the top band for the header.
 *
 * SUPERSEDED, AND LEFT HERE ON PURPOSE.
 *
 * A later block in this file ("THE PICTURE KEEPS ITS SKY") sets the same two
 * selectors at the same specificity, so it wins outright and these values
 * paint nothing. That cost a full tuning round: the numbers here were
 * strengthened against a measurement, the measurement did not move by 0.01,
 * and the reason was that this rule had not been the live one for months.
 *
 * Deleting it would be tidier and would also delete the base the later block
 * is an edit OF. It stays, with this warning, and the live numbers live at
 * the one place that paints them.
 */
.bkx-hero .bkx-layer--world .bkx-hero__grade {
  background:
    linear-gradient(to left, rgba(4, 7, 12, .95) 0%, rgba(4, 7, 12, .86) 26%, rgba(4, 7, 12, .46) 56%, rgba(4, 7, 12, .34) 100%),
    linear-gradient(180deg, rgba(4, 7, 12, .84) 0%, rgba(4, 7, 12, .40) 26%, rgba(4, 7, 12, .34) 58%, rgba(4, 7, 12, .94) 100%);
}
.bkx-hero:dir(ltr) .bkx-layer--world .bkx-hero__grade {
  background:
    linear-gradient(to right, rgba(4, 7, 12, .95) 0%, rgba(4, 7, 12, .86) 26%, rgba(4, 7, 12, .46) 56%, rgba(4, 7, 12, .34) 100%),
    linear-gradient(180deg, rgba(4, 7, 12, .84) 0%, rgba(4, 7, 12, .40) 26%, rgba(4, 7, 12, .34) 58%, rgba(4, 7, 12, .94) 100%);
}

/* --- the standing claims, along the bottom ------------------------------
 * Three commitments, in the reference's stat position: a row at the foot of
 * the frame, quiet, on one line. Not a number of travellers and not an average
 * rating — this product holds neither, and the reference's own "10M+ Happy
 * Travelers" is a mockup label, not a fact we may copy.
 */
.bkx-stats {
  position: absolute;
  z-index: 6;
  inset-block-start: auto;
  inset-block-end: clamp(58px, 7vh, 84px);
  /*
   * THE SAME COLUMN AS THE CONSOLE, not the raw viewport gutter.
   *
   * Measured 2026-09-05 at 1920x1080, both languages: the console sits inside
   * .bkx-hero__body (inline-size: var(--x-max), centred) and starts at x=115,
   * while these claims were anchored to --x-gut and started at x=64. Fifty-one
   * pixels out of line, on the same edge of the same frame — and mirrored
   * exactly in Hebrew, where the row overshot the console's right edge by the
   * same 51px instead. A grid that only NEARLY lines up is the kind of defect
   * a reader feels and cannot name, and the brief calls the hero's composition
   * unbalanced for reasons that include this one.
   *
   * 100% is the hero's own width here, so this is the body column's offset
   * computed rather than restated — one number, and it cannot drift from
   * --x-max. Logical, so Hebrew is the mirror and not a second rule.
   */
  inset-inline-start: max(var(--x-gut), calc((100% - var(--x-max)) / 2));
  inset-inline-end: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: clamp(20px, 3.4vw, 54px);
  max-inline-size: min(760px, 62%);
}
.bkx-stats li { display: block; max-inline-size: 22ch; }
.bkx-stats b { font-size: clamp(1.2rem, .9vw + .9rem, 1.7rem); }
.bkx-stats span { font-size: .74rem; }

@media (max-width: 1180px) {
  /* Below the two-column width the headline and console take the whole frame
     and the claims stack under them. This used to be about clearing a
     floating fare card as well; that card is gone. */
  .bkx-hero__say, .bkx .bkx-hero__say { max-inline-size: 100%; }
  .bkx .bkx-console { max-inline-size: 100%; }
  .bkx-stats { position: static; margin-block-start: 1.4rem; max-inline-size: 100%; }
  .bkx-hero__body { padding-block-end: clamp(40px, 6vh, 64px); }
  /* Below the two-column width there is no reading EDGE — the type spans the
     frame — so the side sweep is dropped and the vertical band carries the
     whole job. Heavier than the desktop band for the same reason: the type
     sits over the middle of the picture rather than beside it. */
  .bkx-hero .bkx-layer--world .bkx-hero__grade,
  .bkx-hero:dir(ltr) .bkx-layer--world .bkx-hero__grade {
    background: linear-gradient(180deg, rgba(4,7,12,.88) 0%, rgba(4,7,12,.62) 28%, rgba(4,7,12,.70) 60%, rgba(4,7,12,.96) 100%);
  }
}

/* --- the header: one bar, not a bar and two loose controls --------------
 * The owner's note is "floating controls detached/debug-like". They were: the
 * actions group sat hard against the far edge of a 92vw bar while the nav sat
 * against the near one, so at 1440 there was half a screen of nothing between
 * the brand and the language button and the pair read as debug overlay rather
 * than as part of the header.
 */
.bkx-nav {
  gap: clamp(14px, 2vw, 30px);
  padding-inline: var(--x-gut);
}
.bkx-nav__links { margin-inline-start: clamp(18px, 3vw, 52px); }
.bkx-nav__acts { margin-inline-start: auto; gap: 8px; }

/* == P0 · THE GLOBE SCENE =================================================
 *
 * The owner's notes were "oversized / bad framing", "pushed low and right",
 * "dead space", "weak relation between title, globe and destination context".
 * Three of the four were the CAMERA and are fixed in bkx_globe.js — it was
 * framing a 1.16-radius body inside a 1.02 half-height and lifting the camera
 * so the planet sat below centre. The fourth is this layout.
 *
 * The heading used to sit in a band ABOVE the scene, so the eye had to travel
 * from a title at the top of the frame, past an empty strip, to a globe that
 * was then blamed for being low. The framing reference has one row: copy on
 * the reading edge, vertically centred; the planet filling its own column with
 * air all round; the destination context on the far edge.
 */
.bkx-globe {
  grid-template-columns: minmax(0, .82fr) minmax(0, 1.5fr) minmax(0, 300px);
  align-items: center;
  gap: clamp(20px, 3vw, 52px);
}
.bkx-globe__say { display: grid; align-content: center; gap: .85rem; justify-items: start; }
.bkx-globe__say .bkx-h2 { margin: 0; }
.bkx-globe__say .bkx-lede { margin: 0; max-inline-size: 34ch; }
/*
 * The CTA is a GRID ITEM here, and .bkx-cta carries no intrinsic size of its
 * own — so the arrow, an <svg> with no width, stretched to the column and the
 * button came out 330px across and 260px tall. A grid child needs its own
 * bounds; `justify-items: start` only stops it filling the track, not its own
 * content from filling it.
 */
.bkx-globe__say .bkx-cta {
  margin-block-start: .4rem;
  inline-size: auto;
  align-self: start;
  justify-self: start;
}
.bkx-globe__say .bkx-cta svg { inline-size: 17px; block-size: 17px; flex: none; }

.bkx-eyebrow {
  display: block;
  font-size: .7rem;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--x-gold);
}

.bkx-globe__stats {
  display: flex;
  gap: clamp(18px, 2.4vw, 38px);
  margin: .6rem 0 0;
  padding: 0;
  list-style: none;
}
.bkx-globe__stats b {
  display: block;
  font-family: "Frank Ruhl Libre", Georgia, serif;
  font-size: clamp(1.4rem, 1.2vw + 1rem, 2rem);
  font-weight: 500;
  line-height: 1.05;
  color: var(--x-ink);
  font-variant-numeric: tabular-nums;
}
.bkx-globe__stats span {
  display: block;
  font-size: .74rem;
  line-height: 1.4;
  color: var(--x-ink-3);
  margin-block-start: .2rem;
  max-inline-size: 18ch;
}

/* The shortcut rail becomes a quiet column against the far edge rather than a
   third block of body text competing with the copy. */
/*
 * The shortcut rail sits UNDER the copy, not in the far column. Both it and
 * the fare panel were placed at column 3 / row 1 and drew on top of each
 * other — a grid does not stack, it overlaps, and the taller of the two simply
 * hid the other.
 */
.bkx-globe__rail {
  grid-column: 1;
  grid-row: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-block-start: .4rem;
}
.bkx-globe__rail a { padding: .45rem .7rem; font-size: .82rem; }
.bkx-globe__panel { grid-column: 3; grid-row: 1 / span 2; align-self: center; }
.bkx-globe__say { grid-column: 1; grid-row: 1; }
.bkx-globe__stage { grid-column: 2; grid-row: 1 / span 2; }

/* The stage gets the whole middle column and a square frame, so the computed
   camera distance has a predictable shape to fit into. */
.bkx-globe__stage {
  aspect-ratio: 1 / 1;
  max-block-size: min(72vh, 700px);
  inline-size: 100%;
}

/*
 * The drag hint. The reference carries one under the planet, and it is the
 * only thing on the page that tells a reader the globe is an instrument
 * rather than a picture.
 */
/* "Drag the world" is true only of the live scene; over the still picture it
   is an instruction nothing answers. bkx_globe.js sets `is-live` on the stage
   the moment a mapped frame has replaced the picture. */
.bkx-globe__stage:not(.is-live) .bkx-globe__hint { display: none; }
.bkx-globe__hint {
  position: absolute;
  inset-block-end: -6px;
  inset-inline: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  font-size: .74rem;
  letter-spacing: .12em;
  color: var(--x-ink-3);
  pointer-events: none;
}
.bkx-globe__hint svg { inline-size: 15px; block-size: 15px; }

@media (max-width: 1100px) {
  .bkx-globe {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(18px, 3vh, 32px);
  }
  /*
   * EVERY child, not three of the four.
   *
   * The desktop layout pins .bkx-globe__say to column 1, .bkx-globe__stage to
   * column 2 and .bkx-globe__panel to column 3. This block collapsed the track
   * list to a single column and re-homed only the rail and the panel — so the
   * STAGE kept `grid-column: 2` and created an implicit second track for
   * itself, and the say/rail/panel were left sharing the first.
   *
   * Measured at 390x844 on the built page, after the globe's canvas mounts and
   * the stage claims its intrinsic 300px: the track list resolved to
   * `33.48px 300px` and the destination panel, the copy and the rail were all
   * 33-35px wide with their text clipped at the frame edge. Nothing reported
   * horizontal overflow, because the squeeze happens INSIDE the grid rather
   * than past the document edge — which is why a scrollWidth check passed on a
   * page a phone renders as a column of sliced words.
   *
   * span 1 as well as column 1: the desktop rules also give two of these
   * `grid-row: 1 / span 2`, which in a one-column grid stacks them on top of
   * each other.
   */
  .bkx-globe__say,
  .bkx-globe__rail,
  .bkx-globe__stage,
  .bkx-globe__panel { grid-column: 1; grid-row: auto / span 1; }
  .bkx-globe__rail { display: flex; flex-wrap: wrap; justify-content: center; }
  .bkx-globe__stage { max-block-size: min(56vh, 460px); }
}

/* == THE COVERFLOW ========================================================
 *
 * The engine writes transform, opacity, z-index and `--cf-a` (the card's own
 * distance from the front, 0 at centre). Everything here is the LOOK, and
 * nothing here animates transform — bkx_coverflow.js is the only animation
 * authority for position, and a CSS transition on top of a spring is two
 * animations arguing about one property.
 *
 * WHAT THIS SHEET MUST NOT DO, learned by doing it:
 * a first version set `position: relative; z-index: 4` on every direct child
 * of a card so the text would sit above the picture. The deals renderer paints
 * its photograph with `<span class="jn-deal__img" style="background-image:…">`
 * positioned absolutely — so the blanket rule pulled the picture back into
 * flow and every card went black. The deck rendered, moved and centred
 * perfectly, with no images in it.
 *
 * So the picture is named explicitly, and nothing here touches "every child".
 */
.bkx-cf {
  position: relative;
  perspective: 1500px;
  perspective-origin: 50% 46%;
  touch-action: pan-y;               /* vertical page scroll still belongs to the page */
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  block-size: var(--cf-h, clamp(430px, 56vh, 560px));
  overflow: hidden;
}
.bkx-cf.is-dragging { cursor: grabbing; }
/* Over a card's painted box the rail is a link, and says so. Written by the
   engine from the same rect test that resolves the click (bkx_coverflow.js). */
.bkx-cf[data-cf-over]:not(.is-dragging) { cursor: pointer; }
.bkx-cf:focus-visible { outline: 2px solid var(--x-gold, #E3BE79); outline-offset: 6px; border-radius: var(--x-r-lg, 22px); }

/* The track is only a positioning context: the cards are placed absolutely
   from the centre, because a flex row would fight the transforms for the left
   edge of every card. */
/*
 * SPECIFICITY, and why these selectors are three classes deep.
 *
 * The renderers style their own cards at TWO classes — `.bkx .jn-deal`
 * gives a fare card `position: relative`, `flex: 0 0 auto` and a fixed
 * 288px, and `.bkx .jn-deals__track` makes its container a flex scroller.
 * A single-class `.bkx-cf__item` loses to both, so the engine was writing
 * transforms onto cards that were still being LAID OUT by a flex row: the
 * deck moved, turned and lit correctly and was centred 431px off, because
 * `inset-inline-start: 50%` was resolving against a 288px card rather than
 * the 1440px frame.
 *
 * Three classes beats two whatever order the sheets load in, which matters
 * because this block is appended and a later edit could move it.
 */
.bkx-cf .bkx-cf__track {
  /*
   * THE TRACK MUST NOT CATCH THE POINTER, and this is not a nicety.
   *
   * Measured: elementFromPoint returned the TRACK at all fifteen points
   * across a side card's own box. Not one pixel of any card except the
   * centre one was hittable, so the headline interaction — hover a side
   * card, the deck turns — was dead for every reader, and so were the links
   * on those cards.
   *
   * The cause is `preserve-3d`: inside it, z-index does not decide stacking,
   * 3D POSITION does. The side cards are pushed back by translateZ, which
   * puts them behind their own parent's plane at z = 0 — and the parent
   * fills the frame, so it wins the hit test everywhere. Raising z-index on
   * the cards cannot fix it; the engine was already writing one.
   */
  pointer-events: none;
  position: absolute;
  display: block !important;
  overflow: visible;
  padding: 0;
  gap: 0;
  inset: 0;
  display: block;
  transform-style: preserve-3d;
}
.bkx-cf .bkx-cf__track .bkx-cf__item {
  /* …and the cards take it back. */
  pointer-events: auto;
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  margin-block-start: calc(var(--cf-card-h, 400px) / -2);
  margin-inline-start: calc(var(--cf-card-w, 300px) / -2);
  inline-size: var(--cf-card-w, 300px);
  block-size: var(--cf-card-h, 400px);
  transform-origin: 50% 58%;
  will-change: transform, opacity;
  border-radius: var(--x-r-lg, 22px);
  overflow: hidden;
  border: 1px solid var(--x-line, rgba(240,236,226,.10));
  background: var(--x-raised, #0C1119);
  box-shadow: 0 34px 76px -30px rgba(0, 0, 0, .96);
  text-decoration: none;
  /* NOT transform — see above. These two are the only properties the
     stylesheet is allowed to ease. */
  transition: box-shadow .34s var(--x-ease, cubic-bezier(.22,1,.36,1)),
              border-color .34s var(--x-ease, cubic-bezier(.22,1,.36,1));
}

/*
 * THE PICTURE, in whichever of the three shapes a renderer emits it: a real
 * <img>, the deals strip's background-image <span>, or the hotel row's.
 * Named rather than matched by position, so a renderer that adds a wrapper
 * does not silently lose its photograph.
 */
.bkx-cf__item > img,
.bkx-cf__item > .jn-deal__img,
.bkx-cf__item > .bkx-card__pic,
.bkx-cf__item > .jn-hot__img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  background-size: cover;
  background-position: center;
  z-index: 0;
  filter: saturate(calc(1 - var(--cf-a, 0) * .20)) brightness(calc(1 - var(--cf-a, 0) * .08));
}

/* The dimming is driven by the SAME number the geometry uses, so a card half
   way to the front is half way lit. */
.bkx-cf__item::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(4,7,12,.04) 0%, rgba(4,7,12,.06) 38%, rgba(4,7,12,.94) 100%),
    /*
     * THERE ARE TWO DIMMERS, AND ONLY ONE OF THEM WAS TUNED.
     *
     * bkx_coverflow.js lowered `fade` from .26 to .13 with a comment saying the
     * reference shows seven cards "receding but all legibly there" — and this
     * veil, at .24 per unit of offset, quietly put the same dimming back. The
     * two multiply. --cf-a saturates at D.range (2.6), so the far card was
     * carrying .62 of near-black ON TOP of an engine opacity of .53: about 20%
     * visible, which is the row of black slabs beside the front card in the
     * 2026-09-05 capture.
     *
     * At .11 the deck recedes 100 -> 77 -> 58 -> 47 percent effective, which
     * is a deck seen in perspective rather than three cards and some shadows.
     * The turn, the scale and the perspective still carry the depth; that was
     * always the engine comment's own argument for keeping opacity low.
     */
    linear-gradient(rgba(4, 7, 12, calc(var(--cf-a, 0) * 0.11)), rgba(4, 7, 12, calc(var(--cf-a, 0) * 0.11)));
  transition: background-color .2s linear;
}
/* The card's own text sits above the veil. Named classes again, never `> *`. */
.bkx-cf__item > .jn-deal__body,
.bkx-cf__item > .bkx-card__body,
.bkx-cf__item > .jn-deal__where,
.bkx-cf__item > .jn-deal__meta,
.bkx-cf__item > .jn-deal__price,
.bkx-cf__item > .jn-deal__note,
.bkx-cf__item > .jn-deal__tag,
.bkx-cf__item > figcaption,
.bkx-cf__item > h3,
.bkx-cf__item > p,
.bkx-cf__item > span:not(.jn-deal__img):not(.bkx-card__pic):not(.jn-hot__img) { position: relative; z-index: 2; }

/* The front card is the primary object: champagne edge, its own light, no
   extra veil at all. */
.bkx-cf__item[data-cf-centre] {
  border-color: var(--x-gold, #E3BE79);
  box-shadow:
    0 44px 96px -28px rgba(0, 0, 0, .98),
    0 0 0 1px rgba(227, 190, 121, .34),
    0 22px 60px -22px rgba(227, 190, 121, .34);
}

/* The floor the deck stands on. */
.bkx-cf__floor {
  position: absolute;
  inset-block-end: 3%;
  left: 50%;                     /* physical, like the translate (RTL centring, 2026-09-12) */
  translate: -50% 0;
  inline-size: min(1180px, 92%);
  block-size: 30%;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(56% 54% at 50% 100%,
    rgba(227, 190, 121, .20), rgba(227, 190, 121, .04) 46%, transparent 74%);
}

@media (max-width: 860px) {
  .bkx-cf { --cf-h: clamp(340px, 56vh, 460px); }
}
@media (prefers-reduced-motion: reduce) {
  .bkx-cf__item { transition: none !important; }
  .bkx-cf__item > img, .bkx-cf__item > .jn-deal__img { filter: none !important; }
  /*
   * THE DECK IS NOT BLANKED, IT IS FLATTENED.
   *
   * The old rail sat in flow, so `transform: none !important` was the right
   * reduced-motion answer for it and the suite pins that. A coverflow card is
   * positioned absolutely at the centre of its frame and placed by transform,
   * so the same rule would stack all eight cards on one spot — a page that
   * respects the preference by destroying the content.
   *
   * The flattening happens where the transform is WRITTEN instead:
   * bkx_coverflow.js sets rotateY and translateZ to zero under the same media
   * query, so a reader who asked for less motion gets a flat, still, readable
   * row and keeps every card. The spring is skipped there too — the deck moves
   * to its target in one frame rather than easing.
   *
   * The old guarantee still holds for every .bkx-card that is NOT in a deck.
   */
  .bkx-card:not(.bkx-cf__item) { transform: none !important; }
}

/* --- the destination list beside the world -----------------------------
 * The reference's right column. Rows, not a card: a thumbnail, a city, a
 * country and a chevron, and NO price — this is navigation, and a figure here
 * would be a claim with nowhere to check it. The measured fare stays in
 * #jn-shot2 above, which janet_home.js fills from a real observation or leaves
 * empty.
 */
.bkx-dests { list-style: none; margin: .9rem 0 0; padding: 0; display: grid; gap: 2px; }
.bkx-dests a {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) 16px;
  align-items: center;
  gap: .75rem;
  padding: .5rem .6rem;
  border-radius: var(--x-r);
  border: 1px solid transparent;
  text-decoration: none;
  color: inherit;
  min-block-size: 56px;
  transition: background-color .25s var(--x-ease), border-color .25s var(--x-ease);
}
.bkx-dests a:hover { background: rgba(255, 255, 255, .04); border-color: var(--x-line-2); }
.bkx-dests img { inline-size: 40px; block-size: 40px; border-radius: 50%; object-fit: cover; }
.bkx-dests b { display: block; font-size: .93rem; font-weight: 600; line-height: 1.2; color: var(--x-ink); }
.bkx-dests small { display: block; font-size: .74rem; color: var(--x-ink-3); margin-block-start: .1rem; }
.bkx-dests svg { inline-size: 16px; block-size: 16px; color: var(--x-ink-3); }
.bkx-dests a:hover svg { color: var(--x-gold); }
@media (max-width: 1100px) {
  .bkx-dests { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
}

/* == THE PLANNER SCENE ====================================================
 *
 * WHAT WAS REJECTED, in the owner's words: "one large Athens image + detached
 * status box + vertical 1-6 list… visually unclear… sparse wireframe-like".
 * That is a fair description of what it was — a photograph with three text
 * pins on it, a bare ordered list beside it, and a card of empty ledger rows
 * with no relationship to either.
 *
 * The approved mockup is a COMPOSITION: copy and numbered stages on the
 * reading edge, and beside them a deck of destination photographs standing in
 * space with a glass panel of capabilities floating over it. The trip
 * assembles into that panel as the reader arrives.
 *
 * NO FIGURES, and the mockup has none either — its own panel reads "Flights /
 * Best options", "Hotels / Handpicked stays". That is both the referenced
 * shape and the honest one: a total belongs to a plan, and this page holds
 * none. /plan is where every number appears beside its observation.
 */
.bkx-scene--plan { overflow: visible; }
.bkx-plan {
  inline-size: var(--x-max);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, .86fr) minmax(0, 1.14fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: center;
}
.bkx-plan__say { display: grid; align-content: center; gap: .8rem; justify-items: start; }
.bkx-plan__say .bkx-h2 { margin: 0; }
.bkx-plan__say .bkx-lede { margin: 0; max-inline-size: 38ch; }

/* --- the five questions, as chips that light in order ------------------- */
.bkx-plan__steps {
  list-style: none;
  margin: .7rem 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
  inline-size: 100%;
  max-inline-size: 420px;
}
.bkx-plan__steps li {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: .8rem;
  padding: .62rem .8rem;
  border-radius: var(--x-r);
  border: 1px solid var(--x-line);
  background: linear-gradient(150deg, rgba(16, 22, 32, .55), rgba(7, 11, 18, .70));
  transition: border-color .5s var(--x-ease), background-color .5s var(--x-ease);
}
html.js .bkx-plan__steps li { opacity: 0; }
html.js [data-bkx-plan].is-built .bkx-plan__steps li {
  animation: bkx-plan-in .6s var(--x-ease-2) both;
  animation-delay: calc(var(--i, 0) * 110ms);
}
[data-bkx-plan].is-built .bkx-plan__steps li.is-on {
  border-color: var(--x-gold-edge);
  background: linear-gradient(150deg, rgba(227, 190, 121, .10), rgba(7, 11, 18, .74));
}
.bkx-plan__n {
  grid-row: 1 / span 2;
  display: grid;
  place-items: center;
  inline-size: 30px;
  block-size: 30px;
  border-radius: 50%;
  border: 1px solid var(--x-line-2);
  font-size: .82rem;
  font-weight: 700;
  color: var(--x-ink-3);
  transition: background-color .45s var(--x-ease), color .45s var(--x-ease), border-color .45s var(--x-ease);
}
.bkx-plan__steps li.is-on .bkx-plan__n {
  background: linear-gradient(160deg, var(--x-gold), var(--x-gold-deep));
  border-color: transparent;
  color: var(--on-sky, #10131A);
}
.bkx-plan__steps b { font-size: .95rem; font-weight: 600; color: var(--x-ink); }
.bkx-plan__steps small { font-size: .76rem; color: var(--x-ink-3); }
/*
 * .bkx-cta carries `inline-size: 100%`, which is right inside the cards it was
 * written for and wrong the moment it becomes a grid item in a column: 100% of
 * a grid AREA is the whole column, and `justify-items: start` does not stop
 * it, so the button came out 740px wide. The large variant is the standalone
 * one and sizes to its own content.
 */
.bkx-cta--lg {
  inline-size: auto;
  align-self: start;
  justify-self: start;
  padding-block: .85rem;
  padding-inline: 1.6rem;
  font-size: 1rem;
  margin-block-start: .6rem;
}
.bkx-cta--lg svg { inline-size: 17px; block-size: 17px; flex: none; }

/* --- the scene: photographs standing in space, panel floating over ------ */
.bkx-plan__scene {
  position: relative;
  perspective: 1500px;
  perspective-origin: 50% 46%;
  min-block-size: clamp(420px, 52vh, 560px);
}
.bkx-plan__glow {
  position: absolute;
  inset: 8% -6% -4% -6%;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(58% 54% at 42% 62%, rgba(227, 190, 121, .16), rgba(227, 190, 121, .03) 48%, transparent 74%);
}
.bkx-plan__deck { position: absolute; inset: 0; transform-style: preserve-3d; }
.bkx-plan__shot {
  position: absolute;
  margin: 0;
  border-radius: var(--x-r-lg);
  overflow: hidden;
  border: 1px solid var(--x-line-2);
  box-shadow: 0 40px 88px -32px rgba(0, 0, 0, .96);
  transform-origin: 50% 60%;
}
.bkx-plan__shot img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }

/* Three photographs at three depths. The lead one is upright and lit; the two
   behind are turned away and dimmed — the same vocabulary the destination deck
   uses one scene up, so the page has one visual system rather than two. */
.bkx-plan__shot[data-shot="1"] {
  inset-block: 12% 12%;
  inset-inline-start: 6%;
  inline-size: min(290px, 40%);
  z-index: 3;
}
.bkx-plan__shot[data-shot="2"] {
  inset-block: 20% 20%;
  inset-inline-start: 34%;
  inline-size: min(230px, 32%);
  z-index: 2;
  filter: brightness(.72) saturate(.85);
}
.bkx-plan__shot[data-shot="3"] {
  inset-block: 27% 27%;
  inset-inline-start: 56%;
  inline-size: min(200px, 27%);
  z-index: 1;
  filter: brightness(.54) saturate(.72);
}
html.js .bkx-plan__shot { opacity: 0; }
html.js [data-bkx-plan].is-built .bkx-plan__shot { animation: bkx-plan-shot .9s var(--x-ease-2) both; }
html.js [data-bkx-plan].is-built .bkx-plan__shot[data-shot="1"] { animation-delay: .10s; }
html.js [data-bkx-plan].is-built .bkx-plan__shot[data-shot="2"] { animation-delay: .26s; }
html.js [data-bkx-plan].is-built .bkx-plan__shot[data-shot="3"] { animation-delay: .40s; }

@keyframes bkx-plan-shot {
  from { opacity: 0; transform: translate3d(0, 26px, -220px) rotateY(-24deg); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) rotateY(-13deg); }
}
@keyframes bkx-plan-in {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}

/* The destination locking in — the one caption in the scene, on the lead
   photograph, because that is the stage the reader is watching complete. */
.bkx-plan__shot--lead figcaption {
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  padding: 2.4rem 1rem .95rem;
  background: linear-gradient(180deg, transparent, rgba(4, 7, 12, .92));
}
.bkx-plan__shot--lead b { display: block; font-size: 1.15rem; font-weight: 600; color: var(--x-ink); }
.bkx-plan__lock {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  margin-block-end: .4rem;
  padding: .2rem .55rem;
  border-radius: 999px;
  background: rgba(227, 190, 121, .16);
  border: 1px solid var(--x-gold-edge);
  color: var(--x-gold);
  font-size: .68rem;
  font-weight: 700;
}
.bkx-plan__lock svg { inline-size: 12px; block-size: 12px; }

/* --- the glass panel the trip assembles into ---------------------------- */
.bkx-plan__panel {
  position: absolute;
  z-index: 4;
  inset-block-end: 6%;
  inset-inline-end: 0;
  inline-size: min(330px, 52%);
  padding: 1rem 1.05rem;
  border-radius: var(--x-r-lg);
  border: 1px solid var(--x-line-2);
  background: linear-gradient(180deg, rgba(31, 34, 40, .90), rgba(13, 15, 18, .95));
  -webkit-backdrop-filter: var(--x-blur);
  backdrop-filter: var(--x-blur);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .96), 0 0 0 1px rgba(227, 190, 121, .08);
}
.bkx-plan__row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  align-items: center;
  gap: .7rem;
  padding-block: .5rem;
  border-block-end: 1px solid var(--x-line);
}
.bkx-plan__row:last-of-type { border-block-end: 0; }
.bkx-plan__row svg { inline-size: 18px; block-size: 18px; color: var(--x-gold); }
.bkx-plan__row b { display: block; font-size: .9rem; font-weight: 600; color: var(--x-ink); }
.bkx-plan__row small { display: block; font-size: .74rem; color: var(--x-ink-3); margin-block-start: .1rem; }
html.js .bkx-plan__row { opacity: 0; }
html.js [data-bkx-plan].is-built .bkx-plan__row {
  animation: bkx-plan-in .55s var(--x-ease-2) both;
  animation-delay: calc(.55s + var(--i, 0) * 160ms);
}
.bkx-plan__truth {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  margin: .7rem 0 0;
  font-size: .72rem;
  line-height: 1.45;
  color: var(--x-ink-3);
}
.bkx-plan__truth svg { inline-size: 14px; block-size: 14px; flex: none; margin-block-start: .12rem; }

@media (max-width: 1080px) {
  .bkx-plan { grid-template-columns: minmax(0, 1fr); }
  .bkx-plan__scene { min-block-size: clamp(360px, 56vh, 460px); perspective: none; }
  .bkx-plan__shot[data-shot="3"] { display: none; }
  .bkx-plan__shot[data-shot="1"] { inline-size: 46%; inset-inline-start: 2%; }
  .bkx-plan__shot[data-shot="2"] { inline-size: 34%; inset-inline-start: 40%; }
  .bkx-plan__panel { inline-size: min(320px, 76%); inset-block-end: 2%; }
  .bkx-plan__steps { max-inline-size: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  html.js .bkx-plan__steps li,
  html.js .bkx-plan__shot,
  html.js .bkx-plan__row { opacity: 1 !important; animation: none !important; }
  html.js [data-bkx-plan].is-built .bkx-plan__shot { transform: none !important; }
}

/* == REFERENCE PASS 2 =====================================================
 * Written after putting the render and the mockup side by side at 1920
 * (artifacts/reference_compare/). Colour was already right; COMPOSITION was
 * not, and these are the four differences that were actually visible.
 */

/* --- 1. HERO: the foreground the reference has and this did not ----------
 *
 * The mockup is framed by dark, OUT-OF-FOCUS foreground: a stone column down
 * the right edge, foliage and lanterns bottom-left. That is what gives it
 * depth — there is something in front of the scene, not just behind it. The
 * render had a photograph running edge to edge with nothing nearer than the
 * subject, which is why it read flat however good the picture was.
 *
 * Built from gradients rather than cut-out photography because the repository
 * holds no foreground plates, and because a blurred mass at the frame edge is
 * exactly what an out-of-focus object IS. It rides `.bkx-layer--haze`, which
 * already travels at the highest parallax rate on the page — so it moves more
 * than the city behind it, which is the whole point.
 */
.bkx-hero__fg {
  position: absolute;
  inset: -4%;
  pointer-events: none;
  /*
   * The PLATE is the foreground now, not a gradient. scripts/build_foreground_plate.js
   * draws a column, low fronds and a canopy sprig, defocuses them, and writes a
   * transparent PNG. A gradient darkened the corners and never read as depth,
   * because the eye takes depth from a recognisable shape occluding a scene.
   *
   * URL is root-absolute: this custom-property-free url() still resolves against
   * the STYLESHEET, which ships from /assets/v/ after versioning.
   *
   * 100% 100% rather than cover, deliberately. Every shape in the plate is
   * anchored to an EDGE, and cover would crop whichever axis overflows — the
   * bottom fronds at 16:9, the canopy at 21:9. Stretching a blurred silhouette
   * is invisible; losing a third of the frame is not.
   */
  background:
    url("/assets/edit/hero_foreground_1600.png") 50% 50% / 100% 100% no-repeat,
    /* the warm bounce a lantern would throw onto the near foliage */
    radial-gradient(18% 26% at 9% 90%, rgba(227, 172, 96, .20) 0%, transparent 72%),
    /* and a general weighting of the corners, under the plate */
    radial-gradient(52% 66% at 2% 106%, rgba(4, 7, 12, .60) 0%, transparent 72%),
    radial-gradient(34% 118% at 100% 48%, rgba(4, 6, 10, .52) 0%, transparent 74%);
}
/* Mirrored in RTL so the relationship to the READING edge is preserved: the
   fronds and the lantern sit where the eye starts, the column falls away on the
   far side. Un-mirrored it would stand the column on top of the headline. */
[dir="rtl"] .bkx-hero__fg { transform: scaleX(-1); }
@media (max-width: 900px) {
  /* At phone width the frame is too narrow to give up its edges. */
  .bkx-hero__fg { display: none; }
}

/* --- 2. COVERFLOW: one ribbon, not seven separate tiles ------------------
 * The mockup's deck is a continuous overlapping ribbon that reaches both frame
 * edges, and the front card is unmistakably lit. The render's cards were
 * narrower with air between them, so it read as a row of pictures rather than
 * one object seen in perspective.
 */
.bkx-rail { --cf-card-w: min(330px, 66vw); --cf-card-h: min(440px, 88vw); }
.bkx-cf { --cf-h: clamp(470px, 60vh, 600px); }
.bkx-cf__item[data-cf-centre] {
  box-shadow:
    0 46px 100px -26px rgba(0, 0, 0, .98),
    0 0 0 1px rgba(227, 190, 121, .46),
    0 0 46px -6px rgba(227, 190, 121, .40),
    0 26px 70px -20px rgba(227, 190, 121, .38);
}
/* A soft ground behind the deck, so the band is a SCENE rather than a hole
   cut in the page — the mockup has a dark photographic backdrop here. */
.bkx-cf::before {
  content: "";
  position: absolute;
  inset: 6% -4% 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(52% 46% at 50% 46%, rgba(58, 96, 150, .16), transparent 68%),
    radial-gradient(70% 40% at 50% 104%, rgba(227, 190, 121, .10), transparent 72%);
}

/* --- 3. GLOBE: bigger in frame, and the column beside it gets room -------
 * The mockup's planet fills its column with a thin margin; the render left a
 * wide gap all round, which made it look smaller than the copy beside it. And
 * the destination list was sharing its column with a large fare card, so it
 * was squeezed into a strip.
 */
/*
 * SCOPED, AND THIS IS THE WHOLE PHONE DEFECT.
 *
 * This three-column refinement sat at TOP LEVEL, after
 * `@media (max-width: 1100px) { .bkx-globe { grid-template-columns: minmax(0,1fr) } }`.
 * A media query adds no specificity, so an unconditional rule further down the
 * file beats it at every width — the single-column mobile layout below it was
 * dead code and had been since it was written.
 *
 * Measured 2026-09-05 at 390x844, both languages: the grid resolved to
 * `0px 0px 308.172px` — the first two tracks collapsed to ZERO. The
 * destination panel came out 2px wide with its content overflowing at 18-35px,
 * and its call to action measured 2px on English and 0px on Hebrew: a control
 * that cannot be seen, read or pressed on a phone.
 *
 * The refinement is right where it was written for, so it is confined there
 * rather than deleted. Desktop is unchanged, byte for byte.
 */
@media (min-width: 1101px) {
  .bkx-globe { grid-template-columns: minmax(0, .78fr) minmax(0, 1.55fr) minmax(0, 320px); }
  .bkx-globe__stage { max-block-size: min(78vh, 760px); }
}
.bkx-globe__panel { inline-size: 100%; }
#jn-shot2-wrap .bkx-panel__pic-slot img,
#jn-shot2-wrap img { max-block-size: 116px; object-fit: cover; }

/* --- 4. PLANNER: the cinematic environment the scene sits in -------------
 * The mockup is a full-bleed dusk landscape with the composition floating over
 * it. The render was the composition alone on flat black, which is most of why
 * it still read as sparse after the rebuild.
 */
.bkx-scene--plan { position: relative; isolation: isolate; }
.bkx-scene--plan::before {
  content: "";
  position: absolute;
  inset-block: -6% -6%;
  inset-inline: calc(50% - 50vw);
  z-index: -2;
  pointer-events: none;
  /*
   * ROOT-ABSOLUTE, and it has to be. A relative url() inside a custom property
   * is resolved against the STYLESHEET that USES the var, not the element that
   * declared it — and this sheet is served content-addressed from /assets/v/,
   * so `url(assets/dest/…)` resolved to /assets/v/assets/dest/… and 404ed.
   * The scene rendered as flat black with no error anyone would notice.
   */
  background-image: var(--x-plan-bg);
  background-size: cover;
  background-position: center 62%;
  opacity: .5;
}
.bkx-scene--plan::after {
  content: "";
  position: absolute;
  inset-block: -6% -6%;
  inset-inline: calc(50% - 50vw);
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(180deg, var(--x-void) 0%, rgba(4, 7, 12, .74) 22%, rgba(4, 7, 12, .80) 68%, var(--x-void) 100%),
    linear-gradient(to left, rgba(4, 7, 12, .90) 0%, rgba(4, 7, 12, .40) 46%, rgba(4, 7, 12, .70) 100%);
}
@media (max-width: 900px) {
  .bkx-scene--plan::before { opacity: .34; }
}

/* EL, in the planner scene. A byline, not a widget: an avatar, her name, her
   role and one line. Her config lists a floating bubble and a persistent
   assistant under never_appears_in, and a persona that follows the reader down
   the page is arguing with them rather than offering something. */
.bkx-plan__who {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  margin: .2rem 0 0;
  padding: .7rem .85rem;
  border-radius: var(--x-r);
  border: 1px solid var(--x-line);
  background: linear-gradient(150deg, rgba(227, 190, 121, .07), rgba(7, 11, 18, .62));
  max-inline-size: 420px;
}
.bkx-plan__who img { inline-size: 34px; block-size: 34px; border-radius: 50%; flex: none; }
.bkx-plan__who b { color: var(--x-ink); font-weight: 600; }
.bkx-plan__who span { font-size: .84rem; color: var(--x-ink-2); line-height: 1.45; }
.bkx-plan__who small { display: block; font-size: .78rem; color: var(--x-ink-3); margin-block-start: .15rem; }

/* == COVERFLOW · PASS 3 — A DECK, NOT A ROW =============================
 *
 * The note was "it reads as a row of portrait cards", and it did. The engine's
 * geometry is fixed in bkx_coverflow.js; these are the three things the
 * stylesheet owns that were also missing.
 */

/* 1. THE PERSPECTIVE WAS TOO FAR AWAY. At 1400px a 58-degree turn foreshortens
 *    by a few percent and reads as a slightly narrower card. At 900 the same
 *    turn is unmistakable, and the receding cards genuinely converge. */
.bkx-cf {
  perspective: 900px;
  perspective-origin: 50% 42%;
}

/* 2. SHADING THAT LEANS. A turned card in the world is lit unevenly: the edge
 *    swinging away from you goes dark, the near edge catches the light. `--cf-s`
 *    is the sign of the card's offset, so the gradient can point at whichever
 *    side is actually the far one. Without this, a rotated card is just a
 *    narrower rectangle — this is what makes the turn legible. */
.bkx-cf .bkx-cf__track .bkx-cf__item::after {
  background:
    linear-gradient(180deg, rgba(4,7,12,.04) 0%, rgba(4,7,12,.06) 38%, rgba(4,7,12,.94) 100%),
    linear-gradient(
      calc(90deg + var(--cf-s, 1) * 180deg),
      /* --cf-a runs to 2.6, so a 0.62 coefficient clamped the far edge of the
         outer cards to solid black and the deck lost its ends. These are priced
         against the RANGE, not against 1. */
      rgba(2, 4, 8, calc(var(--cf-a, 0) * 0.27)) 0%,
      rgba(2, 4, 8, calc(var(--cf-a, 0) * 0.07)) 48%,
      rgba(255, 246, 232, calc(var(--cf-a, 0) * 0.035)) 100%
    );
}

/* 3. THE FLOOR. The reference deck stands on something — there is a soft
 *    reflection and a pool of light under it. A deck floating on flat black is
 *    the other half of why it read as a row of tiles. */
.bkx-cf::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 8%;
  block-size: 24%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(46% 100% at 50% 0%, rgba(227, 190, 121, .16), transparent 70%),
    radial-gradient(70% 100% at 50% 0%, rgba(58, 96, 150, .10), transparent 72%);
  filter: blur(6px);
}

/* The front card carries a real cast shadow now, not just a glow — a lit object
   above a floor throws one, and its absence is subtle but reads as a sticker. */
.bkx-cf .bkx-cf__track .bkx-cf__item[data-cf-centre] {
  box-shadow:
    0 54px 90px -30px rgba(0, 0, 0, .98),
    0 0 0 1px rgba(227, 190, 121, .50),
    0 0 52px -8px rgba(227, 190, 121, .34),
    0 30px 76px -22px rgba(227, 190, 121, .30);
}

/* == HERO · PASS 4 — LIGHT, SCALE, AND SOMETHING IN FRONT ==================
 *
 * Measured against the reference at 1920, not judged by eye:
 *
 *   headline      64px in a 1015px hero — 6.3% of the frame. The reference's
 *                 display is 8.7%. Two lines in both, so this is scale alone.
 *   top of frame  darkened TWICE. `.bkx-layer--sky` carries the base grade
 *                 (.86 at the top) and `.bkx-layer--world` carries the
 *                 directional one (.78), and they stack to near-opaque. The
 *                 reference's sky is the brightest thing in the picture.
 *   foreground    a plate now hangs on the haze layer, and the light in the
 *                 frame has to agree with it: it is lit from the far side.
 */

/* 1. THE SKY LAYER STOPS BEING A SCRIM. It sits above nothing — there is no
 *    photograph on it — so every point of darkness it adds is subtracted from
 *    the one on the layer below. It becomes atmosphere instead: the warm depth
 *    of a low sun, and a bare minimum of weight under the header. */
.bkx-hero .bkx-layer--sky .bkx-hero__grade {
  background:
    linear-gradient(180deg, rgba(4, 7, 12, .52) 0%, rgba(4, 7, 12, .12) 13%, transparent 26%),
    radial-gradient(58% 42% at 62% 24%, rgba(255, 198, 122, .20) 0%, transparent 72%);
}

/* 2. THE PICTURE KEEPS ITS SKY, AND THE TYPE KEEPS ITS GROUND.
 *
 *    THIS IS THE GRADE THAT PAINTS. The block earlier in the file sets the
 *    same selectors and is overridden by this one.
 *
 *    RE-TUNED 2026-09-05 with the photograph. It was written against a night
 *    shot of the Acropolis, where the picture was already almost black behind
 *    the headline, so the vertical band could go fully `transparent` at 34%
 *    and the side sweep down to .10 in the middle. The new hero is a sunset
 *    above the clouds and its brightest band — the lit horizon — falls at
 *    exactly the height the headline sits at.
 *
 *    MEASURED, by scripts/hero_contrast_probe.js, which hides the type and
 *    reads the pixels it was standing on. Before, at every one of the four
 *    widths:
 *
 *        .bkx-h1             worst 2% = 1.86    floor 3    (large text)
 *        .bkx-hero__eyebrow             1.08    floor 4.5
 *        .bkx-hero__sub                 1.05    floor 4.5
 *
 *    A headline at 1.86 is not a headline.
 *
 *    WHAT CHANGED, and what deliberately did not. The vertical band no longer
 *    reaches transparent: it holds around .50 through the band the type
 *    occupies and lets go again below it. The side sweep keeps .40 in the
 *    middle instead of .10. And the warm sun moved to the FAR side of the
 *    frame — it was at 61%, which in Hebrew is behind the headline, so the
 *    one element added to make the picture cinematic was also the one adding
 *    light exactly where the type needed dark. It is now mirrored with the
 *    reading direction like everything else here.
 *
 *    The far half still bottoms out at .30, so the photograph is still a
 *    photograph. THE IMAGE AND THESE NUMBERS ARE ONE DECISION: changing the
 *    hero means re-running the probe, not assuming they travel. */
.bkx-hero .bkx-layer--world .bkx-hero__grade,
.bkx-hero:dir(ltr) .bkx-layer--world .bkx-hero__grade {
  background:
    /* the sun, on the side the type is NOT on */
    radial-gradient(44% 34% at var(--x-sun-x, 32%) 30%, rgba(255, 206, 138, .26) 0%, transparent 68%),
    linear-gradient(to var(--x-read-far, left),
      rgba(4, 7, 12, .93) 0%, rgba(4, 7, 12, .80) 26%, rgba(4, 7, 12, .40) 56%, rgba(4, 7, 12, .30) 100%),
    linear-gradient(180deg,
      rgba(4, 7, 12, .66) 0%, rgba(4, 7, 12, .26) 12%, rgba(4, 7, 12, .46) 30%,
      rgba(4, 7, 12, .50) 48%, rgba(4, 7, 12, .38) 66%, rgba(4, 7, 12, .86) 100%);
}
.bkx-hero { --x-read-far: left; --x-sun-x: 32%; }
.bkx-hero:dir(ltr) { --x-read-far: right; --x-sun-x: 68%; }

/* Below the two-column width there is no reading EDGE: the type spans the
   frame, so the side sweep has nothing to sweep toward and the vertical band
   carries the whole job. Heavier for that reason, and placed AFTER the rule
   above because that rule is unconditional and would otherwise win inside the
   media query too — which is exactly what was happening at 390 and 430. */
@media (max-width: 1180px) {
  .bkx-hero .bkx-layer--world .bkx-hero__grade,
  .bkx-hero:dir(ltr) .bkx-layer--world .bkx-hero__grade {
    background: linear-gradient(180deg,
      rgba(4, 7, 12, .84) 0%, rgba(4, 7, 12, .72) 14%, rgba(4, 7, 12, .78) 34%,
      rgba(4, 7, 12, .82) 56%, rgba(4, 7, 12, .72) 72%, rgba(4, 7, 12, .95) 100%);
  }
}

/* 3. SCALE. The reference's hierarchy is one very large statement and one small
 *    line under it; ours was reading as two medium ones. */
.bkx-hero .bkx-hero__say .bkx-h1 {
  font-size: clamp(2.5rem, 3.9vw + .5rem, 5.1rem);
  letter-spacing: -.028em;
  text-shadow: 0 6px 54px rgba(0, 0, 0, .78), 0 1px 2px rgba(0, 0, 0, .5);
}
.bkx-hero .bkx-hero__say { max-inline-size: min(720px, 56%); }
@media (min-width: 1280px) {
  .bkx .bkx-hero__say { max-inline-size: min(720px, 56%); }
}
.bkx-hero .bkx-hero__eyebrow { letter-spacing: .22em; }

/* 4. The haze is warmer and heavier on the sun side, so the atmosphere and the
 *    grade are lit from one place rather than two. */
.bkx-hero .bkx-hero__haze {
  opacity: .92;
  background:
    radial-gradient(40% 44% at 64% 26%, rgba(255, 200, 132, .22), transparent 70%),
    radial-gradient(48% 44% at 22% 68%, rgba(104, 142, 198, .14), transparent 74%);
}

/* The larger display needs a wider lane. At 81.6px the first Hebrew line is
   about 810px and the 720px column broke it, making THREE lines where the
   reference sets two — a bigger type size that costs the hierarchy it was
   meant to buy. Measured, not guessed: the probe reported lines:3. */
@media (min-width: 1280px) {
  .bkx .bkx-hero__say,
  .bkx-hero .bkx-hero__say { max-inline-size: min(900px, 58%); }
}

/* The plate belongs at the EDGES of the frame and nowhere else. Without this
   the bottom corner's lantern bokeh drifted across the search console — light
   sources floating over an input, which is the opposite of the depth they are
   there to create. The mask keeps the outer ring and discards the middle, so
   the plate can only ever frame the picture. */
.bkx-hero__fg {
  opacity: .88;
  -webkit-mask-image: radial-gradient(78% 74% at 50% 46%, transparent 26%, #000 88%);
          mask-image: radial-gradient(78% 74% at 50% 46%, transparent 26%, #000 88%);
}

/* == GLOBE · DESTINATION LABELS ==========================================
 * Asked for by name: "premium destination labels". The globe carried gold
 * nodes and nothing that said what they were, so the one thing the scene is
 * about — these are the cities we measure prices to — had to be read off the
 * list beside it.
 *
 * The layer is aria-hidden on purpose. The same cities are already in the
 * `.bkx-dests` list next to the globe as real links; a screen reader meeting
 * both would hear every destination twice.
 */
.bkx-globe__labels {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  /* Names are set in the page's own type, never the canvas's. */
  font-family: inherit;
}
.bkx-globe__tag {
  position: absolute;
  /*
   * PHYSICAL, not logical, and this is load-bearing. The tag's position comes
   * from projecting a 3D point to PIXELS, which are physical by definition.
   * With inset-inline-start the RTL homepage anchored every tag to the layer's
   * right edge and then added the projected x to it — measured 1630px for a
   * node the projection put at 858. Logical properties are right for text and
   * wrong for a coordinate that has already been computed.
   */
  top: 0;
  left: 0;
  /* The projected point is the NODE. The tag sits above and just clear of it,
     so the marker it names is not covered by its own name. */
  margin-top: -2.15em;
  margin-left: .55em;
  visibility: hidden;
  white-space: nowrap;
  font-size: clamp(.62rem, .48vw + .3rem, .78rem);
  font-weight: 600;
  letter-spacing: .01em;
  line-height: 1;
  padding: .34em .62em;
  border-radius: 999px;
  color: #F6ECDA;
  background: rgba(9, 13, 21, .62);
  border: 1px solid rgba(227, 190, 121, .34);
  box-shadow: 0 2px 14px rgba(0, 0, 0, .55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: opacity .18s linear;
}
@media (max-width: 760px) {
  /* At phone width twelve pills over a 320px sphere is a wall of text. */
  .bkx-globe__labels { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .bkx-globe__tag { transition: none; }
}

/* == MOBILE TOUCH + THE FINE PRINT THAT CARRIES THE TRUTH =================
 * Measured on live production at 390x844, iPhone emulation, 2026-09-05.
 */

/*
 * THE COVERFLOW DOTS WERE 7x7 CSS PIXELS — measured, eight of them, and on a
 * phone they are the ONLY tap-to-navigate control the deck has: the pointer
 * cruise is a mouse affordance and there is no cursor to put near an edge.
 * So the one control a touch reader can use was a fifth of the 44px minimum.
 *
 * The dot stays 7px. A pseudo-element carries the touch area, so the visual
 * rhythm of the pagination is unchanged and only the hit box grows. Sizing the
 * dot itself to 44px would have turned a discreet row of dots into eight
 * buttons and redesigned a section that reads correctly.
 */
.bkx-dots button { position: relative; }
/*
 * WIDTH IS THE PITCH, HEIGHT IS FREE.
 *
 * Eight 44px-wide boxes over an 8px gap would overlap by 36px each, and the
 * dot a thumb landed on would then be decided by DOM order rather than by
 * aim — worse than a small target, because it is a target that lies about
 * where it is. So the box is exactly the pitch wide (dot + gap, no overlap)
 * and takes its height freely, where nothing competes.
 *
 * 24px is WCAG 2.5.8 AA, and it is what a pitch of 24 buys without spreading
 * eight dots across the whole phone. Widening to the 44px Apple guideline
 * would need a 37px gap and would turn a discreet row into a button bar —
 * redesigning a section that reads correctly, to fix a row that swipe
 * already makes secondary.
 */
/*
 * ONE SOURCE FOR THE PITCH. The hit box is derived from the gap, so the two
 * can never disagree: widen the gap and the box widens with it, and no pair
 * of boxes can overlap by construction. Overlapping boxes are worse than
 * small ones — the dot a tap lands on would be decided by DOM order rather
 * than by aim, which is a target that lies about where it is.
 *
 * The desktop gap is left at its original 8px: a mouse does not need 24px and
 * the dot row is part of a composition that reads correctly. Only touch, where
 * the 7px dot was the ONLY tap-to-navigate control the deck has, buys the
 * wider pitch — 24px, WCAG 2.5.8 AA.
 */
.bkx-dots { --dot-gap: 8px; gap: var(--dot-gap); }
@media (max-width: 900px), (pointer: coarse) { .bkx-dots { --dot-gap: 17px; } }
.bkx-dots button::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  /* PHYSICAL left, not inset-inline-start. transform: translate() is not
     direction-aware, so pairing it with a logical inset centres the box in
     LTR and throws it a full width off in RTL — the same physical/logical
     mismatch that put the globe labels on the wrong edge. */
  left: 50%;
  /* Never narrower than 24px, whatever the pitch: at the desktop gap of 8px
     the box was 15px wide, so the claim above — WCAG 2.5.8 AA — was true on
     a phone and false on the pointer that reaches most of these decks.
     Measured by the release gate's TAP_TARGET rule, 2026-09-07. Adjacent
     boxes overlap by a few pixels; a click in the overlap goes to one dot or
     the other, never to nothing, and the dots themselves do not move. */
  inline-size: max(24px, calc(7px + var(--dot-gap)));
  block-size: 44px;
  transform: translate(-50%, -50%);
}

/*
 * THE OBSERVATION TIME IS NOT DECORATION.
 *
 * `.jn-deal__obs` is the "measured at" stamp — the annotation the whole truth
 * rule rests on, since a price without its observation time is a claim rather
 * than a reading. At .68rem it computed to 10.9px on a phone, which made the
 * load-bearing sentence the least readable thing on the card. It stays visually
 * subordinate to the price; it stops being fine print you cannot read.
 */
@media (max-width: 760px) {
  .bkx .jn-deal__obs,
  .bkx .jn-deal__src,
  .bkx .jn-row__at { font-size: .78rem; }
}

/*
 * THE ANNOTATIONS THAT CARRY THE TRUTH GET A FLOOR ON MOBILE.
 *
 * Measured at 390x844 on live: the observed-price tag, the price basis, the
 * price unit and the no-service-fee statement all computed to 10.9-11.8px —
 * the whole set of sentences the product's honesty rests on, rendered as the
 * least readable text on the page. A price without a legible unit or
 * observation time is a claim rather than a reading, and the rule this site is
 * built on is that the reading has to travel with the number.
 *
 * Scope is deliberately narrow. Eyebrows, section kickers, footer headings and
 * country labels stay where they are: they are navigation, and raising every
 * small class would be a typographic redesign of a page that reads correctly.
 */
@media (max-width: 760px) {
  .bkx .jn-tag,
  .bkx .jn-deal__unit,
  .bkx .jn-row-item__claim,
  .bkx .bkx-note,
  .bkx .bkx-stats li span { font-size: .78rem; }
}

/* --- the origin combobox ------------------------------------------------ */
/*
 * "מאיפה יוצאים?" — the field that used to be a fixed string reading
 * "תל אביב (TLV)". It is now a real search over 3,787 airports and
 * multi-airport cities, so it needs a list that can escape the console.
 *
 * The console carries `transform: perspective(1600px) rotateX(5deg)`, which
 * makes it the containing block for anything absolute inside it — so the list
 * is positioned against the FIELD and rides the deck with it. That is why the
 * deck flattens to 0deg on :focus-within (already in .bkx-console above): a
 * list of airports read at a five-degree tilt is a list read badly.
 *
 * No `overflow: hidden` exists on .bkx-console, deliberately — adding one
 * would clip this list to the console's bottom edge.
 */
.bkx-origin { position: relative; }
  /*
   * WIDER THAN THE FIELD, because the field is a sixth of a search console.
   *
   * This was inset-inline: -1px, i.e. exactly the column width. Measured on an
   * 800px-wide pane: the list came out 99px across and the name inside it 14px,
   * so every row rendered as an icon, a code chip and a sliver of text. The
   * column is sized for a typed code; the list has to hold
   * "Paris Charles de Gaulle Airport".
   *
   * Only the START edge is pinned, so it grows away from the field in the page
   * direction — and bkx_origin.js fit() pulls it back when that would take it
   * off-screen, which no static rule can know.
   */
.bkx-origin__list {
  position: absolute;
  z-index: 40;
  inset-inline-start: -1px;
  inline-size: max(100%, min(340px, 92vw));
  max-inline-size: 92vw;
  inset-block-start: calc(100% - 2px);
  margin: 0;
  padding: .3rem;
  list-style: none;
  max-block-size: min(52vh, 340px);
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--x-line-2);
  border-radius: 0 0 var(--x-r-md, 14px) var(--x-r-md, 14px);
  background: var(--x-raised);
  box-shadow: var(--x-e4);
}
.bkx-origin__opt {
  display: flex;
  align-items: center;
  gap: .6rem;
  /* 44px, the same touch floor the fields keep. A list a thumb cannot hit is
     a list that sends people back to typing a code they do not know. */
  min-block-size: 44px;
  padding: .4rem .55rem;
  border-radius: 10px;
  cursor: pointer;
  color: var(--x-ink);
}
.bkx-origin__opt:hover,
.bkx-origin__opt.is-on { background: rgba(227, 190, 121, .10); }
.bkx-origin__kind { flex: none; color: var(--x-gold); font-size: .82rem; line-height: 1; }
.bkx-origin__text { min-inline-size: 0; flex: 1 1 auto; }
.bkx-origin__text b {
  display: block;
  font-weight: 600;
  font-size: .92rem;
  /* One line, ellipsised. "Paris Charles de Gaulle Airport" wrapping to three
     lines turns eight results into a page nobody scans. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bkx-origin__text small {
  display: block;
  font-size: .74rem;
  color: var(--x-ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bkx-origin__code {
  flex: none;
  font-size: .74rem;
  letter-spacing: .08em;
  color: var(--x-ink-3);
  border: 1px solid var(--x-line);
  border-radius: 7px;
  padding: .12rem .38rem;
  /* The code is Latin in both languages. Without this it renders reversed
     inside the RTL row on Hebrew. */
  direction: ltr;
  unicode-bidi: isolate;
}
.bkx-origin__note {
  padding: .7rem .6rem;
  font-size: .82rem;
  color: var(--x-ink-3);
}
/* The quick-picks header in the destination list. A label for the rows under
   it, never an option: role="presentation", and arrow keys skip it. */
.bkx-origin__note.bkx-origin__head {
  padding: .5rem .6rem .25rem;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .03em;
  color: var(--x-gold);
}
@media (prefers-reduced-motion: no-preference) {
  .bkx-origin__list { animation: bkx-origin-in .16s var(--x-ease, ease-out); }
  @keyframes bkx-origin-in { from { opacity: 0; transform: translateY(-4px); } }
}


/* == THE PORTALS · the hero's third dimension ==============================
 * The owner's note on the previous hero: "יבש מדי, נראה ריק בלי כלום. איפה
 * ה-3D?" — and he was right about what the frame had become. A photograph,
 * a grade, some haze in front of it and a form. Every one of those is a flat
 * plane parallel to the screen; the camera moved them at different rates and
 * that is parallax, not depth. Nothing in the frame was ever seen from an
 * ANGLE, so nothing could look near or far while the mouse stood still.
 *
 * This layer is the answer, and it is a real 3D scene: four photographic
 * planes standing in one perspective context at four different Z distances,
 * each turned on its Y axis. The near one is dominant, sharp and lit; the far
 * ones are smaller because they are further away (translateZ, not a smaller
 * width), softer because they are out of focus (a real blur, a real
 * desaturation), and veiled because there is air between them and the reader
 * (aerial perspective). They overlap so the near one OCCLUDES what is behind
 * it, and the out-of-focus foreground plate on the haze layer occludes them
 * in turn. Depth here is a property of the geometry. A box-shadow is the last
 * thing added, not the first.
 *
 * What the planes are NOT: cards. No text, no price, no city name, no button.
 * A destination card beside the console read as a second thing to look at;
 * these are the world the search is for, and they say so with photographs
 * only. Four cities on three continents, and never Athens — the frame is
 * meant to say WORLD, and the one city the old floating card kept naming is
 * the one it must not name again.
 *
 * WHERE THEY LIVE. The reading side of the hero carries the headline, the
 * console and the origin picker, and they were not touched. The portals take
 * the other side, in a group anchored to `inset-inline-end`, so on the Hebrew
 * page they stand at the left and on the English page at the right without a
 * second set of numbers. Inside the group the positions are logical too —
 * `inset-inline-end` is always the OUTER edge of the frame — and so is the
 * turn: `--p-dir` flips the sign of every rotateY under :dir(ltr), so the
 * planes face the reading side on both pages.
 *
 * MOTION. Two kinds and no more. The pointer moves the camera the hero already
 * has (`--x-cam-*`, written once a frame by bkx.js) and every portal
 * translates by its own `--p-depth`, in vw so the displacement is a fraction
 * of the frame at every width: about ±5.5% for the near plane, ±2.2% for the
 * far one, and the camera eases back to centre on its own when the pointer
 * leaves. Then a breath: each pane drifts a little and swells a little on its
 * own slow clock, four different periods, four different phases, so no two
 * are ever in step and the scene never reads as a loop. Nothing rotates
 * continuously, nothing carousels, nothing moves behind the form.
 *
 * COST. Every animated property is transform or opacity. The pointer parallax
 * is the same custom-property write the existing layers already read. The
 * breath pauses when the hero is off screen or the tab is hidden
 * (`data-parked`, set by bkx.js), and under prefers-reduced-motion it is
 * removed entirely while the 3D placement STAYS — a reader who asked for less
 * motion is shown the composition, not a blank side of the frame.
 */
.bkx-layer--portals { --x-depth: 0px; z-index: 2; }
/* The near foreground now occludes the portals, which is what a foreground is for. */
.bkx-layer--haze { z-index: 3; }

.bkx-portals {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: 42%;
  perspective: 1400px;
  /* The vanishing point sits toward the reading side, so the planes converge
     on the thing the reader is looking at rather than on the frame edge. */
  perspective-origin: var(--p-po, 88%) 46%;
  --p-dir: -1;
}
.bkx-hero:dir(ltr) .bkx-portals { --p-po: 12%; --p-dir: 1; }

.bkx-portal {
  position: absolute;
  inset-inline-end: var(--p-x);
  inset-block-start: var(--p-y);
  inline-size: var(--p-w);
  aspect-ratio: 3 / 4;
  opacity: var(--p-o, 1);
  /*
   * translate first, then turn: the plane is rotated about its own centre and
   * that rotated plane is then carried by the camera, so the parallax reads
   * as the whole object moving and never as the object twisting.
   */
  transform:
    translate3d(
      calc(var(--x-cam-x, 0) * var(--p-depth)),
      calc(var(--x-cam-y, 0) * var(--p-depth) * .6),
      var(--p-z))
    rotateY(calc(var(--p-ry) * var(--p-dir)));
  transform-origin: 50% 50%;
  will-change: transform;
}

.bkx-portal__pane {
  position: absolute;
  inset: 0;
  border-radius: 10px;
  overflow: hidden;
  /* A cast shadow on a turned plane turns with it, which is the point of
     putting it here rather than on the flat parent. */
  box-shadow:
    0 44px 80px -28px rgba(0, 0, 0, .78),
    0 16px 30px -16px rgba(0, 0, 0, .62);
  /* Depth of field is IN THE FILE: build_hero_portals.py blurs and drains the
     far planes once, at cut time, scaled to each width. A runtime filter on a
     pane that is also animating would re-blur a large texture every frame. */
  transform: translate3d(0, 0, 0) scale(1);
  backface-visibility: hidden;
}
.bkx-portal__pane img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
}
/* Aerial perspective, and a foot of shadow so the picture has a bottom. */
.bkx-portal__pane::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(180deg, rgba(4, 7, 12, .08) 0%, transparent 28%, transparent 60%, rgba(4, 7, 12, .44) 100%),
    linear-gradient(to var(--x-read-far, left),
      rgba(8, 12, 20, var(--p-veil, 0)) 0%, rgba(8, 12, 20, calc(var(--p-veil, 0) * .55)) 100%);
}
/* The film edge: one hairline in the brand's champagne and a glancing top
   light. Above the image, which is why it is not an inset shadow on the pane
   itself — that paints under the content. */
.bkx-portal__pane::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  box-shadow:
    inset 0 0 0 1px rgba(227, 190, 121, .22),
    inset 0 1px 0 rgba(255, 244, 222, .18);
}

@keyframes bkx-portal-breathe {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(0, var(--p-drift, -1.4%), 0) scale(var(--p-swell, 1.012)); }
}
/* The "breath" - each pane drifting and swelling on its own clock - is
   gone (owner, 2026-09-06: "the deal planes should feel like physical
   editorial panels in a composed scene, not objects floating in zero
   gravity"). The keyframes stay defined and unused; nothing here loops. */
html.js .bkx-portal__pane { animation: none; }
/* Off screen, or in a hidden tab: nothing moves. Set by bkx.js. */
.bkx-hero[data-parked] .bkx-portal__pane,
.bkx-hero[data-parked] .bkx-hero__haze,
.bkx-hero[data-parked] .bkx-hero__sheen { animation-play-state: paused; }

/*
 * THE FOUR PLANES. Positions are fractions of the group; `--p-z` is the real
 * distance; `--p-depth` is how far the camera carries each one, in vw. Near
 * is last in the DOM so it paints over the others: that is the occlusion.
 *
 *   far      Barcelona from the air     the one that is partly out of frame
 *   mid-far  Amsterdam at night
 *   mid      Paris at blue hour
 *   near     Bangkok at sunset          dominant · sharp · lit · +40px
 */
.bkx-portal--far {
  --p-x: 84%; --p-y: 40%; --p-w: 15%;
  --p-z: -210px; --p-ry: 30deg; --p-depth: 2px;
  --p-veil: .3; --p-o: .8;
  --p-t: 23s; --p-ph: -9s; --p-drift: -1%; --p-swell: 1.008;
}
.bkx-portal--midfar {
  --p-x: 76%; --p-y: 13%; --p-w: 21%;
  --p-z: -120px; --p-ry: 24deg; --p-depth: 3px;
  --p-veil: .2; --p-o: .88;
  --p-t: 20s; --p-ph: -5s; --p-drift: -1.2%; --p-swell: 1.01;
}
.bkx-portal--mid {
  --p-x: 66%; --p-y: 27%; --p-w: 27%;
  --p-z: -40px; --p-ry: 18deg; --p-depth: 5px;
  --p-veil: .08;
  --p-t: 17s; --p-ph: -12s; --p-drift: -1.4%; --p-swell: 1.012;
}
.bkx-portal--near {
  --p-x: 46%; --p-y: 15%; --p-w: 34%;
  --p-z: 30px; --p-ry: 12deg; --p-depth: 8px;
  --p-t: 14s; --p-ph: -3s; --p-drift: -1.6%; --p-swell: 1.014;
}

/* Tablet: three planes, smaller, in the band above the console. Measured at
   1024x768 the console begins at 345px, so the whole group lives above it. */
@media (max-width: 1279px) {
  .bkx-portals { inline-size: 46%; }
  .bkx-portal--far, .bkx-portal--mid { display: none; }
  .bkx-portal--midfar { --p-x: 72%; --p-y: 24%; --p-w: 22%; }
  .bkx-portal--near   { --p-x: 40%; --p-y: 13%; --p-w: 30%; }
}

/* Phone: two planes in the column beside the headline, which is empty on both
   pages (the headline is capped at 56% of the width). Anchored in px from the
   top because the two heroes are different heights — the English headline
   wraps deeper — and a percentage would put the planes in different places
   on the two pages. Neither reaches the console. */
@media (max-width: 900px) {
  .bkx-portals { inline-size: 100%; perspective: 900px; }
  .bkx-portal--far, .bkx-portal--midfar, .bkx-portal--near { display: none; }
  /* One plane behind her, and her. The blue hour behind a warm rim light.
     Shown again explicitly: the tablet rule above hides it, and a phone is
     also under 1280px. */
  .bkx-portal--mid {
    display: block;
    --p-x: 6%; --p-y: 84px; --p-w: 30%;
    --p-z: -60px; --p-ry: 22deg; --p-o: .8; --p-veil: .2;
  }
  .bkx-portal__pane { border-radius: 8px; }
}

/* Less motion: the breath goes, the depth stays. The layer-level rule earlier
   in this file already zeroes the camera, so the planes hold still at their
   3D positions — the composition is shown, it just does not move. */
@media (prefers-reduced-motion: reduce) {
  html.js .bkx-portal__pane { animation: none !important; }
  .bkx-portal { will-change: auto; }
}


/* == EL, IN THE SCENE ======================================================
 * The owner's correction, the same evening: "EL MUST APPEAR IN THE MAIN
 * HERO... a cinematic character inside the travel world. Not an
 * advertisement. Not a floating profile badge. Not a card."
 *
 * So she is a PLANE in the same perspective context as the portals, at the
 * nearest depth (+60px), on the side of the frame the type is not on, facing
 * the console. The destination planes stand behind her and her shadow falls
 * on them; the out-of-focus foreground on the haze layer crosses her outer
 * edge. She is the NEAR layer of the brief's FAR / MID / NEAR / UI, and the
 * headline and the console stay in front of everything.
 *
 * She is one file. assets/brand/_raw/el_master.png is the canonical EL, and
 * the hero portrait, the phone portrait and the 26px mark beside "דברו עם אל"
 * are crops of it (scripts/build_el_hero.py), so the character in the nav and
 * the character in the scene cannot be two people. Her bottom fade and her
 * cast shadow are baked into the file - a runtime drop-shadow on a large
 * animating cutout is recomputed every frame.
 *
 * Under :dir(rtl) the portrait is mirrored, so on the Hebrew page she faces
 * the console at the right the way she faces it at the left in English. The
 * camera carries her by 7.6vw - a little less than the nearest destination
 * plane, on purpose: the brief asked for "slightly more movement than the
 * distant background, but subtle and premium", and a person who swings across
 * the frame is neither.
 */
.bkx-el {
  position: absolute;
  inset-inline-end: var(--p-x);
  inset-block-start: var(--p-y);
  inline-size: var(--p-w);
  aspect-ratio: 3 / 4;
  --p-x: 4%; --p-y: 20%; --p-w: 50%;
  --p-z: 60px; --p-depth: 4px;
  transform: translate3d(
    calc(var(--x-cam-x, 0) * var(--p-depth)),
    calc(var(--x-cam-y, 0) * var(--p-depth) * .6),
    var(--p-z));
  will-change: transform;
}
.bkx-el__pane {
  position: absolute;
  inset: 0;
  transform: translate3d(0, 0, 0);
  backface-visibility: hidden;
}
.bkx-el img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  object-position: center bottom;
  display: block;
}
/* The master faces the viewer's LEFT. On the Hebrew page she stands at the
   left of the frame, so she is mirrored there to face the console; the
   English page, where she stands at the right, shows her as drawn. */
.bkx-el img { transform: scaleX(-1); }
.bkx-hero:dir(ltr) .bkx-el img { transform: none; }
@keyframes bkx-el-breathe {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(0, -.4%, 0) scale(1.004); }
}
/* EL does not breathe, sway or drift (owner, 2026-09-06: "a premium
   concierge portrait integrated into the environment", "grounded"). She
   moves only with the camera, by a few pixels. */
html.js .bkx-el__pane { animation: none; }
.bkx-hero[data-parked] .bkx-el__pane { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  html.js .bkx-el__pane { animation: none !important; }
  .bkx-el { will-change: auto; }
}
/* Her responsive placement sits BELOW her base rule on purpose. The first
   version put these beside the portals' breakpoints, earlier in the file, and
   the base rule - same specificity, declared later - won inside the media
   queries too: on a phone she was 230px wide across the headline while every
   number in the stylesheet said 38%. The rule that paints is the last one. */
@media (max-width: 1279px) {
  .bkx-el { --p-x: 4%; --p-y: 13%; --p-w: 34%; }
}
@media (max-width: 900px) {
  .bkx-el { --p-x: 3%; --p-y: 126px; --p-w: 38%; --p-z: 20px; --p-depth: 4px; }
}


/* == HOT DEALS · the planes carry fares ===================================
 * The owner, on the decorative planes: "הצד סתם דבילי. לפחות שיהיו שם מבצעים
 * חמים שהיו ישר מקשרים אותך לאיזה דיל הכי זול שיש. שהיציאה תהיה גם ממדינות
 * אחרות." So each plane is now a real fare from a real departure city —
 * London, New York, Bangkok, Tel Aviv — observed by the provider, dated,
 * priced in its own currency, and one click from BOOKALLO's results for that
 * exact route. bkx_hot_deals.js writes the cards; the 3D placement, the
 * camera and the breath are untouched, because a card that is also a plane
 * is the whole point.
 *
 * READABILITY BEATS PERSPECTIVE. The far planes were 15–22% of the group
 * and turned 24–30°; a price on them was a smear. They are wider now and
 * turned less (10–22°), the type scales with the plane, and a scrim rises
 * under the words so a bright sky cannot take the price with it.
 *
 * The layer is no longer aria-hidden: these are links, and a screen reader
 * hears "London to Rome, £38 per adult, 6–8 Oct, observed fare, checked 3
 * hours ago. Opens the search." EL beside them stays hidden from it — she
 * is scenery; the deals are not.
 */
/* Three deal cards a reader can actually read, and the fourth plane kept as
   scenery behind them: four priced cards did not fit the 320px the fan has
   beside the headline without one of them shrinking past legibility. The
   far plane keeps its photograph and no number - honest, and still depth. */
/* Desktop only, and scoped on purpose: this block sits at the END of the
   file, so an unscoped rule here would beat the tablet and phone blocks
   above it - which is exactly what happened on the first pass (the phone
   plane jumped to 27% of the hero, under the headline). The rule that paints
   is the last one; a media query is how a later rule stays out of a width
   it was not written for.

   The stack: a card painted OVER another must end above the other's text,
   because every card carries its words at its bottom. So mid sits high and
   mid-far sits low beneath it, and near - painted last - covers only image. */
@media (min-width: 1280px) {
  /* near top-outer · mid top-inner · mid-far low-inner, under mid, so mid
     covers only its picture · far a small scenery plane peeking under near.
     Each card's words are at its bottom, and no card in front reaches the
     words of the card behind it. */
  .bkx-portal--far    { --p-w: 16%; --p-ry: 24deg; --p-x: 62%; --p-y: 40%; }
  .bkx-portal--midfar { --p-w: 24%; --p-ry: 18deg; --p-x: 76%; --p-y: 32%; --p-o: .96; --p-veil: .08; }
  .bkx-portal--mid    { --p-w: 28%; --p-ry: 14deg; --p-x: 72%; --p-y: 13%; --p-veil: .04; }
  .bkx-portal--near   { --p-w: 30%; --p-ry: 10deg; --p-x: 46%; --p-y: 14%; }
}
.bkx-portal--midfar { --p-fs: clamp(10.5px, .78vw, 13px); }
.bkx-portal--mid    { --p-fs: clamp(11.5px, .86vw, 14px); }
.bkx-portal--near   { --p-fs: clamp(12px, .95vw, 16px); }
.bkx-portal--midfar .bkx-deal__fine { display: none; }

.bkx-deal {
  position: absolute;
  inset: 0;
  z-index: 1;                    /* above the pane's aerial veil, under its hairline */
  display: block;
  pointer-events: auto;          /* the layer is inert; the card is not */
  color: #F6ECDA;
  text-decoration: none;
  border-radius: inherit;
  overflow: hidden;
  font-size: var(--p-fs, 13px);
  line-height: 1.25;
}
.bkx-deal__pic {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
  transition: transform .6s var(--x-ease-2, ease);
}
.bkx-deal:hover .bkx-deal__pic { transform: scale(1.02); }
/* No photograph for this city yet: a designed plate, not a grey box. */
.bkx-deal__plate {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 10%;
  text-align: center;
  background:
    radial-gradient(90% 70% at 30% 20%, rgba(227, 190, 121, .22), transparent 60%),
    linear-gradient(160deg, #182338 0%, #0B1220 60%, #070B14 100%);
}
.bkx-deal__plate > span {
  font-family: var(--x-serif, Georgia, serif);
  font-size: 2.1em;
  font-weight: 600;
  letter-spacing: .02em;
  color: rgba(246, 236, 218, .28);
  line-height: 1.05;
}
.bkx-deal__scrim {
  position: absolute;
  inset: 0;
  /* The text block starts a little above the card's middle, and the ramp used
     to reach .58 only at 58% — so the route line sat on a photograph darkened
     by roughly half. Measured on the Budapest and Barcelona planes at glyph
     pixels: 3.1:1 and 3.2:1 for cream at 1440. The ramp now reaches its dark
     band where the text begins; the top third of the picture is untouched. */
  background: linear-gradient(180deg, rgba(4, 7, 12, .10) 0%, rgba(4, 7, 12, .06) 20%, rgba(4, 7, 12, .62) 36%, rgba(4, 7, 12, .82) 50%, rgba(4, 7, 12, .92) 66%, rgba(4, 7, 12, .97) 100%);
}
.bkx-deal__text {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  padding: 9% 9% 8%;
  display: grid;
  gap: .12em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55);
}
.bkx-deal__route {
  font-weight: 700;
  font-size: .84em;
  letter-spacing: .08em;
  text-transform: uppercase;
  opacity: .92;
}
.bkx-hero:dir(rtl) .bkx-deal__route { letter-spacing: 0; text-transform: none; font-size: .9em; }
.bkx-deal__price {
  font-family: var(--x-serif, Georgia, serif);
  font-size: 2.15em;
  font-weight: 700;
  line-height: 1;
  color: var(--x-gold, #E3BE79);
  margin-block: .08em .04em;
}
.bkx-deal__approx {
  display: inline-block;
  margin-inline-start: .45em;
  font-family: var(--x-sans, system-ui, sans-serif);
  font-size: max(.38em, 12px);   /* never under 12px: on the phone row .38em was 8.6px */
  font-weight: 600;
  color: #F6ECDA;
  opacity: .85;
  vertical-align: middle;
}
.bkx-deal__dates { font-size: .95em; font-weight: 600; }
.bkx-deal__meta  { font-size: .7em; opacity: .82; }
.bkx-deal__fine  { font-size: .62em; opacity: .62; }
.bkx-deal:focus-visible { outline: 2px solid var(--x-gold, #E3BE79); outline-offset: 3px; }
/* The card says where its click goes. "לדיל / View deal" only on a verified
   exact offer (LEVEL_3); every cached fare says "השוו מחירים / Compare
   prices", because that is what the click does. */
.bkx-deal__cta {
  margin-block-start: .35em;
  justify-self: start;
  font-size: .72em;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--x-gold, #E3BE79);
  border-block-end: 1px solid rgba(227, 190, 121, .55);
  padding-block-end: 1px;
}
.bkx-hero:dir(rtl) .bkx-deal__cta { letter-spacing: 0; text-transform: none; font-size: .8em; }
.bkx-deal__cta[data-cta="exact"] { color: #F6ECDA; background: var(--x-gold, #E3BE79); color: #12161F; border: 0; border-radius: 999px; padding: .28em .7em; }
.bkx-hot__card .bkx-deal__cta { margin-block-start: .25em; }

/* A plane that carries a deal stops breathing on hover: a moving target is
   not a premium one. */
/* (the hover pause went with the breath it paused) */

/* THE BODY MUST NOT CATCH THE CLICK. .bkx-hero__body is the full-width flex
   column that carries the headline and the console, stacked (z-index 5)
   above every layer. Measured with elementFromPoint on the near card's
   price: the hit was the body, not the card, and a click on a deal did
   nothing. The body itself is inert now; each thing inside it - the
   headline, the phone row, the console, the trust row - takes the pointer
   back, so nothing a reader can touch has changed except that the planes
   behind the empty parts of the body are reachable. */
.bkx-hero__body { pointer-events: none; }
.bkx-hero__body > * { pointer-events: auto; }

/* == THE PHONE ROW ========================================================
 * Between the headline and the console: one primary card, the edge of the
 * next, swipe for more. Native scroll-snap, so it works on the first touch
 * with no script in the way, and every card is a 44px-plus tap target.
 */
.bkx-hot {
  inline-size: 100%;
  margin-block: 14px 2px;
}
.bkx-hot[hidden] { display: none; }
@media (min-width: 901px) { .bkx-hot { display: none !important; } }
.bkx-hot__eyebrow {
  display: block;
  margin-block-end: 8px;
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--x-gold, #E3BE79);
}
.bkx-hero:dir(rtl) .bkx-hot__eyebrow { letter-spacing: .02em; text-transform: none; font-size: .8rem; }
.bkx-hot__row {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-block-end: 6px;
  padding-inline: 2px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.bkx-hot__row::-webkit-scrollbar { display: none; }
.bkx-hot__card {
  position: relative;
  flex: 0 0 84%;
  scroll-snap-align: start;
  min-block-size: 104px;
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  border-radius: 14px;
  background: var(--x-glass, rgba(12, 16, 26, .72));
  border: 1px solid var(--x-line-2, rgba(240, 236, 226, .16));
  color: #F6ECDA;
  text-decoration: none;
  font-size: 13px;
  line-height: 1.25;
}
.bkx-hot__card .bkx-deal__pic,
.bkx-hot__card .bkx-deal__plate {
  position: relative;
  inset: auto;
  inline-size: 88px;
  block-size: 88px;
  border-radius: 10px;
  overflow: hidden;
}
.bkx-hot__card .bkx-deal__plate > span { font-size: 1.05em; }
.bkx-hot__card .bkx-deal__scrim { display: none; }
.bkx-hot__card .bkx-deal__text { position: static; padding: 0; gap: .1em; text-shadow: none; }
.bkx-hot__card .bkx-deal__price { font-size: 1.75em; }
.bkx-hot__card:focus-visible { outline: 2px solid var(--x-gold, #E3BE79); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .bkx-deal__pic { transition: none; }
  .bkx-hot__row { scroll-behavior: auto; }
}


/* == MOBILE PASS · 2026-09-16 =============================================
 * Measured on the live site at 320-430px (12 routes x 8 viewports). No page
 * scrolled sideways; what read as "crooked" was edges, gutters and a jump.
 * Each rule names the defect it closes. Declared last so the cascade, not
 * !important, is why it wins.
 */

/* The hero claims went full-bleed once static (0px from both screen edges). */
@media (max-width: 1180px) {
  .bkx-stats {
    box-sizing: border-box;
    inline-size: min(var(--x-max), 100%);
    margin-inline: auto;
    padding-inline: max(0px, calc((100% - var(--x-max)) / 2));
  }
}

/* The phone deals row un-hid ~660ms after paint and pushed the whole hero
   down (CLS 0.21-0.44 on /). Its measured height (213px at 320, 181 at 390, 165 at 430) is held while the pool is on the
   way; a row that answers empty is released once (data-empty). */
@media (max-width: 900px) {
  /* !important only to outrank the global [hidden]{display:none!important} */
  .bkx-hot[hidden]:not([data-empty]) { display: block !important; visibility: hidden; min-block-size: clamp(150px, calc(353px - 43.6vw), 220px); }
}

/* The EL portrait sat 3-4px from the screen edge while the copy keeps 16-20px. */
@media (max-width: 720px) {
  .bkx-el { --p-x: 16px; }
}

/* An empty-state note was flush against the band edge. */
.bkx .jn-note { padding-inline: clamp(16px, 4vw, 22px); }

/* The destination panel's text touched the card border: the body is a SPAN
   inside the link, and padding on an inline box does not push its lines. */
.bkx-globe__panel #jn-shot2 .bkx-globe__panel-body { display: block; }

/* 7x7 carousel dots: the touch area grows, the drawing does not. */
.bkx-dots button { position: relative; }
.bkx-dots button::after { content: ""; position: absolute; inset: -18px -8px; }

/* Footer links were 44px tall and 26-38px wide. */
.bkx-foot a, .bkx-foot__legal a { min-inline-size: 44px; justify-content: center; }

/* At 320px the header actions pushed the burger to x=0. The pill keeps its
   accessible name; only the visible label steps aside. */
@media (max-width: 360px) {
  .bkx-icon--el { inline-size: 44px; min-inline-size: 44px; padding-inline: 0; gap: 0; }
  .bkx-icon--el > span:last-child {
    position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
}

/* PERFORMANCE · 2026-09-16. bkx.js writes these five on the hero's layers and
   body every scroll frame. As ordinary custom properties they INHERIT, so each
   write restyled the whole subtree: 1.6s of style work in 6s of swiping on a
   throttled phone, a median 299 elements per recalculation. Each is read only
   by the element it is written on (its own transform or opacity), so it does
   not need to inherit — and registered, it does not. The motion is identical. */
@property --x-scroll { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --x-zoom   { syntax: '<number>'; inherits: false; initial-value: 1; }
@property --x-ui-y   { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --x-ui-s   { syntax: '<number>'; inherits: false; initial-value: 1; }
@property --x-ui-o   { syntax: '<number>'; inherits: false; initial-value: 1; }

/* The haze sits at inset:-10%, so its TOP was a fraction of the hero's height:
   any late change to the hero (a console line, the deals row) moved an element
   the size of the screen, and Chrome scored 0.206 of CLS for a layer that
   looked motionless (throttled phone, 2026-09-16). A fixed bleed does not
   follow the hero's height. */
.bkx-hero__haze { inset: -120px; }

/* The phone deals row printed its evidence line at .7em and its fine line at
   .62em of 13px: 9.1px and 8.1px, the two lines that say how old the price is
   and where it was seen (2026-09-16). Never under 12px. */
.bkx-hot__card .bkx-deal__meta,
.bkx-hot__card .bkx-deal__fine { font-size: 12px; line-height: 1.35; }
.bkx-hot__card .bkx-deal__dates { font-size: 12.5px; }
