/* home.css — the search-first homepage only. Loaded after site.css, which it
   borrows tokens from and overrides where the homepage is deliberately its own
   thing: sans-serif instead of serif, a warm neutral page instead of white, and
   white rounded cards in a narrow column instead of a full-width text measure.

   WHAT IS BORROWED AND WHAT IS NOT
     Borrowed from the flight-search sites: the shape of the thing. One
     saturated colour band across the whole top holding the header, the
     headline, the tab row, one dominant search pill and the chips; then a
     narrow column of white rounded cards with photographs in them, one bright
     accent card, and a lot of air. Scroll past the band and it collapses into a
     slim sticky bar in the same colour.

     Not borrowed: colour, type, voice, iconography.

   ON THE NAVY (PALETTE D, owner-approved July 2026)
     The band was a saturated blue mixed from --sky-deep/--sky; it is now navy
     — #14243d family — with the warm accent moved off orange onto copper
     everywhere it appears (buttons, chips, the wordmark, favourites, the chat
     bubble, the one accent card). --sky/--sky-deep themselves are untouched:
     they stay the site's structural ink-blue for headings and body links on
     the white pages, they just no longer color the band. Every text colour
     used on the band is still checked against it below — a gradient is two
     backgrounds, and a contrast ratio that only holds at one end is a
     contrast ratio that does not hold. */

:root {
  --home-bg: #f2efe9;
  --home-card: #ffffff;
  --home-rule: #e5e0d7;
  --home-rule-soft: #efebe3;

  /* The band, navy rather than blue. Lighter at the top where the header
     sits, deeper at the bottom where the chips are — same gradient concept
     as before, retuned around the #14243d family:

       white          on --crown-top #1c3252 = 12.90:1  · on --crown-bot #0d1626 = 18.11:1
       --crown-soft   on --crown-top         =  8.49:1  · on --crown-bot         = 11.25:1
       --crown-faint  on --crown-top         =  7.98:1  · on --crown-bot         = 10.48:1

     Navy is darker than the old blue at both stops, so every one of those six
     numbers has MORE headroom than the blue version did, not less. If you move
     either stop, redo them anyway. */
  --crown: #14243d;
  --crown-top: #1c3252;
  --crown-bot: #0d1626;
  --crown-soft: rgba(255, 255, 255, 0.78); /* body copy on the band */
  --crown-faint: rgba(255, 255, 255, 0.75); /* smallest text on the band */
  --crown-glass: rgba(255, 255, 255, 0.14);
  --crown-glass-hi: rgba(255, 255, 255, 0.24);

  /* The accent card, copper rather than orange. Text on it is still near-black
     rather than white — white on --hot is 3.45:1, still not a card anyone can
     read — and the gradient's darker stop (--hot-2) was picked so the SAME
     near-black ink clears AA at both ends: --hot-ink on --hot is 5.17:1, on
     --hot-2 it is 4.65:1. Do not darken --hot-2 further without rechecking
     that second number — it is the tight one now. */
  --hot: #c07a38;
  --hot-2: #b57334;
  --hot-ink: #241403;

  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 18px;
  --r-pill: 999px;
  /* The control radius. Tabs, chips, the search pill and its button, the
     condensed bar search — all of them were 999px pills and are now rectangles
     with rounded corners, matching the "tell us where you are" buttons the
     owner picked as the house shape. --r-pill survives for the genuinely round
     things: the step numerals, the heart, the chat bubble, the ✓ marker. */
  --r-ctl: 12px;
  /* TWO WIDTHS.
       --col      the reading width. The crown's headline and its search pill
                  live on it, because a search box the width of a desk is not
                  a search box.
       --col-wide the CONTENT width — reads --wide-col from site.css directly
                  rather than declaring its own number, because the owner's
                  width-parity ruling means this measure and the one
                  /us/<state>/'s filter+results layout uses (see .wide-break
                  in site.css) can never legally be two different numbers.
                  Narrower than the second design pass's 76rem on purpose
                  (owner's third-pass ruling, roughly Aviasales' own content
                  measure) — the row carousels do not need the extra width a
                  no-wrapper grid did, since a carousel is allowed to have
                  more cards than fit on one line. */
  --col: 44rem;
  --col-wide: var(--wide-col);
  --bar-h: 64px;
  --sans: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --shadow-sm: 0 1px 2px rgba(18, 32, 58, 0.04), 0 2px 8px rgba(18, 32, 58, 0.04);
  --shadow-md: 0 2px 4px rgba(18, 32, 58, 0.05), 0 10px 28px rgba(18, 32, 58, 0.07);
  --shadow-pill: 0 2px 6px rgba(6, 26, 54, 0.18), 0 14px 34px rgba(6, 26, 54, 0.22);
}

body.home {
  background: var(--home-bg);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.6;
}

body.home h1,
body.home h2,
body.home h3 {
  font-family: var(--sans);
}

body.home main {
  padding: 0 0 3rem;
}

body.home p,
body.home li {
  max-width: none;
}

/* The tab switcher hides things with the `hidden` attribute. Several of them are
   flex containers, and `display: flex` beats the UA stylesheet's `[hidden]`
   rule — so the chips stayed on screen on the skydiving tab. This is the fix,
   and it has to stay ahead of every layout rule below. */
[hidden] {
  display: none !important;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------- header */
/* The header is INSIDE the band: same blue, no rule under it, so the header and
   the crown read as one solid colour block reaching both screen edges. It is
   FIXED — site.css pins it on every page on the site since pass 6, and on this
   page it is also the thing the crown's tabs and search bar dock into. It gains
   a shadow only once something has scrolled under it, so at the top of the page
   the header and the band are still one unbroken colour with no seam in it. */
.page--home .site-header {
  background: var(--crown-top);
  border-bottom: 0;
  box-shadow: none;
  transition: box-shadow 0.2s ease;
}

body.is-docked .site-header {
  box-shadow: 0 2px 14px rgba(6, 26, 54, 0.24);
}

.page--home .site-header__inner {
  max-width: var(--col-wide);
}

/* White brand ON THE BAND only. Scoped to the header on purpose: the footer
   carries the same .brand class on a light background, and an unscoped rule
   here painted it white on white. */
.page--home .site-header .brand {
  color: #fff;
}

.page--home .site-header .brand span {
  color: #f0b876;
}

.page--home .site-nav {
  gap: 0.35rem 1.35rem;
  align-items: center;
}

.page--home .site-nav a {
  color: var(--crown-soft);
}

.page--home .site-nav a:hover,
.page--home .site-nav a[aria-current='page'] {
  color: #fff;
}

.site-nav__quiet {
  opacity: 0.72;
  font-size: 0.84rem;
}

/* The phone link keeps its number on wide screens and drops to the glyph alone
   when the bar runs out of room. It never disappears — it is the product. */
.site-nav__phone {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 600;
  white-space: nowrap;
}

.page--home .site-nav__phone {
  background: var(--crown-glass);
  border: 1px solid var(--crown-glass-hi);
  border-radius: var(--r-ctl);
  padding: 0.3rem 0.85rem;
  color: #fff !important;
}

.page--home .site-nav__phone:hover {
  background: var(--crown-glass-hi);
  text-decoration: none;
}

.site-nav__phone-icon {
  font-size: 0.95em;
}

/* ----------------------------------------------------------- the crown */
/*
   HEIGHT AND GRADIENT (July 2026)
     The owner measured ours against the reference and put it at about 60% of
     its height: the band ended almost as soon as the chips did, so the whole
     top of the page read as a strip rather than a stage. The padding here and
     the margins on the headline, the tab row and the chips below are all
     roughly doubled. This is the one place on the site where empty space IS
     the design — do not tighten it back up because a screenshot looks sparse
     without content in it.

     The fill is a vertical gradient, lighter at the top than the bottom. The
     header above carries --crown-top flat, so the two meet with no seam and
     the whole band reads as one surface deepening downward. Contrast at both
     stops is tabulated at the top of this file.
*/
.crown {
  background: linear-gradient(180deg, var(--crown-top) 0%, var(--crown-bot) 100%);
  /* Shorter at the bottom than it used to be — the search pill moved out into
     .searchdock right below (see build-home.mjs), which carries its own
     padding and its own solid navy fill continuing this gradient's darkest
     stop, so the band still reads as one unbroken surface into the pill. */
  padding: 3.2rem 0 1.4rem;
  color: #fff;
}

/* Same max-width AND same inner padding as .column below, so the headline, the
   search pill and the cards all share one outer edge. Putting the padding on the
   section instead put the crown 20px inboard of the cards.

   The band went wide with the content in the July 2026 polish pass; the pill
   inside it did not (see .searchbar). Everything in here is centred, so a wide
   band with a 44rem pill floating on its middle axis is the reference's own
   shape — it is the CARDS that needed the room, not the search box. */
.crown__inner {
  max-width: var(--col-wide);
  margin: 0 auto;
  padding: 0 1.25rem;
}

/* Centred, like the reference: the headline, the tab row and the chips all sit
   on the middle axis, with the search pill spanning the column between them.
   The header above stays brand-left / nav-right — that contrast is what makes
   the band read as a product header rather than a page of prose. */
.crown h1 {
  font-size: clamp(2rem, 1.2rem + 2.9vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
  margin: 0 0 1.9rem;
  color: #fff;
  font-weight: 800;
  text-align: center;
}

/* THE EXPANDED TABS ARE MEANINGFULLY BIGGER (owner's ruling, pass 6). At the
   old size they were the same control as the compact ones that dock into row 1,
   so the crown's row read as a small widget rather than as the first real
   choice on the page. Here they are a primary control: taller, wider, set at
   full body size. The docked copies keep their old dimensions on purpose — the
   contrast between the two IS the squeeze. */
.crown .tabs {
  justify-content: safe center;
  margin-bottom: 0.4rem;
}

.crown .tab {
  font-size: 1rem;
  padding: 0.82rem 1.45rem;
  gap: 0.5rem;
  border-radius: 14px;
}

.crown__lede {
  font-size: 1.02rem;
  color: var(--crown-soft);
  margin: 0 0 1.5rem;
  max-width: 34rem;
}

/* THE TAB-SQUEEZE SENTINEL. Zero height, no paint, nothing in the
   accessibility tree. .crown__tabtop sits immediately above the tab row and is
   what starts the squeeze — public/home.js watches it with an
   IntersectionObserver whose rootMargin is row 1's own height, so it fires at
   the exact scroll position where the tabs reach the bar. .crown__end is a
   trailing marker after .searchdock in the HTML; nothing reads it any more
   now that the search pill's own docking is CSS `position: sticky`, but it
   costs nothing to leave in place. */
.crown__tabtop,
.crown__end {
  height: 0;
}

/* ---------------------------------------------------- row 1's tab squeeze */
/*
   THE SQUEEZE, TABS ONLY (owner's ruling, pass 6; search-bar half reworked by
   a later addendum — his exact words on the version that grew a second input
   here: it showed two search bars on screen at once mid-scroll). `.site-header`
   is fixed on every page on the site (see site.css) and it is the only bar
   there is. On THIS page it carries one extra piece that ships inert and
   stays inert until the crown's tab row reaches it:

     .site-header__tabs   a slot in row 1 that ALWAYS occupies its width, with
                          the compact tab row inside it at opacity 0. Reserving
                          the space is the whole trick — when the tabs fade in,
                          nothing beside them moves.

   public/home.js puts `is-docked` on <body> at the crossing and the tabs fade
   in in place. Row 1's height never changes, so the document does not reflow
   at the transition point in either direction.

   THE SEARCH PILL DOES NOT NEED ANY OF THIS. It is one element, in one place
   in the HTML (.searchdock, right after .crown — see build-home.mjs), and its
   docking is pure CSS `position: sticky` a few rules down. No class toggle,
   no IntersectionObserver, no second element — it cannot show two bars at
   once because there is only ever the one.
*/
body.home {
  /* The dock is sticky from the moment the page can scroll, not just once
     `is-docked` flips — a visitor can land straight in the results (a
     shared link, a back-navigation) with the dock already pinned and no
     scroll event ever having fired. Clearing both fixed rows unconditionally
     is the honest number in every state. */
  scroll-padding-top: calc(var(--hdr-h) + var(--hdr-row2-h) + 1rem);
}

.site-header__tabs {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  justify-content: center;
  overflow: hidden;
}

.tabs--bar {
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  visibility: hidden;
  margin: 0;
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}

body.is-docked .tabs--bar {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  visibility: visible;
}

/* ------------------------------------------------------- the search dock */
/*
   ONE SEARCH BAR, PINNED BY CSS (owner's addendum — the single-sticky-bar
   fix, his third correction on this element). `.searchdock` sits right after
   `.crown` in the document, inside <main>, which has no height of its own
   beyond its children — so `.searchdock`'s containing block for sticky
   purposes effectively spans the crown, the dock and every row below it, all
   the way to the footer. `position: sticky; top: var(--hdr-h)` means: it
   scrolls up WITH the page in normal flow until its top edge would pass
   underneath the fixed header, and from that instant it pins there instead —
   travelling stops, the header becomes its ceiling. Scroll back up and it
   un-pins at the exact same line, in reverse, because sticky positioning is
   reversible by construction; there is no class being toggled, so there is
   nothing for a fast scroll to get out of sync with.

   THE PILL ITSELF NEVER CHANGES SIZE. `.searchbar` inside here is the exact
   same markup, the exact same CSS, pinned or not — this file draws no second,
   smaller copy of it anywhere. What changes is only the strip behind it: solid
   `--crown-bot`, the darkest stop of the crown's own gradient, so a visitor
   scrolling past the gradient's end and into this solid colour reads it as
   one surface continuing, not a seam. Below the dock the page is already on
   the warm canvas, so the strip's bottom edge is where the band truly ends.
*/
.searchdock {
  position: sticky;
  top: var(--hdr-h);
  z-index: 40;
  background: var(--crown-bot);
}

.searchdock__inner {
  max-width: var(--col-wide);
  margin: 0 auto;
  padding: 0.9rem 1.25rem 1.6rem;
}

/* ------------------------------------------------------------------ tabs */
.tabs {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.9rem;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 0.15rem;
}

.tabs::-webkit-scrollbar {
  display: none;
}

/* Tabs sit ON the blue: the active one is a solid white pill with dark text,
   the rest are white-translucent text with no fill, exactly as on the reference. */
.tab {
  flex: 0 0 auto;
  font: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--crown-soft);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-ctl);
  padding: 0.5rem 1.05rem;
  cursor: pointer;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: background 0.14s ease, color 0.14s ease;
}

.tab:hover {
  background: var(--crown-glass);
  color: #fff;
}

.tab[aria-selected='true'] {
  background: #fff;
  border-color: #fff;
  color: var(--crown);
  box-shadow: 0 1px 3px rgba(6, 26, 54, 0.2);
}

.tab__tag {
  font-size: 0.62rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  font-weight: 700;
  color: #ffd9a8;
  background: var(--crown-glass-hi);
  border-radius: 6px;
  padding: 0.08rem 0.4rem;
}

.tab[aria-selected='true'] .tab__tag {
  color: #a35c07;
  background: #fdeeda;
}

/* The leading glyph. Inherits colour from the pill, so it flips from
   white-translucent to crown-blue the moment the tab becomes active. */
.tab__ico {
  flex: 0 0 auto;
  display: block;
  opacity: 0.85;
}

.tab[aria-selected='true'] .tab__ico {
  opacity: 1;
}

.tab__label {
  white-space: nowrap;
}

/* ------------------------------------------------- tabs in the sticky bar */
/*
   These MUST come after the base .tab rules above: both are single-class
   selectors, so whichever is written last wins. An earlier version put them up
   in the .crownbar block and every override here silently lost, which is how
   the compact row ended up wider than its container.

   `safe center` centres the row when there is room and falls back to the start
   edge when there is not. Plain `center` overflows a too-narrow flex container
   in BOTH directions, which put the first tab underneath the brand wordmark
   where it could be neither read nor clicked. Browsers without `safe` drop the
   declaration and get flex-start, which is the behaviour we want anyway.
*/
.tabs--bar {
  flex: 1 1 auto;
  margin: 0;
  gap: 0.25rem;
  min-width: 0;
  justify-content: safe center;
}

/* Small enough that all four fit beside the brand and the condensed search at
   desktop width — a tab you have to swipe sideways to reach is a tab nobody
   presses. */
.tab--bar {
  font-size: 0.84rem;
  padding: 0.36rem 0.62rem;
  gap: 0.32rem;
}

/* No icons in the docked row (owner's ruling, July 2026): beside the brand and
   the nav links the four tabs were wider than their slot and overflow:hidden
   cut the last one to "Favori". A whole word beats a glyph — the icons stay in
   the crown, where there is room for both. */
.tab--bar .tab__ico {
  display: none;
}

/* Below ~1000px the slot still cannot hold four whole words beside the brand,
   the section links and the phone — so the section links yield, exactly the
   trade the phone breakpoint already makes and for the same reason: only while
   docked, and the phone number never leaves. */
@media (max-width: 1000px) {
  body.is-docked .page--home .site-nav a:not(.site-nav__phone) {
    display: none;
  }
}

.tab__count {
  font-size: 0.72rem;
  font-weight: 700;
  color: #21150a;
  background: var(--sun);
  border-radius: 6px;
  padding: 0.02rem 0.42rem;
}

/* ------------------------------------------------------------- searchbar */
/* One big white pill, ~56px tall, with a bright copper button. Lives inside
   .searchdock now (see above) — same element whether it is sitting in the
   crown's flow or pinned under the header, because .searchdock is the thing
   that moves, not this. */
.searchbar {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* The dock is --col-wide; the pill stays a reading width and sits on the
     middle axis, same measure the headline and the tabs share. */
  max-width: var(--col);
  margin-left: auto;
  margin-right: auto;
  background: #fff;
  border: 0;
  border-radius: var(--r-ctl);
  padding: 0.35rem 0.35rem 0.35rem 1.15rem;
  box-shadow: var(--shadow-pill);
  min-height: 56px;
}

.searchbar:focus-within {
  box-shadow: var(--shadow-pill), 0 0 0 3px rgba(255, 255, 255, 0.65);
}

.searchbar__icon {
  font-size: 1.35rem;
  line-height: 1;
  color: var(--ink-faint);
  transform: translateY(-1px);
}

.searchbar__input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 1.05rem;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--ink);
  padding: 0.55rem 0;
}

.searchbar__input::-webkit-search-cancel-button {
  cursor: pointer;
}

.searchbar__go {
  flex: 0 0 auto;
  font: inherit;
  font-size: 0.98rem;
  font-weight: 700;
  border: 0;
  border-radius: 8px;
  background: var(--hot);
  color: var(--hot-ink);
  padding: 0.78rem 1.6rem;
  cursor: pointer;
  transition: background 0.14s ease;
}

.searchbar__go:hover {
  background: #b57334;
}

.searchbar__note {
  font-size: 0.88rem;
  color: var(--crown-soft);
  margin: 0.75rem 0 0;
}

.searchbar__note a {
  color: #fff;
  font-weight: 600;
  text-underline-offset: 3px;
}

/* --------------------------------------------------------------- typeahead */
.typeahead {
  position: absolute;
  top: calc(100% + 0.45rem);
  left: 0;
  right: 0;
  z-index: 50;
  list-style: none;
  margin: 0;
  padding: 0.35rem;
  background: var(--home-card);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  max-height: 21rem;
  overflow-y: auto;
}

.typeahead li {
  border-radius: var(--r-sm);
}

.typeahead button {
  display: flex;
  width: 100%;
  align-items: baseline;
  gap: 0.5rem;
  font: inherit;
  font-size: 0.95rem;
  text-align: left;
  background: transparent;
  border: 0;
  border-radius: var(--r-sm);
  padding: 0.55rem 0.7rem;
  cursor: pointer;
  color: var(--ink);
}

.typeahead button:hover,
.typeahead li[aria-selected='true'] button {
  background: var(--paper-cool);
}

.typeahead__kind {
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
  flex: 0 0 auto;
  margin-left: auto;
}

.typeahead__where {
  color: var(--ink-faint);
  font-size: 0.85rem;
}

/* THE FILTER RAIL'S OWN RULES LIVE IN site.css NOW (pass 6). The same rail —
   the six researched groups, the "?" bubbles, the checkbox rows — is on every
   /us/<state>/ page, and those pages load site.css and nothing else. Only the
   homepage's own context stays here: the rail has TWO rows of fixed chrome
   above it once the search has docked, not one. */
.page--home .aside-stack {
  top: calc(var(--hdr-h) + var(--hdr-row2-h) + 0.75rem);
  max-height: calc(100vh - var(--hdr-h) - var(--hdr-row2-h) - 1.5rem);
}

@media (max-width: 900px) {
  /* site.css already drops the rail to static at this width; there is no
     viewport to fit it into once it is a full-width block above the results. */
  .page--home .aside-stack {
    max-height: none;
    overflow-y: visible;
  }
}

/* THE MOBILE CHIP BAR HAS THE SAME TWO-ROW PROBLEM THE RAIL ABOVE ALREADY
   SOLVED (July 2026 mobile-filters pass). site.css pins `.mobile-filterbar` at
   `top: var(--hdr-h)`, which is correct on a state page (one fixed row) and
   wrong here: the homepage's own search dock is `position: sticky` from the
   moment the page can scroll (see .searchdock above), so once a phone visitor
   has any results on screen at all there are already two rows of fixed chrome
   above the fold, not one, and the bar needs to clear both or the search pill
   sits on top of it. `--hdr-row2-h` is the same token .aside-stack's own
   offset already reads, so the two never drift apart. */
@media (max-width: 720px) {
  .page--home .mobile-filterbar {
    top: calc(var(--hdr-h) + var(--hdr-row2-h));
  }
}


/* -------------------------------------------------------------- the column */
/*
   ONE WIDTH FOR BOTH STATES (July 2026 polish pass).

   This used to be 44rem for browsing and 68rem for results, switched by a
   `:has()` rule — the results state needed the room for a 240–280px filter rail
   beside a three-zone school card, and the browse state did not.

   The browse state needs it now too, and for the same underlying reason: the
   owner's ruling that no row on this page scrolls sideways. Four state tiles,
   four aircraft cards, five path cards, four well-reviewed cards and four
   guides all have to be visible at once, and none of that fits in 44rem. So
   both states are --col-wide and the conditional rule is gone. The crown keeps
   the narrow measure for its headline and pill — see .crown__inner.
*/
.column {
  max-width: var(--col-wide);
  margin: 0 auto;
  padding: 0 1.25rem;
}

.block {
  background: var(--home-card);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-lg);
  padding: 1.5rem 1.6rem;
  margin: 1rem 0;
  box-shadow: var(--shadow-sm);
}

.block h2 {
  font-size: 1.18rem;
  margin: 0 0 0.5rem;
  letter-spacing: -0.015em;
  color: var(--sky-deep);
}

.block h3 {
  font-size: 1rem;
  margin: 0 0 0.2rem;
  color: var(--sky-deep);
}

.block p {
  margin: 0 0 0.7rem;
  color: var(--ink-soft);
}

.block p:last-child {
  margin-bottom: 0;
}

.block__sub {
  font-size: 0.92rem;
  color: var(--ink-faint) !important;
}

.block__note {
  font-size: 0.83rem;
  color: var(--ink-faint) !important;
  margin: 0.9rem 0 0 !important;
}

.block__more {
  margin: 0.9rem 0 0 !important;
  font-size: 0.92rem;
  font-weight: 600;
}

.block__more a {
  text-decoration: none;
}

.block__more a:hover {
  text-decoration: underline;
}

.block__promise {
  margin: 1.1rem 0 0 !important;
  font-size: 0.88rem;
  color: var(--ink-faint) !important;
  border-top: 1px solid var(--home-rule-soft);
  padding-top: 0.85rem;
}

.notice {
  background: var(--paper-warm);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-md);
  padding: 0.8rem 1rem;
  margin: 0.9rem 0;
}

.notice p {
  margin: 0;
  font-size: 0.86rem;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------------ rows */
/*
   THE ROW, AS A CONTAINER BLOCK AGAIN (owner's ruling, third design pass —
   his live review of the second pass's full-width, no-wrapper card grid was
   "terrible"; the reference is Aviasales' own "Планы на лето" block).

   This REVERSES the second pass's "no wrapper, ever" and "nothing scrolls
   sideways any more" rulings — both are back, on purpose. A row is a white
   rounded container on the warm canvas again: the heading sits inside it at
   the top-left, two small round arrow buttons sit inside it at the top-right,
   and the cards run as a horizontal carousel track inside it — `overflow-x`
   hidden, cards partially peeking at the trailing edge on purpose. That peek
   IS the affordance saying the row moves, the same one the very first version
   of this row had before the second pass took it out.

   ARROWS SCROLL BY ONE CARD, JAVASCRIPT-DRIVEN, HIDDEN WITHOUT IT. They ship
   `hidden` in this HTML and public/home.js only un-hides a row's pair once it
   has measured real overflow on that row — a row whose cards already all fit
   never grows a dead control (see .row--states, whose four tiles fit on one
   line at desktop with no scrolling at all). With scripting off the arrows
   never appear and the track is still a fully readable, fully scrollable —
   and swipeable — list; the browser's own `overflow-x` needs no JavaScript to
   drag, scroll or swipe. See .row__scroll below.
*/
.row {
  margin: 1.5rem 0;
  background: var(--home-card);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-lg);
  padding: 1.35rem 1.4rem 1.5rem;
  box-shadow: var(--shadow-sm);
}

.row__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.row__head h2 {
  font-size: 1.14rem;
  margin: 0;
  letter-spacing: -0.015em;
  color: var(--sky-deep);
}

/* THE ARROWS. Round, small, inside the block's own top-right corner — never
   floating over the cards, which is why they sit in .row__head rather than
   absolutely positioned over the track. */
.row__arrows {
  display: flex;
  gap: 0.4rem;
  flex: 0 0 auto;
}

.row__arrow {
  display: grid;
  place-items: center;
  width: 2.15rem;
  height: 2.15rem;
  border-radius: var(--r-pill);
  border: 1px solid var(--home-rule);
  background: #fff;
  color: var(--sky-deep);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.14s ease, background 0.14s ease, opacity 0.14s ease;
}

.row__arrow:hover {
  border-color: var(--sky);
  background: var(--paper-cool);
}

.row__arrow:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 2px;
}

.row__arrow:disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}

/*
   SEE-ALL, A MODEST CENTERED PILL (owner's ruling, third pass, Aviasales'
   "показать всё" as the reference again — the second pass's own polish
   addendum had stretched this into a full-width bar; that is gone).
   `more.href` on a row with somewhere real to go (states, Ground School)
   makes this a plain <a>; `more.toggle` on a row with nothing beyond what is
   already loaded (aircraft, path, well-reviewed) makes it a <button> that
   unwraps the same cards into a full grid in place instead of inventing a
   destination page that does not exist — see build-home.mjs's row() and the
   toggle handler in home.js. Both render identically. */
.row__foot {
  display: flex;
  justify-content: center;
  margin-top: 0.9rem;
}

.row__all {
  display: inline-flex;
  align-items: center;
  padding: 0.5rem 1.15rem;
  border: 1px solid var(--home-rule);
  border-radius: var(--r-ctl);
  background: #e9e4da;
  color: var(--sky-deep);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.14s ease, border-color 0.14s ease;
}

.row__all:hover {
  background: #e1dbcf;
  border-color: #d8d2c5;
}

.row__all:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 2px;
}

.row__note {
  margin: 0.3rem 0 0;
  font-size: 0.84rem;
  line-height: 1.45;
  color: var(--ink-faint);
  max-width: 42rem;
}

/*
   THE TRACK. Plain CSS `overflow-x`, which is the whole reason this needs no
   JavaScript to scroll, drag or swipe — a browser already does all three for
   free on an overflowing flex row. Cards are a fixed width per row type (the
   modifiers below) rather than sized by the container, on purpose: a fixed
   width is what lets a card peek at the trailing edge, and a peeking card is
   the affordance that says the row moves. `scroll-snap-type: x mandatory`
   (tightened from `proximity`, owner's spec — no half-cut cards, ever) plus
   `scroll-snap-align: start` on every card (below) means a drag, a swipe or
   an arrow click always comes to rest with some card's leading edge flush
   against the track's own edge — never stopped mid-card. public/home.js
   layers a further, JS-only correction on top: it measures the actual
   rendered card width and shrinks the track's own visible width down to the
   nearest whole number of cards, so the TRAILING edge never shows a sliced
   card either (mandatory snap only fixes where scrolling comes to rest, not
   how wide the window is to begin with — see fitWholeCards() in home.js for
   why both pieces are needed together). Without JavaScript, the mandatory
   snap alone still guarantees the honest, no-JS fallback: native
   `overflow-x` scroll/swipe still reaches every card, it just does not
   additionally trim the window down to a whole-card width.
*/
.row__scroll {
  display: flex;
  gap: 0.75rem;
  /* Top padding intentional (owner's spec — hover-lift headroom). Setting
     `overflow-x` to anything other than `visible` silently resolves the
     unset `overflow-y` to `auto` too (CSS Overflow spec's cross-axis rule),
     so a hover state that lifts a card with `transform: translateY(...)` or
     grows its shadow was getting clipped flush against this element's own
     top edge. 0.6rem of padding gives that a few px of headroom to breathe
     in; margin-top drops by the same amount so the visual gap under the
     heading/note is unchanged from before this fix. */
  margin-top: 0.3rem;
  padding-top: 0.6rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 0.3rem;
}

.row__scroll::-webkit-scrollbar {
  display: none;
}

.row__scroll:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.row__scroll > * {
  flex: 0 0 auto;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  width: 14.5rem;
}

/*
   CARD WIDTH + OVERHANG, PER ROW, TOGETHER (owner's spec, July 2026 — the
   half-card overhang that used to be exclusive to the three entry-door rows
   now applies to every carousel on the homepage, "one consistent carousel
   system"). `--row-overhang` is how far this row's track escapes past its
   own box's BORDER on each side — see `.row` and `.row__scroll`'s own
   negative-margin rules below, which are the ONLY place that math lives now.
   Every row sets it to exactly half of ITS OWN card width, so a wider card
   (Ground School's 19.5rem) gets a wider overhang than a narrower one
   (Your path's 12.75rem) — the same "block edge bisects the outermost
   card" relationship at every width, not a single fixed number reused
   everywhere it would not actually fit.
*/
.row--states .row__scroll > * {
  width: 13.5rem;
}
.row--states {
  --row-overhang: 6.75rem;
}

.row--aircraft .row__scroll > * {
  width: 15.5rem;
}
.row--aircraft {
  --row-overhang: 7.75rem;
}

.row--path .row__scroll > * {
  width: 12.75rem;
}
.row--path {
  --row-overhang: 6.375rem;
}

.row--reviewed .row__scroll > * {
  width: 13.5rem;
}
.row--reviewed {
  --row-overhang: 6.75rem;
}

.row--guides .row__scroll > * {
  width: 19.5rem;
}
.row--guides {
  --row-overhang: 9.75rem;
}

.row--entrydoor .row__scroll > * {
  width: 13.5rem;
}
.row--entrydoor {
  --row-overhang: 6.75rem;
}

@media (max-width: 640px) {
  /* One consistent near-full-width peeking card on a phone, whatever the row
     — the point at this size is a thumb swipe, not a declared count, and a
     single shape to learn once beats five different peek widths. */
  .row__scroll > *,
  .row--states .row__scroll > *,
  .row--aircraft .row__scroll > *,
  .row--path .row__scroll > *,
  .row--reviewed .row__scroll > *,
  .row--guides .row__scroll > *,
  .row--entrydoor .row__scroll > * {
    width: 82vw;
    max-width: 21rem;
  }

  /* THE MOBILE OVERHANG IS ONE SHARED NUMBER, NOT HALF THE CARD (same
     reasoning documented at length just below, in the block this replaced —
     see git history for the full working-out). Every row's card converges
     on the same near-full-viewport width at this size, so every row shares
     the same small, fixed overhang too. This only ever fed the TRACK's own
     escape (see `.row__scroll` above) even before the box-width fix below —
     the box itself was already effectively uniform on a phone, since every
     row happened to share this same number. */
  .row--states,
  .row--aircraft,
  .row--path,
  .row--reviewed,
  .row--guides,
  .row--entrydoor {
    --row-overhang: 1.5rem;
  }

  /* THE FIXED BOX WIDTH, MOBILE'S OWN NUMBER (owner's box-consistency
     ruling — see the long note on `.row` above). 3rem = 2 × the 1.5rem
     mobile overhang every row already shared, so this is not a behaviour
     change on a phone, only the same fixed-box mechanism as desktop. */
  .row {
    width: calc(100% - 3rem);
  }
}

/* --------------------------------------------------- entry-door eyebrow */
/* Small caps line above the h2 on the three entry-door rows only — "Door 1
   of 3", etc. (see ENTRY_DOORS in src/data/home.js). Same shape as
   .hot__eyebrow on the accent card below, in the row's own blue rather than
   the accent card's white-on-colour. */
.row__eyebrow {
  display: block;
  font-size: 0.7rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 800;
  color: var(--sky);
  margin-bottom: 0.3rem;
}

/* --------------------------------------------------- the row/track overhang */
/*
   THE HALF-CARD OVERHANG, NOW EVERY ROW (owner's spec, July 2026 — started
   as an entry-doors-only feature, then extended to every carousel on the
   homepage so "the whole homepage reads as one consistent carousel system."
   See git history for the earlier, entry-door-only version of this same
   block if you need it.). Every row's white box is deliberately NARROWER
   than its own card track, so the track's edges cross the box's border and
   a card visibly sticks out past it on each side — the "carousel floats
   wider than its backing box" 3D feel. Card width itself is UNCHANGED by any
   of this — see the per-row width rules above; only the box shrinks and the
   track escapes back out to meet it.

   `--row-overhang` (declared once per row type, just above, alongside that
   row's own card width — the two numbers belong together) is how far the
   track escapes past the box's own BORDER on each side, not just past its
   padding: the `+ 1.4rem` below cancels `.row`'s own padding out of the
   calc, so the escape is measured from the visible edge a reader actually
   sees, which is what lands the border on a card's midpoint rather than a
   card-and-a-bit in.

     .row          width: calc(100% - overhang*2), margin auto — the box
                   shrinks by exactly two overhangs (one per side) and
                   re-centers in the space that frees up.

     .row__scroll  margin: -(overhang + 1.4rem) on each side — a plain
                   negative margin on a block-level flex container, no
                   viewport units, no `.wide-break`-style 100vw trick.

   On DESKTOP, every row's `--row-overhang` is set to exactly half THAT
   row's own card width, so the math is literal: flex lays the first card
   flush against the track's own start edge with no leading padding, so the
   box's left border always lands at exactly that card's horizontal
   midpoint — geometrically guaranteed, not approximate, on every row. The
   trailing edge gets the identical fixed overhang on the box/track
   relationship; which literal card sits there at rest is additionally
   locked down by fitWholeCards() in home.js (see the long note on
   `.row__scroll` above) so it is never a sliced card either.

   ON MOBILE, `--row-overhang` is DELIBERATELY NOT half of the on-screen
   card, for every row. The mobile card is already ~82vw (a deliberate
   near-full-viewport single-peek card — see the shared mobile media query
   above). Do the arithmetic on a 375px phone: the card is ~308px, so
   literally shrinking the box by half of THAT card on each side (154px x2 =
   308px total) would leave next to nothing — the heading and copy would
   have nowhere legible to sit. So on a phone every row shares one smaller,
   fixed overhang instead of a literal half-card: still a real, visible
   overhang on both sides, just sized so the block stays readable. "Roughly
   half a card" per the owner's own brief for mobile, not a literal one.

   `.row` itself carries no `overflow` rule (see row() in build-home.mjs), so
   nothing clips this — the track genuinely paints over the box's border and
   drop shadow where it crosses it.
*/
/* THE BOX WIDTH IS FIXED AND IDENTICAL ON EVERY ROW (owner's ruling —
   overrides the paragraph this replaced, which let each row's own card
   width decide its box width too. That shipped a real, visible bug: Browse
   by aircraft's box measured visibly narrower than every other row's,
   because its card is wider and its half-card overhang (7.75rem) is bigger
   than the 6.75rem the other rows share, so more got subtracted from its
   box. Consistency of THE FRAME wins over exact half-card precision — see
   the priority order Shamil gave explicitly when reporting this bug).

   13.5rem here is not arbitrary: it is exactly what states/reviewed/
   entrydoor always used (2 × 6.75rem, half of their shared 13.5rem card),
   kept as THE one standard every row's box now uses regardless of that
   row's own card size. `--row-overhang` (per-row, declared above) no longer
   has anything to do with the box at all — see `.row__scroll` just below,
   where it still lives, doing only the one job it should: how far the
   TRACK escapes past this now-constant box. */
.row {
  width: calc(100% - 13.5rem);
  margin-left: auto;
  margin-right: auto;
}

.row__scroll {
  margin-left: calc(-1 * (var(--row-overhang, 6.75rem) + 1.4rem));
  margin-right: calc(-1 * (var(--row-overhang, 6.75rem) + 1.4rem));
}

/* The photo credit under the aircraft row. Wikimedia's CC BY file needs a
   visible attribution and the other three are public domain — one quiet line
   covering all four beats a caption on one card out of four. Sits inside the
   block now like everything else in the row. */
.row__credit {
  margin: 0.55rem 0 0;
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--ink-faint);
}

/* ----------------------------------------------------------------- tiles */
/* Photo tiles: image on top, name and count underneath. They were four across
   in a 44rem column, which made them thumbnails; in the rows pass they roughly
   doubled (.tile--lg) and the row scrolls instead of the tile shrinking. The
   photographs are real photographs of the places named — see STATE_PHOTOS in
   src/data/home.js and public/img/states/SOURCES.md. */
.tile {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  text-decoration: none;
  color: var(--ink);
}

.tile__media {
  position: relative;
  display: block;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--paper-cool);
  margin-bottom: 0.45rem;
}

.tile__img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform 0.25s ease;
}

.tile:hover .tile__img {
  transform: scale(1.04);
}

.tile__name {
  font-weight: 700;
  font-size: 0.98rem;
  color: var(--sky-deep);
  line-height: 1.25;
}

.tile:hover .tile__name {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.tile__count {
  font-size: 0.82rem;
  color: var(--ink-faint);
}

/* The row-sized tile. It used to be a fixed 17.5rem so the old overflow track
   cut the third one; the grid sizes it now (see .row__scroll) and the class is
   kept for the larger name only. */
.tile--lg .tile__name {
  font-size: 1.05rem;
}

/* Sits on the photograph, so it carries its own solid background rather than
   relying on whatever the frame happens to look like behind it. */
.tile__badge {
  position: absolute;
  left: 0.4rem;
  bottom: 0.4rem;
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-weight: 700;
  color: #17421f;
  background: #cfe8d3;
  border-radius: 6px;
  padding: 0.12rem 0.5rem;
}

/* ------------------------------------------------------- aircraft cards */
/*
   "Browse by aircraft" (July 2026).

   PHOTOGRAPHS SINCE THE POLISH PASS. These were flat SVG side profiles from
   public/img/art/, on the reasoning that we own no photographs of these
   aeroplanes and a stock shot of somebody else's Cessna is borrowed truth. The
   reasoning survives; the conclusion was wrong. Wikimedia Commons carries
   photographs whose airframe is IDENTIFIED on the file page, usually by
   registration, under licences that permit commercial use — so the caption is
   as defensible as the drawing was and the picture is of the real thing. Every
   file, photographer and licence is in public/img/aircraft/SOURCES.md, and the
   one licence that demands visible credit gets it under the row.

   The drawings are still in the repo and still used: they are the placeholder
   art on school cards with no logo (src/data/card-art.mjs).

   The card is a real link to /?ac=<family>. public/home.js intercepts the click
   and applies the filter in place; with scripting off the href does the same
   job by reloading. Both paths end at the same filtered list. */
.acard {
  display: flex;
  flex-direction: column;
  background: var(--home-card);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  padding-bottom: 0.95rem;
  text-decoration: none;
  color: var(--ink);
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
}

.acard:hover {
  border-color: var(--sky);
  box-shadow: var(--shadow-md);
}

/* Full-bleed to the card's own rounded top edge, the way the state tiles carry
   their photographs. The drawing used to sit inset on a tinted panel because a
   line drawing needs air around it; a photograph does not — it needs the frame. */
.acard__art {
  display: block;
  background: var(--paper-cool);
}

.acard__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2 / 1;
  object-fit: cover;
}

.acard__name {
  display: block;
  margin: 0.8rem 1.05rem 0;
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--sky-deep);
}

.acard:hover .acard__name {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.acard__note {
  display: block;
  margin: 0.18rem 1.05rem 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--ink-soft);
}

/* The count and the models most often named — both counted from the data at
   build time (see familiesWithData in src/data/aircraft.mjs), never typed. */
.acard__n {
  display: block;
  margin: 0.5rem 1.05rem 0;
  font-size: 0.76rem;
  color: var(--ink-faint);
}

/* ----------------------------------------------------------- path cards */
/* "Your path". Small, plain, text-only cards — five of them in a row, so any
   picture would have been a 40px thumbnail nobody could read. The cue line is
   what makes the card honest: "Show these schools" only appears where a real
   filter exists, "Read the guide" only where the guide is written, "Ask us"
   where we hold no data and are saying so. See YOUR_PATH in src/data/home.js. */
.pcard {
  display: flex;
  flex-direction: column;
  gap: 0.28rem;
  padding: 1rem 1.05rem 1.05rem;
  background: var(--home-card);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
}

.pcard:hover {
  border-color: var(--sky);
  box-shadow: var(--shadow-md);
}

.pcard__h {
  font-weight: 700;
  font-size: 0.98rem;
  color: var(--sky-deep);
  line-height: 1.25;
}

.pcard__p {
  flex: 1 1 auto;
  font-size: 0.82rem;
  line-height: 1.42;
  color: var(--ink-soft);
}

.pcard__cue {
  margin-top: 0.45rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--sky);
}

/* ------------------------------------------------- well-reviewed cards */
/* NOT "top schools", and the card is built so that cannot be misread: the
   number sits in a chip that names its platform and its sample size on the
   very next line. It is Google's rating and Google's readers, and we have not
   called any of these — the row's own note says so once, in full. */
.rcard {
  display: flex;
  flex-direction: column;
  gap: 0.32rem;
  padding: 0.95rem 1.05rem 1.05rem;
  background: var(--home-card);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
}

.rcard:hover {
  border-color: var(--sky);
  box-shadow: var(--shadow-md);
}

.rcard__top {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Same deep green and the same shape as .card-rating__chip--top in site.css —
   a 4.8 on this row and a 4.8 on a result card have to look identical. */
.rcard__chip {
  flex: 0 0 auto;
  min-width: 2.15rem;
  text-align: center;
  padding: 0.16rem 0.4rem;
  border-radius: 8px;
  font-weight: 700;
  font-size: 0.82rem;
  line-height: 1.25;
  background: #065f38;
  color: #fff;
}

.rcard__src {
  font-size: 0.74rem;
  line-height: 1.3;
  color: var(--ink-faint);
}

.rcard__name {
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.3;
  color: var(--sky-deep);
}

.rcard:hover .rcard__name {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.rcard__where {
  font-size: 0.8rem;
  color: var(--ink-faint);
}

/* -------------------------------------------------------- door cards */
/* The entry-door carousels (see doorCard() in build-home.mjs). REBUILT
   (owner's spec) from a text-only card into the SAME anatomy as .tile /
   .acard — big image on top, small text below — because the original
   text-only version was "too small... not pretty at all". Modelled most
   closely on .acard specifically (bordered box, image full-bleed to the
   card's own rounded top edge, name + a second line below) since a door
   card and an aircraft card are the same underlying idea: one shared,
   honest, non-per-item photo, then real per-item facts under it. The image
   is a THEMED photo for the whole door (see ENTRY_DOOR_PHOTOS in
   src/data/home.js), never a fabricated per-school photo — text stays a
   name, a city and state, a real link, same honesty rule as before. The
   hover lift is the one deliberate extra touch on these six rows — a small
   nod to the "3D feel" the overhang track itself is built for. */
.dcard {
  display: flex;
  flex-direction: column;
  background: var(--home-card);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  padding-bottom: 0.95rem;
  text-decoration: none;
  color: var(--ink);
  transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
}

.dcard:hover {
  border-color: var(--sky);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.dcard__media {
  display: block;
  background: var(--paper-cool);
}

.dcard__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2 / 1;
  object-fit: cover;
}

.dcard__name {
  display: block;
  margin: 0.8rem 1.05rem 0;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.3;
  color: var(--sky-deep);
}

.dcard:hover .dcard__name {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.dcard__where {
  display: block;
  margin: 0.2rem 1.05rem 0;
  font-size: 0.8rem;
  color: var(--ink-faint);
}

/* ------------------------------------------------------- block headings */
.block__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.block__head h2 {
  margin-bottom: 0;
}

.block__link {
  flex: 0 0 auto;
  font-size: 0.86rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--sky);
  white-space: nowrap;
}

.block__link:hover {
  text-decoration: underline;
}

/* --------------------------------------------------------- accent card */
/* The one bright block on the page. Bright orange fill, near-black text (white
   on this orange is 2.9:1 — see the note on --hot at the top of this file). */
.block--hot {
  display: block;
  background: linear-gradient(135deg, var(--hot) 0%, var(--hot-2) 100%);
  border-color: transparent;
  color: var(--hot-ink);
  text-decoration: none;
  box-shadow: 0 2px 6px rgba(140, 78, 8, 0.18), 0 12px 30px rgba(140, 78, 8, 0.18);
}

.block--hot:hover {
  filter: brightness(1.04);
}

/* SLIMMER (owner's call, July 2026 rows pass). One loud card is the rule and
   this is it — but it was loud AND the tallest thing on the page, which made
   it read as the page's subject rather than its one accent. Same copy, same
   link, same colour; less air around it and a smaller headline. */
.block--hot-slim {
  padding: 1.05rem 1.3rem 1.15rem;
}

.block--hot-slim h2 {
  font-size: 1.22rem;
  margin: 0.1rem 0 0.25rem;
}

.block--hot-slim p {
  font-size: 0.88rem;
}

.block--hot-slim .hot__more {
  margin-top: 0.65rem;
  font-size: 0.86rem;
}

.block--hot h2 {
  color: var(--hot-ink);
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0.15rem 0 0.4rem;
}

.block--hot p {
  color: var(--hot-ink) !important;
  opacity: 0.86;
  margin: 0;
  max-width: 30rem;
}

.hot__eyebrow {
  display: block;
  font-size: 0.7rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 800;
  opacity: 0.72;
}

.hot__more {
  display: inline-block;
  margin-top: 0.9rem;
  font-size: 0.92rem;
  font-weight: 700;
  border-bottom: 2px solid rgba(36, 20, 3, 0.35);
  padding-bottom: 0.1rem;
}

.block--hot:hover .hot__more {
  border-bottom-color: var(--hot-ink);
}

/* THE .steps / .step / .step__n RULES ARE GONE (July 2026 rows pass). They
   dressed the how-it-works block, which the owner deleted outright — see the
   note where HOW_IT_WORKS used to live in src/data/home.js. The promise those
   three steps carried is PRICE_LINE, now rendered on the closing "Talk to us"
   card, and the step-by-step version is on /faq/. */

/* ---------------------------------------------------------------- guides */
/* Thumbnail left, two lines of text right. Was a two-across grid inside a white
   slab, then a fixed-width card in a scrolling row; it is a grid cell now like
   everything else on this page. `align-items: flex-start` rather than centre so
   four cards of unequal text length still line their thumbnails up. */
.guide {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--home-rule);
  border-radius: var(--r-lg);
  background: var(--home-card);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
}

.guide:hover {
  border-color: var(--sky);
  box-shadow: var(--shadow-md);
}

.guide__thumb {
  flex: 0 0 auto;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--paper-cool);
}

.guide__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.guide__text {
  min-width: 0;
}

.guide h3 {
  font-size: 0.92rem;
  margin: 0 0 0.15rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  line-height: 1.3;
}

.guide p {
  font-size: 0.83rem;
  color: var(--ink-faint);
  margin: 0;
  line-height: 1.4;
}

.guide__tag {
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ink-faint);
  background: #eceae4;
  border-radius: 6px;
  padding: 0.08rem 0.42rem;
}

/* ----------------------------------------------------------------- stats */
/* A strip on the canvas, not a card (July 2026 rows pass): four numbers and
   four short labels, no heading, no methodology paragraph. What "verified"
   means is a tooltip on the ✓ marker of every card that carries one. */
.statsrow {
  margin: 2rem 0;
  padding: 1rem 0;
  border-top: 1px solid var(--home-rule);
  border-bottom: 1px solid var(--home-rule);
}

.statsrow .stats {
  margin-top: 0;
}

.statsrow .stats strong {
  font-size: 1.35rem;
}

.stats {
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.8rem;
}

.stats li {
  display: flex;
  flex-direction: column;
}

.stats strong {
  font-size: 1.5rem;
  line-height: 1.15;
  color: var(--sky-deep);
  letter-spacing: -0.02em;
}

.stats span {
  font-size: 0.8rem;
  color: var(--ink-faint);
}

.stats--tight strong {
  font-size: 1.25rem;
}

/* ------------------------------------------------------------------- ask */
.block--ask {
  background: var(--sky-deep);
  border-color: var(--sky-deep);
  color: #dfe8f5;
}

.block--ask h2 {
  color: #fff;
}

.block--ask p {
  color: #c6d5e9 !important;
}

.ask__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1rem;
}

body.home .btn {
  font-family: var(--sans);
  border-radius: var(--r-md);
  cursor: pointer;
}

.btn--quiet {
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
}

.btn--quiet:hover {
  background: rgba(255, 255, 255, 0.2);
}

.block--empty {
  text-align: center;
  padding: 2.4rem 1.6rem;
}

.block--empty p {
  max-width: 26rem;
  margin: 0 auto;
}

/* The .banner and .btn--ghost-dark rules went with the "Run a flight school?"
   card, removed from the homepage column in July 2026. The partner pitch lives
   at /for-schools/, linked from the footer of every page. */

/* --------------------------------------------------------------- results */
.results {
  margin: 0;
}

.results:empty {
  display: none;
}

/*
   NO WRAPPER AROUND THE RESULTS (owner's ruling, July 2026, after checking the
   reference himself). Results used to render inside one white .results-block,
   which meant white cards on a white panel: the column read as a single slab
   with hairlines across it rather than as a list of separate things.

   The page now has exactly two zones, which is what the reference has: the blue
   crown on top, and the warm canvas below it with each result floating on the
   canvas as its own card. So there is no .results-block rule here any more —
   the heading and the notes above a result list sit directly on the canvas, and
   the cards do the rest.
*/
.results-head {
  font-size: 1.05rem;
  margin: 1.4rem 0 0.15rem;
  color: var(--sky-deep);
}

.results-lede {
  margin: 0 0 0.2rem;
  font-size: 0.88rem;
  color: var(--ink-faint);
  max-width: 40rem;
}

/* The .pick / .pick--verified / .pick--discovery rules that used to live here
   went with the two-pick block in July 2026 — a search now renders one list.
   The .expander rules went with them: nothing on this page hides results behind
   a button any more. */

body.home .school-list {
  gap: 0.85rem;
  margin-top: 0.9rem;
}

body.home .school-card {
  border-radius: var(--r-md);
  background: #fff;
  border-color: var(--home-rule);
  box-shadow: var(--shadow-sm);
  position: relative;
  padding-right: 3.1rem;
}

body.home .school-card h3 {
  font-family: var(--sans);
  font-size: 1rem;
  padding-right: 0.2rem;
}

body.home .school-card p {
  font-size: 0.88rem;
}

/* The card's Details button is the same orange as the search button on the
   band, not the slightly deeper --sun the static pages use — on this page the
   two are visible at the same time and a near-miss reads as a mistake. */
body.home .card-btn--primary {
  background: var(--hot);
  color: var(--hot-ink);
}

body.home .card-btn--primary:hover {
  background: #b57334;
}

/* On a phone the Details button goes full width, so the gutter this card
   reserves for the heart moves off the card and onto the heading — the only
   line the heart actually sits beside. Without this the button stops 3rem
   short of the right edge and reads as a mistake. */
@media (max-width: 600px) {
  body.home .school-card {
    padding-right: 1.1rem;
  }

  body.home .school-card h3 {
    padding-right: 2.4rem;
  }
}

/* Still the quietest card in the list, but white like the rest — on this canvas
   a warm-grey card read as disabled rather than as unverified. */
body.home .school-card--listed {
  border-style: solid;
  background: #fff;
}

.results__clear {
  font: inherit;
  font-size: 0.85rem;
  background: transparent;
  border: 0;
  color: var(--ink-faint);
  cursor: pointer;
  text-decoration: underline;
  padding: 0.2rem 0;
}

/* ------------------------------------------------------------ heart button */
.heart {
  position: absolute;
  top: 0.75rem;
  right: 0.8rem;
  width: 2.1rem;
  height: 2.1rem;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  border: 1px solid var(--home-rule);
  background: var(--home-card);
  color: var(--ink-faint);
  cursor: pointer;
  padding: 0;
  line-height: 1;
  font-size: 1rem;
}

.heart:hover {
  border-color: var(--sun);
  color: var(--sun);
}

.heart[aria-pressed='true'] {
  color: #fff;
  background: var(--sun);
  border-color: var(--sun);
}

/* The corner pill and the talk panel moved to site.css (July 2026): they are
   on EVERY page now, injected by public/talk-panel.js, and a homepage-only
   copy of their rules would be the same thing written twice. */

/* ------------------------------------------------------------- narrow-ish */
@media (max-width: 720px) {
  .site-nav__phone-text {
    display: none;
  }

  .page--home .site-nav__phone {
    padding: 0.3rem 0.6rem;
    font-size: 1.05rem;
  }
}

/* ---------------------------------------------------------------- mobile */
@media (max-width: 640px) {
  .crown {
    padding: 2rem 0 2.6rem;
  }

  .crown h1 {
    margin-bottom: 1.4rem;
  }

  .crown .tabs {
    margin-bottom: 1.1rem;
  }

  .crown__inner {
    padding: 0 1rem;
  }

  .page--home .site-header__inner {
    padding-top: 0.7rem;
    padding-bottom: 0.2rem;
  }

  .column {
    padding: 0 1rem;
  }

  .block,
  .row,
  .results-block {
    padding: 1.2rem 1.1rem;
  }

  .searchdock__inner {
    padding: 0.7rem 1rem 1.3rem;
  }

  .searchbar {
    padding: 0.3rem 0.3rem 0.3rem 0.9rem;
    gap: 0.35rem;
    min-height: 52px;
  }

  .searchbar__input {
    font-size: 1rem;
  }

  .searchbar__go {
    padding: 0.7rem 1.05rem;
    font-size: 0.9rem;
  }

  .tabs {
    /* Bleed to the screen edges so the row reads as scrollable rather than cut. */
    margin-left: -1rem;
    margin-right: -1rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }

  /* THE PHONE'S ROW 1, DOCKED (pass 6). At 375px row 1 holds a wordmark, two
     section links and a phone icon, and there is no room left for four tabs
     beside them. The condensed search does not have that problem any more — it
     is its own row now, which is exactly why it was worth moving there, so it
     STAYS on a phone where it used to be dropped entirely.
     What gives instead are the two section links, and only while docked: at the
     top of the page they are exactly where they always were, and the phone
     number — the one thing on this site that is a conversion — never leaves. */
  body.is-docked .page--home .site-nav a:not(.site-nav__phone) {
    display: none;
  }

  .site-header__tabs {
    justify-content: flex-start;
  }

  .tabs--bar {
    justify-content: flex-start;
    margin-right: -0.5rem;
    padding-right: 0.5rem;
  }

  .crown .tab {
    font-size: 0.95rem;
    padding: 0.7rem 1.1rem;
  }

  /* THE BLEED IS GONE WITH THE SCROLLING (July 2026 polish pass). Rows used to
     run off both screen edges so a cut card read as "this moves" rather than
     "this is broken". Nothing moves now: at this width every row is one stacked
     column of full-width cards, which needs no affordance and no bleed. */
  .row__scroll,
  .row--path .row__scroll {
    grid-template-columns: minmax(0, 1fr);
  }

  /* The one exception, and it is about content rather than taste: a state tile
     is a photograph, a name and a count. Full width it is a 343×257 photograph
     four times over, which is most of a phone screen spent on four pictures of
     scenery. Two across is a thumbnail grid, which is what a tile of a
     photograph wants to be. Everything else in the rows carries sentences and
     stays one across, where the sentences are readable. */
  .row--states .row__scroll {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .row {
    margin: 1.6rem 0;
  }

  .stats {
    grid-template-columns: repeat(2, 1fr);
  }

  .block--hot h2 {
    font-size: 1.3rem;
  }

  .block--hot-slim h2 {
    font-size: 1.15rem;
  }
}

/* ------------------------------------------------------ the location card */
/*
   THE LOCATION SECTION, AS A DRILL-DOWN (owner's ruling, pass 6; reworked
   into a drill by a later addendum, and merged into the Filters card as its
   first section by another — see .filter-group--loc in build-home.mjs).

   Built from the results, never from the country: forty-four lines that
   return nothing is what makes a directory feel like a form. Nothing picked
   shows every state in the results as a plain row to pick from; picking one
   drills into its cities, always expanded, with a removable "State ✕" chip as
   the only way back up; a result set that is already a single state shows its
   cities straight away with no picker and no chip, because there was nothing
   to pick from or drill back up to in the first place.

   Everything here is styled off the shared .filter-row component in
   site.css — these rules only add the parts the shared rail has no
   equivalent for.
*/
.loc-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 0.7rem;
}

.loc-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  color: var(--ink);
  background: var(--paper-warm);
  border: 1px solid var(--home-rule);
  border-radius: var(--r-ctl);
  padding: 0.24rem 0.55rem;
  max-width: 100%;
}

.loc-chip:hover {
  border-color: var(--sky);
  color: var(--sky);
}

.loc-chip > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A LONE CITY, NAMED BUT NOT A CONTROL (owner bug report, pass 6 addendum).
   One school picked from the typeahead, or any search that collapses to a
   single city, has nothing left to drill from and no locScope to drop — so
   this reuses the chip's look for visual continuity but drops the pointer
   cursor and the hover state that would promise a click does something. It
   is a `<span>`, never a `<button>`: out of the tab order, because a control
   that cannot change the results does not belong in it. */
.loc-chip--static {
  cursor: default;
}

.loc-chip--static:hover {
  border-color: var(--home-rule);
  color: var(--ink);
}

.loc-chip__x {
  color: var(--ink-faint);
  font-size: 0.8rem;
  line-height: 1;
}

.loc-chip:hover .loc-chip__x {
  color: var(--sky);
}

.loc-state + .loc-state {
  margin-top: 0.2rem;
}

/* THE PICKER ROW. A plain button styled like a .filter-row (site.css), not a
   checkbox — picking a state is a drill, not adding to a set, so there is
   nothing here to tick. Reset to a bare, full-width, left-aligned control
   first, then let .filter-row's own layout rules do the rest. */
.loc-state__pick {
  display: flex;
  width: 100%;
  align-items: center;
  font: inherit;
  text-align: left;
  background: transparent;
  border: 0;
  border-radius: var(--r-sm);
  padding: 0.3rem 0.35rem;
  margin: 0 -0.35rem;
  cursor: pointer;
}

.loc-state__pick:hover {
  background: var(--paper-warm);
}

.loc-state__pick:hover .filter-row__label span:first-child {
  color: var(--sky);
}

.loc-state__pick:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 1px;
}

/* THE DRILLED-IN CITY LIST. Always expanded, never a collapsed disclosure —
   the second pass's toggle-per-state is gone along with the multi-select it
   belonged to. A tall city list still scrolls inside itself so it cannot push
   the rest of the filter rail off the bottom of the viewport. */
.loc-cities {
  margin-top: 0.3rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  max-height: 15rem;
  overflow-y: auto;
}

@media (prefers-reduced-motion: reduce) {
  body.home * {
    transition: none !important;
  }
}
