/* LGP Current Specials. All selectors are namespaced so nothing here can reach
   an Elementor or Jet widget elsewhere on the site.
   Light only by deliberate choice: kit 8 stores single-value globals and no other
   page on letsgopolar.com has a dark mode, so a second token set would drift. */
.lgp-specials{
  --g:#fff; --sf:#f2f7fb; --sf2:#eaf4fa; --sunk:#e6eef5;
  --ink:#042c43; --body:#33434f; --mut:#54595f; --bd:#dbe5ed; --bd2:#c9d8e4;
  --pri:#0074a5; --pri2:#006590; --cy:#08b2dc;
  --save:#c6002b; --urg:#9a4008; --ok:#1f7a5f;
  /* ---- the deal type code. three tones, and there is no fourth. ----
     pink = last minute, green = early bird, blue = everything else. A pink pill
     and a pink section header mean the same thing, which is the whole value: the
     code is learned once in the hero and keeps paying off for 17 sections.

     Two values per tone, because one hue cannot serve both grounds. The pill sits
     on the navy hero and the section header sits on white, and a value dark enough
     to carry white heading text is far too dark to hold 3:1 as a rim on navy. The
     -air value is the navy one. Measured, not assumed:

       --late      #c4006c  5.89:1 on white          text and rim, and the pink
                                                     banner's light gradient stop
       --late-air  #ff8fc0  5.32:1 / 6.87:1 as a rim on the pill fill, light / dark
       --early     #1f7a5f  5.24:1 on white          == --ok, unchanged
       --early-air #4ec79a  5.33:1 / 6.89:1
       --rest      #0074a5  5.20:1 on white          == --pri
       --rest-air  #08b2dc  4.50:1 / 5.82:1          == --cy

     The three -air rims are matched at 5.3, 5.3 and 4.5 so no one tone shouts over
     the others. All three clear the 3:1 that WCAG 1.4.11 asks of a component edge.

     --save #c6002b was tested first and REJECTED for pink. As a rim on the pill
     fill it lands at 1.84:1, less than half of what it needs. And it is already the
     savings colour on every --save badge, so reusing it
     for last minute would make the deal type code and the discount badge the same
     colour and the code would stop being readable. */
  --late:#c4006c; --late-air:#ff8fc0;
  --early:var(--ok); --early-air:#4ec79a;
  --rest:var(--pri); --rest-air:var(--cy);
  --sh:0 1px 2px rgba(4,44,67,.06),0 8px 24px -12px rgba(4,44,67,.18);
  --shl:0 2px 4px rgba(4,44,67,.07),0 18px 44px -18px rgba(4,44,67,.3);
  --r:14px;
  color-scheme:light;
  font-family:Roboto,system-ui,-apple-system,"Segoe UI","Helvetica Neue",Arial,sans-serif;
  color:var(--body);font-size:16px;line-height:1.55;
  /* The full-bleed shaded bands are :before pseudo-elements at inset:0 -100vw, and
     until now the page relied on SOMETHING UPSTREAM clipping them. Rendered without
     an Elementor wrapper the document scrolls horizontally, which is a real bet that
     was fine at two bands and is not fine at nine plus a pink one. This clips them at
     the widget's own edge, which is the viewport, so the bleed still reaches the
     window and the document cannot grow a horizontal scrollbar.
     clip, NOT hidden. overflow:hidden creates a scroll container and would break the
     sticky .lgp-nowbar; clip does not create one, and overflow-x:clip is allowed to
     sit next to an overflow-y of visible where hidden would compute to auto.
     Verified by rendering: bands still full bleed, now bar still sticks, zero
     horizontal document scroll at 1440 and at 375. */
  overflow-x:clip;
}
.lgp-specials *{box-sizing:border-box}
.lgp-specials h1,.lgp-specials h2,.lgp-specials h3{color:var(--ink);margin:0;text-wrap:balance;letter-spacing:-.02em;line-height:1.15}
.lgp-specials h1{font-size:clamp(30px,4.6vw,52px);font-weight:800}
.lgp-specials h2{font-size:clamp(21px,2.5vw,29px);font-weight:800}
.lgp-specials h3{font-size:17px;font-weight:700}
.lgp-specials p{margin:0}
.lgp-specials a{color:var(--pri);text-decoration:none}
.lgp-specials a:hover{text-decoration:underline}
/* DEFECT 1. A 4px corner radius used to sit in this rule and squared off every
   rounded control in the widget on keyboard focus, including the 999px .lgp-fbtn
   region pills and the 10px quick search pills. Each element's own radius applies
   now. Grep for a literal radius value here to confirm it is gone. */
.lgp-specials :focus-visible{outline:3px solid var(--pri);outline-offset:2px}
/* WHITE INSIDE THE HERO. --pri on the hero gradient measures 2.79:1 at the dark end
   and worse at the light end, so the ring the keyboard user needs was the one thing
   they could not see, on the nine controls that matter most: three pole buttons, the
   range, both hero buttons and the three text links. The pills already solved this
   the same way. White is 11.24:1 on the dark end and outline-offset shows the hero
   through the gap on the white selected states. */
.lgp-mast :focus-visible{outline-color:#fff}
.lgp-mast .lgp-range:focus-visible{outline:3px solid #fff;outline-offset:4px}
.lgp-in{max-width:1220px;margin:0 auto;padding:0 20px}

/* masthead. padding was 52px 0 74px. The 74 existed so the season tiles could lift
   38px into the navy. The tiles are gone and nothing overlaps the hero now. */
.lgp-mast{position:relative;overflow:hidden;color:#fff;padding:52px 0 34px;
  background:linear-gradient(160deg,#042c43 0%,#00567c 100%)}
/* ---- aurora ------------------------------------------------------------------
   The hero was a flat two-stop gradient. It is now a slow aurora drifting behind
   the headline, which is the one place on this page worth spending real atmosphere:
   it is the subject's own sky, not decoration borrowed from somewhere else.

   Built to cost nothing. Two blurred radial gradients on pseudo-elements, animated
   on transform only, so both layers live on the compositor and never touch layout
   or paint. 34s and 46s periods, deliberately prime-ish against each other so the
   pattern does not visibly loop. z-index 0 with .lgp-in above at 1.
   ------------------------------------------------------------------------------ */
.lgp-mast:before,.lgp-mast:after{content:"";position:absolute;z-index:0;
  pointer-events:none;border-radius:50%;filter:blur(70px);will-change:transform}
.lgp-mast:before{width:70vw;height:70vw;max-width:900px;max-height:900px;
  top:-38%;left:-14%;opacity:.5;
  background:radial-gradient(circle,rgba(8,178,220,.95) 0%,rgba(8,178,220,0) 68%);
  animation:lgpaur1 34s ease-in-out infinite}
.lgp-mast:after{width:58vw;height:58vw;max-width:760px;max-height:760px;
  bottom:-46%;right:-10%;opacity:.42;
  background:radial-gradient(circle,rgba(78,199,154,.9) 0%,rgba(78,199,154,0) 68%);
  animation:lgpaur2 46s ease-in-out infinite}
@keyframes lgpaur1{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  33%    {transform:translate3d(9%,7%,0) scale(1.13)}
  66%    {transform:translate3d(-6%,4%,0) scale(.94)}
}
@keyframes lgpaur2{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  40%    {transform:translate3d(-11%,-8%,0) scale(1.16)}
  75%    {transform:translate3d(5%,-3%,0) scale(.92)}
}
.lgp-mast .lgp-in{position:relative;z-index:1}

/* ---- the hero arrives -------------------------------------------------------
   Staged entrance, kicker then headline then buttons then the guarantee then the
   controls. Gated on .lgp-lit, which script adds, so with JavaScript off the hero
   is simply present and nothing is ever hidden waiting for an animation that will
   not run. 60ms between steps: enough to read as a sequence, not enough to make
   anyone wait.
   ---------------------------------------------------------------------------- */
   The subjects are named individually rather than taken as `.lgp-in > *`, which is
   what this used to do. The hero is two grid blocks now instead of six stacked
   ones, so a child selector would stage two steps and land the headline, both
   buttons, the guarantee and every control in the same wave. The panels stage as
   whole units, because a panel whose contents arrive one at a time reads as slow
   rather than choreographed. */
.lgp-mast.lgp-lit .lgp-htxt>*,
.lgp-mast.lgp-lit .lgp-hact,
.lgp-mast.lgp-lit .lgp-tool{animation:lgprise .62s cubic-bezier(.16,.84,.24,1) both}
.lgp-mast.lgp-lit .lgp-htxt>*:nth-child(1){animation-delay:.04s}
.lgp-mast.lgp-lit .lgp-htxt>*:nth-child(2){animation-delay:.10s}
.lgp-mast.lgp-lit .lgp-htxt>*:nth-child(3){animation-delay:.16s}
.lgp-mast.lgp-lit .lgp-hact{animation-delay:.22s}
.lgp-mast.lgp-lit .lgp-tool{animation-delay:.30s}
@keyframes lgprise{from{opacity:0;transform:translate3d(0,16px,0)}to{opacity:1;transform:none}}

/* ---- scroll progress --------------------------------------------------------
   A 3px cyan rule across the top, scaled by how far down the page you are. On a
   page this tall it is genuine orientation, not chrome. scaleX only, so it is one
   composited property and never a width animation. */
.lgp-prog{position:fixed;top:0;left:0;right:0;height:3px;z-index:60;
  background:var(--cy);transform:scaleX(0);transform-origin:0 50%;
  will-change:transform;pointer-events:none}
/* ---- hero layout ----------------------------------------------------------
   Two columns, and the ratio is what makes the right one read as a panel rather
   than a stray box: at 1.5fr / .9fr against a 1180px content width the action
   column lands at about 400px, which is wide enough for a full width button and
   narrow enough that the headline still owns the composition.

   align-items:start, not stretch. The panel is as tall as its own content; a
   stretched panel would grow to the headline's height and hold a pocket of empty
   translucent white under the price match line.

   The breakpoint is 980px and it is set by the panel, not the text: below that
   the two buttons and the headline both want more than half the width. */
.lgp-hero{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(300px,.9fr);
  gap:36px;align-items:start}
.lgp-htxt{min-width:0}
/* 20ch, not 18. The headline sits in a column now instead of the full width, so
   the old cap broke it to four lines and left the column looking under-filled. */
/* balance, so the three lines rag evenly instead of leaving "bird discounts"
   alone on the last one. Unsupported browsers ignore it and get the old wrap. */
.lgp-mast h1{color:#fff;max-width:20ch;text-wrap:balance}
.lgp-lede{color:#b7dcee;font-size:clamp(15px,1.7vw,18px);margin-top:14px!important;max-width:62ch}
.lgp-lede b{color:#fff;font-weight:800;font-variant-numeric:tabular-nums}

/* The action panel. Same translucent white and same 1px rim as the control panel
   below it, so the two read as one system rather than two decisions. */
.lgp-hact{display:grid;gap:10px;padding:18px;border-radius:16px;
  background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.18)}
/* .lgp-btn.block carries margin-top:11px for the stacked buttons it was written
   for. Here the grid owns the rhythm, and both would apply. */
.lgp-hact .lgp-btn.block{margin-top:0}
/* The two demoted destinations. Underlined, because in a panel that already holds
   two buttons a bare coloured word is not obviously a link. 13.5px on #cfeaf7 is
   7.4:1 against the lighter hero stop, so it is quiet without being faint. */
.lgp-hlinks{display:flex;flex-wrap:wrap;gap:6px 18px;margin:2px 0 0!important;
  font-size:13.5px;line-height:1.4}
.lgp-hlinks a{color:#cfeaf7!important;text-decoration:underline;font-weight:600}
.lgp-hlinks a:hover{color:#fff!important}
/* The guarantee loses its own box in here. It was authored as a strip for a flat
   hero, and inside a panel it became a box within a box: two rims, two fills, and
   the longest text in the panel reading heavier than the button above it. Unboxed
   it is fine print with a tick, which is what it should have been all along. The
   hairline replaces the rim so it is still a separate statement and not a caption
   on the button. */
.lgp-hact .lgp-pm{background:transparent;border:0;border-top:1px solid rgba(255,255,255,.16);
  border-radius:0;padding:12px 0 0;margin:2px 0 0!important;max-width:none;
  font-size:12.5px;line-height:1.5;font-weight:600}
.lgp-hact .lgp-pm em,.lgp-hact .lgp-pm a{font-size:12px}

/* ---- the control panel ----------------------------------------------------
   Everything the visitor can operate lives in here: the pole set, the budget
   slider, the reset, and the quick search groups. The hairline is the whole point
   of the panel. Above it you narrow the page, below it you jump to a section, and
   those are two different acts that used to sit in one undifferentiated stack. */
.lgp-tool{margin-top:32px;padding:18px 20px 20px;border-radius:18px;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.16)}
/* !important on the border, and it is not laziness. `.lgp-mast .lgp-filter` sets
   border:0 to strip the sticky bar's chrome, it is the same (0,2,0) specificity as
   this selector, and it sits later in the file, so it wins the tie and the hairline
   simply did not paint. Verified in the browser before reaching for this. Raising
   this selector's specificity instead would work too and would put the two rules
   in an arms race the next edit has to lose. */
.lgp-tool .lgp-filter{margin-top:0!important;padding-bottom:16px;
  border-bottom:1px solid rgba(255,255,255,.15)!important}
.lgp-tool .lgp-qs{margin-top:16px}
/* The pole set and the budget anchor opposite ends of the row. Left aligned they
   left half the panel empty and the slider looked like something that had come
   loose from the segmented control beside it. 340px is the width at which "What's
   your budget?" and the value sit on one line with the track under them.

   Guarded to 821 and up. Below that .lgp-filter-in is a single column grid, and a
   fixed width on a grid item sizes the track to that width: 340px in a 310px panel
   pushed the track 30px wider than its own container and took the segmented control
   out with it, because both share the track. Measured at 390px, not guessed.
   max-width:100% does not save it either, since the percentage resolves against the
   track the item just widened. */
@media(min-width:821px){
  .lgp-tool .lgp-price{margin-left:auto;width:340px}
}

/* 980, set by the action panel: below it the two buttons and the headline both
   want more than half the width. The panel goes full width and stays a panel,
   because on a phone it is the first thing under the headline and the two
   destinations still need to look like the quiet option. */
@media(max-width:980px){
  .lgp-hero{grid-template-columns:1fr;gap:22px}
  .lgp-hact{padding:16px}
  .lgp-tool{margin-top:24px;padding:16px}
}
@media(max-width:700px){
  /* 20px horizontal, matching .lgp-qs-row's margin-inline:-20px, so a swipe shelf
     bleeds exactly to the panel's own edge instead of stopping short of it or
     overhanging it. Change one and the other has to change with it. */
  .lgp-tool{padding:16px 20px 6px;border-radius:14px}
}
.lgp-kick{display:inline-flex;align-items:center;gap:8px;font-size:11.5px;font-weight:800;
  letter-spacing:.13em;text-transform:uppercase;padding:6px 13px;border-radius:999px;
  color:var(--pri);background:var(--g)}
.lgp-kick.live{background:rgba(255,255,255,.13);border:1px solid rgba(255,255,255,.24);color:#cfeaf7;margin-bottom:16px}
.lgp-kick.live i{width:7px;height:7px;border-radius:50%;background:#ff6b7f;animation:lgppl 2.2s ease-in-out infinite}
.lgp-kick.cy{color:#08b2dc;background:rgba(8,178,220,.14)}
@keyframes lgppl{0%,100%{opacity:1}50%{opacity:.28}}
/* .lgp-mstats and .lgp-mcta were here. The stats strip was removed at Neill's
   request in an earlier pass and the four button row was replaced by .lgp-hact,
   so both selectors matched nothing. Dead rules on a page this size are worse
   than none: the next person reads them as the layout. */

/* The price match line. It sits under the buttons rather than above the headline,
   because it is a reason to trust the prices on this page and not the reason to be
   on it. Deliberately quiet: no badge, no colour of its own, no exclamation.

   Contrast is computed against the LIGHTER hero stop #00567c and without counting
   the strip's own translucent fill, because the fill lets the gradient through and
   the figure has to hold at the pale end: #eaf6fc is 8.1:1 and #bcd9e8 is 5.9:1, so
   both clear AA as normal text even where the ground is lightest.

   The qualifier is <em> rather than a link while the terms do not exist, so it
   cannot read as something clickable that goes nowhere. price_match() swaps it to a
   real <a> the moment terms_url is set, and this rule styles both the same. */
.lgp-pm{display:flex;align-items:flex-start;gap:9px;max-width:74ch;
  margin:16px 0 0!important;padding:10px 14px;border-radius:11px;
  background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.22);
  font-size:13.5px;line-height:1.5;color:#eaf6fc;font-weight:600}
/* a drawn tick, so the line needs no icon font and no image request */
.lgp-pm-i{flex:0 0 auto;width:15px;height:15px;margin-top:3px;position:relative}
.lgp-pm-i:before{content:"";position:absolute;left:1px;top:6px;width:5px;height:2px;
  background:#7fe3b4;transform:rotate(45deg);border-radius:1px}
.lgp-pm-i:after{content:"";position:absolute;left:3.5px;top:4px;width:10px;height:2px;
  background:#7fe3b4;transform:rotate(-50deg);border-radius:1px}
.lgp-pm em,.lgp-pm a{font-style:normal;font-weight:500;color:#bcd9e8;font-size:12.5px}
.lgp-pm a{text-decoration:underline}
.lgp-pm a:hover{color:#fff}

/* buttons */
.lgp-btn{display:inline-block;background:var(--pri);color:#fff!important;font-size:14px;font-weight:700;
  padding:10px 17px;border-radius:8px;border:0;white-space:nowrap;text-decoration:none!important;transition:.15s}
.lgp-btn:hover{background:var(--pri2);color:#fff!important}
.lgp-btn.big{font-size:15px;padding:12px 22px;background:var(--cy);color:#042c43!important;font-weight:800}
.lgp-btn.big:hover{background:#43c9ec;color:#042c43!important}
.lgp-btn.wire{background:transparent;color:#fff!important;border:1.5px solid rgba(255,255,255,.42)}
.lgp-btn.wire:hover{background:rgba(255,255,255,.12)}
.lgp-btn.ghost{background:transparent;color:var(--pri)!important;border:1px solid var(--bd2)}
.lgp-btn.ghost:hover{border-color:var(--pri);background:var(--sf);color:var(--pri)!important}
.lgp-btn.full,.lgp-btn.block{display:block;width:100%;text-align:center;margin-top:11px;padding:11px 12px}
.lgp-btn.big.block{padding:12px 22px}

/* ---- quick search: two pole rows of live costed pills ----
   Replaces the six season tiles. Each tile carried four stacked numbers about the
   same set and linked out to a season archive, so its one click left the deals
   page. A pill carries one label you can want and one number telling you what it
   costs, and tapping it puts real departures on screen.

   THIS IS THE PAGE'S EXIT. The unfiltered page is 17 sections and about 21,000px.
   The pole filter halves that. A pill cuts it by about 87 percent, to one section.
   The pill, not the pole filter, is what turns deliberate overload into relief, so
   nothing in this block may be quieted to save room.

   The fill is navy at 55 percent, not white at 10 percent. The hero gradient runs
   #042c43 to #00567c at 160deg and the pills sit low in it, so a translucent white
   fill composites to rgb(26,104,137) down there and every pale blue on it collapses
   (--cy lands at 2.48:1). Navy at 55 percent composites to rgb(2,63,93) at the light
   end and to #042c43 at the dark end, so the pill ground barely moves and every
   figure below holds anywhere in the hero.

   THE PILL IS AN ANCHOR, so every rule whose subject is .lgp-qs-pill carries the
   .lgp-specials prefix. Line 23 is `.lgp-specials a{color:var(--pri);text-decoration:
   none}` at (0,1,1) and line 24 is `.lgp-specials a:hover{text-decoration:underline}`
   at (0,2,1). A bare .lgp-qs-pill is (0,1,0) and LOSES the tie on the type selector,
   measured: a one class base rule setting color:#fff computes to rgb(0,116,165) and a
   one class hover rule setting text-decoration:none computes to underline. Do not
   remove a prefix to tidy this up.

   No !important in this block. Nothing from this block belongs at the end of the
   file. See content/current-specials/QUICKSEARCH-VISUAL.md section 7. */
/* The group label moves into a left gutter instead of sitting on its own line
   above the row. Three stacked captions cost three lines and pushed each row's
   pills away from the one above, so the block read as three separate lists; in a
   gutter the three rows share one left edge and the captions stop interrupting.
   Right aligned against the gutter, so the labels and the pills each have a clean
   inner edge.

   104px is measured, not guessed: the longest caption is BOTH POLES at 11px, 800
   weight, .12em tracking, which lays out at 88px, and ANTARCTICA at 92px. nowrap
   is load bearing, because a wrapped caption is 28px tall and would break the
   vertical centring against a 46px row.

   Grid, not float or an absolute label. A hidden group removes both its cells, so
   the pole bar taking a whole group off the page leaves no empty gutter row. */
.lgp-qs{display:grid;grid-template-columns:104px minmax(0,1fr);
  column-gap:14px;row-gap:10px;align-items:start;margin-top:28px;scroll-margin-top:150px}
/* start, not center, with the optical centring done by padding instead. A row that
   wraps to two lines is 100px tall, and centred against that the caption floats in
   the gap between the two lines with nothing beside it. 16px is (46 - 14) / 2, so a
   caption still sits dead centre of a single line row, which is the common case,
   and stays with the first line when the row wraps at narrow widths. */
.lgp-qs-lab{font-size:11px;line-height:14px;font-weight:800;white-space:nowrap;
  /* #9fc6db measured 4.41:1 against the hero's lighter stop #00567c, just under the
     4.5 that 1.4.3 asks of text this size, and the aurora moves the ground under it.
     #a8cde0 is 4.76 there and 8.62 at the dark end, so it clears at every phase of
     the animation rather than at the average of it. Same value the disabled pill
     already uses, so this adds no new colour. */
  letter-spacing:.12em;text-transform:uppercase;color:#a8cde0;margin:0;
  padding-top:16px;text-align:right}
/* row-gap owns the vertical rhythm now, so the row carries no margin of its own.
   A margin here would add to the gap and only on some rows. */
.lgp-qs-row{display:flex;flex-wrap:wrap;gap:8px;margin:0;padding:0;list-style:none}
/* the status line is not a group, so it belongs in the pill column, not the gutter */
.lgp-qs-say{grid-column:2;margin:0!important}

/* height is 46 with NO vertical padding. the two lines are 18 + 2 + 14 = 34 and
   justify-content centres them, leaving 6px either side. flex:0 0 auto on both lines
   is load bearing: with 7px padding the content box is exactly 32px, flex shrinks the
   label to 15px, and the overflow:hidden that text-overflow:ellipsis needs then clips
   the bottom of every $ , and digit. test with scrollHeight === clientHeight on the
   label, not by eye.
   font:inherit is not a UA reset here, an anchor needs no reset. It defends against
   Elementor kit 8 link typography. user-select and tap-highlight are anchor only:
   dragging an anchor selects its text and raises the iOS callout mid swipe. */
/* The rim carries the deal type. Two modifier classes, .pink and .green, named
   identically to the banner's so Monica emits one string in both places, and
   everything else needs no class at all. NOTHING HERE ENCODES A PILL OR A COUNT:
   no nth-child, no per-pill width, no fixed row height. Pills are their content
   width and the row is flex-wrap, so the list can grow or shrink without CSS. */
.lgp-specials .lgp-qs-pill{position:relative;display:flex;flex-direction:column;
  justify-content:center;gap:2px;height:46px;max-width:260px;padding:0 14px;
  /* --qt was var(--rest-air), the cyan, and it is now a plain white rim. See the
     tone block below for why: blue is not a colour on a pill any more. */
  --qt:rgba(255,255,255,.22);--qti:var(--rest);
  /* 2px, not 1px. At 1px the cyan rim nearly vanishes into the navy and the code is
     only legible on the pink, which defeats the point of having a code at all. At 2px
     all three read immediately. box-sizing is border-box so the height stays 46 and
     each pill grows 2px, which is 14px against 352px spare in the longer row.

     NOT 1.5px. Chromium floors a sub-pixel border to 1px, at dpr 1 AND at dpr 2,
     verified by rendering at both: declared 1.5px computes to 1px and the pill width
     does not move. So 1.5px is a no-op here, and .lgp-btn.wire's 1.5px on this same
     hero has always painted at 1px. If a heavier edge is ever wanted there, it needs
     a whole pixel too. */
  border:2px solid var(--qt);border-radius:10px;
  background:rgba(4,44,67,.55);color:#fff;font:inherit;text-decoration:none;
  cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;
  transition:background-color .12s cubic-bezier(.2,0,.4,1),
             border-color .12s cubic-bezier(.2,0,.4,1),
             color .12s cubic-bezier(.2,0,.4,1),
             transform .12s cubic-bezier(.2,0,.4,1)}
/* THE ATTRIBUTE SELECTORS ARE THE ONES THAT WORK. pills() emits data-tone and no
   class at all, so for the whole life of this page these two rules matched nothing
   and every pill in the row painted the same cyan. That is most of why the block
   read as a wall: sixteen identically rimmed chips carry no ranking, so the eye has
   to read all of them. Keep both forms, attribute first in intent, class kept in
   case anyone adds one in the editor. Both are (0,3,0) and beat the base (0,2,0).

   Blue is deliberately NOT a colour any more. Pink means last minute and green
   means early bird, and those are the only two states worth spending colour on; the
   other eleven pills are ordinary navigation and take a plain white rim at 22%.
   Now the two urgent tones are the only thing that pops in the row instead of
   competing with eleven cyan rims for the same attention. --qti stays --rest for
   them, because it is the SELECTED state's rim and figure colour and that sits on
   white, where --pri is 4.6:1. The neutral itself is set on the base rule above,
   not here, so there is only ever one declaration of the resting rim. */
.lgp-specials .lgp-qs-pill[data-tone="pink"],
.lgp-specials .lgp-qs-pill.pink{--qt:var(--late-air);--qti:var(--late)}
.lgp-specials .lgp-qs-pill[data-tone="green"],
.lgp-specials .lgp-qs-pill.green{--qt:var(--early-air);--qti:var(--early)}
.lgp-qs-l{flex:0 0 auto;font-size:14px;line-height:18px;font-weight:700;
  letter-spacing:-.01em;color:#fff;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* line 2 is a cost slot with four fillings and is never empty, or the height moves.
   `up to 25% off`, `from $6,390`, `12 departures`, `none in budget`. The price and
   the percentage get IDENTICAL treatment: same size, same weight, same colour, same
   tabular figures. A price is not a weaker badge than a percentage, it is the same
   answer to the same question, and the value of a uniform second line is that every
   pill stays comparable at a glance. Do not tint the price with --save, which would
   read as a discount, and do not shrink the 10% early bird figure.
   `up to` and `from` are not fluff and do not come out. Without `up to`, a pill
   claims every departure in its set is 25% off when only the best one is, which is
   the overstatement VISUAL-SPEC.md spent three pages preventing. Wording is Waddles'
   and the only constraint from here is that the figure keeps its qualifier. */
.lgp-qs-d{flex:0 0 auto;font-size:11.5px;line-height:14px;font-weight:700;
  color:#dff1fa;font-variant-numeric:tabular-nums lining-nums;white-space:nowrap}

/* THE TICK IS CUT. It was an absolutely positioned \2713 with 17px reserved for it in
   the pill's padding-left, on every pill, at rest, so that selecting one could not
   push another onto the next line. It bought greyscale and projector robustness that
   the luminance inversion already provides on its own, and it cost 17px per pill,
   which is 119px in a seven pill row that is now the constraint. It also cost a stray
   VoiceOver utterance, a desktop-only reservation rule and its mobile counter-rule.
   Gone: no fluff on the pill, and the row got a pill's worth of headroom back.
   Both lines now share a left edge because nothing is in front of either of them. */

/* hover DARKENS the fill and keeps the tone rim. It used to brighten the rim to
   white, which is not available now that the rim carries the deal type.
   Darker is the safe direction: selected goes to white, so a hover that goes the
   other way cannot be misread as half selected, which is the failure mode across a
   row this long. The darker fill also raises the rim's own contrast.
   Three classes, because line 24 is (0,2,1). At two classes the labels underline. */
.lgp-specials .lgp-qs-pill:hover{background:rgba(4,44,67,.75);
  transform:translateY(-1px);text-decoration:none}
.lgp-specials .lgp-qs-pill:hover .lgp-qs-d{color:#fff}

/* :active exists because the pill is an anchor. a native button renders a UA pressed
   state and an anchor renders nothing, so without this a tap has no feedback until
   the script flips aria-current. Same direction as hover, one step further. */
.lgp-specials .lgp-qs-pill:active{transform:translateY(0);background:rgba(4,44,67,.9)}

/* selected. four carriers and only one of them is hue: luminance inversion of the
   fill, elevation, the tone flipping from its -air value to its ink value, and
   aria-current. In greyscale one white slab among a dozen dark ones is instant, which
   is what satisfies 1.4.1 and is why the tick was affordable to lose.
   Both attribute values are matched so the styling cannot fall off if Monica emits
   "page" rather than "true". */
.lgp-specials .lgp-qs-pill[aria-current="true"],
.lgp-specials .lgp-qs-pill[aria-current="page"]{background:#fff;border-color:var(--qti);
  transform:none;box-shadow:0 2px 4px rgba(4,44,67,.24),0 10px 24px -14px rgba(4,44,67,.55)}
.lgp-specials .lgp-qs-pill[aria-current="true"] .lgp-qs-l,
.lgp-specials .lgp-qs-pill[aria-current="page"] .lgp-qs-l{color:var(--ink)}
/* the selected pill's figure carries the tone, not --save. It is the one place the
   pill and its section header show the identical value, which is what makes the code
   legible: you tap a pink pill and land on a pink header. */
.lgp-specials .lgp-qs-pill[aria-current="true"] .lgp-qs-d,
.lgp-specials .lgp-qs-pill[aria-current="page"] .lgp-qs-d{color:var(--qti)}

/* aria-disabled, not the disabled attribute, which anchors do not have anyway. the
   href stays valid because the disabled state is a transient client side consequence
   of the budget slider and the unfiltered URL still resolves. Monica's click handler
   must preventDefault on a pill carrying aria-disabled, or a dead pill still
   navigates. no opacity, it would take the label under AA and the border with it. */
/* the tone drops out with the rest of it. A pill whose set the budget slider has
   emptied should not still be advertising its deal type, and WCAG 1.4.11 exempts an
   inactive component's edge by name, which is why the 2.07:1 border is compliant. */
.lgp-specials .lgp-qs-pill[aria-disabled="true"]{background:rgba(4,44,67,.35);
  border-color:rgba(255,255,255,.16);cursor:not-allowed;transform:none;box-shadow:none}
.lgp-specials .lgp-qs-pill[aria-disabled="true"] .lgp-qs-l,
.lgp-specials .lgp-qs-pill[aria-disabled="true"] .lgp-qs-d{color:#a8cde0}
.lgp-specials .lgp-qs-pill[aria-disabled="true"]:hover{
  background:rgba(4,44,67,.35);border-color:rgba(255,255,255,.16);transform:none}
.lgp-specials .lgp-qs-pill[aria-disabled="true"]:hover .lgp-qs-d{color:#a8cde0}

/* one focus rule for all five states. white reads on the dark pill (11.24:1) and on
   the selected white pill, because outline-offset shows the hero through the 2px gap
   (8.01:1). --pri is 2.79:1 on this hero and --cy is 2.48:1 at the light end, so
   neither can carry it. border-radius restated because line 25 used to set 4px on
   every focused element; kept after that fix so the pill is correct either way. */
.lgp-specials .lgp-qs-pill:focus-visible{outline:3px solid #fff;outline-offset:2px;
  border-radius:10px}

/* sections */
.lgp-sec{padding:40px 0 8px;scroll-margin-top:105px}
.lgp-deck{color:var(--mut);font-size:14.5px;margin-top:6px!important;max-width:68ch}
.lgp-jump{display:flex;gap:8px;overflow-x:auto;padding:18px 0 4px}
.lgp-jump a{white-space:nowrap;font-size:13px;font-weight:600;padding:7px 14px;
  border:1px solid var(--bd2);border-radius:999px;color:var(--body);background:var(--g);text-decoration:none!important}
.lgp-jump a:hover{border-color:var(--pri);color:var(--pri)}
.lgp-jump b{color:var(--mut);font-variant-numeric:tabular-nums}

/* ---- promo banner: the coloured section header ----
   Kept coloured, and kept over a shaded alternating division, deliberately, at 17
   sections. There used to be five tones. Five over 17 means each repeats three or
   four times and the palette reads as random, which is worse than reading as flat.

   THREE TONES NOW, AND TONE ENCODES DEAL TYPE. pink = last minute, green = early
   bird, blue = everything else. Same code as the pills, same class names, so a pink
   pill and a pink header are the same statement. DO NOT ADD A FOURTH TONE. .red,
   .navy and .amber are gone; a stale tone name from the PHP now lands on blue, which
   is the semantically correct fallback for "everything else".

   BLUE IS THE DEFAULT, not a modifier. "Everything else" needs no class, so an
   untoned section is impossible and only two modifiers exist. That is the structural
   protection against a fourth tone: adding one means editing this block.

   DEFECT 6, live today on every coloured header and about to be replicated 17 times.
   Every one of the five old tones failed AA inside the banner. Measured, white text
   on the lighter gradient stop: blue 4.09, green 4.29, amber 4.19, navy 4.39 against
   the 4.5 the 14.5px deck needs. Two of the failures could not be fixed by any
   gradient value, because they were component defects, not ground defects:

     .lgp-kick was #fff on rgba(255,255,255,.2), white on a white wash, 3.03:1. That
     is a near tie by construction and darkening the ground barely moves it. It is a
     white chip with tone ink now, which passes on every ground at 5.2 or better and
     carries the tone a second time for free.

     .lgp-sort had a rgba(255,255,255,.32) border, 1.61:1 against its own ground,
     nowhere near the 3:1 a form control edge needs. It is a solid white field now,
     which also matches the ghost button sitting next to it, so the banner's two
     controls finally read as the same kind of thing.

   With those two fixed, the remaining constraint is solid white text at 4.5:1 on the
   lighter stop, so both surviving stops darken slightly: blue #0a86bb to #077ba6
   (4.09 to 4.78) and green #1f8a68 to #1b8264 (4.29 to 4.75). The deck and the sort
   label drop their .88 and .85 alphas: translucent white text on a saturated ground
   is the anti pattern that caused this, and no alpha value passes.

   margin-bottom is 12 against the section's 30px top padding. The gap above a header
   must be visibly larger than the gap below it or the header floats between two card
   grids and it is ambiguous which one it heads. At 17 repeats that ambiguity is the
   most expensive thing on the page. Ratio is 2.5:1. Do not even it out. */
.lgp-banner{display:flex;gap:20px;align-items:center;flex-wrap:wrap;padding:20px 24px;
  border-radius:var(--r);margin-bottom:12px;border:1px solid transparent;
  --qt:var(--rest-air);--qti:var(--rest);
  background:linear-gradient(100deg,#00567c,#077ba6)}
.lgp-banner.pink{--qt:var(--late-air);--qti:var(--late);
  background:linear-gradient(100deg,var(--late),#8c0049)}
.lgp-banner.green{--qt:var(--early-air);--qti:var(--early);
  background:linear-gradient(100deg,#12604b,#1b8264)}
.lgp-banner h2{color:#fff}
.lgp-banner .lgp-kick{color:var(--qti);background:var(--g)}
.lgp-banner .lgp-btn.ghost{background:#fff;color:#042c43!important;border-color:#fff;font-weight:800}
.lgp-banner .lgp-btn.ghost:hover{background:#e9f6fb}
.lgp-banner .lgp-sortlab{color:#fff}
.lgp-banner .lgp-sort{background:var(--g);border-color:var(--g);color:var(--ink)}

/* Alternating shaded bands, full bleed, so categories read as separate rooms.
   Padding was 36/32. At 5 sections 68px between rooms was rhythm; at 17 it is 1,150px
   of nothing, and it made the header ambiguous (see the ratio note above).

   scroll-margin-top is 150: the 105 the rest of .lgp-sec assumes for the site header,
   plus the 40px .lgp-nowbar, plus 5. A pole change scrolls to the first surviving
   section and it must not land under either sticky thing.

   nth-of-type(even) COUNTS DOM POSITION, NOT VISIBLE POSITION. Picking a pole hides
   eight sections outright via .lgp-block[hidden]{display:none!important}, and an empty
   promo group renders a <section> with no .lgp-block class at all, so on the filtered
   page the alternation scrambles: two pale bands or two white ones end up adjacent and
   the division the tones are there to support disappears. CSS cannot count visible
   siblings, so JS has to. The contract, and Monica owns the emitting half:

     - on the .lgp-blocks container, set data-banded once when the script takes over
     - on every VISIBLE .lgp-block, set data-band="a" or "b" alternating, recomputed
       on every pole change

   Without JS the nth-of-type alternation still runs on source order, which is correct
   because without JS nothing is hidden. The :not() rule below is what lets the JS
   answer beat the source-order answer wherever it disagrees.

   DO NOT put content-visibility:auto on .lgp-block to speed up 136 cards. It implies
   contain:paint, which clips the -100vw pseudo-element and silently kills every
   shaded band. Cards are already loading="lazy". */
.lgp-block{padding:30px 0 26px;position:relative;scroll-margin-top:150px}
.lgp-block:nth-of-type(even):not(.lgp-loud):before,
.lgp-blocks[data-banded] .lgp-block[data-band="b"]:not(.lgp-loud):before{content:"";
  position:absolute;inset:0 -100vw;background:var(--sf);z-index:-1;pointer-events:none}
.lgp-blocks[data-banded] .lgp-block:nth-of-type(even):not([data-band="b"]):before{content:none}
.lgp-blocks{position:relative;z-index:0}

/* ---- ultra last minute: the loudest section on the page ----
   One cross-pole section above the pole split, departures inside 30 days. It has to
   be the loudest thing here and it has to be PINK, the same pink as every other last
   minute section, because there is no fourth tone.

   It was a full-bleed pink band with white cards on it, which Neill cut: at eight
   cards the band is most of a screen of saturated magenta and it stopped reading as
   emphasis. It is now a CONTAINED ROUNDED BOX on the page's own white, framed in the
   same pink. Same tone, a fraction of the area, and it still cannot be mistaken for
   the other sections because it is the only bordered box on the page.

   So the volume now comes from four things, none of which is a hue and none of which
   is area:

     1 IT IS THE ONLY FRAMED BOX. Every other section is a rounded banner on white or
       on an --sf band. This one is the only thing on the page with a border drawn
       around the whole section, so it reads as lifted out rather than shouted.
     2 SCALE. The heading goes up one step and the count goes to display size.
     3 MOTION. .lgp-kick.live's existing 2.2s pulse dot, already reduced-motion
       guarded by the .lgp-specials * rule, reused rather than reinvented.
     4 POSITION. First.

   Contrast, all recomputed for a light ground because none of the old white-on-pink
   figures transfer. On the #fff8fb fill: --late #c4006c is 5.62:1, so the count and
   the framed elements pass as normal text; --ink is 12.9:1 for the heading; --mut is
   4.79:1 for the summary. The kicker inverts to solid --late with #fff on it at
   5.89:1, and the ghost button does the same, which also fixes it having been --pri
   on pink at 1.13:1.

   The full-bleed :before is explicitly cancelled rather than left to be overridden,
   so nothing paints outside the box and the -100vw device cannot reach this section.
   The two band rules above still carry :not(.lgp-loud), so it is never --sf shaded
   underneath the box either. */
.lgp-loud{padding:20px 20px 17px;border:2px solid var(--late);border-radius:16px;
  background:#fff8fb;box-shadow:var(--shl)}
.lgp-loud:before{content:none}
.lgp-loud .lgp-banner{background:none;border-radius:0;border-color:transparent;
  padding:0;margin-bottom:18px}
.lgp-loud .lgp-banner h2{font-size:clamp(24px,3vw,34px);color:var(--ink)}
.lgp-loud .lgp-banner .lgp-kick{color:#fff;background:var(--late)}
.lgp-loud .lgp-banner .lgp-secsum,
.lgp-loud .lgp-banner .lgp-deck{color:var(--mut)}
/* the banner's controls were built for a pink ground and every one of them assumed
   white. On the box they revert to the page's normal light treatment. */
.lgp-loud .lgp-banner .lgp-sortlab{color:var(--mut)}
.lgp-loud .lgp-banner .lgp-sort{background:#fff;border-color:var(--bd);color:var(--ink)}
.lgp-loud .lgp-banner .lgp-btn.ghost{background:var(--late);border-color:var(--late);
  color:#fff!important}
.lgp-loud .lgp-banner .lgp-btn.ghost:hover{background:#a5005b;border-color:#a5005b}
/* cards sat on pink and needed no edge of their own. On the near-white fill they do. */
.lgp-loud .lgpc{border-color:var(--bd)}
@media(max-width:700px){.lgp-loud{padding:20px 16px 16px;border-radius:16px}}

/* Eight of the 23 cards have no discount, and a photo with an empty top left corner
   next to three photos that have a red flag reads as a fault, not as a fact. So no
   card in this section has an empty badge slot: where there is no discount the slot
   carries the thing that IS true and IS urgent, the days to departure, in navy.
   Navy against the red savings chip is 2.38:1 between the two fills, which is the
   point: they are not confusable, so nobody reads a countdown as a discount.
   #fff on --ink is 14.52:1. Monica emits .b1.days in place of .b1, never both. */
.lgpc-badge .b1.days{background:var(--ink);color:#fff}

/* per-category sort */
/* ---- section filter chips: the second, smaller tier ----
   Some sections narrow themselves in place. Early bird Antarctica gets All, 2027/28,
   2028/29. The failure mode to design against is these reading as the same control as
   the hero quick search pills, because they do a different job at a different scope.

   NINE axes differ at once, which is what makes it unmistakable rather than merely
   smaller. Size alone would not do it.

     hero pill                     section chip
     two lines                     one line
     46px tall                     28px tall
     10px radius                   999px capsule
     14px / 700 label              12px / 600 label
     carries a live figure          carries no figure
     CARRIES A DEAL TONE            never carries a tone
     navy hero ground              section white or --sf ground
     inverts to WHITE when picked  inverts to --pri when picked
     <a href>, a shareable URL     <button>, narrows in place

   The tone exclusion is the important one. pink, green and blue mean deal type, and
   only two devices are allowed to speak that language, the hero pills and the section
   headers. A toned chip here would make the code mean two things.

   SAME SELECTED-STATE LOGIC, correctly translated. The rule was never "selected turns
   white", it was "the selected one inverts against its own row". On navy that means
   going to white; on a light section it means going to --pri. Someone who learned the
   hero pills reads this instantly. aria-pressed rather than aria-current because this
   one does not navigate, and that difference is real, not cosmetic.

   It is a segmented control, not three outlined buttons, and that is a contrast
   decision as much as a visual one. --bd2 as a per-chip edge is 1.46:1 on white and
   the whole blue-grey family bottoms out at 2.92:1 before it turns muddy, so no chip
   edge here could carry 3:1. It does not have to: the group is one component, and
   1.4.11 asks that its STATE be identifiable. The state is the --pri fill at 4.43:1
   against the --sunk track, with #fff on it at 5.20:1, and no chip edge is load
   bearing. Same treatment .lgp-mast .lgp-fbtn already uses inside its own track.

   Reuses .lgp-fset, .lgp-fbtn and .lgp-sortlab wholesale. Three rules of new CSS, and
   nothing about it is specific to seasons, so it drops onto any section. */
.lgp-secfilter{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 14px}
.lgp-secfilter .lgp-fset{background:var(--sunk);border-color:var(--bd2)}
.lgp-secfilter .lgp-fbtn{background:transparent;border-color:transparent;
  font-size:12px;font-weight:600;padding:5px 11px}
.lgp-secfilter .lgp-fbtn:hover{color:var(--pri)}
.lgp-secfilter .lgp-fbtn[aria-pressed="true"]{background:var(--pri);
  border-color:var(--pri);color:#fff}
/* The loud section used to need its own chip track and a white sort label, because
   it was a pink band. It is a light box now, so it takes the same treatment as every
   other section and those two overrides are gone. Nothing scoped to .lgp-loud may
   assume white text again. */

.lgp-sortwrap{display:inline-flex;align-items:center;gap:7px}
.lgp-sortlab{font-size:10.5px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--mut)}
.lgp-sort{font:inherit;font-size:13px;font-weight:600;color:var(--body);background:var(--g);
  border:1px solid var(--bd2);border-radius:8px;padding:8px 10px;cursor:pointer}
.lgp-sort:focus{outline:3px solid var(--pri);outline-offset:2px}
.lgp-banner-t{flex:1 1 420px;min-width:0}
/* solid #fff, not rgba(255,255,255,.88). The banner is always a saturated ground now
   and translucent white on saturated colour is what failed AA at 3.52:1. This rule
   sits after .lgp-banner h2 and ties it on specificity, so it has to hold the value. */
.lgp-banner-t p{color:#fff;font-size:14.5px;margin-top:6px!important;max-width:66ch}
.lgp-banner h2{font-size:clamp(20px,2.4vw,28px)}
.lgp-more{margin-top:16px!important;font-weight:700;font-size:13.5px}

/* cards */
.lgp-rail{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:18px}
.lgpc{display:flex;flex-direction:column;background:var(--g);border:1px solid var(--bd);
  border-radius:var(--r);overflow:hidden;box-shadow:var(--sh);transition:transform .18s,box-shadow .18s,border-color .18s}
.lgpc:hover{transform:translateY(-3px);box-shadow:var(--shl);border-color:var(--bd2)}
.lgpc-ph{position:relative;aspect-ratio:3/2;background:var(--sunk);overflow:hidden}
.lgpc-ph img{width:100%;height:100%;object-fit:cover;display:block}
.lgpc-fall{width:100%;height:100%;display:grid;place-items:center;background:linear-gradient(135deg,#0a3e59,#0074a5)}
.lgpc-fall span{color:rgba(255,255,255,.92);font-size:13px;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;text-align:center;padding:0 14px}
.lgpc-badge{position:absolute;top:10px;left:10px;display:flex;flex-direction:column;gap:2px;
  align-items:flex-start;max-width:calc(100% - 20px)}
.lgpc-badge .b1{background:var(--save);color:#fff;font-size:12px;font-weight:800;letter-spacing:.05em;
  padding:5px 10px;border-radius:6px;text-transform:uppercase;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;max-width:100%}
.lgpc-badge .b2{background:rgba(4,44,67,.9);color:#dff1fa;font-size:10.5px;font-weight:600;padding:3px 8px;
  border-radius:5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.lgpc-pole{position:absolute;top:10px;right:10px;background:rgba(255,255,255,.93);color:#042c43;
  font-size:10.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;padding:4px 9px;border-radius:5px}
.lgpc-soon{position:absolute;bottom:10px;left:10px;background:var(--urg);color:#fff;font-size:11px;
  font-weight:800;letter-spacing:.05em;text-transform:uppercase;padding:4px 9px;border-radius:5px}
.lgpc-bd{padding:14px 15px 15px;display:flex;flex-direction:column;gap:9px;flex:1}
.lgpc-bd h3{height:2.3em;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.lgpc-bd h3 a{color:var(--ink)!important}
.lgpc-meta{display:flex;flex-direction:column;gap:3px;font-size:13px;color:var(--mut)}
.lgpc-meta b{color:var(--body);font-weight:600}
.lgpc-price{margin-top:auto;padding-top:11px;border-top:1px solid var(--bd)}
.lgpc-price .lbl{font-size:10px;color:var(--mut);text-transform:uppercase;letter-spacing:.08em;
  font-weight:700;display:block}
.lgpc-price .v{font-size:21px;font-weight:800;color:var(--ink);letter-spacing:-.02em;line-height:1.2;
  display:block;font-variant-numeric:tabular-nums}


/* private */
.lgp-priv{background:#042c43;color:#dff1fa;border-radius:var(--r);padding:32px;display:grid;
  grid-template-columns:1.3fr 1fr;gap:34px;align-items:start}
.lgp-priv h2{color:#fff;margin-top:10px}
.lgp-priv p{color:#9dc4d8;font-size:15px;margin-top:12px!important;max-width:54ch}
.lgp-privform{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.13);
  border-radius:var(--r);padding:24px;position:sticky;top:24px}
.lgp-privlead{color:#cfe6f2!important;font-size:14.5px;margin:0 0 16px!important}

/* trust, links, fine print */
.lgp-rail.why{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.lgp-why-c{background:var(--g);border:1px solid var(--bd);border-radius:var(--r);padding:20px;box-shadow:var(--sh)}
.lgp-why-c h3{margin-bottom:8px}
.lgp-why-c p{font-size:14px;color:var(--mut)}
.lgp-links{margin:14px 0 0;padding-left:18px}
.lgp-links li{font-size:14.5px;color:var(--mut);margin-bottom:7px}
.lgp-links a{font-weight:700}
.lgp-empty{border:1px dashed var(--bd2);border-radius:var(--r);padding:26px;text-align:center;
  color:var(--mut);font-size:14px;background:var(--sf)}
.lgp-fine{margin:44px 0 20px;padding:20px 22px;background:var(--sf);border:1px solid var(--bd);
  border-radius:var(--r);font-size:12.5px;color:var(--mut);line-height:1.65}
.lgp-fine b{color:var(--body);display:block;margin-bottom:6px;font-size:13px}
.lgp-fine ul{margin:0;padding-left:18px}

@media(max-width:860px){
  .lgp-priv{grid-template-columns:1fr;padding:24px}
}
@media(max-width:700px){
  /* was 28px 0 52px. the 52 existed for the tiles' -26px overlap. */
  .lgp-mast{padding:28px 0 30px}
  .lgp-specials h1{font-size:29px}
  .lgp-lede{font-size:14.5px;margin-top:11px!important}
    .lgp-privform{position:static}
  /* DEFECT 3. Was padding:2px 20px 14px. 2px cannot contain a 3px focus ring at 2px
     offset, and overflow-x:auto computes overflow-y to auto, so the scroll box was
     clipping the top of every card's focus ring in every rail on the page. */
  .lgp-rail{display:grid;grid-auto-flow:column;grid-auto-columns:284px;grid-template-columns:none;gap:12px;
    overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding-inline-start:20px;
    padding:8px 20px 14px;margin-inline:-20px;overscroll-behavior-x:contain}
  .lgp-rail>*{scroll-snap-align:start;min-width:0}
  .lgp-rail.why{grid-auto-columns:268px}
  .lgp-stats{grid-template-columns:1fr 1fr}
  .lgp-sec{padding:28px 0 4px}

  /* 17 sections at 8 cards is about 10,500px on a phone, and the ONLY reason that is
     survivable is that .lgp-rail above turns each section into one swipe shelf instead
     of eight stacked cards. 17 shelves is the streaming-service pattern and it reads as
     abundance. 136 stacked cards would be 30,000px and would read as a fault. */
  .lgp-block{padding:20px 0 18px}
  .lgp-banner{padding:13px 15px;margin-bottom:10px}
  .lgp-banner h2{font-size:18px}
  /* the deck is content and stays, but at 17 repeats an unbounded 4 line deck is 800px
     of phone. three lines, clamped, and the cards say the rest. */
  .lgp-banner-t p{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
    overflow:hidden}
  .lgp-nowbar-in{min-height:38px;gap:9px}
  /* the chip is 30.6px on desktop, which is fine for a mouse and small for a thumb.
     9px of vertical padding takes the chip to 38.6 and the track to 46.6. The chip
     itself still sits under 44, which is the same compromise .lgp-fbtn already makes
     in the filter bar at 820px, and it is stated rather than hidden. */
  .lgp-secfilter{margin-bottom:10px;gap:8px}
  .lgp-secfilter .lgp-fbtn{padding:9px 12px}
  .lgp-loud .lgp-banner{margin-bottom:14px}
  .lgp-loud .lgp-banner h2{font-size:22px}

  /* one swipe row per pole. grid-auto-columns is max-content, not the fixed 284px
     .lgp-rail uses, because pills are their content width and the widest that ships
     is 142px, so forcing 210px would waste 68px and add half a screen of swipe.
     proximity not mandatory: pills are variable width and far narrower than the
     window, so mandatory fights corrective swipes and can strand a narrow last pill.
     8px top and 12px bottom padding exist so a 3px ring at 2px offset is not clipped
     by the scroll box, which is what the 2px above used to get wrong.
     no touch-action: pan-x would block a vertical pan starting on a pill. */
  /* The gutter goes away below 700. The rows are horizontal scrollers here, so a
     two column grid would put a 104px caption beside a shelf that already wants
     every pixel of the viewport, and the shelf's negative margin trick has to
     start at the true left edge to bleed correctly. Back to stacked captions. */
  .lgp-qs{display:block;margin-top:22px}
  .lgp-qs-lab{display:block;text-align:left;padding-top:0;margin-bottom:6px}
  .lgp-qs-row{display:grid;grid-auto-flow:column;grid-auto-columns:max-content;
    grid-template-columns:none;flex-wrap:nowrap;gap:8px;margin:0 0 6px;
    overflow-x:auto;scroll-snap-type:x proximity;overscroll-behavior-x:contain;
    scroll-padding-inline-start:20px;padding:8px 20px 12px;margin-inline:-20px}
  .lgp-qs-row>*{scroll-snap-align:start}
  /* the desktop tick reservation and its mobile counter-rule both used to live here.
     With the tick cut, the pill is the same box at every breakpoint and only the cap
     changes, which never binds anyway because the widest pill that ships is 125px. */
  .lgp-specials .lgp-qs-pill{max-width:210px}
}
/* ---- motion ------------------------------------------------------------------
   Four things move, and no more. ui-ux-pro-max's own ux rules say animate one or
   two key elements per view and do not animate everything that moves, so the
   budget went on: a section fading up as it arrives, its cards arriving in one
   wave behind it, the photo answering a hover, and the single display count
   ticking up. Everything else on this page stays still on purpose.

   Numbers are from the same rule set rather than taste. Reveal offset is 12px so
   it reads as a fade and not a slide. Enter is 380ms with an ease-out curve,
   inside the 300 to 400ms band. Per-card stagger is 30ms, inside the 20 to 40ms
   band, and capped at eight cards so the last one is never more than 240ms behind
   the first. Only transform and opacity are animated, never width, height, top or
   left.

   THE HIDDEN STATE IS ARMED BY SCRIPT, NOT BY THIS FILE, and only on sections
   below the fold. Two reasons, both load bearing. A crawler or a visitor without
   JavaScript gets the page fully visible, because nothing here hides anything on
   its own. And content already on screen is never hidden for even one frame, so
   there is no flash of an empty page while the observer wires up.
   ------------------------------------------------------------------------------ */
.lgp-rv{opacity:0;transform:translateY(12px);
  transition:opacity .38s cubic-bezier(.2,.6,.2,1),transform .38s cubic-bezier(.2,.6,.2,1)}
.lgp-rv.lgp-rv-in{opacity:1;transform:none}
/* one wave per section, not one long wave down the whole page */
.lgp-rv .lgpc{opacity:0;transform:translateY(10px)}
.lgp-rv.lgp-rv-in .lgpc{opacity:1;transform:none;
  transition:opacity .3s ease-out var(--lgp-d,0s),transform .3s ease-out var(--lgp-d,0s)}
/* the photo answers the hover the card already had. One rule, and it is most of
   what separates a card that feels built from one that feels laid out. */
.lgpc-ph img{transition:transform .55s cubic-bezier(.2,.6,.2,1)}
.lgpc:hover .lgpc-ph img{transform:scale(1.07)}

/* ---- the gloss --------------------------------------------------------------
   A light sweeps diagonally across the photo on hover. This is the single detail
   that most reads as "someone paid for this", and it costs one pseudo-element and
   one transform. Kept on the photo rather than the whole card so it never washes
   over the price or the button.
   ---------------------------------------------------------------------------- */
.lgpc-ph{isolation:isolate}
.lgpc-ph:after{content:"";position:absolute;inset:-40% -60%;z-index:2;
  pointer-events:none;opacity:0;
  background:linear-gradient(100deg,transparent 38%,rgba(255,255,255,.42) 50%,transparent 62%);
  transform:translate3d(-70%,0,0);
  transition:transform .75s cubic-bezier(.2,.6,.2,1),opacity .2s ease-out}
.lgpc:hover .lgpc-ph:after{opacity:1;transform:translate3d(70%,0,0)}

/* the deepest discounts get a slow sheen so the eye finds them first. Script adds
   .lgp-hotbadge only where the parsed figure is 35% or more, so the page cannot
   decide to shout about a 10% offer. */
.lgp-hotbadge{position:relative;overflow:hidden}
.lgp-hotbadge:after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,transparent 40%,rgba(255,255,255,.55) 50%,transparent 60%);
  transform:translateX(-100%);animation:lgpsheen 3.6s ease-in-out infinite;
  animation-delay:1.2s}
@keyframes lgpsheen{0%,72%{transform:translateX(-100%)}88%,100%{transform:translateX(100%)}}

/* the section header's accent rule draws in as the section arrives */
.lgp-banner{position:relative;overflow:hidden}
.lgp-banner:after{content:"";position:absolute;left:0;bottom:0;height:3px;width:100%;
  background:rgba(255,255,255,.75);transform:scaleX(0);transform-origin:0 50%;
  transition:transform .85s cubic-bezier(.16,.84,.24,1) .12s}
.lgp-rv.lgp-rv-in .lgp-banner:after,.lgp-lit .lgp-banner:after{transform:scaleX(1)}

/* counts and prices need tabular figures or the box jitters as the digits tick */
.lgpc-price .v{font-variant-numeric:tabular-nums}
/* The pre-discount price, when the same cabin's own original figure is on record.
   Beside the price rather than above it: stacked, the two figures compete and the
   eye has to work out which one it pays. --mut and 14px against the live figure's
   21px and --ink is a 1.5x size gap plus a colour gap, so the live price wins at a
   glance with no second look. Line-through is on an <s>, so the saving survives a
   stylesheet failure and reads to a screen reader as struck text with the words
   "was" in front of it. */
.lgpc-price{display:flex;align-items:baseline;flex-wrap:wrap;gap:0 9px}
.lgpc-price .lbl{flex:1 1 100%}
.lgpc-price .was{font-size:14px;font-weight:700;color:var(--mut);
  font-variant-numeric:tabular-nums}
.lgpc-price .was s{text-decoration-thickness:1.5px}
/* visually hidden, still announced. NOT display:none, which removes it from the
   accessibility tree along with the sighted-only shortcut it exists to explain. */
.lgpc-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}


@media (prefers-reduced-motion:reduce){
  .lgp-specials *{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  .lgpc:hover,.lgp-qs-pill:hover{transform:none}
  /* The reveal is DISARMED here rather than sped up. Speeding a transition still
     leaves the element starting at opacity 0, and the script also skips the
     count-up under this query, so without these two rules a reduced-motion
     visitor could be left looking at a blank section. */
  .lgp-rv,.lgp-rv .lgpc{opacity:1!important;transform:none!important}
  .lgpc:hover .lgpc-ph img{transform:none}
  /* Everything added for flash is switched OFF here, not slowed down. The aurora
     and the badge sheen are infinite animations, which is exactly what this query
     exists to stop, and the staged hero entrance starts at opacity 0 so leaving it
     armed at 0.01ms would risk a hero that never appears. */
  .lgp-mast:before,.lgp-mast:after{animation:none;opacity:.3}
  .lgp-mast.lgp-lit .lgp-htxt>*,
  .lgp-mast.lgp-lit .lgp-hact,
  .lgp-mast.lgp-lit .lgp-tool{animation:none;opacity:1;transform:none}
  .lgp-hotbadge:after{animation:none;display:none}
  .lgpc-ph:after{display:none}
  .lgp-banner:after{transition:none;transform:scaleX(1)}
  .lgp-prog{display:none}
}
@media (forced-colors:active){
  /* EVERY PILL RULE IN HERE CARRIES THE .lgp-specials PREFIX TOO. Rendering this
     block found the mistake: the competitor is not a type selector, it is my own
     .lgp-specials .lgp-qs-pill[aria-current="true"] at (0,3,0) further up the file.
     Unprefixed, these rules sat at (0,2,0) and lost, so the selected pill kept its
     light fill and never went to Highlight. Measured before the fix: background
     rgba(255,255,255,.55) instead of Highlight.

     The three tone rims all collapse to CanvasText here, so the deal type code is
     simply unavailable in forced colours. That is correct rather than a problem: the
     code is a shortcut and the section heading always says what it is in words.

     forced-color-adjust:none goes on the SELECTED pill only. The pill is an anchor,
     so the UA forces its text to LinkText, which was overriding HighlightText and
     leaving white-on-Highlight unreadable. Opting one pill out keeps the user's own
     link colour on the other twelve, which is what forced colours exists to honour.
     Same reason .lgpc-badge .b1 already does it. */
  .lgpc,.lgp-why-c{border:1px solid CanvasText}
  .lgp-specials .lgp-qs-pill{border:1px solid CanvasText}
  .lgpc-badge .b1{border:1px solid CanvasText;forced-color-adjust:none}
  .lgp-specials .lgp-qs-pill[aria-current="true"],
  .lgp-specials .lgp-qs-pill[aria-current="page"]{background:Highlight;
    border-color:Highlight;forced-color-adjust:none}
  .lgp-specials .lgp-qs-pill[aria-current="true"] .lgp-qs-l,
  .lgp-specials .lgp-qs-pill[aria-current="true"] .lgp-qs-d,
  .lgp-specials .lgp-qs-pill[aria-current="page"] .lgp-qs-l,
  .lgp-specials .lgp-qs-pill[aria-current="page"] .lgp-qs-d{color:HighlightText}
  .lgp-specials .lgp-qs-pill[aria-disabled="true"]{forced-color-adjust:none;
    background:Canvas;border-color:GrayText}
  .lgp-specials .lgp-qs-pill[aria-disabled="true"] .lgp-qs-l,
  .lgp-specials .lgp-qs-pill[aria-disabled="true"] .lgp-qs-d{color:GrayText}
}

/* ---- top filter bar ----
   Three controls. Sticky, because the page is long and the whole point is
   letting someone shorten it from anywhere in the scroll. */
.lgp-filter{position:sticky;top:0;z-index:40;background:var(--g);border-bottom:1px solid var(--bd);
  box-shadow:0 6px 18px -14px rgba(4,44,67,.5)}
.lgp-filter-in{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding-top:9px;padding-bottom:9px}
.lgp-fbtn{font:inherit;font-size:12.5px;font-weight:600;padding:6px 12px;border-radius:999px;cursor:pointer;
  border:1px solid var(--bd2);background:var(--g);color:var(--body);white-space:nowrap;transition:.14s}
.lgp-fbtn:hover{border-color:var(--pri);color:var(--pri)}
.lgp-fbtn[aria-pressed="true"]{background:var(--pri);border-color:var(--pri);color:#fff}
.lgp-fcount{margin-left:auto!important;font-size:13px;font-weight:600;color:var(--mut);
  font-variant-numeric:tabular-nums}
.lgp-fcount:empty{display:none}
.lgp-fcount a{font-weight:700}
.lgp-freset{font:inherit;font-size:12.5px;font-weight:600;color:var(--mut);background:none;
  border:0;cursor:pointer;text-decoration:underline;padding:6px 4px}
.lgp-freset:hover{color:var(--pri)}
.lgp-fset{display:flex;gap:4px;background:var(--sf);border:1px solid var(--bd);
  border-radius:999px;padding:3px}
.lgp-sm{display:none}
/* region pills carry the whole left side now, so give them size */
.lgp-fset-lg .lgp-fbtn{font-size:14.5px;font-weight:700;padding:10px 20px}
.lgp-fset-lg{padding:4px}

/* ---- now bar: the persistent exit ----
   Every control on this page lives inside .lgp-mast, and line 436 makes the filter
   position:static there. Sticky cannot rescue it either: a sticky child is confined to
   its containing block, so a filter inside the hero leaves the viewport with the hero
   and never comes back. Measured, that used to cost nothing on a 7,000px page. At 17
   sections it costs everything: after one screen of scroll the visitor has about
   20,000px of deliberate overload ahead of them and no way out of it.

   At 375px it is worse. Nothing of the quick search is above the fold on a phone at
   all: the kick badge, a four line H1, the lede and three stacked buttons fill 667px
   before the filter starts, so the escape valve is the one thing a phone visitor never
   sees. This bar is how they get back to it.

   IT IS NOT A SECOND FILTER. No duplicated buttons, so no duplicated aria-pressed to
   keep in sync with the group inside #lgp-filter, and none of the "two devices reading
   as the same control" ambiguity that a repeated All/Antarctica/Arctic row would have.
   It states where you are and links to where the controls are. Markup is Monica's,
   rendered once immediately after </header>, and Waddles owns the wording:

     <div class="lgp-nowbar"><div class="lgp-in lgp-nowbar-in">
       <b>Antarctica</b><span>9 of 17 collections &middot; 214 departures</span>
       <a href="#lgp-qs">Change or search</a>
     </div></div>

   40px on desktop and on a phone, which is 6 percent of a 667px viewport bought back
   from a 10,500px page. top:0 and z-index:40 are the values line 261 already committed
   to for .lgp-filter, which is static now, so nothing competes for them. If the site
   header ever goes sticky both need the same offset, not just this one. */
.lgp-nowbar{position:sticky;top:0;z-index:40;background:var(--g);
  border-bottom:1px solid var(--bd);box-shadow:0 6px 18px -14px rgba(4,44,67,.5)}
.lgp-nowbar-in{display:flex;align-items:center;gap:12px;min-height:40px;
  padding-top:7px;padding-bottom:7px}
.lgp-nowbar b{font-size:13px;font-weight:800;color:var(--ink);letter-spacing:-.01em;
  white-space:nowrap;flex:0 0 auto}
.lgp-nowbar span{font-size:12.5px;color:var(--mut);font-variant-numeric:tabular-nums;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
/* the link is the only thing that must survive a 320px viewport, so the count
   ellipsises before it and the link never shrinks */
.lgp-nowbar a{margin-left:auto;flex:0 0 auto;font-size:12.5px;font-weight:700}

/* price slider */
.lgp-price{display:flex;flex-direction:column;gap:6px;min-width:300px;flex:0 1 360px}
.lgp-pricetop{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.lgp-pricerow{display:flex;align-items:center;gap:10px}
.lgp-priceend{font-size:11.5px;font-weight:700;color:var(--mut);font-variant-numeric:tabular-nums;
  white-space:nowrap}
.lgp-priceout{font-size:13.5px;font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums;
  white-space:nowrap}
.lgp-pricelab{font-size:13px;font-weight:700;color:var(--body);white-space:nowrap;cursor:pointer}

/* 24px tall, with the 6px track drawn as a background band inside it.
   WCAG 2.5.8 asks 24 by 24 of a pointer target and the element itself WAS the
   track: 223 by 6 at 390px, so the thumb painted outside the box that receives
   the touch and a thumb-width miss did nothing. Height is the target, the
   gradient is the line people see, and `height:6px` on the two vendor track
   pseudo-elements keeps the visual band exactly what it was. */
.lgp-range{-webkit-appearance:none;appearance:none;width:100%;height:24px;
  background:linear-gradient(var(--bd2),var(--bd2)) center/100% 6px no-repeat;
  border-radius:999px;outline:none;cursor:pointer;margin:0;padding:0;border:0}
.lgp-range::-webkit-slider-runnable-track{height:6px;border-radius:999px;background:transparent}
.lgp-range::-moz-range-track{height:6px;border-radius:999px;background:transparent}
.lgp-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:22px;height:22px;
  border-radius:50%;background:var(--pri);border:3px solid #fff;cursor:pointer;
  /* the runnable track is 6px inside a 24px box, so Chromium centres the thumb on
     the track rather than the box unless it is nudged back */
  margin-top:-8px;box-shadow:0 1px 4px rgba(4,44,67,.4)}
.lgp-range::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:var(--pri);
  border:3px solid #fff;cursor:pointer;box-shadow:0 1px 4px rgba(4,44,67,.4)}
.lgp-range:focus-visible{outline:3px solid var(--pri);outline-offset:4px}
.lgp-block[hidden]{display:none!important}
.lgpc[hidden]{display:none!important}
/* The pole bar hides the other pole's quick search group by setting the hidden
   attribute on the label and the row. Both carry a display of their own, and an
   author display rule beats the UA sheet's [hidden]{display:none} no matter how
   low its specificity, so without these two rules the attribute is set, the
   accessibility tree drops the group, and the pills stay on screen. Measured that
   way round the first time: sixteen pills still visible with the row reporting
   hidden === true. Any element in this file that is hidden by script and carries
   its own display needs a rule here. */
.lgp-qs-lab[hidden],.lgp-qs-row[hidden]{display:none!important}

/* ---- call to action bands ---- */
.lgp-cta{display:flex;align-items:center;gap:26px;flex-wrap:wrap;margin:40px 0 8px;padding:26px 28px;
  border-radius:var(--r);background:var(--g);border:1px solid var(--bd)}
.lgp-cta.vip{background:linear-gradient(100deg,#042c43,#0074a5);border-color:transparent}
.lgp-cta.vip h3,.lgp-cta.vip p{color:#fff}
.lgp-cta.vip p{color:rgba(255,255,255,.85)}
.lgp-cta.vip .lgp-btn.wire{border-color:rgba(255,255,255,.45)}
.lgp-cta-t{flex:1 1 400px;min-width:0}
.lgp-cta-t h3{font-size:clamp(18px,2.1vw,23px);font-weight:800;letter-spacing:-.02em}
.lgp-cta-t p{color:var(--mut);font-size:14.5px;margin-top:6px!important;max-width:62ch}
.lgp-cta-a{display:flex;gap:10px;flex-wrap:wrap}
.lgp-cta:not(.vip) .lgp-btn.wire{border-color:var(--bd2);color:var(--pri)!important}
.lgp-cta:not(.vip) .lgp-btn.wire:hover{background:var(--g);border-color:var(--pri)}

@media(max-width:820px){
  /* two rows of three equal segments. sticky here too: a long page needs a
     persistent filter most on a phone, and two unlabelled rows fit. */
  .lgp-filter{position:sticky;top:0}
  .lgp-filter-in{display:grid;grid-template-columns:1fr;gap:6px;padding-top:8px;padding-bottom:8px}
  .lgp-fset{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;overflow:visible}
  .lgp-fbtn{padding:9px 4px;text-align:center;font-size:12.5px}
  .lgp-fcount{margin-left:0!important;font-size:12.5px}
  .lgp-freset{justify-self:start;padding-left:0}
  .lgp-cta{margin:28px 0 4px;padding:20px;gap:16px}
  .lgp-cta-a{width:100%}
  .lgp-cta-a .lgp-btn{flex:1 1 100%;text-align:center}
}
@media(max-width:380px){
  .lgp-lg{display:none}
  .lgp-sm{display:inline}
}
/* DEFECT 4 was an unmatched closing brace here. Harmless to the parser, which
   discards a stray close at top level, but it gave every brace matcher, every editor
   fold and every reader the wrong nesting depth for the remaining 130 lines, which is
   exactly how someone appends a rule inside a media query they did not know they were
   in. No comment in this file may contain an unpaired brace character, for the same
   reason: the naive gate counts them and reports a defect that is not there. */

/* fine print folds. it must be present, it need not be 710px tall on a phone. */
details.lgp-fine{padding:0}
details.lgp-fine>summary{cursor:pointer;list-style:none;padding:16px 22px;font-size:13px;font-weight:700;
  color:var(--body);display:flex;align-items:center;gap:10px}
details.lgp-fine>summary::-webkit-details-marker{display:none}
details.lgp-fine>summary::after{content:"+";margin-left:auto;font-size:17px;font-weight:700;color:var(--mut);line-height:1}
details.lgp-fine[open]>summary::after{content:"\2013"}
details.lgp-fine>summary:hover{color:var(--pri)}
details.lgp-fine>ul{padding:0 22px 18px 40px}
details.lgp-fine>ul li{margin-bottom:6px}

/* the unlisted block was the tallest thing on a phone */
@media(max-width:700px){
  .lgp-priv{padding:20px;gap:20px}
  .lgp-priv p{font-size:14px;margin-top:10px!important}
  .lgp-privform{padding:18px}
  .lgp-privlead{font-size:13.5px;margin-bottom:12px!important}
}

/* ---- top band: the private-deals pitch plus the two lists ----
   Sits directly under the hero because the deals worth the most are the ones
   this page is not allowed to show. */
/* Two columns: the pitch on the navy left, the VIP signup on the white right.
   It was display:block with .lgp-top-b unrendered, which left the right half of
   the band as empty navy. The signup is a real Elementor form widget moved in
   from a hidden container, so this column has to tolerate whatever height the
   form takes rather than assume one. */
.lgp-top{display:grid;grid-template-columns:1.35fr 1fr;margin:34px 0 6px;
  border-radius:var(--r);overflow:hidden;border:1px solid var(--bd);box-shadow:var(--sh)}
@media(max-width:820px){.lgp-top{grid-template-columns:1fr}}
.lgp-top-a{background:#042c43;color:#dff1fa;padding:28px 30px}
.lgp-top-a h2{color:#fff;font-size:clamp(21px,2.4vw,28px);margin-top:11px}
.lgp-top-a p{color:#a8cde0;font-size:14.5px;margin-top:10px!important;max-width:70ch}
.lgp-top-btns{display:flex;gap:10px;flex-wrap:wrap;margin-top:18px}
.lgp-top-a .lgp-btn.wire{border-color:rgba(255,255,255,.45)}
.lgp-top-b{background:var(--g);padding:28px 30px;display:flex;flex-direction:column;justify-content:center}
.lgp-top-b h3{font-size:17px;font-weight:800}
.lgp-top-b p{color:var(--mut);font-size:13.5px;margin-top:7px!important;margin-bottom:15px!important}
.lgp-top-b .lgp-btn.block{margin-top:0;margin-bottom:9px}
.lgp-top-b .lgp-btn.block:last-child{margin-bottom:0}

/* The inline VIP signup. The form itself is an Elementor Pro form widget moved
   here from a hidden container, so almost nothing here styles the form: these
   rules only trim Elementor's own spacing so a two field form does not sit in a
   panel sized for a page. Anything heavier belongs in the widget's own settings,
   or the next person editing it in Elementor will not see what they are fighting.
   The slot keeps its height before the move so the band does not jump. */
.lgp-vipinline-slot{min-height:150px}
.lgp-vipinline-slot .elementor-form-fields-wrapper{margin-bottom:0}
.lgp-vipinline-slot .elementor-field-group{margin-bottom:10px}
.lgp-vipinline-slot .elementor-field-label{font-size:12.5px!important;font-weight:700!important;
  color:var(--ink)!important;margin-bottom:4px!important}
/* LAYOUT IS ELEMENTOR'S. Do not set flex, width or direction on a field group
   here. An earlier version of this block did, having been read off a local mirror
   that cannot load Elementor's own stylesheet, and on the real page the two
   fought: the group stayed a row, `flex:1 1 100%` then demanded the full
   container width beside the label, and both inputs were pushed outside the
   panel. Elementor's own rules already stack the label and fill the field. This
   block is cosmetics only. */
.lgp-vipinline-slot input[type=text],
.lgp-vipinline-slot input[type=email]{font-size:15px!important;padding:10px 12px!important;
  border:1.5px solid var(--bd)!important;border-radius:9px!important;background:#fff!important;
  color:var(--ink)!important}
.lgp-vipinline-slot input:focus-visible{outline:3px solid var(--cy);outline-offset:1px}
.lgp-vipinline-slot .elementor-button{border-radius:10px!important;font-weight:800!important;
  font-size:15px!important;padding:12px 18px!important;background:var(--cy)!important;
  color:var(--ink)!important}
.lgp-vipinline-slot .elementor-button:hover{background:#3ac6e8!important}
.lgp-vipinline-slot .lgp-vip-consent{font-size:11.5px;color:var(--mut);line-height:1.5;
  margin:2px 0 0!important}
/* Elementor renders the success and error notices inside the widget. They must
   not be the one thing on the panel with no styling. */
.lgp-vipinline-slot .elementor-message{font-size:13.5px;margin-top:8px}
.lgp-vipinline-slot .elementor-message-success{color:var(--ok);font-weight:700}
.lgp-vipinline-slot .elementor-message-danger{color:var(--save);font-weight:700}
.lgp-btn.wa{background:var(--pri2);color:#fff!important}
.lgp-btn.wa:hover{background:var(--pri)}
/* the tiles used to lift into the hero. the band sits there now. */
@media(max-width:820px){
  .lgp-top{margin-top:20px}
  .lgp-top-a,.lgp-top-b{padding:20px}
  .lgp-top-btns .lgp-btn{flex:1 1 100%;text-align:center}
}



@media(max-width:700px){
  /* horizontal scrollers with no edge cue. one mask tells a thumb there is more to
     the right. The season tile scroller is gone and the two pill rows join.

     DEFECT 2, .lgp-fset REMOVED from this list. Line 323 makes it a three column grid
     with overflow:visible at 820px and below, so it does not scroll on a phone at all,
     and the mask was fading the right edge of the Arctic filter button off on every
     phone. A fade on a control that cannot scroll is a broken control. */
  .lgp-qs-row,.lgp-rail{
    -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 30px),transparent 100%);
            mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 30px),transparent 100%)}
  .lgp-top-a h2{font-size:20px}
  .lgp-top-a p{font-size:13.5px;line-height:1.5;margin-top:8px!important}
  .lgp-top-a,.lgp-top-b{padding:18px}
  .lgp-top-btns{margin-top:14px;gap:8px}
}

/* season row: outbound to the archives, sitting after the deals because a
   season is a decision you make once you have seen prices */
.lgp-seasons{margin:40px 0 8px}
.lgp-seasons h2{font-size:19px}

/* DEFECT 5, found in this pass. A @media(max-width:700px) block here used to set
   .lgp-blocks{display:flex;flex-direction:column} and then hand order:1..5 to five
   sections by hardcoded id, to lead with last minute on a phone.

   At 17 sections that scrambles the page. Twelve sections keep the initial order:0
   and every one of them jumps AHEAD of all five named sections, so the phone order
   becomes twelve arbitrary sections, then the five that were meant to lead. Two of
   the five ids may not even exist after the restructure.

   Deleted rather than extended. Ordering 17 sections by hardcoded id in a stylesheet
   is not maintainable, and the pole grouping is now the structure the visitor is
   given, so phone order must equal desktop order. If last minute should lead, it
   leads in the $promos array, in PHP, once, for every viewport. */

/* the filter now sits inside the hero, on navy */
.lgp-mast .lgp-filter{position:static;background:transparent;border:0;box-shadow:none;margin-top:22px}
.lgp-mast .lgp-filter-in{padding:0;gap:20px;max-width:none;margin:0}
.lgp-mast .lgp-fset{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.2)}
.lgp-mast .lgp-fbtn{background:transparent;border-color:transparent;color:#cfeaf7}
.lgp-mast .lgp-fbtn:hover{color:#fff}
.lgp-mast .lgp-fbtn[aria-pressed="true"]{background:#fff;border-color:#fff;color:#042c43}
.lgp-mast .lgp-fcount{color:#b7dcee}
.lgp-mast .lgp-fcount a{color:#fff;text-decoration:underline}
.lgp-mast .lgp-pricelab{color:#dff1fa}
.lgp-mast .lgp-priceout{color:#fff}
/* 3.97:1 on the lighter hero stop, and these are the two labels that tell you what
   the slider's range even is. #a8cde0 is 4.76 there. Outside the hero .lgp-priceend
   keeps --mut on white, which was never the problem. */
.lgp-mast .lgp-priceend{color:#a8cde0}
/* the track is a background gradient now, not a flat fill, so the hero override has
   to restate the gradient or it wipes the line entirely. Raised from .26 to .42:
   measured 1.88 and 2.27 against the two hero stops, under the 3:1 that 1.4.11 asks
   of a control boundary, and .42 clears it at both ends. */
.lgp-mast .lgp-range{background:linear-gradient(rgba(255,255,255,.42),rgba(255,255,255,.42)) center/100% 6px no-repeat}
.lgp-mast .lgp-range::-webkit-slider-thumb{background:#08b2dc;border-color:#042c43}
.lgp-mast .lgp-range::-moz-range-thumb{background:#08b2dc;border-color:#042c43}
.lgp-mast .lgp-fset-lg{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.22)}
.lgp-mast .lgp-filter-in{align-items:flex-end}
.lgp-mast .lgp-freset{color:#b7dcee}
.lgp-mast .lgp-freset:hover{color:#fff}
@media(max-width:820px){
  .lgp-mast .lgp-filter{position:static}
  .lgp-mast .lgp-filter-in{grid-template-columns:1fr;align-items:stretch}
  .lgp-price{min-width:0}
  .lgp-fset-lg .lgp-fbtn{font-size:13.5px;padding:10px 6px}
  .lgp-banner{padding:16px 18px}
  .lgp-banner-a{width:100%;justify-content:space-between}
  .lgp-block{padding:26px 0 24px}
}

/* ---- Check availability popup ------------------------------------------------
   The card CTA was a mailto carrying a 500 character body: a dead click on webmail,
   no lead record, nothing to measure, on all 152 cards. It is now a real link to
   /trip-request-form/ that the script upgrades into this dialog. Markup and
   behaviour are in lgp-current-specials.php.

   Named .lgp-ck* after the .lgp-vip* popup in lgp-promotions-routing.php, because
   it is the same object doing the same job and the two get read together.
   ---------------------------------------------------------------------------- */
.lgp-ckmask{position:fixed;inset:0;z-index:99997;display:none;padding:24px;
  background:rgba(4,44,67,.66);
  /* No align-items and no justify-content: the box carries margin:auto, which wins
     over both and centres it on either axis. The VIP mask sets flex-start because it
     is the mask that scrolls there; here it is the box, so a tall dialog is capped
     rather than pushed off the top.
     The MASK does not scroll and the body is not locked either. Pinning the body is
     how a modal loses the reader's place on a page 17 sections long, and on iOS it
     jumps to the top on close. The box scrolls instead. One step under the VIP
     mask's 99998 so the two can never contend for a layer; they are never both up. */
  overflow:hidden}
.lgp-ckmask.is-open{display:flex}
.lgp-ckbox{position:relative;margin:auto;width:100%;max-width:560px;max-height:100%;
  /* y auto, x hidden, stated separately rather than left to compute. overflow-y on
     its own makes overflow-x compute to auto, and the form's honeypot is parked at
     left:-9999px, which would hand the box 9999px of horizontal scroll. */
  overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  background:var(--g);border-radius:16px;padding:28px 26px 20px;
  box-shadow:0 30px 80px -20px rgba(4,44,67,.65);animation:lgpckin .16s ease-out}
@keyframes lgpckin{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.lgp-ckbox h2{font-size:23px;padding-right:38px}   /* clear of the close button */
.lgp-cklede{margin-top:6px!important;font-size:14.5px;color:var(--mut);max-width:52ch}
.lgp-ckclose{position:absolute;top:12px;right:12px;z-index:2;width:34px;height:34px;border:0;
  border-radius:50%;background:var(--sf);color:var(--mut);font-size:20px;line-height:1;cursor:pointer}
.lgp-ckclose:hover{background:var(--sunk);color:var(--ink)}
.lgp-ckslot{margin-top:18px}
/* Nothing here styles the form or the departure block inside it. Both are the
   enquiry pipeline's own markup and its own CSS, and the script only writes text
   into the slots that file publishes. */
@media(max-width:600px){
  /* 14px a side leaves a 362px box at 390, and the box is the only thing that
     scrolls, so an on-screen keyboard cannot push the page sideways. */
  .lgp-ckmask{padding:14px}
  .lgp-ckbox{padding:22px 16px 14px;border-radius:14px}
  .lgp-ckbox h2{font-size:20px;padding-right:34px}
}
@media (prefers-reduced-motion:reduce){
  /* Disarmed rather than sped up. The entrance starts at opacity 0, and the blanket
     0.01ms rule further up this file still runs it; the reveal above needs the same
     treatment for the same reason. */
  .lgp-ckbox{animation:none}
}
