.elementor-kit-4{--e-global-color-primary:#0C2A44;--e-global-color-secondary:#F39321;--e-global-color-text:#22303F;--e-global-color-accent:#17B8D4;--e-global-color-htcream:#F6F1E6;--e-global-color-htnavymid:#134668;--e-global-color-htnavydeep:#081E33;--e-global-color-htaccsoft:#F7B04A;--e-global-color-htinksoft:#55636F;--e-global-color-htwhite:#FFFFFF;--e-global-color-htfooter:#050F1C;--e-global-typography-primary-font-family:"Josefin Sans";--e-global-typography-primary-font-weight:600;--e-global-typography-primary-text-transform:uppercase;--e-global-typography-primary-letter-spacing:0.12em;--e-global-typography-secondary-font-family:"Josefin Sans";--e-global-typography-secondary-font-weight:300;--e-global-typography-secondary-text-transform:uppercase;--e-global-typography-secondary-letter-spacing:0.13em;--e-global-typography-text-font-family:"Jost";--e-global-typography-text-font-size:17.5px;--e-global-typography-text-font-weight:300;--e-global-typography-text-line-height:1.65em;--e-global-typography-accent-font-family:"Cormorant Garamond";--e-global-typography-accent-font-size:1.35rem;--e-global-typography-accent-font-weight:500;--e-global-typography-accent-font-style:italic;background-color:#F6F1E6;color:#22303F;font-family:"Jost", Sans-serif;font-size:17.5px;font-weight:300;line-height:1.65em;}.elementor-kit-4 e-page-transition{background-color:#FFBC7D;}.elementor-kit-4 a{color:#134668;}.elementor-kit-4 a:hover{color:#F39321;}.elementor-section.elementor-section-boxed > .elementor-container{max-width:1180px;}.e-con{--container-max-width:1180px;}.elementor-widget:not(:last-child){--kit-widget-spacing:20px;}.elementor-element{--widgets-spacing:20px 20px;--widgets-spacing-row:20px;--widgets-spacing-column:20px;}{}h1.entry-title{display:var(--page-title-display);}.site-header .site-branding{flex-direction:column;align-items:stretch;}.site-header{padding-inline-end:0px;padding-inline-start:0px;}.site-footer .site-branding{flex-direction:column;align-items:stretch;}@media(max-width:1024px){.elementor-section.elementor-section-boxed > .elementor-container{max-width:1024px;}.e-con{--container-max-width:1024px;}}@media(max-width:767px){.elementor-section.elementor-section-boxed > .elementor-container{max-width:767px;}.e-con{--container-max-width:767px;}}
/* Start custom CSS *//* ================================================================
   HEROIC TRAVEL kit CSS — generated by elementor/_build_kit.py
   Do NOT edit in wp-admin; edit the generator and re-run.
   ---- PRE adaptation: Elementor structure -> static design ---- */

/* neutralize Elementor default spacing; our classes own all spacing */
.elementor-widget:not(:last-child) { margin-block-end: 0; }
.e-con { padding: 0; gap: 0; }

/* Hello theme re-adds element margins (p ~15px, heading margins) at (0,0,1),
   beating the static site's * reset — restate the reset at element level */
h1, h2, h3, h4, h5, h6, p, figure, blockquote, ul, ol {
  margin: 0; padding: 0; }

/* the kit's body typography declares line-height as a LENGTH (inherits as a
   fixed px to every element) — restate the static site's body type exactly,
   with a NUMBER line-height so it scales per element like the static site */
body, body.elementor-kit-4 { font-family: var(--font-body); font-weight: 300;
  font-size: 17.5px; line-height: 1.65; color: var(--ink);
  background: var(--cream); }

/* .wrap as an Elementor container */
.e-con.wrap { max-width: var(--wrap); width: 100%; margin: 0 auto; padding: 0 28px; }

/* headings: Elementor resets .elementor-heading-title AND the kit globals emit
   .elementor-widget-heading .elementor-heading-title{color/font/transform} at
   (0,2,0) — restate at (0,2,1) so our type system wins; contextual color
   overrides then need (0,2,1)+ too (see POST) */
.elementor-widget-heading h1.elementor-heading-title { font-family: var(--font-display);
  text-transform: uppercase; font-size: clamp(2.4rem, 4.6vw, 3.8rem); font-weight: 300;
  letter-spacing: 0.13em; line-height: 1.12; color: var(--white); }
  /* ^ 2026-08-11: homepage hero h1 downsized (2.6/6vw/4.6 -> 2.4/4.6vw/3.8) so the
     2-line lockup holds and the line-logo marquee stays above the fold; matches
     the static .hero h1 override. page-hero h1 mirrors in cluster fragments
     already restate their own (identical 3.8rem-max) clamp. */
.elementor-widget-heading h2.elementor-heading-title { font-family: var(--font-display);
  text-transform: uppercase; font-size: clamp(1.7rem, 3.4vw, 2.5rem); font-weight: 400;
  letter-spacing: 0.14em; line-height: 1.2; color: inherit; }
.elementor-widget-heading h3.elementor-heading-title { font-family: var(--font-display);
  text-transform: uppercase; font-size: 1.02rem; font-weight: 600; letter-spacing: 0.12em;
  line-height: 1.65; color: var(--navy); }
.elementor-widget-heading span.elementor-heading-title,
.elementor-widget-heading p.elementor-heading-title,
.elementor-widget-heading div.elementor-heading-title {
  font: inherit; color: inherit; line-height: inherit; letter-spacing: inherit;
  text-transform: inherit; }

/* text-editor wrappers are capped max-width:100% by an Elementor
   doubled-specificity rule (.elementor.elementor .e-con > .elementor-widget,
   (0,3,0)) — width-limited text classes need !important */
.elementor-widget.lead { max-width: 640px !important; }
.elementor-widget.hero-sub { max-width: 560px !important; }
/* Restore the hero copy -> CTA gap. styles.css sets this via a `margin` on
   `.hero-sub`, but in WP `.hero-sub` is a class on the WIDGET WRAPPER, and the
   PRE rule `.elementor-widget:not(:last-child){margin-block-end:0}` above
   zeroes it — the buttons ended up touching the paragraph (measured gap: 0px).
   Restate the same clamp at wrapper level so the floor survives. */
.elementor-widget.hero-sub { margin-block-end: clamp(1.8rem, 3.4vh, 2.4rem) !important; }

/* the Text Editor widget re-declares a FIXED line-height, 0.9em paragraph
   margins and the global text color via rules injected AFTER the kit CSS —
   neutralize ONLY those at (0,2,0). (Not font-size/family: that would beat
   our wrapper-level classes like .lead/.hero-sub.) Color mirrors for
   wrapper-level color classes live in the POST block. */
.elementor-widget.elementor-widget-text-editor { line-height: inherit; }
.elementor-widget-text-editor p { margin-block-start: 0; margin-block-end: 0; }

/* Button widget: classes live on the WIDGET wrapper (btn btn-accent …),
   the styled element is the inner .elementor-button. The wrapper itself must
   NOT take the .btn box styles (padding/gradient/shadow would paint a ghost
   box behind the real button) — neutralize wrapper, restyle inner. */
.elementor-widget-button.btn { padding: 0; border: 0; border-radius: 0;
  background: none !important; box-shadow: none !important; }
.elementor-widget-button.btn:hover { transform: none; box-shadow: none !important; }
.elementor-widget-button.btn .elementor-button { font-family: var(--font-display);
  text-transform: uppercase; letter-spacing: 0.16em; font-weight: 600; font-size: 0.86rem;
  font-style: normal; line-height: 1.65; display: inline-block;
  padding: 17px 36px 15px; border-radius: 3px;
  text-decoration: none; border: 1px solid transparent; cursor: pointer;
  background-image: none;
  transition: transform 0.25s ease, box-shadow 0.25s ease, background 0.25s ease, color 0.25s; }
.elementor-widget-button.btn .elementor-button:hover { transform: translateY(-2px); }
.elementor-widget-button.btn-accent .elementor-button {
  background: linear-gradient(135deg, var(--accent-soft), var(--accent));
  color: var(--navy-deep); box-shadow: 0 8px 24px rgba(243, 147, 33, 0.35); }
.elementor-widget-button.btn-accent .elementor-button:hover {
  box-shadow: 0 14px 30px rgba(243, 147, 33, 0.5); }
.elementor-widget-button.btn-ghost .elementor-button {
  background: rgba(255, 255, 255, 0.08); color: var(--white);
  border-color: rgba(255, 255, 255, 0.65); backdrop-filter: blur(3px); }
.elementor-widget-button.btn-ghost .elementor-button:hover {
  background: rgba(255, 255, 255, 0.18); }
.elementor-widget-button.btn-navy .elementor-button {
  background: var(--navy); color: var(--cream); box-shadow: 0 8px 22px rgba(8, 30, 51, 0.3); }
.elementor-widget-button.btn-navy .elementor-button:hover {
  background: var(--navy-2); box-shadow: 0 14px 30px rgba(8, 30, 51, 0.4); }


/* Nav Menu widget mapped to .site-nav link styling.
   !important: the widget's style DEFAULTS emit element-scoped rules at
   (0,4,0) (.elementor-NNN .elementor-element-xxx …) that beat any class.
   SPECIFICITY (0,4,0) via the .elementor-widget-nav-menu prefix is load-bearing:
   the header template CSS (post-144.css) enqueues AFTER the kit CSS and carries
   the widget's GLOBAL-typography defaults at (0,3,0)
   (.elementor-widget-nav-menu .elementor-nav-menu .elementor-item
    {font-weight:600; letter-spacing:0.12em; …}) — at equal (0,3,0) it would win
   on load order. AND Pro's widget-nav-menu.min.css re-applies the default
   padding:13px 20px at (0,3,1) on a:hover/a:focus/a.highlighted, which made the
   hovered link balloon and the whole menu row jump sideways on mouseover. */
.site-nav .elementor-nav-menu--main .elementor-nav-menu { display: flex; gap: 26px;
  flex-wrap: nowrap; }
.site-nav .elementor-nav-menu--main li { margin: 0; }
.elementor-widget-nav-menu.site-nav .elementor-nav-menu--main .elementor-item {
  font-family: var(--font-display);
  text-transform: uppercase; font-size: 0.8rem; font-weight: 400; letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.85) !important; text-decoration: none; padding: 0 0 4px;
  border-bottom: 1px solid transparent; transition: color 0.2s, border-color 0.2s; }
.elementor-widget-nav-menu.site-nav .elementor-nav-menu--main .elementor-item:hover,
.elementor-widget-nav-menu.site-nav .elementor-nav-menu--main .elementor-item:focus,
.elementor-widget-nav-menu.site-nav .elementor-nav-menu--main .elementor-item.highlighted,
.elementor-widget-nav-menu.site-nav .elementor-nav-menu--main .elementor-item.elementor-item-active {
  color: var(--accent-soft) !important; border-color: var(--accent-soft);
  padding: 0 0 4px; }

/* Elementor Pro Form mapped to the static .form-card look.
   !important on colors/backgrounds: the Form widget's style DEFAULTS emit
   element-scoped rules at (0,4,0) (field bg #fff, button bg = global accent,
   button color #fff) that beat any class-based rule. */
/* Row spacing. This was `margin-bottom: 0`, which removed ALL separation
   between field rows: the label only had 7px beneath it and nothing above, so
   every label sat flush against the PREVIOUS row's input and read as belonging
   to the wrong control ("PHONE" hugging the Full Name box). Elementor's own
   row gap comes from the widget's column padding, which the card layout
   overrides — so state the gap here explicitly. */
.form-card .elementor-field-group { margin-bottom: 18px; }
.form-card .elementor-field-group:last-of-type { margin-bottom: 0; }
/* the submit row already carries its own top margin on the button */
.form-card .elementor-field-type-submit { margin-bottom: 0; }
.form-card .elementor-field-group label { display: block;
  font-family: var(--font-display) !important; text-transform: uppercase;
  font-size: 0.7rem !important; font-weight: 600 !important;
  letter-spacing: 0.18em !important; line-height: 1.65;
  color: var(--navy) !important;
  /* bind the label to the field BELOW it, not the one above */
  margin-top: 0; margin-bottom: 7px; }
.form-card .elementor-field-group .elementor-field-textual { width: 100%;
  font-family: var(--font-body) !important; font-size: 1rem !important;
  font-weight: 300 !important;
  color: var(--ink) !important; background: var(--cream) !important;
  border: 1px solid #ddd2b8 !important; border-radius: 5px !important;
  line-height: normal; padding: 13px 15px;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s; }
.form-card .elementor-field-group .elementor-field-textual:focus { outline: none;
  border-color: var(--teal) !important; background: var(--white) !important;
  box-shadow: 0 0 0 3px rgba(23, 184, 212, 0.22); }
.form-card textarea.elementor-field-textual { resize: vertical; min-height: 96px; }
.form-card .elementor-select-wrapper .select-caret-down-wrapper { display: none; }
.form-card select.elementor-field-textual { appearance: auto; -webkit-appearance: menulist; }
.form-card .elementor-field-type-submit .elementor-button { width: 100%; margin-top: 8px;
  font-family: var(--font-display); text-transform: uppercase; letter-spacing: 0.16em;
  font-weight: 600; font-size: 0.86rem; padding: 17px 36px 15px; border-radius: 3px;
  border: 1px solid transparent; background: var(--navy) !important;
  color: var(--cream) !important; box-shadow: 0 8px 22px rgba(8, 30, 51, 0.3);
  background-image: none !important;
  transition: transform 0.25s ease, box-shadow 0.25s ease, background 0.25s ease; }
.form-card .elementor-field-type-submit .elementor-button:hover {
  transform: translateY(-2px); background: var(--navy-2) !important;
  box-shadow: 0 14px 30px rgba(8, 30, 51, 0.4); }
/* ---- end PRE ---- */

/* ============================================================
   HEROIC TRAVEL — Golden Age of Ocean Travel
   Palette from brand logo: deep navy / cream / sun orange / sky teal
   Type: Josefin Sans (display caps) · Jost (body) · Cormorant Garamond (accents)
   ============================================================ */

:root {
  /* palette — accent colors sampled from the Heroic Travel logo */
  --navy: #0c2a44;
  --navy-2: #134668;
  --navy-deep: #081e33;
  --cream: #f6f1e6;
  --cream-2: #efe7d6;
  --white: #ffffff;
  --accent: #f39321;      /* logo sun orange — decorative use + on dark only */
  --accent-soft: #f7b04a;
  /* Accessible text-on-light variant of the sun orange. The logo orange is
     2.07:1 on cream / 2.33:1 on white — small italic eyebrow text needs 4.5:1
     (21.6px @ weight 500 is NOT WCAG "large text"). Same hue family, darkened
     until it passes: 4.63:1 on cream, 5.22:1 on white. Use for TEXT on light
     surfaces; keep --accent for fills, rules, borders and dark-section text. */
  --accent-ink: #a35a0c;
  --teal: #17b8d4;        /* logo sky teal — small doses only */
  --ink: #22303f;
  --ink-soft: #55636f;

  /* page-specific imagery — swap per service/page, never hardcode in rules */
  --img-hero: url("https://heroictravel.com/wp-content/uploads/2026/08/hero-ship.jpg");
  --img-band: url("https://heroictravel.com/wp-content/uploads/2026/08/band-sunset.jpg");
  --img-band-2: url("https://heroictravel.com/wp-content/uploads/2026/08/band-sunset-2.jpg");

  --font-display: "Josefin Sans", sans-serif;
  --font-body: "Jost", sans-serif;
  --font-accent: "Cormorant Garamond", serif;

  --shadow-card: 0 10px 30px rgba(8, 30, 51, 0.12);
  --shadow-card-hover: 0 22px 44px rgba(8, 30, 51, 0.22);
  --radius: 10px;
  --wrap: 1180px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal {
    animation: none !important; transition: none !important;
    opacity: 1 !important; transform: none !important;
  }
}
/* testing hook: ?noanim=1 (set by main.js) renders everything without motion */
html.noanim { scroll-behavior: auto; }
html.noanim .reveal {
  animation: none !important; transition: none !important;
  opacity: 1 !important; transform: none !important;
}
/* full-page screenshot mode: vh + fixed backgrounds misbehave in a tall headless window */
html.noanim .hero { min-height: 860px; }
html.noanim .page-hero { min-height: 640px; }
html.noanim .band { min-height: 0; }
html.noanim .hero, html.noanim .page-hero, html.noanim .band, html.noanim .form-section {
  background-attachment: scroll;
}

body {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 17.5px;
  line-height: 1.65;
  color: var(--ink);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 28px; }

/* ---------- type ---------- */
h1, h2, h3 { font-family: var(--font-display); text-transform: uppercase; }

h1 {
  font-size: clamp(2.6rem, 6vw, 4.6rem);
  font-weight: 300;
  letter-spacing: 0.13em;
  line-height: 1.12;
  color: var(--white);
}
h1 strong { font-weight: 700; color: var(--accent-soft); }

h2 {
  font-size: clamp(1.7rem, 3.4vw, 2.5rem);
  font-weight: 400;
  letter-spacing: 0.14em;
  line-height: 1.2;
}

h3 { font-size: 1.02rem; font-weight: 600; letter-spacing: 0.12em; }

.eyebrow {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 500;
  font-size: 1.35rem;
  letter-spacing: 0.02em;
  color: var(--accent-ink);   /* WCAG AA on cream/white; see --accent-ink */
  display: block;
  margin-bottom: 0.6rem;
}
/* on dark grounds the brand orange is already 7.9:1 — keep the true brand color */
.on-dark .eyebrow { color: var(--accent-soft); }

.lead { font-size: 1.14rem; color: var(--ink-soft); max-width: 640px; }
.on-dark .lead { color: rgba(246, 240, 226, 0.82); }

/* deco divider: — ◆ —  (PURE CSS, no markup)
   Was 533 HTML widgets on WP (a <div class="rule-deco"><span></span></div> per
   section head). It carries zero content, so it is now drawn entirely as a
   pseudo-element on the elements that surround it — see --deco.

   One pseudo-element has to carry all three marks, so the two gradient rules
   and the diamond are three background LAYERS in a single 161x13 box
   (64 + 12 + 16 + 12 + 64 = 168). The diamond must be a real rotated square:
   a conic-gradient fills its whole box regardless of angle and renders as a
   SQUARE, so the mark is an inline-SVG data URI.
   2026-08-12: the teal diamond is now a small CRUISE LINER (hull +
   superstructure + funnel) at Frank's request — it reads unmistakably as a
   ship at 16px on both cream and navy, and it is one variable so the swap
   lands on every divider site-wide. Box grew 13px -> 16px to fit the hull. */
:root {
  --deco-w: 168px;
  --deco-h: 16px;
  /* 2026-08-13: the ship was teal (#17b8d4) and popped out of the divider —
     it read as a third colour sitting between two orange dashes. It is now
     GOLD by default so the whole mark reads as one continuous rule, and
     WHITE on dark sections (see .deco-on-dark below) where gold-on-navy is
     lower contrast than white.

     The fill is a variable, NOT baked into the data URI, so a section can
     re-colour the ship without restating the whole SVG. Note the fill value
     must be URL-ENCODED inside the data URI — `#` becomes `%23`, which is why
     these are `%23f39321` rather than `#f39321`. */
  --deco-ship: %23f39321;         /* = --accent (#f39321), URI-encoded */
  --deco: linear-gradient(90deg, transparent, var(--accent)) left center / 64px 1px no-repeat,
          linear-gradient(90deg, var(--accent), transparent) right center / 64px 1px no-repeat,
          url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2716%27%20height%3D%2716%27%20viewBox%3D%270%200%2016%2016%27%3E%3Cpath%20d%3D%27M1.6%2010.2h12.8l-1.5%203.1a1%201%200%200%201-.9.6H4a1%201%200%200%201-.9-.6Z%27%20fill%3D%27%23f39321%27%2F%3E%3Crect%20x%3D%274.2%27%20y%3D%276.9%27%20width%3D%277.6%27%20height%3D%273%27%20fill%3D%27%23f39321%27%2F%3E%3Crect%20x%3D%279.4%27%20y%3D%273.6%27%20width%3D%271.8%27%20height%3D%273%27%20fill%3D%27%23f39321%27%2F%3E%3C%2Fsvg%3E") center center / var(--deco-h) var(--deco-h) no-repeat;

  /* White-hulled variant for dark/navy sections. A white ship on navy is
     considerably more legible than gold, and it echoes the real thing. */
  --deco-white: linear-gradient(90deg, transparent, var(--accent)) left center / 64px 1px no-repeat,
          linear-gradient(90deg, var(--accent), transparent) right center / 64px 1px no-repeat,
          url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2716%27%20height%3D%2716%27%20viewBox%3D%270%200%2016%2016%27%3E%3Cpath%20d%3D%27M1.6%2010.2h12.8l-1.5%203.1a1%201%200%200%201-.9.6H4a1%201%200%200%201-.9-.6Z%27%20fill%3D%27%23ffffff%27%2F%3E%3Crect%20x%3D%274.2%27%20y%3D%276.9%27%20width%3D%277.6%27%20height%3D%273%27%20fill%3D%27%23ffffff%27%2F%3E%3Crect%20x%3D%279.4%27%20y%3D%273.6%27%20width%3D%271.8%27%20height%3D%273%27%20fill%3D%27%23ffffff%27%2F%3E%3C%2Fsvg%3E") center center / var(--deco-h) var(--deco-h) no-repeat;
}

/* The divider always sat in one of two positions:
   (a) immediately BEFORE a .lead / .hero-sub paragraph  -> ::before on that
   (b) as the LAST child of .section-head / .form-aside  -> ::after on the parent
   Margins reproduce the old .rule-deco `margin: 1.15rem 0 1.6rem`. */
.section-head > .lead::before,
.form-aside > .lead::before,
.hero .wrap > .hero-sub::before {
  content: ""; display: block;
  width: var(--deco-w); height: var(--deco-h);
  margin: 1.15rem 0 1.6rem;
  background: var(--deco);
}
.section-head:not(:has(> .lead))::after,
.form-aside:not(:has(> .lead))::after {
  content: ""; display: block;
  width: var(--deco-w); height: var(--deco-h);
  margin: 1.15rem 0 0;   /* trailing margin collapses away when it ends the head */
  background: var(--deco);
}
/* centered heads center the flourish (was .rule-deco.center{justify-content:center}) */
.section-head.center > .lead::before,
.section-head.center::after { margin-inline: auto; }

/* On phones/tablets the hero copy runs full-width, so a fixed 168px deco with
   `margin: ... 0 ...` sits hard left and reads as broken alignment. Centre it.
   (Desktop keeps it left-aligned: there the copy is a narrow left column.) */
@media (max-width: 860px) {
  .hero .wrap > .hero-sub::before { margin-inline: auto; }
}

/* White-hulled ship on DARK backgrounds. The gold ship is right on cream, but
   on navy it sits close in value to the orange dashes and muddies; a white
   hull reads instantly and matches a real ship. Every dark context is listed
   here — hero, page hero, parallax bands, and the navy form section. */
.hero .wrap > .hero-sub::before,
.hero .section-head > .lead::before,
.hero .section-head::after,
.page-hero .section-head > .lead::before,
.page-hero .section-head::after,
.band .section-head > .lead::before,
.band .section-head::after,
.band > .lead::before,
.form-section .section-head > .lead::before,
.form-section .section-head::after,
.form-aside > .lead::before,
.form-aside:not(:has(> .lead))::after,
/* .bg-navy is a FLAT dark section (no photo) — the biggest single consumer of
   the divider, and it was missed on the first pass: the gold ship sat on navy
   and read muddy. Any `.on-dark` section gets the white hull too. */
.bg-navy .section-head > .lead::before,
.bg-navy .section-head::after,
.on-dark .section-head > .lead::before,
.on-dark .section-head::after {
  background: var(--deco-white);
}

/* ---------- buttons ---------- */
.btn {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-weight: 600;
  font-size: 0.86rem;
  display: inline-block;
  padding: 17px 36px 15px;
  border-radius: 3px;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.25s ease, box-shadow 0.25s ease, background 0.25s ease, color 0.25s;
}
.btn:hover { transform: translateY(-2px); }

/* sun orange — primary on dark sections */
.btn-accent {
  background: linear-gradient(135deg, var(--accent-soft), var(--accent));
  color: var(--navy-deep);
  box-shadow: 0 8px 24px rgba(243, 147, 33, 0.35);
}
.btn-accent:hover { box-shadow: 0 14px 30px rgba(243, 147, 33, 0.5); }

/* ghost — only ever on dark/photo sections */
.btn-ghost {
  background: rgba(255, 255, 255, 0.08);
  color: var(--white);
  border-color: rgba(255, 255, 255, 0.65);
  backdrop-filter: blur(3px);
}
.btn-ghost:hover { background: rgba(255, 255, 255, 0.18); }

/* navy — primary on light sections */
.btn-navy {
  background: var(--navy);
  color: var(--cream);
  box-shadow: 0 8px 22px rgba(8, 30, 51, 0.3);
}
.btn-navy:hover { background: var(--navy-2); box-shadow: 0 14px 30px rgba(8, 30, 51, 0.4); }

/* ---------- header ---------- */
.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  padding: 22px 0;
  transition: background 0.35s ease, padding 0.35s ease, box-shadow 0.35s;
}
/* Unscrolled, the header floats over whatever photo is behind it. A soft
   top-down scrim guarantees the logo, descriptor and nav always have ground
   to sit on — without this, legibility depends on which ship frame is
   showing. Disappears once .scrolled paints a solid bar. */
.site-header::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(rgba(8, 30, 51, 0.55), rgba(8, 30, 51, 0));
  transition: opacity 0.35s ease;
}
.site-header.scrolled::before { opacity: 0; }
.site-header.scrolled {
  background: rgba(8, 30, 51, 0.94);
  padding: 13px 0;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(8px);
}
.site-header .wrap { display: flex; align-items: center; justify-content: space-between; gap: 20px; }

/* Logo only — the art already carries the wordmark. The "Cruise Specialists"
   descriptor was removed 2026-08-12: beside the nav it read as a run-on menu,
   stacked under the logo it read as out of place. The positioning line lives
   in the hero H1, the <title> and the schema instead. */
.brand { display: flex; align-items: center; text-decoration: none; }
.brand-plate { display: flex; align-items: center; }
.brand-plate img {
  /* larger at rest (was 74px) so the wordmark is legible before scroll;
     still shrinks to a compact bar once .scrolled kicks in */
  height: 92px; width: auto; display: block;
  transition: height 0.35s ease;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.35));
}
.site-header.scrolled .brand-plate img { height: 54px; }

.site-nav { display: flex; align-items: center; gap: 26px; }
.site-nav a, .nav-actions .btn { white-space: nowrap; }
.site-nav a:not(.btn) {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.8rem; font-weight: 400; letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.95);
  /* the header is transparent over photos until it sticks — hold an edge */
  text-shadow: 0 1px 3px rgba(8, 30, 51, 0.7);
  text-decoration: none;
  padding-bottom: 4px;
  border-bottom: 1px solid transparent;
  transition: color 0.2s, border-color 0.2s;
}
.site-nav a:not(.btn):hover { color: var(--accent-soft); border-color: var(--accent-soft); }
.site-nav .btn { padding: 12px 24px 10px; font-size: 0.76rem; }

/* ---------- hero ---------- */
.hero {
  position: relative;
  min-height: 100vh;
  padding-bottom: 0; /* generic section padding would float the logo strip above the hero's bottom edge */
  display: flex; flex-direction: column; justify-content: flex-start;
  overflow: hidden;
}
/* ---- rotating hero ship photos ----
   Each ship is its own layer BEHIND the gradient scrim, so a crossfade never
   touches the scrim (fading the whole stack would visibly pulse the overlay
   and the headline's contrast with it). The .hero background-image gradient
   above still paints over these because they sit at z-index 0 and .hero's own
   background renders behind its children — so the scrim is re-applied here as
   a sibling layer instead. */
.hero-slides { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero-slide {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center 38%;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 1.5s ease-in-out;
  will-change: opacity;
}
.hero-slide.is-active { opacity: 1; }
/* The scrim, restated above the slides.
   TWO layers, because a single top-to-bottom gradient can't solve this:
   the ship photos put bright sunlit mountain/glare exactly where the copy
   sits, and measured worst-case pixel contrast fell to ~1.0:1 (invisible)
   even though the AVERAGE looked fine. So:
   1) a left-to-right wash that darkens the text column specifically, and
   2) the original vertical scrim for overall depth + the logo strip.
   Text lives in the left ~55%, hence the horizontal ramp. */
.hero-slides::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(95deg, rgba(8, 30, 51, 0.72) 0%, rgba(8, 30, 51, 0.55) 32%,
      rgba(8, 30, 51, 0.12) 58%, rgba(8, 30, 51, 0.02) 100%),
    linear-gradient(178deg, rgba(8, 30, 51, 0.30) 0%,
      rgba(8, 30, 51, 0.12) 42%, rgba(8, 30, 51, 0.72) 100%);
}
/* on narrow screens the copy spans the full width — go back to an even wash */
@media (max-width: 860px) {
  .hero-slides::after {
    background:
      linear-gradient(rgba(8, 30, 51, 0.62), rgba(8, 30, 51, 0.62)),
      linear-gradient(178deg, rgba(8, 30, 51, 0.58) 0%,
        rgba(8, 30, 51, 0.36) 45%, rgba(8, 30, 51, 0.86) 100%);
  }
}
/* When the rotation is present the container's own photo would double up.
   Uses an explicit class rather than :has() so the fallback is never a
   double-painted background on an older engine. */
.hero.has-slides { background-image: none; background-color: var(--navy-deep); }
/* .hero-slides carries its own scrim — never let a second one stack on it */
.hero.has-slides::after { display: none; }
@media (prefers-reduced-motion: reduce) {
  .hero-slide { transition: none; }
}
html.noanim .hero-slide { transition: none; }

/* margin-block auto centers the content in the space above the logo strip */
.hero .wrap { position: relative; z-index: 2; margin-block: auto;
  padding-top: clamp(96px, 12vh, 110px); padding-bottom: clamp(20px, 4vh, 36px); }
/* sized so the authored 2-line lockup holds at desktop widths (same max as .page-hero h1) */
.hero h1 { font-size: clamp(2.4rem, 4.6vw, 3.8rem); }

.hero-compass {
  position: absolute; right: -140px; top: 50%;
  width: 560px; height: 560px;
  transform: translateY(-50%);
  opacity: 0.1; z-index: 1;
  animation: compass-spin 240s linear infinite;
  pointer-events: none;
}
@keyframes compass-spin { to { transform: translateY(-50%) rotate(360deg); } }

.hero-sub {
  font-size: 1.2rem; font-weight: 300;
  color: rgba(246, 240, 226, 0.88);
  max-width: 560px;
  /* bottom gap sets the CTA separation — keep a real floor so the buttons
     never crowd the copy on short viewports */
  margin: clamp(0.9rem, 2vh, 1.3rem) 0 clamp(1.8rem, 3.4vh, 2.4rem);
}
.hero-ctas { display: flex; gap: 18px; flex-wrap: wrap; }

.hero-stats {
  display: flex; gap: 0;
  margin-top: clamp(1.4rem, 3vh, 2.8rem);
  border-top: 1px solid rgba(247, 176, 74, 0.35);
  max-width: 720px;
}
.hero-stats div {
  padding: 22px 44px 0 0;
  margin-right: 44px;
  border-right: 1px solid rgba(247, 176, 74, 0.22);
}
.hero-stats div:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.hero-stats b {
  display: block;
  font-family: var(--font-display);
  font-size: 2rem; font-weight: 300; letter-spacing: 0.06em;
  color: var(--accent-soft);
}
.hero-stats span {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.68rem; letter-spacing: 0.22em;
  color: rgba(255, 255, 255, 0.75);
}

/* short viewports (laptops ~720-850px tall): shed hero height so the logo
   strip still lands on the fold instead of below it */
@media (min-width: 861px) and (max-height: 850px) {
  .hero h1 { font-size: clamp(2rem, 3.4vw, 2.7rem); }
  .hero-sub { font-size: 1.04rem; max-width: 620px; margin-bottom: 1.6rem; }
  .hero-ctas .btn { padding: 13px 26px 11px; }
  .hero-stats { margin-top: 1rem; }
  .hero-stats div { padding-top: 12px; }
  .hero-stats b { font-size: 1.5rem; }
  .line-marquee { padding: 12px 0; }
  .line-marquee img { height: 24px; }
  .line-marquee img[src*="virgin-voyages"] { height: 37px; }
}
@media (min-width: 861px) and (max-height: 740px) {
  .hero .wrap { padding-top: 92px; }
  .hero-stats { display: none; } /* last thing to go: keeps the strip on the fold */
}

.hero-scroll {
  position: absolute; left: 50%; bottom: 26px; z-index: 2;
  transform: translateX(-50%);
  color: rgba(255, 255, 255, 0.7);
  font-size: 1.4rem; text-decoration: none;
  animation: bob 2.4s ease-in-out infinite;
}
@keyframes bob { 0%, 100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 9px); } }

/* ---------- generic sections ---------- */
section { padding: 96px 0; }
.section-head { max-width: 720px; margin-bottom: 3.2rem; }
.section-head.center { margin-inline: auto; text-align: center; }

.bg-cream { background: var(--cream); }
.bg-white { background: var(--white); }
.bg-navy {
  background:
    radial-gradient(1100px 500px at 85% -10%, rgba(243, 147, 33, 0.08), transparent 60%),
    linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
  color: var(--cream);
}
.bg-navy h2 { color: var(--white); }

/* scroll-reveal */
.reveal { opacity: 0; transform: translateY(34px); transition: opacity 0.8s ease, transform 0.8s cubic-bezier(0.16, 1, 0.3, 1); }
.reveal.in { opacity: 1; transform: none; }

/* ---------- why cards (white cards on cream) ---------- */
.why-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px;
}
.why-card {
  height: 100%;
  background: var(--white);
  border-radius: var(--radius);
  border-top: 3px solid var(--accent);
  padding: 34px 28px 30px;
  box-shadow: var(--shadow-card);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.why-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-card-hover); }
/* House rule: a card must contrast the section it sits on. .why-card is white,
   which is correct on .bg-cream (homepage) but invisible-by-shade on .bg-white
   (all 10 cruise-line pages) where only the 3px accent rule + shadow separated
   it. Flip those to cream — the same opposite-shade treatment .line-card
   already uses on navy. Section shade is NOT changed: cruise-line rhythm is
   page-hero/cream/white/navy/band/cream, so a cream section here would collide
   with the cream section above it. */
.bg-white .why-card { background: var(--cream); }
.why-card .icon {
  width: 52px; height: 52px;
  margin-bottom: 20px;
  color: var(--navy);
}
.why-card h3 { color: var(--navy); margin-bottom: 10px; }
.why-card p { font-size: 0.98rem; color: var(--ink-soft); }

/* ---------- cruise lines (cream cards on navy) ---------- */
.lines-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 20px;
}
.line-card {
  position: relative;
  height: 100%;
  background: var(--cream);
  border-radius: var(--radius);
  padding: 30px 20px 24px;
  text-align: center;
  overflow: hidden;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.line-card:hover { transform: translateY(-6px); box-shadow: 0 22px 44px rgba(0, 0, 0, 0.5); }
.line-card .pennant {
  position: absolute; top: 0; left: 50%;
  transform: translateX(-50%);
  width: 30px; height: 22px;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 62%, 0 100%);
}
.line-card h3 { color: var(--navy); font-size: 0.95rem; margin: 14px 0 6px; }
.line-card p {
  font-family: var(--font-accent);
  font-style: italic;
  font-size: 1.02rem; line-height: 1.35;
  color: var(--ink-soft);
}
a.line-card {
  text-decoration: none;
  display: flex;
  flex-direction: column;
  align-items: center;
}
a.line-card p { flex: 1; }
.line-more {
  display: inline-block;
  margin-top: auto;
  padding-top: 14px;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.66rem; font-weight: 600; letter-spacing: 0.18em;
  color: var(--navy-2);
  border-bottom: 2px solid var(--accent);
  padding-bottom: 2px;
  opacity: 0.85;
  transition: color 0.2s, opacity 0.2s;
}
.line-card:hover .line-more { color: var(--accent); opacity: 1; }
.lines-note {
  text-align: center;
  margin-top: 2.6rem;
  font-family: var(--font-accent); font-style: italic;
  font-size: 1.25rem;
  color: rgba(246, 240, 226, 0.75);
}

/* ---------- destinations (photo cards on white) ---------- */
.dest-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 26px;
}
.dest-card {
  position: relative;
  height: 100%; min-height: 380px;
  border-radius: var(--radius);
  overflow: hidden;
  display: flex; align-items: flex-end;
  box-shadow: var(--shadow-card);
  transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.dest-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-card-hover); }
.dest-card img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.6s ease;
}
.dest-card:hover img { transform: scale(1.06); }
/* per-photo crop bias so the subject survives the portrait crop */
.dest-card.crop-med img { object-position: 60% 40%; }
.dest-card .veil {
  position: absolute; inset: 0;
  background: linear-gradient(185deg, rgba(8, 30, 51, 0) 40%, rgba(8, 30, 51, 0.88) 92%);
}
.dest-card { text-decoration: none; }
.dest-card figcaption, .dest-caption { position: relative; padding: 24px 22px; width: 100%; }
.dest-more {
  display: inline-block;
  margin-top: 10px;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.18em;
  color: var(--white);
  border-bottom: 1px solid var(--accent-soft);
  padding-bottom: 3px;
  opacity: 0.85;
  transition: opacity 0.25s, color 0.25s;
}
.dest-card:hover .dest-more { opacity: 1; color: var(--accent-soft); }
.dest-card h3 { color: var(--white); margin-bottom: 4px; }
/* These are full sentences, not labels. Cormorant Garamond is a high-contrast
   DISPLAY serif — at ~15px, italic, on a dark photo its thin strokes break up
   and it reads as decorative rather than legible. House rule keeps the accent
   serif for eyebrows and pull-quotes only; body copy uses the body face. */
.dest-caption p,
.dest-card p {
  font-family: var(--font-body); font-style: normal; font-weight: 300;
  color: var(--accent-soft); font-size: 0.98rem; line-height: 1.45;
}

/* ---------- parallax band ---------- */
.band {
  position: relative;
  min-height: 62vh;
  display: flex; align-items: center;
  text-align: center;
  padding: 110px 0;
}
.band blockquote {
  font-family: var(--font-accent);
  font-style: italic; font-weight: 500;
  font-size: clamp(1.7rem, 3.6vw, 2.7rem);
  line-height: 1.35;
  color: var(--cream);
  max-width: 820px; margin: 0 auto 2rem;
}
.band blockquote em { color: var(--accent-soft); font-style: inherit; }

/* ---------- steps ---------- */
.steps-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; }
.step-card {
  height: 100%;
  background: var(--white);
  border-radius: var(--radius);
  padding: 40px 30px 32px;
  text-align: center;
  box-shadow: var(--shadow-card);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.step-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-card-hover); }
.step-num {
  width: 62px; height: 62px;
  margin: 0 auto 20px;
  border-radius: 50%;
  border: 1px solid var(--accent);
  outline: 3px solid rgba(243, 147, 33, 0.18);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display);
  font-size: 1.5rem; font-weight: 300;
  color: var(--navy);
  background: linear-gradient(160deg, var(--cream), var(--white));
}
.step-card h3 { color: var(--navy); margin-bottom: 10px; }
.step-card p { font-size: 0.98rem; color: var(--ink-soft); }

/* ---------- interest form (light panel on navy) ---------- */
.form-section {
  color: var(--cream);
}
.form-columns {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 70px;
  align-items: start;
}
.form-aside .perk { display: flex; gap: 16px; margin-top: 26px; }
.form-aside .perk svg { width: 26px; height: 26px; flex: none; color: var(--accent-soft); margin-top: 3px; }
.form-aside .perk b {
  display: block;
  font-family: var(--font-display); text-transform: uppercase;
  font-weight: 600; font-size: 0.88rem; letter-spacing: 0.14em;
  color: var(--white); margin-bottom: 3px;
}
.form-aside .perk p { font-size: 0.96rem; color: rgba(246, 240, 226, 0.75); }

.form-card {
  background: var(--white);
  color: var(--ink);
  border-radius: var(--radius);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}
.form-card-head {
  background: linear-gradient(135deg, var(--navy), var(--navy-2));
  border-bottom: 3px solid var(--accent);
  padding: 22px 34px;
  display: flex; justify-content: space-between; align-items: center;
}
.form-card-head h3 { color: var(--white); font-size: 1.05rem; }
.form-card-head span {
  font-family: var(--font-body); font-style: normal; font-weight: 300;
  color: var(--accent-soft); font-size: 0.96rem; line-height: 1.5;
}
.form-card form { padding: 34px; }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.field { margin-bottom: 18px; }
.field label {
  display: block;
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.18em;
  color: var(--navy);
  margin-bottom: 7px;
}
.field input, .field select, .field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem; font-weight: 300;
  color: var(--ink);
  background: var(--cream);
  border: 1px solid #ddd2b8;
  border-radius: 5px;
  padding: 13px 15px;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--teal);
  background: var(--white);
  box-shadow: 0 0 0 3px rgba(23, 184, 212, 0.22);
}
.field textarea { resize: vertical; min-height: 96px; }
.form-card .btn { width: 100%; margin-top: 8px; }
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.form-error {
  margin-top: 16px;
  padding: 12px 16px;
  border-radius: 5px;
  background: #fdecea;
  border: 1px solid #e5b5ae;
  color: #96281b;
  font-size: 0.92rem;
  text-align: center;
}
.form-note {
  margin-top: 16px;
  font-size: 0.85rem; text-align: center;
  color: var(--ink-soft);
}
.form-success {
  display: none;
  padding: 60px 40px; text-align: center;
}
.form-success svg { width: 60px; height: 60px; color: var(--accent); margin: 0 auto 18px; }
.form-success h3 { color: var(--navy); font-size: 1.3rem; margin-bottom: 10px; }
.form-card.sent form { display: none; }
.form-card.sent .form-success { display: block; }

/* ---------- footer ---------- */
.site-footer {
  background: #050f1c;
  border-top: 2px solid var(--accent);
  color: rgba(246, 240, 226, 0.65);
  padding: 56px 0 34px;
  font-size: 0.92rem;
}
.footer-cols {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 40px; flex-wrap: wrap;
  margin-bottom: 34px;
}
.site-footer .brand-plate img { height: 54px; }
.footer-links { display: flex; gap: 26px; flex-wrap: wrap; }
.footer-links a {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 0.74rem; letter-spacing: 0.18em;
  color: rgba(246, 240, 226, 0.7);
  text-decoration: none;
}
.footer-links a:hover { color: var(--accent-soft); }
/* Touch targets: .footer-links is a standalone nav row, so its links are real
   tap targets and were only 20px tall (font box, no padding) on phones.
   Pad to a >=44px hit area below the burger breakpoint; the 26px flex gap
   absorbs the extra height without changing the desktop layout. */
@media (max-width: 860px) {
  .footer-links { gap: 8px 26px; }
  .footer-links a { padding: 12px 0; }
}
.footer-fine {
  border-top: 1px solid rgba(246, 240, 226, 0.12);
  padding-top: 22px;
  font-size: 0.8rem;
  color: rgba(246, 240, 226, 0.4);
  text-align: center;
}

/* ---------- responsive ---------- */
@media (max-width: 1080px) {
  .lines-grid { grid-template-columns: repeat(4, 1fr); }
  .why-grid, .dest-grid { grid-template-columns: repeat(2, 1fr); }
  .form-columns { grid-template-columns: 1fr; gap: 46px; }
}
@media (max-width: 860px) {
  .site-nav a:not(.btn) { display: none; }
  .lines-grid { grid-template-columns: repeat(3, 1fr); }
  .hero-stats { flex-wrap: wrap; }
  .hero-stats div { border-right: 0; padding-right: 0; margin-right: 30px; }
}
@media (max-width: 640px) {
  section { padding: 70px 0; }
  /* bigger logo on phones (was 44px) — it is the only brand mark visible
     once the descriptor is hidden, so it should carry real presence */
  .brand-plate img { height: 78px; }
  .lines-grid { grid-template-columns: repeat(2, 1fr); }
  .why-grid, .dest-grid, .steps-grid { grid-template-columns: 1fr; }
  .field-row { grid-template-columns: 1fr; gap: 0; }
  .hero-compass { display: none; }

  /* HEADER: logo + burger on ONE line, nothing else.
     The header CTA duplicated the hero's "Plan My Cruise" two lines below it
     and forced the burger to wrap onto its own row. */
  .site-header .wrap { flex-wrap: nowrap; gap: 12px; align-items: center; }
  .nav-actions .btn { display: none; }
  .nav-actions { flex: 0 0 auto; margin-left: auto; }
  .nav-toggle { display: inline-flex; }
  .site-header { padding: 14px 0; }

  /* hero rhythm: give the copy and the stacked CTAs real breathing room */
  /* the authored <br> shapes the desktop 2-line lockup; on a phone the text
     ALSO wraps naturally, so the forced break produced ragged 2-word lines */
  .br-desktop { display: none; }
  /* start the copy closer to the header on small screens */
  .hero .wrap { padding-top: 84px; }
  .hero-sub { margin: 1rem 0 1.6rem; }
  .hero-ctas { gap: 12px; }
  .hero-ctas .btn { width: 100%; text-align: center; }
  .hero-stats { margin-top: 2rem; }

  /* HERO STATS on phones — was a ragged 1-then-2 wrap. The base row metrics
     (margin-right:30px + flex-wrap:wrap) put item 1 alone on row one and items
     2+3 side by side on row two, at three different widths and two different
     left edges. Force one stat per row, full width, common left edge, with a
     hairline separator so the group reads as a deliberate list. */
  .hero-stats { flex-direction: column; flex-wrap: nowrap;
    width: 100%; max-width: none; }
  .hero-stats div {
    width: 100%; margin: 0; padding: 14px 0;
    border-right: 0;
    border-bottom: 1px solid rgba(247, 176, 74, 0.22);
    display: flex; align-items: baseline; gap: 14px;
  }
  .hero-stats div:last-child { border-bottom: 0; }
  /* number + label share a baseline; min-width aligns the figures optically */
  .hero-stats b { min-width: 68px; font-size: 1.7rem; line-height: 1.1; }
  .hero-stats span { line-height: 1.2; }
}

/* HERO STATS at tablet (641-860px): all three stay on one row at EQUAL widths.
   The <=860px rule drops the dividers and relies on intrinsic text width, which
   left the three blocks visibly uneven. */
@media (min-width: 641px) and (max-width: 860px) {
  .hero-stats { flex-wrap: nowrap; width: 100%; }
  .hero-stats div { flex: 1 1 0; margin-right: 0;
    padding: 22px 18px 0 0;
    border-right: 1px solid rgba(247, 176, 74, 0.22); }
  .hero-stats div:last-child { padding-right: 0; border-right: 0; }
}
/* INLINE 3-COL GRIDS: several pages hard-code
   style="grid-template-columns:repeat(3,1fr)" on a grid. An inline style beats
   every media query, so those grids stayed 3-up on phones — at 390px that is
   ~94px columns with the copy spilling outside the cards. Catch them by
   attribute so this covers any page, present or future, not just the ones we
   happened to find. */
@media (max-width: 860px) {
  .why-grid[style*="repeat(3"], .dest-grid[style*="repeat(3"],
  .lines-grid[style*="repeat(3"], .steps-grid[style*="repeat(3"] {
    grid-template-columns: repeat(2, 1fr) !important; }
}
@media (max-width: 640px) {
  .why-grid[style*="repeat(3"], .dest-grid[style*="repeat(3"],
  .lines-grid[style*="repeat(3"], .steps-grid[style*="repeat(3"] {
    grid-template-columns: 1fr !important; }
}

/* ---------- cruise-line logo marquee (bottom of hero, above the fold) ---------- */
.line-marquee {
  position: relative; z-index: 2;
  margin-top: auto;            /* pins the strip to the hero's bottom edge */
  /* Flush to the hero's bottom edge. An earlier margin-bottom lifted it, but
     that exposed a sliver of hero photo BELOW the strip which read as a stray
     thin line. Breathing room comes from the strip's own padding instead. */
  margin-bottom: 0;
  width: 100%;
  background: rgba(8, 30, 51, 0.52);
  /* gold rule, matching the hero CTA gradient — was a faint .28 wash that
     read as a grey hairline rather than a deliberate brand line */
  border-top: 1px solid var(--accent);
  padding: 22px 0 26px;
  overflow: hidden;
}
.line-marquee-track {
  display: flex;
  align-items: center;
  /* Equal GAP, not equal slot. An earlier attempt gave every logo an identical
     168px slot: mathematically even, visually worse — wide marks (Disney,
     Holland America) crowded their neighbours while narrow ones (Virgin, MSC)
     sat in obvious pockets. What actually reads as even is consistent optical
     weight: each mark is capped in WIDTH as well as height so no logo
     dominates, then separated by a uniform gap. */
  gap: 56px;
  width: max-content;
  padding-inline: 28px;
  animation: line-marquee-scroll 45s linear infinite;
}
.line-marquee:hover .line-marquee-track { animation-play-state: paused; }
.line-marquee img {
  /* Optical balance, not identical boxes: cap the wide wordmarks (Disney,
     Holland America, Cunard) AND give the compact marks a minimum footprint,
     so Virgin's small portrait emblem doesn't sit in a visible pocket next to
     a 132px wordmark. Width spread goes 5.4x -> ~1.6x; contain keeps every
     logo's own aspect ratio intact. */
  height: 28px;
  width: auto;
  min-width: 84px;
  max-width: 132px;
  object-fit: contain;
  object-position: center;
  display: block;
  opacity: 0.92;
  flex: 0 0 auto;
}
/* Virgin is a tall portrait mark — it needs more height to carry the same
   optical weight as the wordmarks at this size */
.line-marquee img[src*="virgin-voyages"] { height: 40px; }
/* Virgin's mark is a portrait emblem — needs more height to match visual weight */
.line-marquee img[src*="virgin-voyages"] { height: 46px; }
@keyframes line-marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); } /* track holds two copies of the set */
}
@media (prefers-reduced-motion: reduce) {
  .line-marquee-track { animation: none; flex-wrap: wrap; justify-content: center; width: 100%; }
  .line-marquee-track .line-marquee-dup { display: none; }
}
html.noanim .line-marquee-track { animation: none; }
@media (max-width: 640px) {
  .line-marquee { padding: 14px 0; margin-bottom: 0; }
  .line-marquee img { height: 22px; }
  .line-marquee img[src*="virgin-voyages"] { height: 34px; }
  .line-marquee-track { gap: 40px; }
}
/* fixed backgrounds are janky/unsupported on touch devices */
@media (hover: none), (max-width: 860px) {
  .hero, .band, .form-section { background-attachment: scroll; }
}

/* ============================================================
   DESTINATION PAGES (template — each page sets its own
   --img-hero / --img-band in a page-scoped <style> block)
   ============================================================ */

.page-hero {
  position: relative;
  /* 74vh + bottom-aligned content left a huge empty band between the header
     and the first line of text on every inner page, at every viewport — the
     taller the screen, the worse it got. Sized to the content instead, with
     the copy CENTRED so the photo frames it rather than stranding it. */
  min-height: 52vh;
  display: flex; align-items: center;
}
/* padding-top only clears the fixed header; the rest is breathing room */
.page-hero .wrap { padding-top: 118px; padding-bottom: 54px; }
@media (max-width: 860px) {
  .page-hero {
    min-height: 40vh;
    /* narrow screens: copy spans the full width, so an even wash reads better
       than a left-weighted one */
  }
  .page-hero .wrap { padding-top: 96px; padding-bottom: 40px; }
}
@media (max-width: 640px) {
  .page-hero { min-height: 34vh; }
  .page-hero .wrap { padding-top: 84px; padding-bottom: 32px; }
}
.page-hero h1 {
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  margin: 0.4rem 0 1rem;
}
.page-hero .lead { color: rgba(246, 241, 230, 0.9); font-size: 1.16rem; }

.breadcrumbs {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.72rem; letter-spacing: 0.22em;
  color: rgba(246, 241, 230, 0.75);
}
.breadcrumbs a { color: var(--accent-soft); text-decoration: none; }
.breadcrumbs a:hover { text-decoration: underline; }
.breadcrumbs .sep { margin: 0 8px; color: rgba(246, 241, 230, 0.4); }

/* quick facts chips */
.facts-row { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 1.8rem; }
.fact-chip {
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(247, 176, 74, 0.45);
  backdrop-filter: blur(4px);
  border-radius: 4px;
  padding: 10px 18px;
}
.fact-chip b {
  display: block;
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 0.62rem; font-weight: 600; letter-spacing: 0.2em;
  color: var(--accent-soft);
}
.fact-chip span { font-size: 0.95rem; color: var(--white); }

/* alternating photo/text port rows */
.port-block {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 60px;
  align-items: center;
  padding: 34px 0;
}
.port-block + .port-block { border-top: 1px solid rgba(12, 42, 68, 0.1); }
.port-block.flip .port-media { order: 2; }
.port-media { position: relative; }
.port-media img {
  width: 100%; height: auto;
  border-radius: var(--radius);
  box-shadow: var(--shadow-card-hover);
}
.port-media::after {
  content: "";
  position: absolute; inset: 14px -14px -14px 14px;
  border: 2px solid var(--accent);
  border-radius: var(--radius);
  z-index: -1; opacity: 0.55;
}
.port-block.flip .port-media::after { inset: 14px 14px -14px -14px; }
/* COLOUR-AUDIT: this eyebrow ("Glacier Bay National Park", "Juneau", …) used
   the raw logo orange --accent as BODY TEXT on a white card: 19.2px italic at
   weight 300 measured 2.33:1 — not WCAG "large text", so it needs 4.5:1 and
   failed badly. --accent-ink is the palette's WCAG-passing orange for exactly
   this case (same hue family; 5.22:1 on white, 4.63:1 on cream). Keep --accent
   for fills/rules/icons and for text on DARK sections; .port-copy is a
   light-surface block only (its sibling h3 is navy, its p is --ink-soft). */
.port-copy .tag {
  font-family: var(--font-accent); font-style: italic;
  font-size: 1.2rem; color: var(--accent-ink);
}
.port-copy h3 {
  font-size: 1.5rem; font-weight: 400; letter-spacing: 0.1em;
  color: var(--navy); margin: 0.4rem 0 1rem;
}
.port-copy p { color: var(--ink-soft); margin-bottom: 1rem; }
.exc-list { list-style: none; margin-top: 1.2rem; }
.exc-list li {
  padding: 9px 0 9px 30px;
  position: relative;
  border-bottom: 1px dashed rgba(12, 42, 68, 0.15);
  font-size: 0.98rem;
}
.exc-list li:last-child { border-bottom: 0; }
.exc-list li::before {
  content: "";
  position: absolute; left: 4px; top: 16px;
  width: 8px; height: 8px;
  background: var(--teal);
  transform: rotate(45deg);
}
.exc-list b { color: var(--navy); font-weight: 500; }

/* excursion photo cards (on navy) */
.exc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
}
.exc-card {
  height: 100%;
  background: var(--white);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.4);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.exc-card:hover { transform: translateY(-6px); box-shadow: 0 26px 50px rgba(0, 0, 0, 0.55); }
.exc-card img { width: 100%; height: 210px; object-fit: cover; }
.exc-card .exc-body { padding: 22px 24px 24px; flex: 1; }
.exc-card h3 { color: var(--navy); font-size: 0.95rem; margin-bottom: 8px; }
.exc-card p { font-size: 0.93rem; color: var(--ink-soft); }

/* FAQ */
.faq-list { max-width: 820px; margin: 0 auto; }
.faq-list details {
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  margin-bottom: 14px;
  overflow: hidden;
}
.faq-list summary {
  cursor: pointer;
  list-style: none;
  padding: 20px 54px 20px 26px;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.9rem; font-weight: 600; letter-spacing: 0.1em;
  color: var(--navy);
  position: relative;
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary::after {
  content: "+";
  position: absolute; right: 24px; top: 50%;
  transform: translateY(-50%);
  font-size: 1.4rem; font-weight: 300; color: var(--accent);
  transition: transform 0.25s ease;
}
.faq-list details[open] summary::after { transform: translateY(-50%) rotate(45deg); }
/* Answer panel padding.
   The native nested-accordion nests the answer as:
     details.e-n-accordion-item > DIV.e-con  (the content container)
       > DIV.elementor-widget-text-editor > p
   The container was rendering `0 26px 22px` — NO top padding, so the answer
   sat hard against the question while 22px of air pooled beneath it. The
   earlier fix missed because it keyed on .e-n-accordion-item-content, which
   this Elementor version does not emit; the container is a plain .e-con.
   Target the item's direct child container instead, and keep the legacy
   <details> markup working for anything not yet converted. */
.faq-list .e-n-accordion-item > div,
.faq-list .e-n-accordion-item > .e-con,
.faq-list .elementor-accordion-content {
  padding: 18px 26px 20px !important;
  color: var(--ink-soft);
}
.faq-list details > p { padding: 18px 26px 20px; color: var(--ink-soft); }
/* inner widget wrappers must not add their own vertical padding on top */
.faq-list .e-n-accordion-item > div > .elementor-element,
.faq-list .e-n-accordion-item > .e-con > .elementor-widget { padding-block: 0; margin: 0; }

/* pre-footer CTA panel */
.cta-panel { text-align: center; }
.cta-panel .btn { margin-top: 1.6rem; }

/* sister-destination links */
.more-dest { display: flex; justify-content: center; gap: 18px; flex-wrap: wrap; margin-top: 2.4rem; }
.more-dest a {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 0.78rem; letter-spacing: 0.16em;
  color: var(--cream);
  text-decoration: none;
  border: 1px solid rgba(246, 241, 230, 0.4);
  border-radius: 3px;
  padding: 12px 22px 10px;
  transition: border-color 0.2s, color 0.2s, background 0.2s;
}
.more-dest a:hover { border-color: var(--accent-soft); color: var(--accent-soft); }

@media (max-width: 900px) {
  .port-block { grid-template-columns: 1fr; gap: 30px; }
  .port-block.flip .port-media { order: 0; }
  .exc-grid { grid-template-columns: 1fr; }
  .page-hero { background-attachment: scroll; }
}

/* excursion-guide links under port blocks */
.exc-guide-link { margin-top: 14px; }
.exc-guide-link a {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.76rem; font-weight: 600; letter-spacing: 0.16em;
  color: var(--navy-2);
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 3px;
}
.exc-guide-link a:hover { color: var(--accent); }

/* ============================================================
   df-optimize pass: mobile nav, focus states, a11y hardening
   ============================================================ */

/* actions cluster (CTA + burger) */
.nav-actions { display: flex; align-items: center; gap: 14px; }

/* burger — hidden on desktop */
.nav-toggle {
  display: none;
  flex-direction: column; justify-content: center; gap: 5px;
  width: 46px; height: 44px;
  padding: 10px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 5px;
  cursor: pointer;
}
.nav-toggle span {
  display: block; height: 2px; width: 100%;
  background: var(--white);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.25s ease;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 860px) {
  .nav-toggle { display: flex; }
  .nav-actions { gap: 10px; }
  .nav-actions .btn {
    padding: 11px 14px 9px;
    font-size: 0.66rem;
    letter-spacing: 0.12em;
    white-space: nowrap;
  }
  .site-header { padding: 12px 0; }
  .site-header .wrap { gap: 10px; }
  /* the earlier rule hid links entirely; the panel now owns them */
  .site-nav { gap: 0; }
  .site-nav a:not(.btn) {
    display: block;
    padding: 16px 28px;
    font-size: 0.95rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  }
  .site-nav {
    position: fixed;
    top: 0; left: 0; right: 0;
    padding-top: 84px;
    flex-direction: column;
    align-items: stretch;
    background: rgba(8, 30, 51, 0.98);
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
    transform: translateY(-105%);
    visibility: hidden;
    transition: transform 0.3s ease, visibility 0.3s;
    z-index: -1; /* beneath the header bar itself */
  }
  .site-nav.open { transform: none; visibility: visible; }
}

/* keyboard focus — visible everywhere, teal ring per brand */
a:focus-visible, button:focus-visible, summary:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 2px;
  border-radius: 3px;
}

/* submit button while sending */
.btn:disabled { opacity: 0.55; cursor: wait; transform: none; }

/* contrast lifts (house rule: no sub-0.55 alphas on body text) */
.footer-fine { color: rgba(246, 241, 230, 0.65); }
.site-footer { color: rgba(246, 241, 230, 0.78); }
.footer-links a { color: rgba(246, 241, 230, 0.82); }

/* reduced motion: stop the compass and the burger/panel animation too */
@media (prefers-reduced-motion: reduce) {
  .hero-compass { animation: none !important; }
  .site-nav, .nav-toggle span, .hero-scroll { transition: none !important; animation: none !important; }
}
html.noanim .hero-compass { animation: none !important; }

/* ============================================================
   Printable checklists (resources/)
   ============================================================ */
.printable {
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 44px 48px;
  max-width: 900px;
  margin: 0 auto;
}
.printable-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 20px;
  border-bottom: 3px solid var(--accent);
  padding-bottom: 18px; margin-bottom: 26px;
}
.printable-head h2 { color: var(--navy); font-size: 1.4rem; }
.printable-head .pmark {
  font-family: var(--font-body); font-style: normal; font-weight: 300;
  color: var(--ink-soft); font-size: 0.94rem; text-align: right;
}
.chk-cols { columns: 2; column-gap: 44px; }
.chk-group { break-inside: avoid; margin-bottom: 22px; }
.chk-group h3 {
  color: var(--navy-2); font-size: 0.85rem;
  border-bottom: 1px solid rgba(12, 42, 68, 0.15);
  padding-bottom: 6px; margin-bottom: 10px;
}
.chk { list-style: none; }
.chk li {
  position: relative;
  padding: 4px 0 4px 30px;
  font-size: 0.96rem;
  color: var(--ink);
}
.chk li::before {
  content: "";
  position: absolute; left: 2px; top: 8px;
  width: 14px; height: 14px;
  border: 2px solid var(--navy-2);
  border-radius: 3px;
}
.chk li small { color: var(--ink-soft); }
.print-actions { text-align: center; margin: 2rem 0 0; }
.printable-foot {
  margin-top: 26px; padding-top: 16px;
  border-top: 1px solid rgba(12, 42, 68, 0.15);
  font-size: 0.82rem; color: var(--ink-soft);
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
}

@media (max-width: 700px) {
  .chk-cols { columns: 1; }
  .printable { padding: 28px 22px; }
}

@media print {
  .site-header, .page-hero, .band, .form-section, .site-footer,
  .print-actions, .bg-cream .section-head, section.bg-cream:first-of-type { display: none !important; }
  body, section { background: #fff !important; padding: 0 !important; }
  .printable { box-shadow: none; border-radius: 0; padding: 0; max-width: none; }
  .printable-head { border-color: #333; }
  .printable-head h2, .chk-group h3 { color: #000; }
  .chk li { color: #000; }
  .chk li::before { border-color: #000; }
  .reveal { opacity: 1 !important; transform: none !important; }
  @page { margin: 0.6in; }
}

/* ---------- blog archive / single-post hero ----------
   The shared .page-hero is sized for destination pages (74vh + 150px top
   padding, bottom-aligned). On the blog that stranded the H1 271px down the
   page with nothing above it. These pages carry less hero content, so the
   hero is shallower and the copy sits higher. */
.blog-hero.page-hero { min-height: 46vh; }
/* The shared .page-hero is align-items:flex-end — content hugs the bottom, so
   on a short blog hero the H1 sat 271px down with nothing above it. Centre the
   content instead: the sky becomes balanced framing rather than dead space. */
.e-con.e-flex.blog-hero.page-hero { align-items: center; }
.blog-hero.page-hero .wrap { padding-top: 96px; padding-bottom: 40px; }
@media (max-width: 640px) {
  .blog-hero.page-hero { min-height: 38vh; }
  .blog-hero.page-hero .wrap { padding-top: 88px; padding-bottom: 30px; }
}

/* ---------- blog post cards ----------
   WP Compress injects width/height attrs + an inline `aspect-ratio` from the
   MEDIUM thumbnail (300x225) onto the featured image. At rest the card CSS
   wins, but on hover Elementor's own rules re-assert and that inline ratio
   snapped the image to 300px wide — it visibly shrank and shifted right.
   Pin the frame and let object-fit do the cropping in every state. */
.elementor-post__thumbnail { position: relative; overflow: hidden; }
/* Blog card thumbnails are owned entirely by kit-additions/blog.css, which
   pins the image with `position:absolute; inset:0` inside a padding-ratio
   frame and applies the hover zoom. An earlier rule here forced
   `width/height:100% !important` + `aspect-ratio:auto` onto that absolutely
   positioned image, which broke the containment: on hover the image escaped
   its frame (measured 169px right, 112px below the container) instead of
   zooming inside it. The ONLY thing still needed here is neutralising WP
   Compress's injected inline `aspect-ratio`, scoped so it cannot fight the
   absolute positioning. */
.elementor-post__thumbnail img[style*="aspect-ratio"] {
  aspect-ratio: auto !important;
}

/* ---- POST adaptation: must beat styles.css + Elementor element rules ---- */

/* ---- STICKY HEADER MUST BE OPAQUE ONCE STUCK ----
   The stuck header is rgba(8,30,51,0.94) — 6% transparent. On a long article
   that is enough for the prose scrolling underneath to ghost through the bar,
   which reads as a line of text sliced in half. A fixed header ALWAYS overlaps
   content that scrolls beneath it; extra page margin cannot fix that (margin
   only moves where the page starts). The fix is to make the bar fully opaque
   so whatever passes under it is cleanly hidden.
   The unstuck/transparent-over-hero state is untouched — only the stuck bar.

   DO NOT add `.elementor-sticky--active` to this list. That class means
   "sticky behaviour is engaged", NOT "the user has scrolled" — Elementor
   applies it at scrollY 0 on some templates (it did exactly that on the
   search-results page, which rendered the header permanently navy while
   every other template was correctly transparent over its hero).
   `--effects` is the scroll-triggered class and is the right hook; `.scrolled`
   is the static site's own JS class, kept for parity. */
.site-header.elementor-sticky--effects,
.site-header.scrolled {
  background-color: var(--navy-deep) !important;
  backdrop-filter: none;
}

/* ---- PARALLAX BAND FRAMING ----
   2026-08-13: the three photos were REPLACED with 3200px-wide originals that
   are properly framed (subject in the lower-middle, not the bottom quarter).
   Measured detail-centre is now ~66% for band-sunset, ~72% for band-sunset-2,
   ~63% for hero-ship — versus 83/77/87% on the old 1024px files.

   With `background-attachment: fixed`, the image is sized to cover the
   VIEWPORT (e.g. 1440x900), not the section. A 558px-tall band is then just a
   window onto that taller image, so the focal point still has to be pulled
   below centre for the vessel and horizon to land inside the band — but far
   less than before. The old 78%/72% compensation was tuned to the OLD photos'
   low subject placement and now overshoots, pushing the vessel off the bottom.

   Verified by simulating the fixed-attachment crop (viewport-cover -> 558px
   band window) and then screenshotting the live band: 48% seats the vessel in
   the lower third of the band, clear of the centred quote + CTA button (at
   55% the hull ran behind the "START MY VOYAGE" button).
   Set here rather than per call-site so every consumer (bands, page heroes,
   the form section, the 404) is framed consistently from one place. */
.e-con.band,
.e-con.form-section {
  background-position: 50% 48% !important;
}
.e-con.page-hero {
  background-position: 50% 52% !important;
}
/* On short viewports the fixed-attachment window is shorter still, so bias
   a little further toward the subject. */
@media (max-height: 800px) {
  .e-con.band,
  .e-con.form-section { background-position: 50% 60% !important; }
}
/* Phones drop fixed attachment (iOS never supported it and repaints badly),
   so the image is sized to the SECTION and normal centring is correct. */
@media (max-width: 860px) {
  .e-con.band,
  .e-con.form-section,
  .e-con.page-hero { background-position: 50% 60% !important; }
}

/* ---- BACK-TO-TOP ----
   Markup + behaviour come from the ht-seo mu-plugin (wp_footer), so the
   control exists on every page type including the archive, single posts and
   the 404. Sits bottom-right, above the sticky header's z-index but below any
   modal. Navy disc + gold chevron so it reads as part of the furniture rather
   than a browser default. */
.ht-to-top {
  position: fixed;
  right: clamp(16px, 2vw, 28px);
  bottom: clamp(16px, 2.4vh, 30px);
  z-index: 70;                 /* header is 60 */
  width: 46px; height: 46px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid rgba(247, 176, 74, 0.55);
  border-radius: 50%;
  background: rgba(8, 30, 51, 0.92);
  color: var(--accent-soft);
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32);
  backdrop-filter: blur(6px);
  /* fade/slide in — the JS toggles `hidden` for semantics and `.is-in` for
     the transition, so the button is never focusable while invisible */
  opacity: 0; transform: translateY(8px);
  transition: opacity 0.22s ease, transform 0.22s ease,
              background 0.2s ease, border-color 0.2s ease;
}
.ht-to-top.is-in { opacity: 1; transform: none; }
.ht-to-top:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--navy);
}
.ht-to-top:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 3px;
}
.ht-to-top svg { display: block; }
/* `hidden` must actually hide it — Elementor's reset sets display on buttons */
.ht-to-top[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .ht-to-top { transition: opacity 0.01ms; transform: none; }
}
/* keep it clear of the phone's bottom browser chrome */
@media (max-width: 640px) {
  .ht-to-top { width: 42px; height: 42px; bottom: max(16px, env(safe-area-inset-bottom)); }
}

/* photo-section scrims (formerly part of the CSS background stack; the photo
   itself is the Elementor container background now) */
.hero, .page-hero, .band, .form-section { position: relative; }
.hero::after, .page-hero::after, .band::after, .form-section::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.hero::after { background: linear-gradient(178deg, rgba(8, 30, 51, 0.62) 0%,
  rgba(8, 30, 51, 0.4) 45%, rgba(8, 30, 51, 0.83) 100%); }
.page-hero::after { background:
  linear-gradient(95deg, rgba(8, 30, 51, 0.74) 0%, rgba(8, 30, 51, 0.58) 34%,
    rgba(8, 30, 51, 0.18) 64%, rgba(8, 30, 51, 0.06) 100%),
  linear-gradient(178deg, rgba(8, 30, 51, 0.42) 0%, rgba(8, 30, 51, 0.22) 45%,
    rgba(8, 30, 51, 0.72) 100%); }
.band::after { background: rgba(8, 30, 51, 0.55); }
.form-section::after { background: linear-gradient(rgba(8, 30, 51, 0.9), rgba(8, 30, 51, 0.94)); }
.hero .wrap, .page-hero .wrap, .band .wrap, .form-section .wrap {
  position: relative; z-index: 2; }
.hero .hero-compass, .hero .hero-scroll { z-index: 1; }

/* ---- PAGE-HERO: CENTRE THE COPY VERTICALLY ----
   styles.css gives the hero wrap `padding-top: 96px; padding-bottom: 40px`
   (and 84/30 on phones). The CONTAINER is already `align-items: center`, so
   the box measures as centred — but that 56px of asymmetry inside the wrap
   pushes the breadcrumb/title/date visibly low in the frame.

   Make the padding symmetric and let the flex centring actually do its job.
   Kept as a floor rather than zero so the copy never touches the fixed header
   on a short viewport. */
.e-con.page-hero > .e-con.wrap,
.e-con.page-hero .wrap {
  padding-top: 68px;
  padding-bottom: 68px;
}
@media (max-width: 860px) {
  .e-con.page-hero > .e-con.wrap,
  .e-con.page-hero .wrap {
    padding-top: 30px;
    padding-bottom: 30px;
  }
}

/* section rhythm padding (containers aren't <section> .elementor-kit-4-safe vs .e-con) */
.e-con.htsec { padding: 96px 0; }
@media (max-width: 640px) { .e-con.htsec { padding: 70px 0; } }
/* hero: no bottom padding, so the logo marquee pins to the real bottom edge */
.e-con.htsec.hero { padding-bottom: 0; }

/* Rotating hero photos: the .hero-slides wrapper is emitted inside an HTML
   WIDGET, and that widget wrapper collapses to height 0 (its only child is
   absolutely positioned). The slide layers then have no painted ancestor box
   and the photo never appears — the hero rendered as flat navy on WP while
   being correct on the static site. Give the widget wrapper the full hero box
   and take it out of flex flow so it cannot claim a row of its own.
   (Same family as trap #8: widget wrappers are position:relative and size to
   their in-flow children.) */
.elementor-widget-html.hero-slides-slot {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; padding: 0; z-index: 0; pointer-events: none;
}
/* .hero-slides paints its OWN scrim (::after). The container's .hero::after
   scrim must not also fire, or the photo is darkened twice and the ship
   disappears into the navy. */
.hero.has-slides::after { display: none; }
/* short-viewport hero shrink (styles.css @media max-height:850px) sets a bare
   `.hero h1`, which loses to the kit's (0,2,1) heading rule — mirror it */
@media (min-width: 861px) and (max-height: 850px) {
  .hero .elementor-widget-heading h1.elementor-heading-title {
    font-size: clamp(2rem, 3.4vw, 2.7rem); }
  /* WP's header occupies flow space (static's is fixed), so 100vh would push
     the strip past the fold — subtract the header from the hero's min-height */
  .e-con.htsec.hero { min-height: calc(100vh - var(--ht-header-h, 96px)); }
  .e-con.htsec.hero > .wrap { padding-top: 24px; }
}

/* HTML widget wrappers must not hijack absolutely-positioned children
   (compass, hero-scroll, pennants, dest-card img/veil anchor to the CARD,
   not the widget wrapper, which Elementor makes position:relative) */
.elementor-widget-html { position: static; }

/* .e-con.e-flex sets flex-direction at (0,2,0), beating bare-class rules —
   mirror every static rule that needs a non-default direction.
   (Cluster agents: any class whose static CSS sets flex-direction needs an
   .e-con.e-flex.CLASS mirror here.) */
.e-con.e-flex.dest-card { flex-direction: row; }
.e-con.e-flex.band { flex-direction: row; align-items: center; }
.e-con.e-flex.hero { flex-direction: column; justify-content: flex-start; }
/* logo marquee pins to the hero's bottom edge; .wrap margin-block:auto
   (styles.css) centers the content in the space above it */
.e-con.hero > .elementor-widget-html.line-marquee-slot { margin-top: auto; width: 100%; }
.hero .line-marquee { z-index: 2; }
.e-con.e-flex.page-hero { flex-direction: row; align-items: center; }
.e-con.e-flex.line-card { flex-direction: column; align-items: center; }

/* contextual heading colors/sizes that must beat the (0,2,1) PRE restatements
   (cluster agents: contextual h1/h2/h3 tweaks in styles.css need mirrors at
   hX.elementor-heading-title specificity here) */
.bg-navy h2.elementor-heading-title { color: var(--white); }
.line-card h3.elementor-heading-title { font-size: 0.95rem; }
.exc-card h3.elementor-heading-title { font-size: 0.95rem; }
.port-copy h3.elementor-heading-title { font-size: 1.5rem; font-weight: 400;
  letter-spacing: 0.1em; color: var(--navy); }

/* static flex containers blockify inline SVG children; inside an HTML widget
   the svg stays inline and grows a baseline gap — force block */
.why-card .icon { display: block; }

/* Hello theme sets h3{line-height:1.2}; static h3 inherits the body 1.65 */
h3 { line-height: 1.65; }

/* widget-margin neutralizer above also kills class margins on wrappers —
   restate the ones our layout relies on */
.elementor-widget.eyebrow { margin-block-end: 0.6rem; }
/* ---- rule-deco: the — ◆ — divider, now PURE CSS (533 html widgets deleted) ----
   styles.css draws it as a pseudo-element on the elements that surrounded it.
   Two Elementor-DOM adaptations are needed:

   (a) In Elementor, `.lead` / `.hero-sub` sit on the WIDGET WRAPPER
       (.elementor-widget.lead), which is still a direct child of
       .section-head / .form-aside — so styles.css's `> .lead::before` already
       matches. But `.hero .wrap > .hero-sub` does NOT: the homepage hero's
       wrap holds widget wrappers, so restate it at wrapper specificity.
   (b) `:has()` in styles.css tests `> .lead`; that holds in the Elementor DOM
       too (same direct-child relationship), so the ::after branch needs no
       mirror — but .form-aside's deco is followed by a lead on EVERY page, so
       only the ::before branch ever fires there.

   NOTE: the old markup version needed
   `.section-head > .elementor-widget:last-child .rule-deco{margin-bottom:0}`
   because a widget wrapper stops the trailing margin collapsing. The
   pseudo-element replaces that with an explicit `margin-bottom:0` on the
   ::after branch, so no wrapper rule is required. */
.hero .wrap > .elementor-widget.hero-sub::before {
  content: ""; display: block;
  width: var(--deco-w); height: var(--deco-h);
  margin: 1.15rem 0 1.6rem;
  background: var(--deco);
}

/* HERO DECO ON MOBILE — centre it.
   The deco is a fixed 168px pseudo-element with `margin: ... 0 ...`, i.e.
   left-aligned. On desktop that is invisible because the hero copy column is
   narrow and left-aligned anyway. On a phone the hero text runs the full
   width, so a 168px flourish sitting hard left reads as broken alignment
   (reported twice with screenshots).

   styles.css only ever centres the deco for `.section-head.center`; the hero
   variant was never given a centring path at all. `margin-inline: auto` is the
   same mechanism, applied to the .elementor-kit-4 that actually wins in the Elementor
   DOM (the widget-wrapper one above).

   Scoped to <=860px: that is where the hero copy stops being a narrow column.
   Verified at 412px and 768px. */
@media (max-width: 860px) {
  .hero .wrap > .elementor-widget.hero-sub::before {
    margin-inline: auto;
  }
}

/* Elementor's `.elementor a { box-shadow:none }` beats bare-class card rules
   on linked containers — restore at a.card specificity */
a.line-card { box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35); }
a.line-card:hover { box-shadow: 0 22px 44px rgba(0, 0, 0, 0.5); }
a.dest-card { box-shadow: var(--shadow-card); }
a.dest-card:hover { box-shadow: var(--shadow-card-hover); }

/* wrapper-level text colors/sizes: Elementor's late-injected
   .elementor-widget-text-editor{color/font-size:…} beats bare classes —
   mirror every text class that sets its own color or size */
.elementor-widget-text-editor.lead { color: var(--ink-soft); font-size: 1.14rem; }
.on-dark .elementor-widget-text-editor.lead { color: rgba(246, 240, 226, 0.82); }
.elementor-widget-text-editor.hero-sub { color: rgba(246, 240, 226, 0.88);
  font-size: 1.2rem; }
.elementor-widget-text-editor.lines-note { color: rgba(246, 240, 226, 0.75);
  font-size: 1.25rem; }

/* static inline-style equivalents */
.section-head.center .lead { margin-inline: auto; }
.dest-grid.dest-grid-3 { grid-template-columns: repeat(3, 1fr) !important; }
/* ...but NOT on phones. The static site's inline 3-col style applied at every
   width, which at 390px produced three ~100px columns with the card copy
   overflowing outside them. Stack instead. */
@media (max-width: 860px) {
  .dest-grid.dest-grid-3 { grid-template-columns: repeat(2, 1fr) !important; }
}
@media (max-width: 640px) {
  .dest-grid.dest-grid-3 { grid-template-columns: 1fr !important; }
}

/* line-card flex distribution across widget wrappers */
.line-card > .elementor-widget-text-editor { flex: 1 1 auto; }
.line-card > .elementor-widget:last-child { margin-top: auto; }
.band .wrap { align-items: center; }

/* form card: form padding split so the note HTML widget sits inside the card */
.form-card form { padding: 34px 34px 0; }
.form-card .ht-form-note { padding: 0 34px 34px; }
.form-card .elementor-message { margin-top: 16px; font-size: 0.92rem; text-align: center; }
.form-card .elementor-message.elementor-message-success { color: var(--navy); }

/* sticky header (Elementor sticky replaces .scrolled JS) */
.site-header.elementor-sticky--effects { background: rgba(8, 30, 51, 0.94);
  padding: 13px 0; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35); backdrop-filter: blur(8px); }
.site-header.elementor-sticky--effects .brand-plate img { height: 54px; }
.site-header.elementor-sticky__spacer, .elementor-sticky__spacer.site-header {
  display: none !important; height: 0 !important; }

/* flex-row groups: Elementor children default to width:100%, which defeats
   space-between/intrinsic layouts — make them shrink-to-fit like static */
.site-header .wrap > *, .footer-cols > *, .brand > *, .nav-actions > *,
.hero-ctas > * { width: auto; }

/* Brand block = logo only (descriptor removed 2026-08-12). Pin it so the flex
   row cannot squeeze it into the nav. `.e-con.e-flex` sets flex-direction at
   (0,2,0) — hence the mirror (cascade-war trap #7). */
.e-con.e-flex.brand, .site-header .brand {
  flex: 0 0 auto; flex-direction: row; align-items: center; }
.site-header .wrap { gap: 34px; }

/* MOBILE header + hero rhythm (<=640px).
   The header CTA duplicated the hero's own "Plan My Cruise" a few lines
   below and pushed the burger onto its own row. Logo + burger only.
   Hero CTAs go full-width and stack: at 390px they were 225/284px wide,
   ragged and unequal. Note the .btn classes live on the WIDGET WRAPPER on
   WP (trap #9), so the width rules must target the wrapper AND the inner
   .elementor-button, or they silently miss. */
@media (max-width: 640px) {
  .site-header .wrap { flex-wrap: nowrap; gap: 12px; align-items: center; }
  .site-header .nav-actions .elementor-widget-button.btn { display: none; }
  /* burger vertically centred against the taller mobile logo */
  .site-header .nav-actions { flex: 0 0 auto; margin-left: auto;
    align-self: center; align-items: center; }
  .site-header .brand, .e-con.e-flex.brand { align-self: center; }
  .site-header .brand-plate img { height: 78px; }
  .e-con.e-flex.hero-ctas { flex-direction: column; gap: 12px; width: 100%; }
  .hero-ctas .elementor-widget-button.btn { width: 100% !important; }
  .hero-ctas .elementor-widget-button.btn .elementor-button {
    display: block; width: 100%; text-align: center; }
  /* (hero duplicate-CTA rule lives in its own <=1024px query below, matching
     the breakpoint at which .ht-cta-bar appears) */
  .elementor-widget.hero-sub { margin-bottom: 1.6rem !important; }
  /* the authored <br> shapes the desktop 2-line lockup; on a phone the text
     also wraps naturally, so it produced ragged 2-word lines */
  .br-desktop { display: none; }
  /* Copy starts closer to the header on phones. This was `.e-con.wrap
     { padding-top: 0 }` — far too broad: at (0,2,0) it beat
     `.page-hero .wrap` (0,1,1) and zeroed the top padding on EVERY inner
     page, so the breadcrumb rendered ~20px UNDER the fixed header. Scope it
     to the homepage hero only, and restate page-hero at equal specificity. */
  .e-con.hero > .e-con.wrap { padding-top: 84px !important; }
  /* page-hero needs the same 84px clearance so the breadcrumb never renders
     under the fixed header — but it must be SYMMETRIC, or the copy sits low
     in the frame (was 84 top / 30 bottom, which read as bottom-weighted even
     though the container is align-items:center). */
  .e-con.page-hero > .e-con.wrap {
    padding-top: 84px !important;
    padding-bottom: 84px !important;
  }
  .hero .hero-stats { margin-top: 2rem; }

  /* HERO STATS on phones (<=640px) — was a ragged 1-then-2 wrap.
     Base CSS gives each block `margin-right:30px` with `flex-wrap:wrap`, so at
     390px item 1 took row one and items 2+3 shared row two, at three different
     intrinsic widths (157/119/146px) and two different left edges (28/28/177).
     That is what read as unintentional. Force ONE stat per row, every block the
     full column width and flush to the same left edge, separated by a hairline
     rule so the group reads as a deliberate list rather than floating text. */
  .hero .hero-stats {
    flex-direction: column;
    flex-wrap: nowrap;
    width: 100%;
    max-width: none;
  }
  .hero .hero-stats > div {
    /* override the base row metrics (margin-right/padding-right/border-right),
       which only make sense when the blocks sit side by side */
    width: 100%;
    margin: 0 !important;
    padding: 14px 0 !important;
    border-right: 0 !important;
    /* hairline separator between stacked rows, matching the strip's top rule */
    border-bottom: 1px solid rgba(247, 176, 74, 0.22);
    display: flex;
    align-items: baseline;
    gap: 14px;
  }
  /* the strip's own top border already closes the bottom of the last row */
  .hero .hero-stats > div:last-child { border-bottom: 0; }
  /* number and label on one baseline: at full width a stacked b+span left a
     large dead gap on the right of every row */
  .hero .hero-stats > div b {
    display: block;
    min-width: 68px;   /* aligns "10+", "$0", "1:1" into one optical column */
    font-size: 1.7rem;
    line-height: 1.1;
  }
  .hero .hero-stats > div span { line-height: 1.2; }
}

/* ------------------------------------------------------------------
   HERO CTA vs STICKY BAR — kill the duplicate "Plan My Cruise".

   `.ht-cta-bar` (sticky-cta.css) is a fixed bottom bar carrying an
   identical orange "Plan My Cruise" button. It is visible at
   `max-width: 1024px`, so on phones AND tablets the hero button and the
   sticky bar showed the same CTA on one screen, ~150px apart.

   BREAKPOINT MUST MATCH THE BAR, not the phone breakpoint. An earlier
   version of this rule used <=640px and left 641-1024px still duplicated
   — verified at 768px, where both were visible.

   Hide the HERO copy, not the sticky one: the sticky bar follows the user
   down the entire page, whereas the hero button scrolls away. Targeting
   `.btn-accent` leaves "Explore Cruise Lines" (.btn-ghost) in place, so
   the hero still offers an action. Scoped to `.hero` so inner-page heroes
   are untouched.
   ------------------------------------------------------------------ */
@media (max-width: 1024px) {
  .hero .hero-ctas .elementor-widget-button.btn-accent { display: none; }
}

/* HERO STATS at tablet (641-860px): keep all three on ONE row and give them
   equal widths. The base rule at <=860px drops the dividers and relies on
   intrinsic text width, which left the three blocks visibly uneven. */
@media (min-width: 641px) and (max-width: 860px) {
  .hero .hero-stats { flex-wrap: nowrap; width: 100%; }
  .hero .hero-stats > div {
    flex: 1 1 0;            /* equal columns regardless of label length */
    margin-right: 0 !important;
    padding: 22px 18px 0 0 !important;
    border-right: 1px solid rgba(247, 176, 74, 0.22);
  }
  .hero .hero-stats > div:last-child { padding-right: 0 !important; border-right: 0; }
}

/* ---- DROPDOWN SUBMENUS (added 2026-08-12) ----
   The primary menu was five flat links from when the site had a handful of
   pages; it now has 130+, so every section carries a curated submenu. The Nav
   Menu widget ships its own dropdown styling that does not match the house
   look, so map it here. Desktop = hover dropdown panel; the widget's own
   mobile dropdown owns small screens and just needs indentation. */
.site-nav .elementor-nav-menu--dropdown,
.site-nav .elementor-nav-menu .sub-menu {
  background: rgba(8, 30, 51, 0.97);
  border: 1px solid rgba(246, 241, 230, 0.12);
  border-top: 2px solid var(--accent);
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(8px);
  padding: 6px 0;
  /* Sized to the longest label ("Mayan Ruins: Tulum & Chichén Itzá") so nothing
     wraps to a second line — `max-content` measures the real text, and the cap
     stops one long entry from making an absurdly wide panel. */
  min-width: max-content;
  max-width: 340px;
}
.site-nav .elementor-nav-menu .sub-menu a.elementor-sub-item {
  font-family: var(--font-display);
  /* Match the main bar: same uppercase treatment, one step down in size.
     --font-display is an italic face, and italic small-caps at this size is
     hard to read in a dense list — force it upright. */
  font-style: normal;
  text-transform: uppercase;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  line-height: 1.25;
  color: rgba(246, 241, 230, 0.86);
  padding: 7px 20px !important;   /* was 10px 22px — tightened per feedback */
  border-bottom: 0;
  white-space: nowrap;            /* no wrapping, ever */
  text-shadow: none;
}
.site-nav .elementor-nav-menu .sub-menu a.elementor-sub-item:hover,
.site-nav .elementor-nav-menu .sub-menu a.elementor-sub-item:focus-visible {
  background: rgba(247, 176, 74, 0.14);
  color: var(--white);
  padding: 7px 20px !important;   /* beat Pro's hover padding (trap #9) */
}
/* The <li> carries its own spacing in Pro; zero it so the padding above is the
   only thing setting the row rhythm. */
.site-nav .elementor-nav-menu .sub-menu > li { margin: 0; }
.site-nav .elementor-nav-menu .sub-menu a.elementor-sub-item.elementor-item-active {
  color: var(--accent-soft);
}
/* The caret on parents that have children. It was rendering at 0.75 opacity
   against a photographic hero — effectively invisible — and Pro spaces it off
   the label with its own margin, so it read as a stray mark rather than as
   part of the word. Full-strength accent, pulled in tight. */
.site-nav .elementor-nav-menu .menu-item-has-children > a .sub-arrow,
.site-nav .elementor-nav-menu .menu-item-has-children > a i,
.site-nav .elementor-nav-menu .menu-item-has-children > a svg {
  opacity: 1;
  color: var(--accent);
  fill: var(--accent);
  margin-left: 4px !important;
  margin-right: 0 !important;
  transition: transform 0.18s ease;
}
.site-nav .elementor-nav-menu .menu-item-has-children > a .sub-arrow {
  padding: 0 !important;
  display: inline-flex;
  align-items: center;
}
/* Size the SVG itself, in absolute units. An `em` size here compounded down
   the a > span > svg chain and rendered the caret at 4.9px — it read as a
   middot separating the words rather than as a dropdown indicator. */
.site-nav .elementor-nav-menu .menu-item-has-children > a .sub-arrow svg,
.site-nav .elementor-nav-menu .menu-item-has-children > a > svg {
  width: 9px;
  height: 9px;
  font-size: 9px;
  flex: 0 0 auto;
}
.site-nav .elementor-nav-menu > li.menu-item-has-children:hover > a .sub-arrow,
.site-nav .elementor-nav-menu > li.menu-item-has-children:hover > a i {
  transform: translateY(1px);
}

/* ---- RESOURCES MEGA PANEL ----
   Guides + Printables folded into one parent (page 143, /resources/), shown as
   a single wide panel with two labelled column groups. Two levels, not three:
   a real 3rd-level flyout needs a precise diagonal mouse path and collapses to
   flat nesting on touch anyway, so the group headings are non-clickable labels
   and every destination stays exactly one hover deep. */
/* Two columns via CSS multi-column rather than grid: the item counts differ
   (10 vs 8) and `break-inside` lets the two labelled groups flow into their
   own columns without hard-coding a row count. A `grid-auto-flow: column`
   version with an explicit row count silently collapsed to one column. */
/* Layout only — NO `display` here. `display: block !important` on this
   .elementor-kit-4 beat Elementor's own `.elementor-nav-menu ul { display: none }`
   default, so the RESOURCES panel hung open permanently on desktop from a
   cold page load. The multi-column geometry is safe to declare at all times;
   visibility is toggled by the hover rule below. */
.site-nav .elementor-nav-menu > li.has-mega > ul.sub-menu {
  columns: 2;
  column-gap: 26px;
  column-fill: auto;
  height: 322px;              /* forces the break after the Guides group */
  padding: 14px 22px 16px !important;
  max-width: none;
  width: max-content;
}
.site-nav .elementor-nav-menu > li.has-mega > ul.sub-menu > li {
  margin: 0;
  break-inside: avoid;
  display: block;
  width: 100%;
}
/* Open the mega panel on hover / keyboard focus, and only then. Elementor's
   SmartMenus JS also toggles it, so this is belt-and-braces for the pointer
   case; the `:focus-within` arm keeps it reachable by keyboard. */
@media (min-width: 1025px) {
  .site-nav .elementor-nav-menu > li.has-mega:hover > ul.sub-menu,
  .site-nav .elementor-nav-menu > li.has-mega:focus-within > ul.sub-menu {
    display: block;
  }
}

/* start column 2 at the Printables heading */
.site-nav .elementor-nav-menu > li.has-mega > ul.sub-menu > li.mega-group-label
  ~ li.mega-group-label {
  break-before: column;
  margin-top: 0;
}
/* The column headings. These are section titles, NOT links — they must not
   look clickable, must not hover, and must not take the caret. Bigger, bolder
   and wider-tracked than the items beneath, with a rule under them so the
   panel reads as two labelled groups rather than one long list. */
.site-nav .elementor-nav-menu .sub-menu > li.mega-group-label > a.elementor-sub-item {
  font-family: var(--font-display);
  font-style: normal;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  color: var(--accent);
  padding: 2px 8px 7px !important;
  margin-bottom: 6px;
  border-bottom: 1px solid rgba(247, 176, 74, 0.38);
  pointer-events: none;      /* it is a label, not a link */
  cursor: default;
  background: transparent !important;
}
.site-nav .elementor-nav-menu .sub-menu > li.mega-group-label > a.elementor-sub-item:hover,
.site-nav .elementor-nav-menu .sub-menu > li.mega-group-label > a.elementor-sub-item:focus {
  background: transparent !important;
  color: var(--accent);
}
/* second group needs air above it when the columns are side by side */
.site-nav .elementor-nav-menu .sub-menu > li.mega-group-label ~ li.mega-group-label
  > a.elementor-sub-item { margin-top: 0; }
.site-nav .elementor-nav-menu > li.has-mega > ul.sub-menu > li:not(.mega-group-label)
  > a.elementor-sub-item {
  padding: 6px 8px !important;
}

/* ---- EDGE-AWARE DROPDOWNS ----
   Panels are left-anchored and 248px wide, so the last items in the bar opened
   OVER the "Plan My Cruise" CTA — Blog's panel ran to x=1169 and Printables' to
   x=1262 at a 1440 viewport while the CTA starts at x=1104. At 1100 the
   Printables panel reached x=1099, one pixel from leaving the viewport.

   Fix the geometry rather than the menu: the last two parents flip to
   right-aligned so they open INWARD, away from the CTA and the edge. This is
   the standard menubar behaviour (Office, Figma, macOS) — a submenu near the
   right edge opens leftward. `:nth-last-child` means it keeps working if the
   menu is reordered; it is keyed on position, not on a label. */
.site-nav .elementor-nav-menu > li.menu-item-has-children:nth-last-child(-n+2) > .sub-menu {
  left: auto;
  right: 0;
  border-radius: 0 0 var(--radius) var(--radius);
}
/* Pro positions the panel with an inline `left` on the <ul>; restate at a
   specificity that beats it (0,4,1 here vs Pro's inline needs !important). */
.site-nav .elementor-nav-menu > li.menu-item-has-children:nth-last-child(-n+2) > ul.sub-menu {
  left: auto !important;
  right: 0 !important;
}
/* The LAST item needs one more step. Right-aligning to its own <li> still
   overhung the CTA, because that <li> ends only ~35px left of the button while
   the panel is 248px wide. Align this one to the NAV BAR's right edge instead:
   the nav ends exactly where the CTA's gap begins, so the panel lands flush
   beside the button and can never cross it, at any viewport width. */
.site-nav .elementor-nav-menu > li.menu-item-has-children:last-child {
  position: static;   /* let the panel resolve against the positioned nav */
}
.site-nav .elementor-nav-menu > li.menu-item-has-children:last-child > ul.sub-menu {
  left: auto !important;
  right: 0 !important;
  top: 100% !important;
}
/* `position: static` on that <li> makes the panel resolve against the nearest
   positioned ancestor. Choosing that ancestor matters: the inner <ul
   class="elementor-nav-menu"> and its <nav> are 951px wide and overhang the
   nav's visible box to x=1163 — past the CTA — so anchoring there put the
   panel back on top of the button. Neutralise those two and let the widget
   DIV (760px, ending at the nav's true right edge) be the anchor. */
.site-header .site-nav .elementor-nav-menu--main,
.site-header .site-nav ul.elementor-nav-menu { position: static; }
.site-header .site-nav > .elementor-widget-container,
.site-header .site-nav.elementor-widget { position: relative; }
/* The panel must be able to escape the nav box to sit under its parent; the
   nav container clipping it would cut the flipped panel off. */
.site-header .site-nav,
.site-header .site-nav .elementor-widget-container { overflow: visible; }

/* ---- THE ACTUAL OVERLAP BUG ----
   The menu bar overflowed its own slot and painted over BOTH the logo and the
   CTA. Measured identically at 1280/1366/1440/1600: the <ul> needs 951px, the
   nav widget is only 760px, and because the list is `nowrap` with
   `overflow: visible` the extra 191px spilled 61px LEFT over the brand and
   35px RIGHT under the "Plan My Cruise" button. It was not a breakpoint
   problem — it was broken at every desktop width.

   Cause: the widget is `flex: 0 1 auto; min-width: 0`, so flexbox happily
   shrank the box while the contents refused to shrink with it.

   Fix: let the nav take exactly the width it needs (`flex: 1 1 auto` +
   `min-width: max-content` so it is never shrunk below its contents), and
   absorb the pressure in the item gap rather than in the words. */
.site-header .site-nav {
  flex: 1 1 auto;
  min-width: 0;
  justify-content: center;
}
/* The logo IMAGE paints wider than its .brand box — the wordmark's script "H"
   and the ship badge overhang the element, which is why "DESTINATIONS" still
   sat under the logo while a getBoundingClientRect() check on .brand reported
   34px of clearance. Reserve the real painted width so the nav starts clear
   of the artwork, not clear of the box. */
/* 168px was tuned while ElementsKit's nav-menu.css was still loading and
   contributing left padding to the menu. ElementsKit was removed on
   2026-08-13 (zero widgets in use, 7 stylesheets of dead weight) and the
   links slid 5-11px into the logo at >=1366. Reserve the real painted width
   of the wordmark plus a hard gutter, so the nav can never touch the brand
   regardless of what other CSS is present. */
.site-header .brand { flex: 0 0 auto; min-width: 190px; margin-right: 18px; }
/* ALL of the horizontal-bar geometry below is DESKTOP-ONLY and must stay
   inside this query. The `:not(.elementor-nav-menu--dropdown)` guard reads
   like it excludes the burger menu, but it does not: on mobile that class
   sits on the <nav>, not on this <ul>, so these rules matched the phone menu
   too and laid its items out as a horizontal flex row. */
@media (min-width: 1025px) {
  .site-header .site-nav ul.elementor-nav-menu:not(.elementor-nav-menu--dropdown) {
    padding-left: clamp(12px, 2vw, 40px);
  }
  .site-header .site-nav > .elementor-widget-container,
  .site-header .site-nav .elementor-nav-menu--main,
  .site-header .site-nav ul.elementor-nav-menu:not(.elementor-nav-menu--dropdown) {
    width: 100%;
  }
  /* Pack the items and centre the group rather than stretching them across the
     slot. `space-between` was wrong here: it pinned the last item to the slot's
     right edge, and that edge sits inside the CTA — so "Printables" landed on
     the button even with zero overflow. Centring keeps the group inside its box
     with real air on both sides. */
  .site-header .site-nav ul.elementor-nav-menu:not(.elementor-nav-menu--dropdown) {
    display: flex;
    flex-wrap: nowrap;
    justify-content: center;
    gap: clamp(6px, 1.1vw, 26px);
    /* Guards on BOTH sides. There was only a padding-right, so a CENTRED
       group had nothing stopping it expanding leftward into the logo — which
       is exactly what happened when ElementsKit's nav-menu.css was removed
       and its incidental left padding went with it (links landed 5-11px over
       the wordmark at >=1366). A min-width on .brand cannot fix this: the
       centred group simply grows past it. The guard has to be on the list. */
    padding-left: clamp(12px, 2vw, 40px);
    padding-right: clamp(12px, 2vw, 40px);
  }
  .site-header .site-nav ul.elementor-nav-menu:not(.elementor-nav-menu--dropdown) > li {
    flex: 0 0 auto;
    position: relative;   /* panels anchor to their own parent by default */
  }
}
/* Elementor sets a fixed horizontal padding on each item that was a big part
   of the 951px; let the gap above own the spacing instead.
   MUST stay inside a min-width query. The `:not(.elementor-nav-menu--dropdown)`
   guard does NOT hold on mobile: the burger's dropdown class lives on the
   <nav>, not on this <ul>, so the .elementor-kit-4 matched the phone menu too and its
   `!important` zeroed the row padding — every label sat flush against the
   panel edge with its first glyph clipped. */
@media (min-width: 1025px) {
  .site-header .site-nav ul.elementor-nav-menu:not(.elementor-nav-menu--dropdown)
    > li > a.elementor-item {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
}
/* Below ~1300 the seven labels genuinely need less type to stay on one line
   without touching the logo or the button. */
@media (min-width: 1025px) and (max-width: 1300px) {
  .site-header .site-nav ul.elementor-nav-menu:not(.elementor-nav-menu--dropdown)
    > li > a.elementor-item {
    font-size: 0.72rem;
    letter-spacing: 0.05em;
  }
}

/* ---- MOBILE MENU REPAIR ----
   The desktop submenu rules above were leaking into the burger panel and
   laying the items out HORIZONTALLY — they ran off the right edge of the
   phone ("DESTINATIONS · CRUISE LINES · POR…"). Cause: the mobile panel
   carries BOTH classes (`class="sub-menu elementor-nav-menu--dropdown"`), so
   every `.sub-menu` rule — `min-width: max-content`, `white-space: nowrap`,
   the multi-column mega grid — matched it too.

   Restate the mobile contract at a specificity that wins, unconditionally. */
@media (max-width: 1024px) {
  /* NOTE: deliberately no `display` here. Elementor opens this panel by
     flipping `aria-hidden`, and the reveal rule is a plain
     `[aria-hidden="false"] { display: block }`. An unconditional
     `display: block !important` on the same element outranked BOTH the hide
     and the reveal, so the burger stopped opening the menu entirely. Let the
     aria-hidden pair own visibility; only correct the LAYOUT here. */
  /* `display` applies ONLY to the top-level list. Including `.sub-menu` here
     forced every child panel open simultaneously. */
  .site-nav nav.elementor-nav-menu--dropdown > ul.elementor-nav-menu {
    display: block !important;
  }
  .site-nav nav.elementor-nav-menu--dropdown ul.elementor-nav-menu,
  .site-nav nav.elementor-nav-menu--dropdown .sub-menu,
  .site-nav .elementor-nav-menu > li.has-mega > ul.sub-menu {
    columns: auto !important;
    column-gap: normal !important;
    height: auto !important;
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    grid-template-columns: none !important;
    padding: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
  }
  /* Child panels inside the open burger: these are safe to force, because the
     burger itself (the element carrying aria-hidden) is excluded above. */
  /* Child panels stay COLLAPSED until their parent row is tapped. An earlier
     `display: block !important` here forced every submenu open at once, so the
     burger showed one stray grandchild per section ("Caribbean & Bahamas",
     "Carnival", "All Cruise Ports"…) instead of the six top-level items.
     Elementor's own SmartMenus JS owns the open/closed state — do not fight
     it; only style what is already visible. */
  .site-nav nav.elementor-nav-menu--dropdown .sub-menu {
    background: rgba(8, 30, 51, 0.55);
  }
  /* …and the RESOURCES panel specifically was popping open on its own. The
     desktop mega rule sets `display: grid/block` plus a fixed `height` on
     `li.has-mega > ul.sub-menu`; inside the burger that both forced the panel
     visible and capped the parent list at 333px so "Blog" fell off the end.
     Collapse it here and let SmartMenus toggle it like any other section. */
  .site-nav nav.elementor-nav-menu--dropdown li.has-mega > ul.sub-menu {
    display: none;
  }
  .site-nav nav.elementor-nav-menu--dropdown li.has-mega.elementor-active > ul.sub-menu,
  .site-nav nav.elementor-nav-menu--dropdown li.has-mega[aria-expanded="true"] > ul.sub-menu {
    display: block;
  }
  .site-nav nav.elementor-nav-menu--dropdown ul.elementor-nav-menu > li,
  .site-nav nav.elementor-nav-menu--dropdown .sub-menu > li {
    display: block !important;
    width: 100% !important;
    float: none !important;
    break-inside: auto !important;
    break-before: auto !important;
  }
  .site-nav nav.elementor-nav-menu--dropdown a {
    white-space: normal !important;   /* labels wrap instead of overflowing */
    width: 100%;
    /* Top-level rows had NO horizontal padding, so every label sat flush on
       the panel's left edge and its leading glyph was visually clipped
       ("ESTINATIONS", "ORTS"). I originally misread this as the panel
       overhanging the viewport; the panel is inside the viewport — the
       padding was simply missing. `box-sizing` guards the 100% width above. */
    padding-left: 22px !important;
    padding-right: 18px !important;
    box-sizing: border-box;
  }
  /* children indent one step further so the hierarchy still reads */
  .site-nav nav.elementor-nav-menu--dropdown .sub-menu a {
    padding-left: 40px !important;
  }
  /* With sections expanded the list can exceed the screen — let the panel
     scroll on its own rather than being clipped. The desktop mega-panel sets
     an explicit `height`, which was inherited here and cut the list off at
     333px (Blog fell outside the box); clear it and cap by viewport instead. */
  .site-nav nav.elementor-nav-menu--dropdown {
    height: auto !important;
    max-height: calc(100vh - 92px) !important;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    /* Anchor the panel to the RIGHT, directly under the hamburger that opened
       it, instead of drifting to the left edge of the screen. The widget is
       `order: 3` (far right of the header), so pinning right:0 puts the panel
       under the button — the standard phone pattern, and it keeps the tap
       origin and the menu in the same place. */
    /* `right: 0` resolves against the nav widget, whose own box extends past
       the viewport edge — the panel hung off-screen and clipped the start of
       every label ("ESTINATIONS", "ORTS"). Anchor to the RIGHT EDGE OF THE
       BURGER itself: the toggle is 46px wide, so right:0 on the widget plus a
       small inset lands the panel inside the screen. */
    left: auto !important;
    right: 0 !important;
    transform: translateX(12px);
    width: min(320px, calc(100vw - 32px)) !important;
    border-radius: 0 0 var(--radius) var(--radius);
    border: 1px solid rgba(246, 241, 230, 0.12);
    border-top: 2px solid var(--accent);
  }
  .site-nav nav.elementor-nav-menu--dropdown > ul.elementor-nav-menu {
    height: auto !important;
    max-width: none !important;
  }
  /* the mega column headings become plain section headers in the burger */
  .site-nav nav.elementor-nav-menu--dropdown li.mega-group-label > a {
    color: var(--accent) !important;
    font-weight: 700;
    letter-spacing: 0.18em;
    border-bottom: 1px solid rgba(247, 176, 74, 0.3);
    margin: 6px 0 2px;
  }
}

/* mobile: the widget's dropdown panel — indent children so the hierarchy
   reads, and keep tap targets at 44px */
@media (max-width: 1024px) {
  .site-nav .elementor-nav-menu--dropdown a.elementor-sub-item {
    padding-left: 38px !important;
    font-size: 0.9rem;
    min-height: 44px;
    display: flex;
    align-items: center;
  }
  .site-nav .elementor-nav-menu--dropdown .sub-menu {
    background: rgba(8, 30, 51, 0.6);
    border: 0; border-radius: 0; box-shadow: none; padding: 0;
  }
}

/* mobile: burger sits right of the CTA like the static site; the widget's
   dropdown container must not flow into the header bar, and the toggle is
   restyled to the static .nav-toggle look */
@media (max-width: 1024px) {
  /* `position: relative` makes the widget the anchor for the burger panel, so
     `right: 0` on the panel lands under the hamburger rather than at the far
     left of the page. */
  .site-header .site-nav { order: 3; width: auto; position: relative; }
  .site-nav .elementor-nav-menu--dropdown { display: none; position: absolute;
    top: 100%; left: 0; right: 0; width: 100%;
    background: rgba(8, 30, 51, 0.98); box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
    z-index: 60; }
  /* Reveal the burger panel. This used to key ONLY on
     `[aria-hidden="false"]`, but Elementor never flips that attribute on this
     widget — clicking the toggle sets `aria-expanded="true"` and adds
     `.elementor-active` to the TOGGLE, and leaves the panel at
     `aria-hidden="true"` forever. The menu therefore could not be opened on
     any phone or tablet: the click registered, the button went active, and
     nothing appeared. Match the class Elementor actually sets, and keep the
     aria form as a fallback in case a future version starts using it. */
  /* The panel is the <nav class="elementor-nav-menu--dropdown"> that directly
     follows the toggle button — NOT a <ul>. (A ul.elementor-nav-menu--dropdown
     also exists nested inside a menu item; targeting that one measures 0px
     wide and never opens.) */
  .site-nav .elementor-menu-toggle.elementor-active + nav.elementor-nav-menu--dropdown,
  .site-nav .elementor-menu-toggle[aria-expanded="true"] + nav.elementor-nav-menu--dropdown,
  .site-nav nav.elementor-nav-menu--dropdown[aria-hidden="false"] { display: block; }
  .site-nav .elementor-menu-toggle { visibility: visible; width: 46px; height: 44px;
    background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 5px; color: var(--white); margin: 0; }
  .site-nav .elementor-menu-toggle svg { fill: var(--white); }
  /* .elementor-widget-nav-menu prefix: post-144.css (loads after kit) carries
     widget dropdown typography defaults at (0,3,0) (accent family/size/weight/
     style — italic serif!) that would beat a (0,3,0) kit rule on load order */
  .elementor-widget-nav-menu.site-nav .elementor-nav-menu--dropdown .elementor-item {
    font-family: var(--font-display); text-transform: uppercase;
    font-size: 0.95rem; font-weight: 400; font-style: normal; letter-spacing: 0.18em;
    color: rgba(255, 255, 255, 0.85) !important; text-decoration: none;
    display: block; padding: 16px 28px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08); }
}
/* ---- HEADER CTA SIZING (desktop) ----
   The header button was inheriting the PAGE-BODY button padding
   (`17px 36px 15px`), which is right for a hero CTA but oversized in a nav
   bar: it measured 222x57 in a 136px header — 42% of the header's height —
   and it was actually WIDER than its own container (222px button in a 193px
   .nav-actions), so it overhung the wrap.

   Size it as a nav control instead: tighter padding, slightly smaller type,
   and a height that relates to the nav links beside it rather than to a
   full-page CTA. Still comfortably above the 44px touch target. Mobile keeps
   its own rule below. */
@media (min-width: 861px) {
  .site-header .nav-actions .elementor-widget-button.btn .elementor-button {
    padding: 12px 22px 11px;
    font-size: 0.78rem;
    letter-spacing: 0.13em;
    white-space: nowrap;
  }
}

@media (max-width: 860px) {
  /* the header CTA is the site's primary conversion control; the phone
     shrink left it 39px tall (below the 44px touch minimum). Keep the
     narrower type/tracking that makes it fit beside the burger, but restore
     a >=44px hit area via padding. */
  .nav-actions .elementor-widget-button.btn .elementor-button {
    padding: 13px 14px 12px; font-size: 0.66rem; letter-spacing: 0.12em;
    white-space: nowrap; }
  /* the static site's own mobile-panel CSS (.site-nav{position:fixed;
     transform:translateY(-105%)}) must not hijack the Nav Menu WIDGET —
     the widget's dropdown handles the mobile menu instead */
  .site-header .elementor-widget-nav-menu.site-nav { position: static;
    transform: none; visibility: visible; background: none; box-shadow: none;
    padding-top: 0; z-index: auto; width: auto; }
}

/* parallax off on touch/mobile + noanim (must beat Elementor element rules) */
@media (hover: none), (max-width: 860px) {
  .hero, .page-hero, .band, .form-section { background-attachment: scroll !important; }
}
html.noanim .hero, html.noanim .page-hero, html.noanim .band, html.noanim .form-section {
  background-attachment: scroll !important; }
html.noanim .hero { min-height: 860px !important; }
html.noanim .page-hero { min-height: 640px !important; }
html.noanim .band { min-height: 0 !important; }
/* screenshot mode: entrance animations must not hide content */
html.noanim .elementor-invisible { visibility: visible !important; opacity: 1 !important;
  animation: none !important; }
html.noanim .animated { animation: none !important; }

/* ===== kit-additions/404.css ===== */
/* ================= 404 TEMPLATE (Theme Builder error-404) ================
   Appended after the shared PRE + styles.css + POST blocks by _build_kit.py.
   The 404 reuses the site's existing classes (page-hero / section-head /
   why-card / more-dest / band / form-section); rules here exist ONLY to
   (a) style the Pro Search Form widget into the house field look,
   (b) adapt why-card/dest-card patterns to this page's grids, and
   (c) out-specificity the shared adaptation layer where it wins.
   ---------------------------------------------------------------------- */

/* ---- hero -------------------------------------------------------------
   .page-hero h1 + .lead: the shared PRE/POST restatements sit at (0,2,1) /
   (0,3,0); cluster-e.css already restates the .page-hero variants, and this
   file sorts AFTER it, so a bare repeat would be redundant — instead only
   the 404-specific deltas are declared here. */
.e-con.e-flex.ht-404-hero { flex-direction: column; }
.e-con.htsec.page-hero.ht-404-hero { min-height: 78vh; }
.ht-404-hero .breadcrumbs { margin-bottom: 0.2rem; }
.ht-404-hero h1.elementor-heading-title strong {
  color: var(--accent-soft); font-weight: inherit; }
.ht-404-hero .elementor-widget-text-editor.lead { max-width: 620px; }

/* ---- hero search box --------------------------------------------------
   The Pro Search Form widget emits .elementor-search-form__container /
   __input / __submit and styles them from its own widget CSS at (0,2,0)+
   with element-scoped defaults — matched here with the site's .field look.
   Class-based throughout (.ht-404-search on the widget wrapper). */
.e-con.e-flex.ht-404-searchbox { flex-direction: column; }
.e-con.ht-404-searchbox { margin-top: 2rem; max-width: 620px; }
.ht-404-searchbox .eyebrow { margin-bottom: 0.6rem; display: block; }

.ht-404-search .elementor-search-form { width: 100%; }
.ht-404-search .elementor-search-form__container {
  background: rgba(246, 241, 230, 0.1) !important;
  border: 1px solid rgba(246, 241, 230, 0.45) !important;
  border-radius: 3px;
  overflow: hidden;
  min-height: 56px; }
.ht-404-search .elementor-search-form--focus .elementor-search-form__container {
  border-color: var(--accent) !important;
  background: rgba(246, 241, 230, 0.16) !important; }
/* input: same post-<id>.css global-typography problem as the submit — the
   widget-class prefix puts these at (0,3,1), later, so they win */
.elementor-widget-search-form.ht-404-search input[type="search"].elementor-search-form__input {
  background: transparent !important;
  color: var(--cream) !important;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 1rem;
  line-height: 1.65;
  padding: 0 18px;
  border: 0; }
.elementor-widget-search-form.ht-404-search input[type="search"].elementor-search-form__input::placeholder {
  color: rgba(246, 241, 230, 0.6); opacity: 1; }
/* submit: a real accent CTA, contrasting the dark hero (never translucent).
   Cascade note (same shape as conversion-note trap #5/#9): the per-document
   sheet post-<id>.css enqueues AFTER the kit CSS and carries
   (a) `.elementor-widget-search-form .elementor-search-form__submit` with the
       GLOBAL typography vars at (0,2,0) — beaten here by prefixing the widget
       class, giving (0,3,0) later in the cascade; and
   (b) an ID-scoped `.elementor-<post> .elementor-element-<hash>
       .elementor-search-form__submit{min-width:50px}` at (0,3,0) that NO class
       .elementor-kit-4 can outrank (and whose hash changes on every regenerate) —
       min-width therefore needs !important. Styling stays class-based; the
       !important exists only to beat an element-ID-derived rule we don't own. */
.elementor-widget-search-form.ht-404-search .elementor-search-form__submit {
  background-color: var(--accent) !important;
  background-image: linear-gradient(135deg, var(--accent) 0%, var(--accent-soft) 100%) !important;
  color: var(--navy) !important;
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: 0.78rem;
  line-height: 1.65;
  min-width: 152px !important;
  padding: 0 26px;
  border: 0;
  border-radius: 0;
  transition: filter 0.2s ease; }
.elementor-widget-search-form.ht-404-search .elementor-search-form__submit:hover,
.elementor-widget-search-form.ht-404-search .elementor-search-form__submit:focus {
  filter: brightness(1.08); }
.elementor-widget-search-form.ht-404-search .elementor-search-form__submit:focus-visible {
  outline: 2px solid var(--cream); outline-offset: 2px; }

/* ---- cluster cards (white cards on the cream section) -----------------
   why-card markup inside an <a>. Three traps handled:
   (1) .elementor a{box-shadow:none} (POST trap #6) kills the card shadow on
       linked cards -> restate at a.why-card specificity;
   (2) the link needs the flex column layout .why-card assumes;
   (3) 6 cards: .why-grid is repeat(4,1fr) -> 3 columns here. */
.e-con .why-grid.ht-404-grid,
.why-grid.ht-404-grid { grid-template-columns: repeat(3, 1fr); }
.ht-404-grid .elementor-widget-html { display: flex; }
a.why-card.ht-404-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  text-decoration: none;
  box-shadow: var(--shadow-card); }
a.why-card.ht-404-card:hover {
  box-shadow: var(--shadow-card-hover);
  transform: translateY(-6px); }
a.why-card.ht-404-card p { flex: 1; }
.ht-404-card .ht-404-more {
  display: inline-block;
  margin-top: 16px;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.16em;
  color: var(--navy-2);
  border-bottom: 2px solid var(--accent);
  padding-bottom: 3px;
  align-self: flex-start; }
a.why-card.ht-404-card:hover .ht-404-more { color: var(--accent); }

/* ---- popular pages (cream cards on the navy section) ------------------
   Opposite-shade cards on a dark section, per the house contrast rule. */
.ht-404-poplist {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* grid rows size independently, so a 2-line title in row 2 made row 2's
     cards 23px taller than row 1's — 1fr auto-rows equalizes ALL eight */
  grid-auto-rows: 1fr;
  gap: 20px; }
a.ht-404-pop {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--cream);
  border-radius: var(--radius);
  border-top: 3px solid var(--accent);
  padding: 24px 22px 22px;
  text-decoration: none;
  box-shadow: var(--shadow-card);
  transition: transform 0.3s ease, box-shadow 0.3s ease; }
a.ht-404-pop:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-card-hover); }
a.ht-404-pop b {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.86rem; font-weight: 600; letter-spacing: 0.1em;
  color: var(--navy);
  margin-bottom: 8px; }
a.ht-404-pop span {
  font-size: 0.92rem;
  color: var(--ink-soft);
  line-height: 1.55; }

/* the section-head on a navy section: lead + eyebrow colors come from
   .on-dark in styles.css; the text-editor mirror (POST trap #4) beats it */
.bg-navy .elementor-widget-text-editor.lead {
  color: rgba(246, 240, 226, 0.82); }

/* ---- band -------------------------------------------------------------
   The shared .band scrim is only 55% navy, so pill legibility must not depend
   on what the photo happens to be doing behind any one pill: give each
   .more-dest link its own translucent-navy fill (the pills sit ON a dark
   section, so a dark fill + light text/border is the correct contrast pair). */
.htsec.band .more-dest a {
  background: rgba(8, 30, 51, 0.55);
  backdrop-filter: blur(2px); }
.htsec.band .more-dest a:hover {
  background: rgba(8, 30, 51, 0.75); }

/* ---- responsive ------------------------------------------------------- */
@media (max-width: 1040px) {
  .ht-404-poplist { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
  .e-con .why-grid.ht-404-grid,
  .why-grid.ht-404-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .e-con .why-grid.ht-404-grid,
  .why-grid.ht-404-grid { grid-template-columns: 1fr; }
  .ht-404-poplist { grid-template-columns: 1fr; }
  .e-con.htsec.page-hero.ht-404-hero { min-height: 0; }
  .ht-404-search .elementor-search-form__container { min-height: 52px; }
  .ht-404-search .elementor-search-form__submit {
    min-width: 0; padding: 0 18px; font-size: 0.7rem; }
}

/* ===== kit-additions/audit-visual.css ===== */
/* ===================================================================
   audit-visual.css — kit fragment owned by the VISUAL/THEME audit pass
   (df-design-audit, 2026-08-12). See AUDIT-VISUAL.md.

   Kept separate from blog.css / 404.css on purpose: those two were being
   authored by other agents concurrently and _build_kit.py auto-merges every
   fragment in this directory, so a new file avoids a write collision.
   =================================================================== */

/* -------------------------------------------------------------------
   HUB INDEX CARDS  (/destinations/ /ports/ /cruise-lines/ /excursions/
   /guides/ /resources/ — generator: elementor/_build_hubs.py)

   The 6 parent hubs had NO content at all before this pass; they are
   net-new design assembled from existing classes. The one genuinely new
   component is this text index card.

   Why not reuse .dest-card: that is the site's PHOTO card (absolutely
   positioned <img>, min-height 380px, veil overlay) and these entries are
   text-only. .hub-card is built from the SAME tokens as .why-card
   (--radius, --shadow-card, 3px accent top rule, navy display title) so it
   reads as the same family, and sits white on .bg-cream — the opposite-shade
   pairing the homepage uses for .why-card.
   ------------------------------------------------------------------- */
.hub-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
  /* CSS grid sizes each ROW independently, so a 2-line card title makes its
     whole row taller than the others (/ports/ measured 202px vs 180px).
     grid-auto-rows:1fr makes every row equal — the same fix already recorded
     for .ht-404-poplist in ELEMENTOR-CONVERSION-NOTES.md. */
  grid-auto-rows: 1fr;
}
.hub-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--white);
  border-radius: var(--radius);
  border-top: 3px solid var(--accent);
  padding: 30px 26px 26px;
  text-decoration: none;
  box-shadow: var(--shadow-card);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
/* trap #6: `.elementor a { box-shadow:none }` beats a bare-class rule on a
   linked container — restate at a.hub-card specificity (same fix already
   applied to a.line-card / a.dest-card in _build_kit.py POST) */
a.hub-card { box-shadow: var(--shadow-card); }
a.hub-card:hover { box-shadow: var(--shadow-card-hover); }
.hub-card:hover { transform: translateY(-6px); }
.hub-card:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 3px;
}
.hub-card-title {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.35;
  color: var(--navy);
  margin-bottom: 10px;
}
.hub-card-blurb {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 0.98rem;
  line-height: 1.65;
  color: var(--ink-soft);
  flex: 1 1 auto;
}
/* the "Read the guide ->" affordance sits flush to the card bottom so every
   card in a row ends on the same baseline regardless of blurb length */
.hub-card-go {
  margin-top: 18px;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: var(--navy-2);
  transition: color 0.2s;
}
.hub-card:hover .hub-card-go { color: var(--accent); }
.hub-card-go span { display: inline-block; transition: transform 0.25s ease; }
.hub-card:hover .hub-card-go span { transform: translateX(4px); }

@media (max-width: 900px) {
  .hub-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .hub-grid { grid-template-columns: 1fr; }
}

/* The hub hero holds more copy than a normal .page-hero (H1 + rule + lead),
   so give the lead the same 640px measure it has elsewhere and keep the
   section from growing taller than the content needs. */
.e-con.e-flex.page-hero.hub-hero { flex-direction: column; justify-content: flex-end; }
.hub-hero .elementor-widget.lead { max-width: 640px !important; }

/* the helper CTA under the index sits centered like a .section-head */
.hub-cta { align-items: center; margin-top: 1.6rem; }

/* ===== kit-additions/blog.css ===== */
/* ================================================================
   BLOG cluster — archive + single post Theme Builder templates.
   Owned by the blog agent; merged automatically by _build_kit.py.
   There is no static blog page: this is net-new design in the house
   style, reusing the ported section grammar (page-hero / htsec
   rhythm / dest-card-flavored photo cards / form-section).
   ================================================================ */

/* ---------------------------------------------------------------- shared */

/* The theme-builder title widgets (theme-archive-title / theme-post-title)
   extend Widget_Heading, so their wrapper carries elementor-widget-heading
   too and the kit's (0,2,1) heading rules already apply. What they do NOT
   inherit is .page-hero h1's SIZE override from styles.css (a bare `.page-hero
   h1` rule loses to the kit's `.elementor-widget-heading h1.elementor-heading-title`
   at (0,2,1)) — restate it at matching specificity, exactly like the cluster
   fragments do for their own page-hero h1s. */
.page-hero .elementor-widget-heading h1.elementor-heading-title {
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  margin: 0.4rem 0 1rem;
}

/* breadcrumb current-page token (the ported pages end the trail in bare text;
   the single-post trail needs a span so the color can differ from the links) */
.breadcrumbs .crumb-current { color: rgba(246, 241, 230, 0.75); }

/* Post hero photos are the POST's featured image — unlike the curated hero
   photos on the ported pages, they can be bright (beach/sky) at the top of the
   frame, where the page-hero scrim is at its lightest (0.25 at 45%). The
   breadcrumb and meta line sit exactly there and were washing out. A local
   text-shadow keeps them legible on any featured image without darkening the
   photo for everyone. */
.blog-post-hero .breadcrumbs,
.blog-post-hero .blog-post-meta {
  text-shadow: 0 1px 10px rgba(8, 30, 51, 0.75);
}

/* A post with NO featured image renders NO .elementor-post__thumbnail__link at
   all (Skin_Base::render_thumbnail() returns early), so the card is simply
   shorter — there is no empty box to fill and no CSS hook to add one. Elementor
   offers no per-skin fallback image. The rule is therefore editorial, not CSS:
   EVERY POST NEEDS A FEATURED IMAGE, or its card sits short next to the others.
   (The default "Hello world!" post was moved to draft for exactly this reason.)
   Cards still align to the top of the row, so a missing image degrades
   gracefully rather than breaking the grid. */

/* The archive intro section contains ONLY a .section-head. styles.css gives
   .section-head `margin-bottom:3.2rem` to separate it from the grid that
   normally follows; with nothing after it, that 51px becomes trailing dead
   space on top of the section's own 96px bottom padding. In the static site
   this would collapse — inside an Elementor container (flex, and the head sits
   in its own child wrapper) margins do not collapse. Zero it when the head is
   the section's last content. */
.blog-intro .wrap > .section-head:last-child { margin-bottom: 0; }

/* ------------------------------------------------- archive: the card grid */

/* Section: NAVY, so the cream cards read as opposite-shade (house rule 2).
   .bg-navy already paints the section; .blog-list only owns grid mechanics. */
.e-con.htsec.blog-list { padding-bottom: 96px; }
@media (max-width: 640px) { .e-con.htsec.blog-list { padding-bottom: 70px; } }

/* Elementor renders the loop as .elementor-grid (a CSS grid whose column count
   comes from the widget's own element-scoped rules at (0,4,0)); we only add
   the gap + stretch. Cards must be EQUAL HEIGHT in a row: the grid item and
   the card both need height:100% (house rule 4). Elementor's own
   `.elementor-posts-container:not(.elementor-posts-masonry){align-items:stretch}`
   handles the item; .elementor-post gets the explicit height. */
.blog-grid .elementor-posts-container.elementor-grid {
  align-items: stretch;
}
.blog-grid .elementor-post {
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--cream);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.blog-grid .elementor-post:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-card-hover);
}

/* photo crop — mirrors .dest-card img behavior (cover + hover push-in) */
.blog-grid .elementor-post__thumbnail__link {
  display: block;
  margin: 0;
  overflow: hidden;
}
.blog-grid .elementor-post__thumbnail {
  position: relative;
  padding-bottom: 62%;          /* consistent 8:5-ish crop across mixed sources */
  overflow: hidden;
}
.blog-grid .elementor-post__thumbnail img {
  position: absolute; inset: 0;
  /* !important because WP Compress injects width="300" height="225" ATTRIBUTES
     (the medium thumbnail's intrinsic size) onto the img. At rest our CSS wins,
     but in the :hover state Elementor's own widget CSS re-asserts and those raw
     attributes took over — the photo collapsed to a 300px box in the top-right
     corner of the frame instead of filling it. Pin the geometry so it holds in
     EVERY state; the transform below is then the only thing that changes. */
  width: 100% !important; height: 100% !important;
  max-width: none !important; min-width: 0;
  object-fit: cover; object-position: center;
  transition: transform 0.6s ease;
}
.blog-grid .elementor-post:hover .elementor-post__thumbnail img,
.blog-grid .elementor-post:focus-within .elementor-post__thumbnail img {
  transform: scale(1.06);
  /* restated so the hover state cannot fall back to the injected attributes */
  width: 100% !important; height: 100% !important; inset: 0;
}

/* text column — grows so the read-more pins to the card bottom and every
   card in the row ends on the same line regardless of excerpt length */
.blog-grid .elementor-post__text {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  padding: 24px 22px 26px;
  margin: 0;
}

/* CASCADE WAR — the archive-posts widget's GLOBAL-TYPOGRAPHY defaults.
   Elementor writes per-document CSS (uploads/elementor/css/post-<id>.css) that
   ENQUEUES AFTER the kit CSS and restates the widget's global typography at
   (0,2,0):
     .elementor-widget-archive-posts .elementor-post__title, … a
         {color: --e-global-color-secondary; font-family: primary; …}
     .elementor-widget-archive-posts a.elementor-post__read-more
         {font-family: accent (Cormorant ITALIC); font-style: italic}
     .elementor-widget-archive-posts .elementor-post__read-more
         {color: --e-global-color-accent (teal)}
     .elementor-widget-archive-posts .elementor-post__meta-data {font-family: secondary}
   At equal specificity those beat a bare `.blog-grid …` rule ON LOAD ORDER —
   the exact trap documented for the Nav Menu and Form widgets (conversion
   notes items 5 and 9). Every rule below therefore carries the
   `.elementor-widget-archive-posts` prefix to reach (0,3,0)+.
   Symptom if you drop the prefix: orange card titles and a teal italic serif
   "Read the guide". */

/* title: house display type. The post title is an h3 (title_tag h3) but it is
   NOT a heading widget — it is .elementor-post__title inside the loop, so the
   kit's heading rules do not reach it. Style it directly. */
.elementor-widget-archive-posts.blog-grid .elementor-post__title {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 1.45;
  margin: 0 0 10px;
}
.elementor-widget-archive-posts.blog-grid .elementor-post__title,
.elementor-widget-archive-posts.blog-grid .elementor-post__title a {
  color: var(--navy);
  text-decoration: none;
  transition: color 0.25s;
}
.elementor-widget-archive-posts.blog-grid .elementor-post:hover .elementor-post__title a {
  color: var(--navy-2);
}

/* date meta: the eyebrow treatment. Pro ALSO ships
   `.elementor-posts .elementor-post__meta-data{color:#adadad;font-size:12px}`
   at (0,2,0) in widget-posts.min.css — the prefix beats that too. */
.elementor-widget-archive-posts.blog-grid .elementor-post__meta-data {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  line-height: 1.65;
  color: var(--ink-soft);
  margin: 0 0 12px;
  order: -1;                    /* date sits ABOVE the title, like an eyebrow */
}
/* the widget's meta_separator default injects `content:"///"` between spans;
   we show a single meta item, but neutralize it so a future author/terms item
   doesn't render slashes */
.elementor-widget-archive-posts.blog-grid .elementor-post__meta-data span + span::before {
  content: "·" !important;
  margin: 0 8px;
  color: var(--accent);
}

/* excerpt: Pro sets .elementor-posts .elementor-post__excerpt p{color:#777;
   font-size:14px;line-height:1.5em} at (0,3,0) — beat it on the <p>. */
.elementor-widget-archive-posts.blog-grid .elementor-post__excerpt { margin: 0 0 18px; }
.elementor-widget-archive-posts.blog-grid .elementor-post__excerpt p {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0;
}

/* read-more: the .dest-more underline treatment. margin-top:auto pins it to
   the bottom of every card so the row's buttons align (house rule 4). */
.blog-grid .elementor-post__read-more-wrapper { margin-top: auto; }
/* the `a.` + widget prefix is load-bearing: post-<id>.css restates the widget's
   ACCENT global typography on `a.elementor-post__read-more` (Cormorant Garamond
   ITALIC) and the accent COLOR (teal) at (0,2,0)/(0,2,1). font-style:normal is
   required — the global accent face is italic, same fix as the submit button. */
.elementor-widget-archive-posts.blog-grid a.elementor-post__read-more {
  display: inline-block;
  align-self: flex-start;
  font-family: var(--font-display);
  font-style: normal;
  text-transform: uppercase;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--navy);
  border-bottom: 1px solid var(--accent);
  padding-bottom: 3px;
  text-decoration: none;
  opacity: 0.9;
  transition: opacity 0.25s, color 0.25s;
}
.elementor-widget-archive-posts.blog-grid .elementor-post:hover a.elementor-post__read-more {
  opacity: 1;
  color: var(--accent);
}

/* ------------------------------------------------------------ pagination */
/* On the NAVY section, so links are light and the current page is accent
   (house rule 3: never a dark/translucent control on a dark section). */
/* prefix again: post-<id>.css restates the widget's SECONDARY global typography
   on .elementor-widget-archive-posts .elementor-pagination at (0,2,0) */
.elementor-widget-archive-posts.blog-grid .elementor-pagination {
  margin-top: 46px;
  text-align: center;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.76rem;
  letter-spacing: 0.16em;
}
.blog-grid .elementor-pagination .page-numbers {
  display: inline-block;
  min-width: 42px;
  padding: 11px 12px 9px;
  margin: 0 4px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 3px;
  color: rgba(246, 240, 226, 0.85);
  text-decoration: none;
  transition: background 0.25s, color 0.25s, border-color 0.25s;
}
.blog-grid .elementor-pagination a.page-numbers:hover {
  background: rgba(255, 255, 255, 0.14);
  border-color: var(--accent-soft);
  color: var(--white);
}
.blog-grid .elementor-pagination .page-numbers.current {
  background: linear-gradient(135deg, var(--accent-soft), var(--accent));
  border-color: transparent;
  color: var(--navy-deep);
  font-weight: 600;
}

/* empty-state copy on the navy section (search with no results) */
.elementor-widget-archive-posts.blog-grid .elementor-posts-nothing-found {
  color: rgba(246, 240, 226, 0.85);
  font-family: var(--font-body);
  font-size: 1.08rem;
  text-align: center;
  padding: 28px 0;
}

/* ------------------------------------------------------- single: the post */

/* meta line under the post title, in the hero (on-dark) */
.blog-post-meta .elementor-inline-items {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}
.blog-post-meta .elementor-icon-list-item,
.blog-post-meta .elementor-icon-list-item a,
.blog-post-meta .elementor-icon-list-text {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  line-height: 1.65;
  color: rgba(246, 241, 230, 0.8);
  text-decoration: none;
}
/* Pro's inline layout injects a separator via ::after on every item but the
   last; restyle rather than re-invent so no stray bullet appears. */
.blog-post-meta .elementor-icon-list-item:not(:last-child)::after {
  content: "·";
  margin: 0 12px;
  color: var(--accent-soft);
  border: 0;
}

/* the post BODY: classic WP content rendered by theme-post-content.
   styles.css has no rules for raw post markup (the static site had no blog),
   so the full prose treatment lives here — matched to the .port-copy /
   guide-body look used across the ported content pages. */
/* CASCADE MIRROR (conversion-notes item 7): .e-con.e-flex sets flex-direction
   at (0,2,0). .post-body-col is a container, so a bare-class rule loses —
   restate at .e-con.e-flex.CLASS. It only needs the default column direction,
   but the width cap must also beat Elementor's
   `.elementor.elementor .e-con > .elementor-widget` sizing, hence the mirror
   carries the max-width too. */
.e-con.e-flex.post-body-col { flex-direction: column; }
.blog-post-section .post-body-col,
.e-con.post-body-col { max-width: 760px; margin-inline: auto; width: 100%; }

/* ---- BREATHING ROOM AROUND THE FAQ ACCORDION ----
   The closing paragraphs started at EXACTLY the accordion's bottom edge
   (measured gap: 0px), so the prose looked glued to the last question row.
   Cause is the kit PRE rule `.elementor-widget:not(:last-child)
   { margin-block-end: 0 }`, which strips every widget's default spacing; the
   accordion never had anything restore it. Give the block real separation on
   both sides — it is a distinct component, not another paragraph. */
.blog-post-body .faq-list,
.elementor-widget.faq-list {
  margin-block-start: 1.6rem !important;
  margin-block-end: 2.2rem !important;
}
@media (max-width: 640px) {
  .blog-post-body .faq-list,
  .elementor-widget.faq-list {
    margin-block-start: 1.3rem !important;
    margin-block-end: 1.7rem !important;
  }
}

/* ---- ICON-LIST TEXT COLOUR ----
   The article "term — description" lists (`post-list`, built with the native
   icon-list widget) rendered their <b> lead-ins in the ACCENT ORANGE
   (#f39321): "Icon class", "Oasis class", "Quantum class" and so on came out
   orange mid-article while the surrounding prose was ink. Nothing in our CSS
   set that — the icon-list widget inherits the kit's accent for its text, and
   our list styling targets different classes so it never overrode it.

   Orange body copy on cream also fails contrast (that is why --accent-ink
   exists), so this was a legibility bug as much as a styling one. Put the
   list back on the body ink ramp: description in --ink like every other
   paragraph, the <b> term in navy so it still reads as a lead-in. */
.blog-post-body .post-list .elementor-icon-list-text,
.blog-post-body .post-list .elementor-icon-list-item > a,
.blog-post-body .post-list .elementor-icon-list-item {
  color: var(--ink);
}
.blog-post-body .post-list .elementor-icon-list-text b,
.blog-post-body .post-list .elementor-icon-list-text strong {
  color: var(--navy);
  font-weight: 600;
}

/* ---- TIGHTEN THE HERO -> ARTICLE GAP ----
   `.e-con.htsec { padding: 96px 0 }` is the site-wide section rhythm, and it
   is right for marketing sections that sit between two blocks of content. On
   an ARTICLE it is wrong: the hero already ends in a full-bleed photo, so 96px
   of cream before the first sentence reads as dead space rather than as
   breathing room. Halve it here only — the rest of the site keeps 96px.
   The bottom padding stays: the article does need separation from the CTA
   band that follows it. */
.e-con.htsec.blog-post-section { padding-top: 44px; }
@media (max-width: 640px) {
  .e-con.htsec.blog-post-section { padding-top: 32px; }
}

/* ---- ANCHOR-JUMP CLEARANCE ----
   The header is fixed and 83px tall once stuck, so anything an anchor jumps
   to lands BEHIND it without an offset. `scroll-margin-top` is already set on
   h2/h3 further down, but that misses the post title and any other #hash
   target (a link shared from search, the skip link), so state it once on the
   scroll container where it covers every target.

   NOTE: no top padding on `.blog-post-section` — the hero already provides
   the page's opening spacing, and extra padding there only moves where the
   page STARTS, which was never the issue. The real fix for "ON THIS PAGE"
   sitting too high was the sticky offset on `.e-con.post-toc-col` (the
   COLUMN, not `.post-toc`, which is not positioned and ignores `top`). */
html { scroll-padding-top: 110px; }
@media (max-width: 1024px) {
  html { scroll-padding-top: 88px; }   /* shorter header on phones */
}

.blog-post-body { font-family: var(--font-body); font-weight: 300; color: var(--ink); }
.blog-post-body p { font-size: 1.06rem; line-height: 1.75; margin: 0 0 1.25rem; }
/* NOTE the class is `post-lead`, NOT `lead`. The kit PRE block caps
   `.elementor-widget.lead{max-width:640px !important}` for section leads; a
   `lead` class inside the post body inherited that cap and rendered the opening
   paragraph 640px wide inside a 760px column, which reads as a broken
   left-shifted indent. Post bodies use their own class. */
.blog-post-body p.post-lead {
  font-family: var(--font-body);
  font-size: 1.2rem;
  line-height: 1.65;
  color: var(--ink-soft);
  margin-bottom: 1.8rem;
}
.blog-post-body h2 {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  font-weight: 400;
  letter-spacing: 0.12em;
  line-height: 1.3;
  color: var(--navy);
  margin: 2.4rem 0 1rem;
}
.blog-post-body h3 {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--navy);
  margin: 1.9rem 0 0.7rem;
}
.blog-post-body a { color: var(--navy-2); text-decoration: underline; }
.blog-post-body a:hover { color: var(--accent); }
.blog-post-body ul, .blog-post-body ol { margin: 0 0 1.25rem 1.3rem; }
.blog-post-body li { font-size: 1.06rem; line-height: 1.75; margin-bottom: 0.5rem; }
.blog-post-body blockquote {
  font-family: var(--font-accent);
  font-style: italic;
  font-size: 1.3rem;
  line-height: 1.5;
  color: var(--navy-2);
  border-left: 3px solid var(--accent);
  padding-left: 22px;
  margin: 2rem 0;
}
.blog-post-body img { max-width: 100%; height: auto; border-radius: var(--radius); }

/* --------------------------------------------------------------- mobile */
@media (max-width: 860px) {
  .blog-grid .elementor-post__text { padding: 20px 18px 22px; }
}
@media (max-width: 640px) {
  .blog-grid .elementor-pagination .page-numbers {
    min-width: 36px; padding: 9px 8px 7px; margin: 0 2px; font-size: 0.7rem; }
  .blog-post-body p, .blog-post-body li { font-size: 1.02rem; }
}

/* ============================================================
   SINGLE POST — sticky table of contents
   Built client-side from the article's own H2/H3s (see TOC_JS in
   _build_blog.py), so it needs no per-post configuration and stays
   correct if an article is edited.
   `.e-con.e-flex` sets flex-direction at (0,2,0) — hence the mirror
   (cascade-war trap #7).
   ============================================================ */
.e-con.e-flex.post-layout {
  flex-direction: row;
  align-items: flex-start;
  gap: 48px;
}
.e-con.post-body-col { flex: 1 1 auto; min-width: 0; }
/* Sticky offset: the stuck header is 83px, so this must clear it AND leave
   visible breathing room — at the previous 118px "ON THIS PAGE" still came to
   rest hard against the top of the viewport. `!important` because Elementor
   emits container position/offset rules at (0,3,0) that beat a bare class. */
.e-con.post-toc-col  { flex: 0 0 240px; position: sticky; top: 132px !important; }

.post-toc {
  border-left: 2px solid var(--accent);
  padding: 2px 0 2px 18px;
}
.post-toc b {
  display: block;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  color: var(--ink-soft);
  margin-bottom: 12px;
}
.post-toc ol { list-style: none; margin: 0; padding: 0; }
.post-toc li { margin: 0 0 10px; line-height: 1.35; }
.post-toc li.toc-sub { padding-left: 14px; }
.post-toc a {
  font-size: 0.9rem;
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.2s, border-color 0.2s;
}
.post-toc a:hover { color: var(--accent-ink); border-color: var(--accent-ink); }
.post-toc a.is-current { color: var(--navy); font-weight: 500; }
.post-toc li.toc-sub a { font-size: 0.84rem; }

/* headings need scroll clearance under the fixed header when jumped to */
.blog-post-body h2, .blog-post-body h3 { scroll-margin-top: 110px; }

/* Tablet/mobile: the TOC moves ABOVE the article and un-sticks, so it reads
   as a jump list instead of stealing width from the text. */
@media (max-width: 1024px) {
  .e-con.e-flex.post-layout { flex-direction: column; gap: 26px; }
  .e-con.post-toc-col {
    flex: 1 1 auto; position: static; width: 100%; order: -1;
  }
  .post-toc {
    border-left: 0;
    border-top: 2px solid var(--accent);
    padding: 16px 0 0;
  }
  .post-toc ol { columns: 2; column-gap: 30px; }
  .post-toc li { break-inside: avoid; }
}
@media (max-width: 640px) {
  .post-toc ol { columns: 1; }
}
@media print { .post-toc-col { display: none; } }

/* ---- sticky conversion card in the post sidebar ---- */
.post-cta {
  display: block;
  margin-top: 26px;
  background: var(--navy);
  border-radius: var(--radius);
  padding: 22px 20px 24px;
  box-shadow: var(--shadow-card);
}
.post-cta b {
  display: block;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.82rem;
  letter-spacing: 0.16em;
  color: var(--white);
  margin-bottom: 10px;
}
.post-cta p {
  font-size: 0.88rem;
  line-height: 1.5;
  color: rgba(246, 241, 230, 0.8);
  margin-bottom: 16px;
}
/* the .btn class carries the gradient; width/centring is card-specific */
.post-cta .btn {
  display: block;
  width: 100%;
  text-align: center;
  padding: 14px 18px 12px;
  font-size: 0.78rem;
}
.post-cta-note {
  display: block;
  margin-top: 12px;
  font-size: 0.72rem;
  line-height: 1.45;
  color: rgba(246, 241, 230, 0.55);
  text-align: center;
}

/* Tablet/mobile: the sidebar collapses ABOVE the article. A CTA there would
   sit between the reader and the copy they came for, so it drops BELOW the
   jump list and reads as a normal block rather than an interruption. */
@media (max-width: 1024px) {
  .post-cta {
    max-width: 520px;
    margin: 22px auto 0;
  }
  .post-cta .btn { display: inline-block; width: auto; min-width: 240px; }
}
@media print { .post-cta { display: none; } }

/* Card titles reserve TWO lines of height so the date, excerpt and
   "Read the guide" link sit on the same baseline across a row regardless of
   title length. Without this, a one-line title pulls its whole metadata
   stack up and the row reads as misaligned. Titles longer than two lines
   are clamped with an ellipsis rather than pushing the card taller. */
.blog-grid .elementor-post__title {
  min-height: calc(2 * 1.32em);   /* 2 lines at the title's line-height */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-bottom: 6px;
}
.blog-grid .elementor-post__title a { display: inline; }

/* ---- archive: category navigation ---- */
.blog-cats { margin: 0 0 34px; }
.blog-cats-list {
  display: flex; flex-wrap: wrap; gap: 10px;
  list-style: none; margin: 0; padding: 0;
}
.blog-cats-list li { margin: 0; }
.elementor-kit-4 .blog-cats-list a.blog-cat,
.blog-cat {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  /* near-full-strength cream: at 0.82 on a 7%-white fill these chips read as
     dark-on-dark and were effectively invisible against the navy section */
  color: rgba(246, 241, 230, 0.96);
  background: rgba(246, 241, 230, 0.14);
  border: 1px solid rgba(246, 241, 230, 0.42);
  border-radius: 100px;
  padding: 9px 16px 8px;
  text-decoration: none;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.elementor-kit-4 .blog-cats-list a.blog-cat:hover,
.blog-cat:hover {
  background: rgba(247, 176, 74, 0.14);
  border-color: var(--accent-soft);
  color: var(--white);
}
.elementor-kit-4 .blog-cats-list a.blog-cat.is-current,
.blog-cat.is-current {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--navy-deep);
  font-weight: 600;
}
.blog-cat-n {
  font-size: 0.66rem;
  opacity: 0.85;
  font-weight: 400;
}
.blog-cat.is-current .blog-cat-n { opacity: 0.75; }
@media (max-width: 640px) {
  .blog-cat { font-size: 0.68rem; padding: 8px 13px 7px; letter-spacing: 0.1em; }
  .blog-cats { margin-bottom: 26px; }
}

/* The blog intro ("Advice from people who book these trips daily") is
   blog-HOME framing. On a category archive it pushes the actual articles down
   the page to restate a mission the reader has already moved past — they
   clicked a topic because they want that topic. Show it on the posts page
   only. The body class comes from ht-seo.php (both views share template 329).
   Same for the archive lead paragraph, which reads as a site intro. */
body.ht-term-archive .blog-intro { display: none; }
/* The lead is no longer generic site copy on a term archive — it now carries
   the CATEGORY'S OWN description and article count (see [ht_archive_heading]),
   so it stays visible. Only the blog-home intro section is suppressed. */
/* the section head keeps a smaller top gap once the intro above it is gone */
body.ht-term-archive .blog-list { padding-top: 64px; }

/* ===== kit-additions/cluster-b.css ===== */
/* ================================================================
   Cluster B — destinations (10) + ports (26) kit additions.
   Appended after PRE + styles.css + POST by _build_kit.py; rules here
   win specificity ties against everything above. Some rules duplicate
   other clusters' fragments on purpose (identical values) so this
   cluster stays self-sufficient if another fragment changes.
   ================================================================ */

/* page-hero h1: the PRE restatement (.elementor-widget-heading
   h1.elementor-heading-title, (0,2,1)) beats static .page-hero h1 (0,1,1)
   — mirror the page-hero clamp + margins at the same specificity, later. */
.page-hero h1.elementor-heading-title {
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  margin: 0.4rem 0 1rem; }

/* page-hero lead: POST's .on-dark .elementor-widget-text-editor.lead
   ((0,3,0)) beats static .page-hero .lead (0,2,0) — mirror, later wins. */
.page-hero .elementor-widget-text-editor.lead {
  color: rgba(246, 241, 230, 0.9);
  font-size: 1.16rem; }

/* static inline style="color:var(--navy)" on bg-white section h2s ->
   ported as widget class h2-navy */
.elementor-widget-heading.h2-navy h2.elementor-heading-title {
  color: var(--navy); }

/* static inline style="margin-bottom:1.6rem" on section-heads -> class
   (same name/value as cluster E's) */
.e-con.section-head.sh-mb16 { margin-bottom: 1.6rem; }

/* kit global link color beats these (0,1,1) static link rules — restate
   at (0,2,1), later (breadcrumbs + more-dest also in cluster D's file) */
.page-hero .breadcrumbs a { color: var(--accent-soft); text-decoration: none; }
.page-hero .breadcrumbs a:hover { text-decoration: underline; }
.form-section .more-dest a { color: var(--cream); text-decoration: none; }
.form-section .more-dest a:hover { color: var(--accent-soft);
  border-color: var(--accent-soft); }
.htsec .exc-guide-link a { color: var(--navy-2); text-decoration: none; }
.htsec .exc-guide-link a:hover { color: var(--accent); }

/* ===== kit-additions/cluster-c.css ===== */
/* ============ cluster C (cruise-lines) kit additions ============
   Appended after PRE + styles.css + POST by _build_kit.py — rules here win
   specificity ties against everything above. */

/* page-hero h1: the PRE restatement (.elementor-widget-heading
   h1.elementor-heading-title, (0,2,1)) beats static .page-hero h1 (0,1,1) —
   mirror the page-hero size + margins at the same-or-higher specificity */
.page-hero h1.elementor-heading-title {
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  margin: 0.4rem 0 1rem;
}

/* page-hero lead: .on-dark .elementor-widget-text-editor.lead (POST, (0,3,0))
   beats static .page-hero .lead (0,2,0) — mirror the hero-lead color/size */
.page-hero .elementor-widget-text-editor.lead {
  color: rgba(246, 241, 230, 0.9);
  font-size: 1.16rem;
}

/* line pages force the vibe-card grid to 3 columns at every viewport
   (static: inline style on .why-grid), beating the 1080/640 media queries
   exactly like the inline style did */
.why-grid.why-grid-3 { grid-template-columns: repeat(3, 1fr) !important; }
/* DELIBERATE deviation (logged in ELEMENTOR-CONVERSION-NOTES-C.md): the
   static inline style keeps 3 columns even at phone widths, which overflows
   the viewport (543px doc at 390px) — an oversight in the static build, not
   a design intent. Collapse to one column at the site's mobile breakpoint. */
@media (max-width: 640px) {
  .why-grid.why-grid-3 { grid-template-columns: 1fr !important; }
}

/* combo pages: 'The Pairing, Explained'-style h2 is navy on bg-white
   (static: inline style color:var(--navy) on the h2) */
.elementor-widget-heading.h2-navy h2.elementor-heading-title {
  color: var(--navy);
}

/* kit global link color (.elementor-kit-4 a, (0,2,0)) beats the static
   (0,1,1) link rules — restate at (0,2,1), later. Duplicated across cluster
   fragments on purpose (identical values) so each stays self-sufficient. */
.page-hero .breadcrumbs a { color: var(--accent-soft); text-decoration: none; }
.page-hero .breadcrumbs a:hover { text-decoration: underline; }
.form-section .more-dest a { color: var(--cream); text-decoration: none; }
.form-section .more-dest a:hover { color: var(--accent-soft);
  border-color: var(--accent-soft); }

/* form submit: the kit's global accent typography leaks font-style italic
   into the Form widget's submit button (the POST .form-card submit rule
   restates everything except font-style) — site-wide fix, found on the
   cluster-C visual gate */
.form-card .elementor-field-type-submit .elementor-button {
  font-style: normal;
}

/* ===== kit-additions/cluster-d.css ===== */
/* ================================================================
   Cluster D — excursions pages (generated pages: /excursions/<slug>/)
   Mirrors for static rules that lose to the kit PRE/POST restatements
   or to Elementor's own element rules. See ELEMENTOR-CONVERSION-NOTES-D.md
   ================================================================ */

/* .page-hero h1 sizing: the PRE block restates h1 at
   .elementor-widget-heading h1.elementor-heading-title (0,2,1), which beats
   the static .page-hero h1 (0,1,1) — mirror at the same specificity. */
.page-hero h1.elementor-heading-title {
  font-size: clamp(2.2rem, 5vw, 3.8rem); margin: 0.4rem 0 1rem; }

/* .page-hero .lead color/size: POST's .on-dark .elementor-widget-text-editor.lead
   (0,3,0) would win over the static .page-hero .lead — mirror, later wins. */
.page-hero .elementor-widget-text-editor.lead {
  font-size: 1.16rem; color: rgba(246, 241, 230, 0.9); }

/* the static up-close H2 carries inline style="color:var(--navy)" — ported
   as widget class h2-navy (inline styles don't survive the Heading widget) */
.h2-navy h2.elementor-heading-title { color: var(--navy); }

/* kit global link color (.elementor-kit-4 a, (0,2,0)) beats these (0,1,1)
   static link styles — restate at (0,2,1)+ */
.page-hero .breadcrumbs a { color: var(--accent-soft); text-decoration: none; }
.page-hero .breadcrumbs a:hover { text-decoration: underline; }
.form-section .more-dest a { color: var(--cream); text-decoration: none; }
.form-section .more-dest a:hover { color: var(--accent-soft);
  border-color: var(--accent-soft); }

/* margin-collapse compensation: in static flow the last port-copy <p>
   (margin-bottom 1rem) and .exc-list (margin-top 1.2rem) collapse to 1.2rem;
   split across Text Editor + HTML widget wrappers they would add to 2.2rem */
.e-con.port-copy .exc-list { margin-top: 0.2rem; }

/* ===== kit-additions/cluster-e.css ===== */
/* ================= CLUSTER E (guides / printables / departure ports) =====
   Appended after the shared PRE + styles.css + POST blocks by _build_kit.py.
   Rules here exist ONLY to out-specificity the shared adaptation layer. */

/* page-hero h1: the PRE restatement (.elementor-widget-heading
   h1.elementor-heading-title, (0,2,1)) forces the homepage hero size and a
   zero margin; restate the .page-hero variant at the same specificity, later
   in the sheet, so template pages get the static clamp + margins. */
.page-hero h1.elementor-heading-title {
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  margin: 0.4rem 0 1rem; }

/* page-hero lead: the POST text-editor mirrors ((0,2,0)/(0,3,0)) beat the
   static .page-hero .lead (0,1,1) — mirror it at (0,3,0), later. */
.page-hero .elementor-widget-text-editor.lead {
  color: rgba(246, 241, 230, 0.9);
  font-size: 1.16rem; }

/* inline style="color:var(--navy)" on story-section h2s -> class */
.elementor-widget-heading.h2-navy h2.elementor-heading-title {
  color: var(--navy); }

/* inline section-head margin-bottom overrides -> classes */
.e-con.section-head.sh-mb16 { margin-bottom: 1.6rem; }
.e-con.section-head.sh-mb20 { margin-bottom: 2rem; }

/* printables print output: the static @media print rules (in styles.css,
   already in this kit) hide .site-header/.page-hero/.band/.form-section/
   .site-footer. On WP additionally: the theme-builder wrapper divs, the
   sticky-header spacer, and Elementor entrance-animation states
   (.elementor-invisible = opacity 0) must not leak into print. */
@media print {
  .elementor-location-header, .elementor-location-footer,
  header.site-header, footer.site-footer,
  .elementor-sticky__spacer { display: none !important; }
  .elementor-invisible, .animated {
    visibility: visible !important;
    opacity: 1 !important;
    animation: none !important;
    transform: none !important; }
}

/* ===== kit-additions/contact.css ===== */
/* ============================================================
   /contact/ — contact methods + expectations
   ------------------------------------------------------------
   Reuses the site's existing section rhythm (.page-hero, .bg-cream,
   .bg-navy), so only the two components unique to this page need rules.

   Section order is white-hero / cream / navy / form-band, which keeps the
   alternating-shade rule intact and puts light cards on the cream section
   rather than same-on-same.
   ============================================================ */

/* ---- contact method cards ----
   Real anchors (tel: / mailto:), so they must look and behave clickable:
   pointer cursor, hover lift, and a visible focus ring for keyboards. */
.contact-methods {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 22px;
  margin-top: 34px;
}

.contact-card {
  display: flex;
  flex-direction: column;
  height: 100%;                 /* equal height regardless of note length */
  background: #fff;             /* white on cream — opposite shade, so it pops */
  border-radius: var(--radius);
  padding: 28px 26px 24px;
  text-decoration: none;
  box-shadow: var(--shadow-card);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.contact-card:hover,
.contact-card:focus-visible {
  transform: translateY(-4px);
  box-shadow: var(--shadow-card-hover);
}

.contact-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.contact-label {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--accent-ink);     /* WCAG-passing orange for text on light */
  margin-bottom: 10px;
}

/* The number/address itself is the point of the card, so it carries the
   visual weight. Not a link colour — the whole card is the link. */
.contact-value {
  font-family: var(--font-display);
  font-size: 1.32rem;
  font-weight: 600;
  color: var(--navy);
  line-height: 1.25;
  margin-bottom: 10px;
  word-break: break-word;       /* long email must not overflow on mobile */
}

/* Availability sits directly under the number/address, because someone about
   to dial checks "are they open?" before reading anything else. Weighted
   between the value and the note so it reads as fact, not marketing. */
.contact-hours {
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--navy);
  opacity: 0.78;
  margin-bottom: 8px;
}

.contact-note {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin-top: auto;             /* pins the note to the card bottom */
}

/* ---- what to expect ----
   On the navy section, so text is light and the accent marker carries. */
.contact-expect {
  list-style: none;
  margin: 30px auto 0;
  padding: 0;
  max-width: 760px;
}

.contact-expect > li {
  position: relative;
  padding-left: 30px;
  margin-bottom: 20px;
  font-size: 1.04rem;
  line-height: 1.7;
}

.contact-expect > li:last-child { margin-bottom: 0; }

.contact-expect > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 12px;
  height: 2px;
  background: var(--accent);
}

.contact-expect b {
  font-weight: 600;
  color: #fff;
}

/* The hero carries little copy and no CTA, so it does not need the full
   inner-page hero height. */
.e-con.contact-hero { min-height: 0; }

@media (max-width: 640px) {
  .contact-value { font-size: 1.18rem; }
  .contact-card { padding: 24px 22px 20px; }
}

/* ===== kit-additions/faq.css ===== */
/* FAQ: hand-built <details> HTML widgets -> native `nested-accordion`.
   See HTML-BLOCK-AUDIT.md §3 and ELEMENTOR-CONVERSION-NOTES.md
   "FAQ conversion to native accordion".

   The native widget renders the SAME <details>/<summary> elements the static
   markup used, so `.faq-list` in styles.css already supplies background,
   radius, shadow, font-family/size/weight and uppercase. Only four measured
   deltas needed fixing; these are those six rules, re-measured to exact
   equality (820px wrapper, 20px 54px 20px 26px padding, rgb(12,42,68),
   1.44px letter-spacing). */

/* 1. WRAPPER WIDTH. `.faq-list{max-width:820px}` in styles.css targets the
      inner <div>, but the class now lands on the Elementor WIDGET wrapper,
      which sits inside the 1180px .wrap and would otherwise run full width. */
.elementor-widget.faq-list {
  max-width: 820px !important;
  margin-left: auto !important;
  margin-right: auto !important;
  width: 100%;
}

/* 2. ITEM SPACING. The static rule is `.faq-list details{margin-bottom:14px}`;
      the native item is `details.e-n-accordion-item`, and the widget's own
      stylesheet zeroes the margin at a higher specificity. */
.faq-list details.e-n-accordion-item { margin-bottom: 14px !important; }
.faq-list details.e-n-accordion-item:last-child { margin-bottom: 0 !important; }

/* 3. TITLE COLOUR + TRACKING + SIZE.
      MEASURED CASCADE TRAP (#5/#11, hit for real here): the widget ships
      `widget-nested-accordion.min.css` with
        .elementor-widget-n-accordion .e-n-accordion-item-title { padding: 10px }
        .elementor-widget-n-accordion .e-n-accordion-item-title-text {
            font-size: var(--n-accordion-title-font-size) }
      That is (0,2,0) — the SAME specificity as `.faq-list .e-n-...` — but it is
      enqueued AFTER the kit CSS, so on a tie the widget wins. First attempt at
      these rules measured padding:10px and font-size:16px instead of the
      targets. Fixed by matching the widget's own two-class prefix so we
      out-specify it at (0,3,0), and by setting the CSS VARIABLE the widget's
      own rule reads rather than fighting the declaration.
      Targets (from HTML-BLOCK-AUDIT.md §3.3): 14.4px / 1.44px / rgb(12,42,68). */
.faq-list .e-n-accordion-item-title-text,
.faq-list .e-n-accordion-item-title {
  color: #0c2a44;
  letter-spacing: 0.1em;
}
/* `title_tag: div` makes the widget set --n-accordion-title-font-size: 1rem
   (16px). The static summary is 0.9rem (14.4px) — set the variable so the
   widget's own rule computes the right value. */
.elementor-widget.faq-list { --n-accordion-title-font-size: 0.9rem; }

/* COLOUR-AUDIT: the <summary> itself computed rgb(31,33,36) (#1f2124) — an
   off-system near-black in NO palette token (body ink is #22303f). It comes
   from the nested-accordion widget's OWN default variable,
   `--n-accordion-title-normal-color: #1f2124`, which the widget's stylesheet
   reads; that is why the `color: #0c2a44` rule above did not change it and why
   no author rule shows up as matching in the CSSOM.

   Today it paints nothing visible: every title's text sits in the nested
   `.e-n-accordion-item-title-text` div, which our rule correctly renders navy.
   But the value still leaks to any direct text child of <summary> (the "+"
   marker, and anything a future author adds), so normalise it at the source —
   set the VARIABLE the widget reads rather than fighting the declaration,
   exactly as the font-size fix above does. */
.elementor-widget.faq-list {
  --n-accordion-title-normal-color: #0c2a44;
  --n-accordion-title-hover-color: #0c2a44;
  --n-accordion-title-active-color: #0c2a44;
}
.elementor-widget-n-accordion.faq-list .e-n-accordion-item-title-text {
  font-size: 0.9rem;
  letter-spacing: 0.1em;
  color: #0c2a44;
}

/* 4. PADDING. The static padding lives on `summary`; the native widget puts
      its own 10px padding on `.e-n-accordion-item-title` at (0,2,0) from a
      later stylesheet, so this must carry the widget's own class prefix too.
      The answer lives in a nested container (.e-con), not a bare <p>. */
.elementor-widget-n-accordion.faq-list .e-n-accordion-item-title {
  padding: 20px 54px 20px 26px;
}
.faq-list .e-n-accordion-item > .e-con { padding: 0 26px 22px; }

/* --- supporting rules (not part of the four deltas) --- */

/* The site's own rotating "+" is drawn by `.faq-list summary::after`. The
   widget's Font-Awesome icon pair is suppressed in the generator
   (accordion_item_title_icon: ""), but the widget still reserves a flex slot
   for the icon wrapper — collapse it so the CSS "+" sits where it always did. */
.faq-list .e-n-accordion-item-title-icon { display: none; }

/* The widget's title header span is a flex child; without this the title text
   does not fill the row and the ::after "+" anchors against the wrong box. */
.faq-list .e-n-accordion-item-title-header { flex: 1; min-width: 0; }

/* Answer prose: styles.css targets `.faq-list details p`, which still matches,
   but the text-editor widget wrapper re-introduces Elementor's own margins. */
.faq-list .e-n-accordion-item > .e-con .elementor-widget-text-editor { margin: 0; }
.faq-list .e-n-accordion-item > .e-con p { padding: 0; color: var(--ink-soft); }

/* ===== kit-additions/fleet-grid.css ===== */
/* ================================================================
   "Ships in the Fleet" grid — the section _relink_ships.py inserts
   into each of the 10 cruise-line pages. Ships are GROUPED BY CLASS:
   class groups run biggest to smallest (by the largest gross tonnage
   in the class), and hulls run newest to oldest inside each group.

   WHY THIS FILE EXISTS AT ALL
   ---------------------------
   The 70 wave-1 ship pages shipped ORPHANED: they were reachable
   only from a sitemap, because no page linked to them. Every ship
   page links UP to its line page, but nothing linked DOWN. This
   grid is the down-link, so the section is a crawl path first and
   a design element second — which is why every card is a real <a>
   container (link on the container, not on an inner heading), and
   why the facts are plain text rather than an icon row.

   DESIGN RULES THIS ENCODES (house rules, non-negotiable)
   -------------------------------------------------------
   * CARDS CONTRAST THEIR SECTION. The grid is inserted on a
     `.bg-cream` section, so the cards are WHITE. This is the same
     opposite-shade treatment `.why-card` uses on cream and
     `.line-card` uses on navy. Note the deliberate asymmetry with
     `.why-card`: that rule FLIPS to cream on `.bg-white` because
     the line pages' third section is white. Our section is cream,
     so white is the contrasting choice here — do not "harmonise"
     the two, they are opposite shades for the same reason.

   * EQUAL HEIGHT, ALWAYS. Ship names run from "Costa" length to
     "Carnival Sunshine" length, and the fact lines vary from two
     to FOUR items — a "Last refurbished" line is emitted only for
     the 61 hulls with a publishable refurb year, so a 3-fact card
     and a 4-fact card routinely sit in the same row. `height:100%`
     is set on BOTH the grid item (the Elementor container that IS
     the card) and its inner flex column, and the facts block is
     pushed down with `margin-top: auto`, so a 3-fact card's footer
     still lines up with a 4-fact one.

   * CLASSES, NEVER IDS. Every .elementor-kit-4 below is a semantic class
     that _relink_ships.py sets via `css_classes` (containers) /
     `_css_classes` (widgets). Elementor regenerates element IDs on
     copy, duplicate, template import and v3->v4 atomic conversion,
     so an ID-keyed rule here would silently stop matching the day
     anyone touches the section in the editor.

   Loaded by _build_kit.py, which merges every kit-additions/*.css
   fragment in sorted filename order after styles.css.
   ================================================================ */

/* ---------- the class group heading ---------- */
/* Ships are grouped by class (biggest class first, newest hull first inside
   each), so each group is a heading followed by its OWN `.fleet-grid`. One
   grid with headings interleaved would place cards from different classes in
   the same CSS grid row, and a row that spans a heading cannot honour the
   equal-height rule — the heading would be stretched as a grid item.

   `.ht-fleet-class-head` is a real reusable class set via `_css_classes` on
   the heading widget. Never an element ID: Elementor regenerates IDs on copy,
   duplicate, template import and v3->v4 atomic conversion. */
.ht-fleet-class-head,
.ht-fleet-class-head .elementor-heading-title {
  color: var(--navy);
  font-size: 1.24rem;
  line-height: 1.25;
  letter-spacing: 0.02em;
  margin: 0;
}
.ht-fleet-class-head {
  margin-top: 2.4rem;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--accent);
}
/* The first group's heading sits directly under the section lead, which
   already carries its own spacing, so it does not need the inter-group gap.
   Selected as "a class head that immediately follows the section head" rather
   than with :first-of-type — Elementor renders BOTH the heading widget and the
   grid container as <div>, so :first-of-type would match on div-ness and pick
   the wrong element the moment the markup nests differently. */
.section-head + .ht-fleet-class-head { margin-top: 2.2rem; }

/* ---------- the grid ---------- */
/* Top margin is smaller than it was for the single flat grid: each grid now
   follows its own class heading rather than the section lead, so the heading
   supplies the separation between groups. */
.fleet-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  margin-top: 1.1rem;
}

/* ---------- the card ---------- */
/* The card IS the grid item (an Elementor container with html_tag "a"), so
   the height:100% that equalises the row and the height:100% that fills it
   are the same declaration — but Elementor wraps nothing around it, so this
   single rule has to do both jobs. `align-self: stretch` is belt-and-braces
   for the case where a future edit adds a wrapper. */
a.fleet-card,
.fleet-card {
  height: 100%;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border-radius: var(--radius);
  border-top: 3px solid var(--accent);
  padding: 26px 24px 22px;
  box-shadow: var(--shadow-card);
  text-decoration: none;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
a.fleet-card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-card-hover);
}

/* Ship name. A heading widget inside the card container, so the rule has to
   reach through Elementor's widget wrapper. */
.fleet-card .fleet-name,
.fleet-card .fleet-name .elementor-heading-title {
  color: var(--navy);
  font-size: 1.06rem;
  line-height: 1.3;
  margin: 0 0 10px;
}
a.fleet-card:hover .fleet-name .elementor-heading-title { color: var(--navy-2); }

/* The facts block. `margin-top: auto` is what keeps the fact lines bottom-
   aligned across a row whose names wrap to different line counts — without
   it, equal-height cards still look ragged because the content floats to
   the top of each box. */
.fleet-card .fleet-facts {
  margin-top: auto;
  padding-top: 4px;
}
.fleet-card .fleet-facts p {
  margin: 0 0 4px;
  font-size: 0.93rem;
  line-height: 1.45;
  color: var(--ink-soft);
}
.fleet-card .fleet-facts p:last-child { margin-bottom: 0; }
.fleet-card .fleet-facts b {
  color: var(--navy-2);
  font-weight: 600;
}

/* The "view the ship guide" affordance. Drawn as a real span in the markup
   (never a ::before/::after) so it survives an Elementor v4 atomic
   conversion, which flattens pseudo-elements. */
.fleet-card .fleet-more {
  display: block;
  margin-top: 14px;
  font-size: 0.86rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-ink);   /* WCAG AA on white; see --accent-ink */
}
a.fleet-card:hover .fleet-more { color: var(--accent); }

/* ---------- responsive ---------- */
@media (max-width: 1000px) {
  .fleet-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .fleet-grid { grid-template-columns: 1fr; gap: 18px; }
}

/* ===== kit-additions/internal-links.css ===== */
/* ============================================================
   Internal link treatments
   ------------------------------------------------------------
   Two treatments, chosen by CONTEXT rather than by taste.

   1. WHOLE-ELEMENT LINKS (fact chips, cards, tiles) get NO text
      styling at all. The container already reads as clickable
      through its border, background and hover state; underlining
      the text inside it is redundant and looks broken. The whole
      chip becomes the hit area, which is also a bigger tap target
      on mobile than a few underlined words would be.

   2. PROSE LINKS get a subtle accent underline. They are NOT left
      unstyled: an unstyled link in a paragraph is undiscoverable,
      which fails WCAG 1.4.1 (colour/appearance must not be the
      only signal) and — more practically — an internal link nobody
      can see is an internal link nobody clicks.

   MEASURED, NOT ASSUMED: this kit has NO global `a {}` rule, so an
   unstyled link inherits the browser default. Verified on the live
   Royal Caribbean hero: chip text is rgb(255,255,255) while an
   unstyled anchor computed to rgb(19,70,104) — dark navy on a dark
   translucent chip, effectively invisible. Hence every rule below
   sets colour explicitly.
   ============================================================ */

/* ---- 1. Fact chips: the whole chip is the link ---- */

/* The anchor wraps the chip's contents and must not introduce any
   box of its own -- display:contents keeps the existing flex layout
   exactly as it was, so a linked chip and a plain chip are pixel
   identical at rest. */
/* Every anchor inside a chip, at any depth. The chips on the line hubs are
   RAW HTML (<div class="fact-chip"><b>LABEL</b><span>value</span></div>), not
   the Elementor container/heading structure, so `.fact-chip > a` matched
   nothing and a linked ship name rendered in the browser default navy --
   invisible on the dark hero, showing only the separator dots. Descendant
   .elementor-kit-4, and colour forced, because there is no global `a {}` rule to
   inherit from. */
.fact-chip a {
  color: var(--white) !important;
  text-decoration: none;
  border-bottom: none;
}

.fact-chip a:hover,
.fact-chip a:focus-visible {
  color: var(--accent-soft) !important;
}

/* Elementor renders the chip's value inside .elementor-heading-title,
   which carries its own colour. Without this the link would inherit
   that element's colour rather than the chip's, which is the trap
   that made `color: inherit` alone fail in testing. */
.fact-chip a .elementor-heading-title,
.fact-chip a span {
  color: inherit;
}

/* A linked chip signals itself the way the rest of the site does:
   the accent border brightens and the chip lifts slightly. No text
   decoration, no colour change to the label. */
.fact-chip:has(a):hover,
.fact-chip.is-linked:hover {
  border-color: var(--accent);
  background: rgba(255, 255, 255, 0.16);
  transform: translateY(-1px);
}

.fact-chip:has(a),
.fact-chip.is-linked {
  cursor: pointer;
  transition: border-color .18s ease, background .18s ease, transform .18s ease;
}

/* Keyboard users must see what mouse users get from hover. */
.fact-chip a:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---- 2. Prose links ---- */

/* Body copy on light sections. Underline is a border rather than
   text-decoration so its colour and weight are controllable
   independently of the text, and it never collides with descenders.

   SCOPE NOTE: `.port-prose` alone is NOT enough. Most prose on this site
   lives in a plain Elementor text-editor widget whose paragraphs carry no
   class at all -- the first link inserted into the Royal Caribbean hub landed
   in a bare <p> and rendered navy with no underline, i.e. invisible as a link.
   So the .elementor-kit-4 targets the text-editor widget itself, which is what
   actually wraps body copy sitewide. */
.port-prose a,
.exc-list a,
.faq-list a,
.e-n-accordion-item a,
.elementor-widget-text-editor p a,
.elementor-widget-text-editor li a {
  color: var(--navy);
  text-decoration: none;
  border-bottom: 1px solid rgba(243, 147, 33, .5);
  transition: color .18s ease, border-color .18s ease;
}

.port-prose a:hover,
.exc-list a:hover,
.faq-list a:hover,
.e-n-accordion-item a:hover,
.elementor-widget-text-editor p a:hover,
.elementor-widget-text-editor li a:hover,
.port-prose a:focus-visible,
.exc-list a:focus-visible,
.faq-list a:focus-visible,
.e-n-accordion-item a:focus-visible,
.elementor-widget-text-editor p a:focus-visible {
  color: var(--accent-ink);
  border-bottom-color: var(--accent);
}

/* Same copy on a dark section: navy would vanish, so invert to the
   section's own text colour with the accent rule beneath. */
.on-dark .port-prose a,
.on-dark .exc-list a,
.on-dark .lead a,
.on-dark .elementor-widget-text-editor p a {
  color: var(--white);
  border-bottom-color: rgba(247, 176, 74, .55);
}

.on-dark .port-prose a:hover,
.on-dark .exc-list a:hover,
.on-dark .lead a:hover,
.on-dark .elementor-widget-text-editor p a:hover {
  color: var(--accent-soft);
  border-bottom-color: var(--accent-soft);
}

/* Focus ring for prose links, matching the chip treatment. */
.port-prose a:focus-visible,
.exc-list a:focus-visible,
.faq-list a:focus-visible,
.on-dark .port-prose a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Links already carrying their own component styling must not pick
   up the prose underline: buttons, pill rows and card links are
   whole-element links by the rule above. */
.more-dest a,
.btn,
.hub-card a,
.fleet-card a,
.port-prose .btn,
.breadcrumbs a,
.facts-row a,
.elementor-widget-text-editor .more-dest a,
.elementor-widget-text-editor .btn {
  border-bottom: none;
}

/* ---- 3. Blog category row (.ht-cat-row / .ht-cat-links) ----
   Added to the ht-archive template so the 8 populated blog categories are
   reachable: every one of them had ZERO inbound links and was an orphan, which
   also cost their posts a whole navigational layer.

   Reuses `.more-dest`, the site's existing pill-row, so it inherits the
   established spacing and hover. These rules only correct the two things the
   pill row does not handle in this position: the row sits directly under a
   dark hero on a cream section, so the pills need the cream-section treatment
   rather than the dark one, and the container needs the page's own measure. */
.ht-cat-row {
  padding-top: 26px;
  padding-bottom: 6px;
}

.ht-cat-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

.ht-cat-links a {
  display: inline-block;
  padding: 7px 16px;
  border: 1px solid rgba(12, 42, 68, 0.18);
  border-radius: 999px;
  background: var(--white);
  color: var(--navy);
  font-size: 0.85rem;
  text-decoration: none;
  transition: border-color .18s ease, background .18s ease, color .18s ease;
}

.ht-cat-links a:hover,
.ht-cat-links a:focus-visible {
  border-color: var(--accent);
  color: var(--accent-ink);
}

@media (max-width: 767px) {
  .ht-cat-row { padding-top: 18px; }
  .ht-cat-links a { font-size: 0.8rem; padding: 6px 13px; }
}

/* ---- 4. Algolia autocomplete, wearing the site's search styling ----

   APPROACH: Algolia's own input is the visible one; the site's field is
   hidden. The reverse (site field visible, Algolia's hidden, keystrokes
   mirrored across) produced correct suggestions that never PAINTED --
   autocomplete-js only opens its panel for an input with genuine focus, and
   synthetic focus events do not satisfy that. Swapping which input is visible
   turns the problem into pure CSS, which is far more reliable.

   Values below are lifted from the site's own computed styles, not eyeballed:
     form   44px tall, 420px wide, 1px solid var(--accent), radius 10px,
            white, shadow 0 18px 44px rgba(8,30,51,.34) + 0 0 0 3px accent
     input  42px tall, padding 8px 16px, 16px Jost, colour rgb(34,48,63)
     button 52x42, background var(--navy), white glyph
   ============================================================ */

/* Hide the site's own form once Algolia has mounted -- the class is added by
   the mu-plugin, so if the script never runs the original form stays visible
   and the search still works. Fail-visible, not fail-blank. */
.ht-search-form--replaced {
  display: none !important;
}

/* The Algolia host now carries the panel geometry. */
.ht-algolia-ac {
  width: 420px;
  max-width: 100%;
}

/* --- the form chrome, matched to .ht-search-form --- */
.ht-algolia-ac .aa-Form {
  display: flex;
  align-items: center;
  height: 44px;
  width: 100%;
  background: var(--white);
  border: 1px solid var(--accent);
  border-radius: 10px;
  box-shadow: 0 18px 44px rgba(8, 30, 51, .34),
              0 0 0 3px rgba(243, 147, 33, .28);
  overflow: hidden;
}

/* --- the field itself, matched to .ht-search-input --- */
.ht-algolia-ac .aa-Input {
  height: 42px;
  padding: 8px 16px;
  font-family: Jost, sans-serif;
  font-size: 16px;
  color: rgb(34, 48, 63);
  background: transparent;
  border: 0;
  outline: none;
  width: 100%;
  flex: 1 1 auto;
}

.ht-algolia-ac .aa-Input::placeholder {
  color: rgb(85, 99, 111);
  opacity: 1;
}

/* autocomplete-js puts a magnifier before the field; the site's design has
   the button AFTER it, so the prefix is dropped and the suffix restyled into
   the navy submit button. */
.ht-algolia-ac .aa-InputWrapperPrefix,
.ht-algolia-ac .aa-Label,
.ht-algolia-ac .aa-LoadingIndicator {
  display: none !important;
}

.ht-algolia-ac .aa-InputWrapper {
  flex: 1 1 auto;
  display: flex;
}

.ht-algolia-ac .aa-InputWrapperSuffix {
  flex: 0 0 52px;
  display: flex;
}

.ht-algolia-ac .aa-ClearButton {
  width: 52px;
  height: 42px;
  background: var(--navy);
  color: var(--white);
  border: 0;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.ht-algolia-ac .aa-ClearButton svg {
  width: 17px;
  height: 17px;
}

/* The second renderer (ais-*) ships with the plugin too and would add its own
   field; only the autocomplete-js one is wanted on screen. */
.ht-algolia-ac .ais-Autocomplete,
.ht-algolia-ac .ais-SearchBox {
  display: none !important;
}

/* The autocomplete-js panel is appended to <body> and positioned absolutely
   against the input it belongs to. Since that input is visually hidden inside
   the search dropdown, anchor the panel to the site's search panel instead so
   suggestions appear under the field the visitor is actually looking at. */
.aa-Panel {
  z-index: 100000;
}

.aa-Panel .aa-Item {
  padding: 9px 14px;
  font-size: .9rem;
  line-height: 1.35;
  border-bottom: 1px solid rgba(12, 42, 68, .08);
}

.aa-Panel .aa-Item a,
.aa-Panel .aa-ItemLink {
  color: var(--navy);
  text-decoration: none;
  border-bottom: none;
}

.aa-Panel mark,
.aa-Panel em {
  font-style: normal;
  font-weight: 700;
  color: var(--accent-ink);
  background: transparent;
}

/* The panel itself needs a surface: autocomplete-js ships almost no chrome,
   and the site's dropdown is dark, so an unstyled panel rendered invisibly
   (correct position, 15 real results, nothing on screen). */
.aa-Panel {
  background: var(--white);
  border: 1px solid rgba(12, 42, 68, .14);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card-hover);
  overflow: hidden;
  max-height: 60vh;
  overflow-y: auto;
}

.aa-Panel .aa-List {
  list-style: none;
  margin: 0;
  padding: 0;
}

.aa-Panel .aa-Item:last-child { border-bottom: none; }

.aa-Panel .aa-ItemContent,
.aa-Panel .aa-ItemContentBody {
  color: var(--ink);
}

.aa-Panel .aa-ItemContentTitle {
  color: var(--navy);
  font-weight: 600;
  display: block;
  margin-bottom: 2px;
}

.aa-Panel .aa-ItemContentDescription {
  color: var(--ink-soft);
  font-size: .82rem;
}

.aa-Panel .aa-SourceHeader {
  padding: 8px 14px 4px;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--ink-soft);
}

/* ---- 4b. Mobile: the search panel goes FIXED and full-width ----
   Below 1024px `.ht-search-panel` becomes
       position: fixed; left: 12px; right: 12px
   i.e. a full-width sheet, not a dropdown anchored to the header.

   Two things broke against that:
   1. `.ht-algolia-ac` was hardcoded to 420px, so on a 390px phone the input
      overflowed its own panel.
   2. The suggestion panel is positioned by JS from getBoundingClientRect(),
      which returns VIEWPORT coordinates -- correct for an absolutely
      positioned panel on desktop, wrong inside a fixed parent, so the
      dropdown jumped away from the field as soon as it was tapped.

   Fix: let the host fill the panel, and let the suggestions flow in normal
   document order beneath the field rather than being JS-positioned. */
@media (max-width: 1024px) {
  .ht-algolia-ac {
    width: 100%;
  }

  .ht-algolia-ac .aa-Form {
    width: 100%;
    /* the desktop drop-shadow is a floating-dropdown affordance; inside a
       full-width sheet it just muddies the edge */
    box-shadow: none;
  }

  /* Anchor the suggestions to the panel, not to computed coordinates. The
     JS still sets inline position/top/left with !important, so those are
     explicitly unset here. */
  .aa-Panel {
    position: static !important;
    top: auto !important;
    left: auto !important;
    right: auto !important;
    width: 100% !important;
    margin-top: 8px;
    max-height: 62vh;
    box-shadow: none;
    border: 1px solid rgba(12, 42, 68, .14);
  }

  /* Roomier rows: these are tap targets, not hover targets. */
  .aa-Panel .aa-Item {
    padding: 12px 14px;
  }
}

/* ---- 5. Pill row spacing in the closing form section ----
   `.more-dest` carries `margin-top: 2.4rem` and NO bottom margin, so on the
   form section that ends every page the pills finish flush against the
   section edge and read as cut off. Measured on /destinations/alaska-cruises/:
   the row's bottom (8284) was exactly the container's bottom (8284), with
   padding-bottom: 0 on the wrapper.

   The section's own 96px padding sits ABOVE the row rather than below it,
   because the row is the last child of an inner wrapper. Adding the breathing
   room to the row itself fixes it everywhere the pattern is used without
   touching the section rhythm. */
.more-dest {
  margin-bottom: 2.4rem;
}

/* The band variant sits mid-page between two sections, where the closing
   margin would double up with the next section's padding. */
.htsec.band .more-dest {
  margin-bottom: 0;
}

@media (max-width: 767px) {
  .more-dest {
    margin-bottom: 1.6rem;
  }
}

/* ===== kit-additions/port-notice.css ===== */
/* ============================================================
   .port-notice — a dated, time-sensitive advisory band
   ------------------------------------------------------------
   For facts that are true NOW and will stop being true: a closed
   attraction, a pier out of service, a suspended ferry. Placed
   directly under the page hero so a reader planning a port day
   sees it before the recommendations it contradicts.

   Deliberately NOT an alarm. This is travel advice, not an error
   state, so it uses the brand accent as a left rule rather than a
   red alert box — visible on scan, but it does not shout over the
   page.

   WHY WHITE, NOT CREAM: the band sits between the dark page hero
   and the first `.bg-cream` section. A cream notice there would be
   cream-on-cream — the exact adjacent-same-shade problem the house
   rules forbid. White contrasts the dark hero above AND the cream
   section below, so it reads as its own object from both sides.

   Every value is a token. First use is Juneau (Goldbelt Tram
   closed for the 2026 season); the class is generic so any port
   or destination page can carry one.
   ============================================================ */

/* The section container runs full-bleed (like every .htsec on this site) and
   constrains its CHILD to the 1180px content width. So the card treatment must
   live on the inner child, not the outer container -- putting the background
   on the outer one made the white run to the screen edges while the text
   stayed inset, leaving the accent rule stranded 260px from its own copy. */
.port-notice {
  background: transparent;
  padding: 0;
  margin: 28px auto 0;
}

.port-notice > .elementor-widget,
.port-notice > .e-con-inner,
.port-notice > div {
  background: var(--white);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  padding: 20px 24px;
  box-shadow: var(--shadow-card);
}

.port-notice p {
  margin: 0;
  color: var(--ink);
  font-size: 1rem;
  line-height: 1.6;
}

/* The "Update, August 2026:" lead-in. Dating the notice is the point:
   an undated "currently closed" rots silently, while a dated one tells
   a later reader the line may be stale. */
.port-notice strong {
  color: var(--accent-ink);
}

/* On mobile the padding belongs to the CARD, not the outer container --
   the container is padding-free by design (see the note above), so tightening
   it here would pad the wrong element and leave the card at desktop spacing. */
@media (max-width: 767px) {
  .port-notice {
    margin-top: 22px;
  }

  .port-notice > .elementor-widget,
  .port-notice > .e-con-inner,
  .port-notice > div {
    padding: 16px 18px;
  }
}

/* ===== kit-additions/ports-missing7.css ===== */
/* ================================================================
   The seven missing port pages — Cozumel, Nassau, Grand Cayman,
   St. Thomas, Juneau, Ketchikan, Skagway.

   These pages are AUTHORED (no static HTML source), so rather than
   porting the ~200 inline styles the other clusters carry, the two
   recurring ones are declared here as real classes:

     style="max-width:820px;margin:0 auto 1rem;color:var(--ink-soft)"
       on every body <p>            ->  .port-prose
     style="margin-top:3rem" on .more-dest
     style="max-width:820px;margin:1.4rem auto 0" on .exc-list
     style="text-align:center;margin-top:1.6rem" on .exc-guide-link

   Loaded by _build_kit.py after PRE + styles.css + POST + cluster-b,
   so these win specificity ties against everything above.
   ================================================================ */

/* Body copy measure. The static pages set this inline on each <p>; here
   the text-editor widget wrapper carries the class and the <p>s inherit,
   which is why the rule targets the widget and not the paragraph. */
.elementor-widget-text-editor.port-prose {
  max-width: 820px;
  margin-inline: auto;
}
.elementor-widget-text-editor.port-prose p {
  margin: 0 auto 1rem;
  color: var(--ink-soft);
}
.elementor-widget-text-editor.port-prose p:last-child { margin-bottom: 0; }

/* The excursion list sat at style="max-width:820px;margin:1.4rem auto 0".
   .port-prose already supplies the measure, so only the top gap is left. */
.elementor-widget-text-editor.port-prose .exc-list { margin-top: 1.4rem; }

/* .exc-guide-link was style="text-align:center;margin-top:1.6rem" */
.elementor-widget-text-editor.port-prose .exc-guide-link {
  text-align: center;
  margin-top: 1.6rem;
}

/* .more-dest was style="margin-top:3rem". It lives in a text-editor here
   (a button widget renders <a class="elementor-button"> inside a wrapper,
   which `.more-dest a` would not match), so the widget is the flex parent
   -- the div inside it needs the layout, not the widget itself. */
.elementor-widget-text-editor.ht-more-dest .more-dest { margin-top: 3rem; }

/* The kit's global link colour (0,1,1) beats the static .more-dest a and
   .exc-guide-link a rules, exactly as it does for cluster B — restate at
   higher specificity, later in the cascade. Without these the pills render
   in the kit accent instead of cream and the guide link loses its underline
   colour. Mirrors cluster-b.css deliberately: same values, own file, so
   this page set stays self-sufficient. */
.form-section .ht-more-dest .more-dest a {
  color: var(--cream);
  text-decoration: none;
}
.form-section .ht-more-dest .more-dest a:hover {
  color: var(--accent-soft);
  border-color: var(--accent-soft);
}
.htsec .port-prose .exc-guide-link a {
  color: var(--navy-2);
  text-decoration: none;
}
.htsec .port-prose .exc-guide-link a:hover { color: var(--accent); }

/* In-prose links (the internal links to hubs and excursion pages that make
   these pages non-orphans). The kit's global <a> colour is fine on cream and
   white, but the underline needs to read as a link in body copy. */
.elementor-widget-text-editor.port-prose p a {
  color: var(--navy-2);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(12, 42, 68, 0.35);
}
.elementor-widget-text-editor.port-prose p a:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}

/* Fact chips are now NATIVE (container + two heading widgets) per
   HTML-BLOCK-AUDIT.md §4.8, instead of one html widget holding raw markup.
   The static CSS styles `.fact-chip b` and `.fact-chip span`; Elementor wraps
   each heading in `.elementor-widget-heading > .elementor-heading-title`, so
   the tag .elementor-kit-4s alone no longer reach them. These restate the same
   declarations against the widget structure — measured to equality with the
   static chip (background, border, radius, padding, both type ramps). */
.e-con.fact-chip {
  display: block;
  width: auto;
  flex: 0 0 auto;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(247, 176, 74, 0.45);
  backdrop-filter: blur(4px);
  border-radius: 4px;
  padding: 10px 18px;
}
/* MEASURED GOTCHA — do not "simplify" these back to tag .elementor-kit-4s.
   The chip is built as two heading widgets whose header_size is `b` (label)
   and `span` (value). Elementor's heading widget WHITELISTS its header_size
   values (h1-h6, div, span, p) and SILENTLY falls back to <div> for anything
   else — so the label renders as `<div class="elementor-heading-title">`, not
   `<b>`. A `b.elementor-heading-title` .elementor-kit-4 therefore matches nothing and
   the label inherits body colour, which on a photo hero is almost invisible
   (caught on a 1400px screenshot, not in any automated check).
   The `span` value tag IS honoured, but these are matched by POSITION anyway
   so the pair cannot drift apart again if a tag changes. */
.e-con.fact-chip > .elementor-widget-heading:first-child
    .elementor-heading-title {
  display: block;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--accent-soft);
}
.e-con.fact-chip > .elementor-widget-heading:last-child
    .elementor-heading-title {
  font-size: 0.95rem;
  color: var(--white);
  font-family: var(--font-body);
  text-transform: none;
  letter-spacing: normal;
  /* 300, not 400 — measured against the raw-HTML chip on
     /ports/roatan-cruise-port/, where the value inherits the body's Jost 300.
     Elementor's heading widget applies its own 400, so this restates the
     inherited weight to keep the two implementations pixel-identical. */
  font-weight: 300;
}
/* The chips row: a flex container of chip containers. Elementor containers
   default to `width:100%` children, which would stack the chips full-width
   instead of letting them size to content. */
.e-con.facts-row {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 1.8rem;
  align-items: stretch;
}

/* The band pull-quote moved from an html widget to a text-editor (the native
   blockquote widget injects a "John Doe" author line and drops <br>/<em> —
   HTML-BLOCK-AUDIT.md §4.5). The static `.band blockquote` rules still apply;
   this only stops the text-editor wrapper from adding its own spacing. */
.band .elementor-widget-text-editor blockquote { margin: 0; }

/* ===== kit-additions/search.css ===== */
/* =============================================================
   SEARCH — header icon-expand control, live dropdown, results page.

   Engine: Relevanssi Live Ajax Search 2.6 (the Relevanssi author's own
   companion plugin). Its default stylesheet is DEQUEUED in ht-search.php;
   everything below restyles the plugin's OWN classes to the house language
   rather than restructuring its markup (its JS depends on those classes).

   Type: Josefin Sans (display caps) · Jost (body)
   Palette: --navy / --navy-deep / --cream / --accent, per css/styles.css.

   NOTE: another workstream owns the header/nav layout rules. Nothing here
   restyles .site-header, .site-nav, .nav-actions or the burger — the control
   is a NEW self-contained element appended inside .nav-actions, and every
   .elementor-kit-4 below is scoped to .ht-search* or the plugin's own classes.
   ============================================================= */

/* ------------------------------------------------- 1. the header control */

.ht-search {
  position: relative;
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  /* NO corrective margin here any more.
     This used to carry `margin-left: 44px` to absorb the "Plan My Cruise"
     button, which rendered 175px wide inside a 139px `width-auto` wrapper and
     therefore overflowed its own layout box by 36px, pushing the magnifier
     under it at 1366-1600. The button was removed 2026-08-13 (the CTA is now
     the sticky tab), so the overflow it caused is gone and the margin would
     only push the icon off its reserved slot.
     Spacing is now owned by ONE rule, in sticky-cta.css:
       `.site-header .nav-actions { flex:0 0 auto; min-width:44px; ... }`
     which reserves the icon's slot and gives the centred nav a hard edge.
     Measured after removal — no overlap at 1600/1440/1366/1280/1100. */
}

/* The magnifier button. A real <button> (not a styled span) so it is
   focusable and Enter/Space activate it natively — no key handlers needed. */
.ht-search-toggle {
  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: var(--white);
  cursor: pointer;
  transition: background 0.25s ease, border-color 0.25s ease,
              color 0.25s ease, transform 0.25s ease;
}
.ht-search-toggle:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--navy-deep);
  transform: translateY(-1px);
}
/* Visible focus ring — keyboard users must be able to see where they are. */
.ht-search-toggle:focus-visible {
  outline: 3px solid var(--accent-soft);
  outline-offset: 3px;
}
.ht-search-toggle svg {
  width: 19px;
  height: 19px;
  display: block;
}
/* Icon swap: magnifier at rest, X while open.
   SPECIFICITY: these MUST out-weigh `.ht-search-toggle svg` (0,1,1) above,
   which otherwise forces display:block on BOTH icons and renders the
   magnifier and the X on top of each other (observed at 1366-1600). Matching
   through .ht-search-toggle gives (0,2,1) and settles it. */
.ht-search-toggle .ht-search-close-icon { display: none; }
.ht-search.is-open .ht-search-toggle .ht-search-icon { display: none; }
.ht-search.is-open .ht-search-toggle .ht-search-close-icon { display: block; }
.ht-search.is-open .ht-search-toggle {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--navy-deep);
}

/* ---- the expanding panel ------------------------------------------------
   Desktop: an absolutely-positioned flyout anchored to the button's right
   edge, so expanding the field CANNOT reflow the logo, the nav links or the
   PLAN MY CRUISE button (the header is already tight at 1280).
   It animates width/opacity rather than display, so the transition runs. */
.ht-search-panel {
  position: absolute;
  /* Clear the header bar, not just the 40px button: the toggle is vertically
     centred in a ~92px bar, so `100% + 12px` put the field's top edge level
     with the CTA and the flyout visually collided with it. 26px drops the
     panel clear of the bar's lower edge. */
  top: calc(100% + 26px);
  right: 0;
  width: min(420px, calc(100vw - 40px));
  z-index: 1200;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.22s ease, transform 0.22s ease, visibility 0.22s;
}
.ht-search.is-open .ht-search-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
/* [hidden] must win over the flex/block display of the panel */
.ht-search-panel[hidden] { display: none; }

/* ---- the field ---- */
.ht-search-form {
  display: flex;
  align-items: stretch;
  background: var(--white);
  border-radius: var(--radius, 14px);
  box-shadow: 0 18px 44px rgba(8, 30, 51, 0.34);
  overflow: hidden;
  border: 1px solid rgba(12, 42, 68, 0.12);
}
.ht-search-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  outline: 0;
  background: transparent;
  padding: 14px 16px;
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 1rem;
  font-weight: 300;
  color: var(--ink);
  /* kill the UA search-field affordances so it matches the house field look */
  -webkit-appearance: none;
  appearance: none;
}
.ht-search-input::placeholder {
  color: var(--ink-soft);
  opacity: 0.85;
}
.ht-search-input::-webkit-search-cancel-button { -webkit-appearance: none; }
.ht-search-form:focus-within {
  border-color: var(--accent);
  box-shadow: 0 18px 44px rgba(8, 30, 51, 0.34),
              0 0 0 3px rgba(243, 147, 33, 0.28);
}

.ht-search-submit {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  cursor: pointer;
  flex: 0 0 auto;
  width: 52px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--navy);
  color: var(--white);
  transition: background 0.25s ease;
}
.ht-search-submit:hover { background: var(--accent); color: var(--navy-deep); }
.ht-search-submit:focus-visible {
  outline: 3px solid var(--accent-soft);
  outline-offset: -3px;
}
.ht-search-submit svg { width: 18px; height: 18px; display: block; }

/* ------------------------------------------------- 2. the live dropdown */

/* The plugin injects its results wrapper into .ht-search-dropdown (set via
   the input's data-rlvparentel). It positions the wrapper with inline
   left/top, which is meant for a body-appended element — inside our own
   relatively-positioned panel that would push it off-screen, so we neutralise
   the inline geometry with !important and let flow position it. */
.ht-search-dropdown { position: relative; }
.ht-search-dropdown .relevanssi-live-search-results {
  position: static !important;
  left: auto !important;
  top: auto !important;
  width: 100% !important;
  max-height: min(66vh, 520px);
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-top: 10px;
  padding: 0;
  background: var(--navy-deep);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius, 14px);
  box-shadow: 0 22px 54px rgba(8, 30, 51, 0.46);
  /* hidden until the plugin adds its showing class */
  display: none;
}
.ht-search-dropdown .relevanssi-live-search-results.relevanssi-live-search-results-showing {
  display: block;
}
/* the wrapper carries tabindex="0" from the plugin; don't double-ring it */
.ht-search-dropdown .relevanssi-live-search-results:focus { outline: none; }

.ht-search-results-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Each result. Cream-on-navy separation mirrors the blog card treatment
   (house rule 2: cards contrast their surface). */
.ht-search-result {
  margin: 0;
  padding: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.09);
}
.ht-search-result:last-child { border-bottom: 0; }

.ht-search-result-link {
  display: block;
  padding: 13px 16px;
  text-decoration: none;
  color: var(--white);
  transition: background 0.18s ease;
}
.ht-search-result-link:hover,
.ht-search-result-link:focus,
.ht-search-result.relevanssi-live-search-result--focused .ht-search-result-link {
  background: rgba(243, 147, 33, 0.16);
  outline: none;
}
/* keyboard focus must be unmistakable, not just a tint */
.ht-search-result-link:focus-visible {
  box-shadow: inset 3px 0 0 var(--accent);
  background: rgba(243, 147, 33, 0.2);
}
.ht-search-result.relevanssi-live-search-result--focused .ht-search-result-link {
  box-shadow: inset 3px 0 0 var(--accent);
}

.ht-search-result-type {
  display: inline-block;
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-soft);
  margin-bottom: 4px;
}
.ht-search-result-title {
  display: block;
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.28;
  color: var(--white);
  margin-bottom: 3px;
}
.ht-search-result-excerpt {
  display: block;
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 0.82rem;
  font-weight: 300;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.72);
}
/* Relevanssi wraps matched terms in <strong> (or <mark>, per its settings) */
.ht-search-result-excerpt strong,
.ht-search-result-excerpt mark {
  background: transparent;
  color: var(--accent-soft);
  font-weight: 600;
}

/* "See all N results" footer */
.ht-search-seeall {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 16px;
  background: rgba(255, 255, 255, 0.06);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 0.76rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-soft);
  text-decoration: none;
  transition: background 0.2s ease, color 0.2s ease;
}
.ht-search-seeall:hover,
.ht-search-seeall:focus-visible {
  background: var(--accent);
  color: var(--navy-deep);
  outline: none;
}

/* empty + loading states */
.ht-search-noresults { padding: 18px 16px; }
.ht-search-noresults-title {
  margin: 0 0 6px;
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 0.9rem;
  color: var(--white);
}
.ht-search-noresults-hint,
.ht-search-dropdown .ht-search-didyoumean {
  margin: 0;
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 0.82rem;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.72);
}
.ht-search-dropdown .ht-search-didyoumean { margin-top: 8px; }
.ht-search-dropdown .ht-search-didyoumean a { color: var(--accent-soft); }

/* the plugin's spinner element */
.ht-search-dropdown .live-ajax-messages { padding: 0; }
.ht-search-dropdown #relevanssi-live-ajax-search-spinner {
  display: none;
  padding: 16px;
  text-align: center;
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 0.8rem;
  color: rgba(255, 255, 255, 0.7);
}
.ht-search-dropdown #relevanssi-live-ajax-search-spinner.rlv-has-spinner {
  display: block;
}
/* a real spinner rather than the plugin's default gif */
.ht-search-dropdown #relevanssi-live-ajax-search-spinner.rlv-has-spinner::before {
  content: "";
  display: inline-block;
  width: 16px;
  height: 16px;
  margin-right: 8px;
  vertical-align: -3px;
  border: 2px solid rgba(255, 255, 255, 0.25);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: ht-search-spin 0.7s linear infinite;
}
@keyframes ht-search-spin { to { transform: rotate(360deg); } }
/* honour reduced-motion / the site's ?noanim=1 escape hatch */
@media (prefers-reduced-motion: reduce) {
  .ht-search-dropdown #relevanssi-live-ajax-search-spinner.rlv-has-spinner::before {
    animation: none;
  }
  .ht-search-panel { transition: none; }
}
html.noanim .ht-search-panel { transition: none; }

/* ---- mobile / tablet ----------------------------------------------------
   At <=1024 the burger appears and .nav-actions gets tight, so the panel
   becomes a full-width sheet pinned under the header instead of a flyout.
   Anchored to the VIEWPORT via position:fixed so it can never be clipped by
   the header's overflow or push the burger out of the bar. */
@media (max-width: 1024px) {
  .ht-search-panel {
    position: fixed;
    /* The sheet must hang BELOW the real header, and the header is not a
       fixed height: measured 102px at 390 / 116px at 768 at rest, shrinking
       to 80px once Elementor's sticky `--effects` state kicks in. A
       hardcoded 76px put the sheet's top ABOVE the bar's bottom edge, so it
       overlapped the logo and burger. `--ht-search-header-h` is written from
       JS on open (and on resize/scroll) with the header's measured height,
       so the sheet tracks both states; the 96px fallback only applies for
       the first frame or if JS never runs. */
    top: calc(var(--ht-search-header-h, 96px) + 8px);
    left: 12px;
    right: 12px;
    width: auto;
  }
  .ht-search-dropdown .relevanssi-live-search-results {
    max-height: min(60vh, 440px);
  }
}
@media (max-width: 480px) {
  .ht-search-toggle { width: 38px; height: 38px; }
  .ht-search-toggle svg { width: 18px; height: 18px; }
  .ht-search-result-title { font-size: 0.92rem; }
}

/* =============================================================
   3. SEARCH RESULTS PAGE (Elementor `search-results` template)
   Reuses the page-hero + card grammar; only search-specific bits here.
   ============================================================= */

/* the query echo + count under the H1 */
.ht-search-summary {
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 1.05rem;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.86);
  margin: 6px 0 0;
}
.ht-search-didyoumean {
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 1rem;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.86);
  margin: 10px 0 0;
}
.ht-search-didyoumean a {
  color: var(--accent-soft);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.ht-search-didyoumean a:hover { color: var(--white); }

/* the results-page H1 — matches the blog archive's page-hero h1 treatment */
.ht-search-h1 { margin: 0; }
.ht-search-h1 strong { font-weight: 700; color: var(--accent-soft); }

/* the refine field on the results page itself */
.ht-search-page {
  position: relative;
  max-width: 620px;
  margin: 26px 0 0;
}
.ht-search-page .ht-search-form { box-shadow: 0 14px 34px rgba(8, 30, 51, 0.28); }
/* its dropdown flows below the field rather than floating over the hero */
.ht-search-page-dropdown .relevanssi-live-search-results { margin-top: 10px; }

/* "Showing 6 guides · 3 articles" above the grid */
.ht-search-groupline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 26px;
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 0.92rem;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.78);
}
.ht-search-onthispage {
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-soft);
}
.ht-search-typecount b { color: var(--white); font-weight: 600; }
.ht-search-dot { opacity: 0.5; margin: 0 2px; }

/* per-card type badge on the search grid (Guide / Article) */
.ht-search-card-type {
  display: inline-block;
  align-self: flex-start;
  margin-bottom: 8px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(12, 42, 68, 0.09);
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

/* group labels: Pages vs Articles serve different intents on this site */
.ht-search-group-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin: 0 0 18px;
}
.ht-search-group-head h2 {
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 1.15rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin: 0;
}
.ht-search-group-count {
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 0.85rem;
  font-weight: 300;
  color: var(--ink-soft);
}
.on-dark .ht-search-group-count { color: rgba(255, 255, 255, 0.7); }

/* ---- the empty state: real routes onward, never a dead end ---- */
.ht-search-empty { margin-top: 8px; }
.ht-search-empty-lead {
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 1.05rem;
  font-weight: 300;
  color: var(--ink-soft);
  margin: 0 0 26px;
  text-align: center;
}
.on-dark .ht-search-empty-lead { color: rgba(255, 255, 255, 0.78); }

.ht-search-routes {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  align-items: stretch;          /* equal-height cards (house rule 4) */
}
@media (max-width: 900px) {
  .ht-search-routes { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .ht-search-routes { grid-template-columns: 1fr; }
}

/* White cards on the navy section — opposite shade, maximum pop. */
.ht-search-route {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 26px 24px 24px;
  background: var(--cream);
  border-radius: var(--radius, 14px);
  box-shadow: var(--shadow-card, 0 10px 30px rgba(8, 30, 51, 0.16));
  text-decoration: none;
  color: var(--ink);
  transition: transform 0.32s ease, box-shadow 0.32s ease;
}
.ht-search-route:hover,
.ht-search-route:focus-visible {
  transform: translateY(-6px);
  box-shadow: var(--shadow-card-hover, 0 18px 44px rgba(8, 30, 51, 0.26));
  outline: none;
}
.ht-search-route:focus-visible { box-shadow: 0 0 0 3px var(--accent); }
.ht-search-route h3 {
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--navy);
  margin: 0 0 8px;
}
.ht-search-route p {
  font-family: var(--font-body, "Jost", sans-serif);
  font-size: 0.92rem;
  font-weight: 300;
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0 0 16px;
  flex-grow: 1;                  /* pins the CTA to the card bottom */
}
.ht-search-route-more {
  font-family: var(--font-display, "Josefin Sans", sans-serif);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

/* The results grid reuses .blog-grid wholesale (see blog.css) so a search
   result card is visually identical to an archive card. Only the "nothing
   found" default needs neutralising — our own empty state replaces it. */
.ht-search-list .elementor-posts-nothing-found { display: none; }

/* ===== kit-additions/seo-aeo.css ===== */
/* ===========================================================================
   seo-aeo.css — owned by the SEO/AEO audit pass (2026-08-12).
   Do not edit from other agents' fragments; add to your own file instead.

   Currently empty by design.

   An earlier revision of this pass styled a bespoke `.ht-search-title` H1 that
   ht-seo.php injected into the search-results hero, because Elementor Pro's
   theme-archive-title widget was rendering nothing on some search terms. That
   turned out to be the wrong fix — it produced TWO competing <h1>s on the
   queries where the widget DID render.

   The real cause was Title_Widget_Base::should_show_page_title() reading
   hide_title off get_the_ID(), which on a search page is the FIRST RESULT POST
   (all our generated pages carry hide_title:yes). ht-seo.php now neutralises
   that lookup on search, so the widget renders exactly once and the heading
   comes from Elementor's own dynamic tag — inheriting the standard
   `.page-hero .elementor-widget-heading h1.elementor-heading-title` typography
   with no bespoke CSS to keep in sync.

   Keeping the file so the fragment slot stays owned by this pass and the
   history of the decision is not lost.
   =========================================================================== */

/* ===== kit-additions/sticky-cta.css ===== */
/* =========================================================================
   STICKY CTA — right-edge tab (desktop) + bottom bar (phones) + slide-out
   panel holding the shared Cruise Interest Form.

   Markup + behaviour: mu-plugins/ht-sticky-cta.php (repo: elementor/).
   This file is merged into the Elementor kit by _build_kit.py; it is never
   edited in wp-admin and never hand-patched into the exported CSS.

   Z-INDEX MAP for this site (documented here because it is now shared):
       60  .site-header (Elementor sticky)
       70  .ht-to-top          back-to-top disc, bottom-right
       80  .ht-cta-tab / .ht-cta-bar   the sticky triggers
       90  .ht-cta-scrim       dims the page behind the panel
      100  .ht-cta-panel       the dialog itself
   The panel and its scrim deliberately sit ABOVE the back-to-top button: while
   a modal dialog is open nothing behind it should be clickable. The triggers
   sit above the header but BELOW the scrim, and are positioned so they never
   cover .ht-to-top (see the clearance rules at the end of each block).
   ========================================================================= */

/* ---------------------------------------------------------------- triggers */

/* Shared look. Gold on navy, matching .btn-accent, so the control reads as the
   same offer the header button used to make. */
.ht-cta-tab,
.ht-cta-bar-btn {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  background: var(--accent);
  color: var(--navy);
  border: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

/* ---- DESKTOP: vertical tab pinned to the right edge, mid-viewport --------
   Hidden below 1025px, where the bottom bar takes over. The breakpoint matches
   the nav's burger breakpoint (dropdown: tablet => <=1024px) so the page has
   exactly one CTA affordance at every width. */
.ht-cta-tab {
  display: none;                    /* enabled in the >=1025 query below */
  position: fixed;
  right: 0;
  top: 50%;
  z-index: 80;
  /* Rotate about the right edge so the tab hangs off the viewport side. */
  transform: translateY(-50%) rotate(180deg);
  writing-mode: vertical-rl;
  padding: 22px 12px;
  min-height: 44px;                 /* touch target floor, even on hybrid laptops */
  border-radius: 0 10px 10px 0;     /* rounded on the side facing the page */
  font-size: 0.78rem;
  box-shadow: -4px 0 18px rgba(0, 0, 0, 0.28);
  transition: background 0.2s ease, padding 0.2s ease, box-shadow 0.2s ease;
}
@media (min-width: 1025px) {
  .ht-cta-tab { display: inline-flex; align-items: center; justify-content: center; }
}
.ht-cta-tab:hover {
  background: var(--accent-soft);
  padding-right: 16px;              /* slides a touch out of the edge */
}
.ht-cta-tab:focus-visible {
  outline: 3px solid #fff;
  outline-offset: -3px;
}
.ht-cta-tab-label { display: block; }

/* The tab is vertically CENTRED and the back-to-top disc is bottom-right, so
   they cannot collide at any realistic viewport height: the tab's half-height
   (~90px) plus its centre offset leaves the bottom ~340px clear at 900px tall.
   Guard the pathological short-viewport case anyway — below 620px of height a
   centred tab starts to reach the disc, so pull it up off centre. */
@media (min-width: 1025px) and (max-height: 620px) {
  .ht-cta-tab { top: 38%; }
}

/* ---- MOBILE: short bar across the bottom ---------------------------------
   Deliberately SHORT: two tight lines of type, ~64px of bar plus the phone's
   safe-area inset. It must feel like a persistent offer, not a drawer that
   eats a tenth of the viewport. */
.ht-cta-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 80;
  display: block;
  background: var(--navy);
  border-top: 1px solid rgba(247, 176, 74, 0.4);
  box-shadow: 0 -6px 22px rgba(0, 0, 0, 0.3);
  /* iPhone home-indicator: pad the BAR, not the button, so the gold surface
     runs to the physical edge while the tappable text stays above the bar. */
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
@media (min-width: 1025px) {
  .ht-cta-bar { display: none; }
}
.ht-cta-bar-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 100%;
  min-height: 56px;                 /* >=44px touch target with room to spare */
  padding: 9px 16px;
  border-radius: 0;
  text-align: center;
}
.ht-cta-bar-btn:focus-visible {
  outline: 3px solid #fff;
  outline-offset: -4px;
}
.ht-cta-bar-text { font-size: 0.88rem; line-height: 1.1; }
.ht-cta-bar-sub {
  font-family: var(--font-body, inherit);
  text-transform: none;
  letter-spacing: 0.01em;
  font-size: 0.7rem;
  opacity: 0.78;
  line-height: 1.1;
}

/* ---- FOOTER / BACK-TO-TOP CLEARANCE FOR THE MOBILE BAR -------------------
   THE REQUIREMENT: the bottom bar is `position: fixed`, so it is out of flow
   and sits ON TOP of whatever the page ends with — on this site the footer
   fine print, which is the legal text. Reserving space is not optional.

   Done with scroll-padding on <body> rather than a margin on .site-footer so
   it works on EVERY template (pages, blog archive, single posts, search
   results, 404) without touching six Elementor templates, and so it survives
   any future footer rebuild.

   The reserve is the bar's own height (56px button + 18px padding = 74px)
   plus the safe-area inset plus a 16px breathing gap. */
@media (max-width: 1024px) {
  /* Reserve the clearance INSIDE THE FOOTER, not on the body.
     `body { padding-bottom: … }` reserved the right amount of space but the
     body is CREAM while the footer is navy, so the reservation rendered as a
     visible cream stripe between the end of the footer and the bar. Padding
     the footer keeps the surface navy all the way down to the bar — same
     clearance, no seam. `!important` because .site-footer padding is set by
     the section-rhythm rule at (0,2,0). */
  .site-footer,
  .e-con.site-footer {
    padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px) + 16px) !important;
  }
  /* The back-to-top disc must sit ABOVE the bar, not behind it. Its own rule
     is `bottom: max(16px, env(safe-area-inset-bottom))`, which the bar would
     cover entirely — lift it by the full bar height. */
  .ht-to-top {
    bottom: calc(74px + env(safe-area-inset-bottom, 0px) + 14px);
  }
}

/* ------------------------------------------------------------------ scrim */
.ht-cta-scrim {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(4, 16, 28, 0.55);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity 0.28s ease;
}
.ht-cta-scrim.is-open { opacity: 1; }
.ht-cta-scrim[hidden] { display: none; }

/* ------------------------------------------------------------------ panel */
.ht-cta-panel {
  position: fixed;
  z-index: 100;
  /* CREAM, not a cold grey. `--cloud` is NOT a token in this palette — it does
     not exist in styles.css :root — so `var(--cloud, #f4f7fa)` silently fell
     back to a blue-grey that looked like a browser default sitting next to the
     site's warm cream. Use the real token. */
  background: var(--cream, #f6f1e6);
  display: flex;
  flex-direction: column;
  overscroll-behavior: contain;     /* scrolling the form must not scroll the page */
  -webkit-overflow-scrolling: touch;
}
.ht-cta-panel[hidden] { display: none; }

/* Desktop: slides in from the right edge, under the tab. */
@media (min-width: 1025px) {
  .ht-cta-panel {
    top: 0;
    right: 0;
    bottom: 0;
    width: min(460px, 92vw);
    max-height: 100vh;
    overflow-y: auto;
    transform: translateX(100%);
    transition: transform 0.32s cubic-bezier(0.22, 0.61, 0.36, 1);
    box-shadow: -12px 0 40px rgba(0, 0, 0, 0.32);
  }
  .ht-cta-panel.is-open { transform: none; }
}

/* Mobile: bottom sheet. Capped at 88vh so the page behind stays visible and
   the sheet reads as dismissible rather than as a new page. */
@media (max-width: 1024px) {
  .ht-cta-panel {
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 88vh;
    overflow-y: auto;
    border-radius: 16px 16px 0 0;
    transform: translateY(100%);
    transition: transform 0.32s cubic-bezier(0.22, 0.61, 0.36, 1);
    box-shadow: 0 -14px 40px rgba(0, 0, 0, 0.38);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .ht-cta-panel.is-open { transform: none; }
}

/* Reduced motion: appear/disappear with no slide. The panel must still become
   visible, so only the TRANSFORM animation is dropped, never the visibility. */
@media (prefers-reduced-motion: reduce) {
  .ht-cta-panel,
  .ht-cta-scrim {
    transition: none;
  }
  .ht-cta-panel { transform: none; }
  .ht-cta-tab { transition: none; }
}

/* Lock background scrolling while the dialog is open. */
html.ht-cta-open,
html.ht-cta-open body { overflow: hidden; }

/* ---- panel chrome -------------------------------------------------------- */
.ht-cta-panel-head {
  position: sticky;                 /* the close button stays reachable while scrolling */
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 20px;
  background: var(--navy);
  color: #fff;
}
.ht-cta-panel-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.05rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: #fff;
}
.ht-cta-close {
  flex: 0 0 auto;
  width: 44px;                      /* 44px touch target */
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  background: transparent;
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.ht-cta-close:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--navy);
}
.ht-cta-close:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 2px;
}
/* The body MUST scroll. The form is taller than the panel on most viewports,
   and without this the submit button is simply unreachable — the textarea ran
   off the bottom edge with the button cut off entirely. `flex: 1` lets it take
   the space the header does not, and the generous bottom padding keeps the
   button clear of the panel edge (and of the phone home indicator). */
.ht-cta-panel-body {
  flex: 1 1 auto;
  min-height: 0;                    /* required or a flex child will not scroll */
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 20px 22px calc(32px + env(safe-area-inset-bottom, 0px));
}

/* The panel renders the SHARED global form widget, whose page styling assumes
   the wide .form-card layout on a dark section. Inside a ~460px panel the
   two-column 50% fields would be unreadably narrow, so stack them here.
   Scoped to .ht-cta-panel so the on-page form is untouched. */
/* ---- FORM STYLING ----
   Deliberately almost EMPTY. The panel's body carries the `form-card` class
   (see ht-sticky-cta.php), so it inherits the site's real form treatment from
   the kit's `.form-card` block — same labels, same cream inputs, same navy
   button as the on-page form. That is the correct mechanism: ONE definition,
   inherited, rather than a second copy kept in sync by hand.

   An earlier version of this file restated every property here. It worked, but
   it recreated exactly the drift problem the global-widget conversion removed:
   two places to change, and they WILL diverge. Deleted.

   Only genuine panel-specific deviations belong below. */

/* A ~460px panel cannot carry the card's 50% two-column fields — stack them. */
.ht-cta-panel .elementor-field-group {
  width: 100% !important;
  flex-basis: 100% !important;
  max-width: 100% !important;
}

/* iOS Safari zooms the viewport when a focused input is under 16px. The card
   uses 1rem (16px) already, so this is a floor, not a restyle. */
.ht-cta-panel .elementor-field-textual { font-size: max(16px, 1rem) !important; }

/* The card's textarea is 96px tall; in a panel that crowds the submit button
   below the fold on short viewports. */
.ht-cta-panel textarea.elementor-field-textual { min-height: 76px; }
.ht-cta-panel .elementor-message { margin-top: 14px; font-size: 0.9rem; }
.ht-cta-fallback { padding: 8px 0; }

/* =========================================================================
   HEADER RE-TUNE AFTER REMOVING THE CTA (2026-08-13)
   -------------------------------------------------------------------------
   The header nav guards in _build_kit.py were all sized against the "Plan My
   Cruise" button, which occupied ~217px at 1440px. Measured before removal:

       1600:  brand ends 428, nav ul 480-1115, LAST LINK OVERLAPPED the CTA
       1440:  brand ends 348, nav ul 400-1029, gap to CTA = -6px  (overlap)
       1366:  brand ends 311, nav ul 363- 991, gap to CTA = -5px  (overlap)
       1280:  gap 46px      1100:  gap 19px

   The nav <ul> was CENTRED inside a slot whose right edge sat under the
   button, with clamp(12px,2vw,40px) padding guards on both sides fighting to
   keep the centred group off the logo and off the CTA.

   With the button gone the slot is ~217px wider and the pressure is gone, so
   the guards are re-tuned rather than left over-tight:
     - the nav slot now ends at the search icon, not at a 217px button, so the
       right guard only needs to clear a 40px magnifier plus air;
     - the left guard still has to clear the logo ARTWORK (the wordmark paints
       wider than its box), so it is kept, not dropped.
   These override the base rules by load order: kit-additions are merged AFTER
   the main kit body, at equal specificity. Selectors are copied EXACTLY from
   _build_kit.py so specificity matches and the later rule wins.
   ========================================================================= */
@media (min-width: 1025px) {
  /* Right guard reduced 40px -> 20px max: it now only has to clear the search
     icon, and .nav-actions below reserves that space explicitly. The left
     guard is UNCHANGED (clamp(12px,2vw,40px)) because the logo artwork that
     forced it is unchanged. */
  .site-header .site-nav ul.elementor-nav-menu:not(.elementor-nav-menu--dropdown) {
    padding-right: clamp(10px, 1.2vw, 20px);
  }
  /* The search control is now the only thing in .nav-actions. Reserve a fixed
     slot for it so the centred nav has a hard edge to stay clear of, and so
     the icon never sits flush against the viewport edge. */
  .site-header .nav-actions {
    flex: 0 0 auto;
    min-width: 44px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
  }
}

/* -------------------------------------------------------------------------
   HEADER RENDERED BOXED (1140px) ON THE SEARCH-RESULTS TEMPLATE — real bug.

   Measured at 1440px: on /?s=... the header box was l225 r1365 (w1140) with
   75px auto margins, while /blog/ and inner pages rendered it 0-1440. It was
   NOT a visual artifact of the hero photo.

   CAUSE: a CLASS-NAME COLLISION with the Hello Elementor theme. Our header
   container carries our own semantic class `site-header`; hello-elementor's
   theme.css styles ITS markup with the same class name:

       .site-header:not(.dynamic-header) { margin-inline: auto; width: 100% }
       @media (min-width:1200px) { ... { max-width: 1140px } }

   Our header has no `dynamic-header` class, so the guard does not exclude it
   and the theme caps it at 1140px. On most templates the kit's inline CSS is
   printed after theme.css and the Elementor `e-con-full` geometry wins; on the
   search template the kit CSS arrives as an external post-4.css BEFORE
   theme.css, so the theme rule wins on load order and the header goes boxed.
   (Confirmed by enumerating the matching rules per stylesheet on both pages.)

   FIX: restate full-bleed geometry on the header, scoped by the Elementor
   container class so it cannot leak onto the theme's own header markup on any
   template that legitimately uses it. Not !important — `.e-con.site-header`
   is (0,2,0) and beats the theme's (0,1,0) rule regardless of load order,
   which is the durable fix rather than a specificity arms race. */
.e-con.site-header,
.e-con.site-header.ht-header {
  max-width: none;
  width: 100%;
  margin-inline: 0;
}

/* ---- SAME BUG, FOOTER ----
   Hello Elementor's theme.css also styles `.site-footer:not(.dynamic-footer)`
   with `max-width: 1140px` (plus a 500/600/800px responsive ladder), and our
   footer container carries that same class name. Identical load-order
   dependency to the header above: fine on most templates, boxed to 1140px on
   the search-results template where post-4.css arrives before theme.css.
   Measured there: footer 150–1290 (1140 wide) inside a 1440 viewport.

   Same durable fix — `.e-con.site-footer` is (0,2,0) and beats the theme's
   (0,1,0) regardless of which stylesheet loads first. */
.e-con.site-footer {
  max-width: none;
  width: 100%;
  margin-inline: 0;
}

/* -------------------------------------------------------------------------
   BURGER CLIPPED OFF-SCREEN AT 390px — real bug, found while verifying the
   mobile CTA bar.

   Measured at 390px BEFORE: toggle box l354 r400 on a 390px viewport, i.e. the
   right 10px of the burger sat outside the viewport, and past the .wrap's own
   right edge (r380). Visible as a burger with its right border shaved off.
   (No document overflow, because the header is `overflow: hidden` in effect —
   which is exactly why it clipped instead of scrolling.)

   CAUSE: `.site-header .site-nav` is `flex: 1 1 auto; min-width: 0` so the nav
   can absorb width pressure on desktop. Below the burger breakpoint its menu
   list is display:none, so the widget's CONTENT width is 0 and flexbox
   collapses the box to w0 (measured: nav l354 r354 w0). The 46px toggle is
   still painted inside that zero-width box and simply overflows it to the
   right, past the wrap's padding.

   FIX: below the burger breakpoint the nav is no longer a flexible column —
   it is just a 46px button. Stop it flexing and let it size to its content, so
   the toggle sits inside the wrap's right padding like every other child.
   Scoped to <=1024px so the desktop flex behaviour above is untouched. */
@media (max-width: 1024px) {
  .site-header .site-nav {
    flex: 0 0 auto;
    min-width: max-content;
  }
  /* Second half of the same bug. `.site-header .brand { min-width: 190px }` in
     the kit body is UNSCOPED, so the desktop logo-artwork reservation also
     applied at 390px. The wrap's three children then demanded
     190 (brand) + 84 (.nav-actions/search) + 46 (burger) = 320px plus gaps
     inside a 370px content box, and the overflow was pushed onto the last
     child — the burger — shoving it 10px off-screen.

     On phones the logo is sized by `.brand-plate img { height: 78px }` and
     needs no width reservation (there is no centred nav to keep off it), so
     release the min-width and let the brand shrink to its content. */
  .site-header .brand,
  .e-con.e-flex.brand {
    min-width: 0;
    margin-right: 0;
  }
}

/* The brand's 190px min-width was reserving the logo ARTWORK's painted width
   against a nav being squeezed by the CTA. The artwork has not changed, so the
   min-width stays; only the extra 18px margin-right is relaxed to 12px now
   that there is ~217px of slack in the row. Deliberately conservative: the
   guard that stopped "DESTINATIONS" sitting under the wordmark is kept. */
@media (min-width: 1025px) {
  .site-header .brand { margin-right: 12px; }
}

/* ===== kit-additions/thankyou.css ===== */
/* ============================================================
   /thank-you/ — post-submission page
   ------------------------------------------------------------
   Reuses the site's existing section rhythm (.page-hero, .bg-cream,
   .bg-navy) so nothing here re-invents layout. Only the two components
   unique to this page need rules: the numbered "what happens next"
   list, and the onward-reading cards.
   ============================================================ */

/* ---- numbered next-steps list ----
   A real <ol> so it is announced correctly by a screen reader, with the
   default marker replaced by a counter in the brand accent. */
.ty-steps {
  list-style: none;
  counter-reset: ty;
  margin: 0;
  padding: 0;
  max-width: 760px;
  margin-inline: auto;
}
.ty-steps > li {
  counter-increment: ty;
  position: relative;
  padding-left: 62px;
  margin-bottom: 30px;
}
.ty-steps > li:last-child { margin-bottom: 0; }
.ty-steps > li::before {
  content: counter(ty);
  position: absolute;
  left: 0;
  top: -2px;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--navy);
  background: var(--accent);
  border-radius: 50%;
}
.ty-steps b {
  display: block;
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--navy);
  margin-bottom: 6px;
}
.ty-steps p {
  font-size: 1.04rem;
  line-height: 1.7;
  color: var(--ink-soft);
  margin: 0;
}

/* ---- onward reading cards ----
   White cards on the navy section — opposite-shade per the house rule, so
   they genuinely pop rather than sitting as a tinted panel. Equal height
   regardless of blurb length. */
.ty-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 22px;
  margin-top: 34px;
}
.ty-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--cream);
  border-radius: var(--radius);
  padding: 26px 24px 22px;
  text-decoration: none;
  box-shadow: var(--shadow-card);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.ty-card:hover,
.ty-card:focus-visible {
  transform: translateY(-4px);
  box-shadow: var(--shadow-card-hover);
}
.ty-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.ty-card b {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--navy);
  margin-bottom: 10px;
}
.ty-card p {
  font-size: 0.97rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0 0 16px;
  flex-grow: 1;              /* pins the "Read this" to the card bottom */
}
.ty-card-more {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: var(--accent-ink);   /* WCAG-passing orange for TEXT on light */
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
  align-self: flex-start;
}

/* The hero on this page carries no CTA and little copy, so it does not need
   the full inner-page hero height. */
.e-con.thankyou-hero { min-height: 0; }

@media (max-width: 640px) {
  .ty-steps > li { padding-left: 52px; }
  .ty-steps > li::before { width: 36px; height: 36px; font-size: 0.95rem; }
}

/* ===== kit-additions/voice-search.css ===== */
/* ============================================================
   RELEVANSSI VOICE SEARCH — house styling
   ------------------------------------------------------------
   Relevanssi Premium wraps the search input in
   `<div class="relevanssi-voice-search-wrapper">` and absolutely positions a
   `.relevanssi-mic-button` inside it. Its own stylesheet
   (premium/relevanssi-voice-search.css) is deliberately minimal and carries
   NO colour beyond `#666` on the mic — so the pale blue seam Frank saw is not
   the plugin's colour at all. It is the SEAM: the input keeps its own
   1px #666 left border while the wrapper sits flush against the navy submit
   button, and the light input background showing through that gap reads as a
   pale bar between the mic and the magnifier.

   Fixed by treating input + mic + submit as ONE control: kill the interior
   border, give the mic real separation with an intentional divider in the
   palette, and put the mic on the brand ink ramp instead of #666.

   Kept in its OWN file rather than search.css because another workstream owns
   that file; kit-additions/*.css are auto-merged by _build_kit.py in glob
   order, so a separate file composes cleanly.
   ============================================================ */

/* The wrapper must not introduce its own box — it is a positioning context
   only. `flex: 1` so the input still fills the control. */
.ht-search .relevanssi-voice-search-wrapper,
.ht-search-dropdown .relevanssi-voice-search-wrapper {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
}

/* Kill the interior seam. The input sits INSIDE the bordered control, so it
   must contribute no border of its own — the visible border belongs to the
   control as a whole. `!important` because the plugin ships
   `padding-right: 35px !important` on this element and Elementor's own
   search-form rules land at (0,3,0). */
.ht-search .relevanssi-voice-search-wrapper .ht-search-input,
.ht-search .relevanssi-voice-search-wrapper input[type="search"] {
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  /* room for the mic + its divider, so typed text never runs underneath */
  padding-right: 46px !important;
}

/* The mic: brand ink rather than #666, with a real divider to its left so the
   grouping reads as [ field | mic ] [ search ] instead of a stray seam. */
.ht-search .relevanssi-mic-button {
  right: 12px;
  width: 26px;
  height: 26px;
  color: var(--ink-soft, #55636f);
  opacity: 0.75;
  transition: color 0.18s ease, opacity 0.18s ease;
}
.ht-search .relevanssi-mic-button::before {
  content: "";
  position: absolute;
  left: -11px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 20px;
  background: rgba(12, 42, 68, 0.16);   /* navy at low alpha — not a raw grey */
  pointer-events: none;
}
.ht-search .relevanssi-mic-button:hover,
.ht-search .relevanssi-mic-button:focus-visible {
  color: var(--accent-ink, #a35a0c);
  opacity: 1;
}
.ht-search .relevanssi-mic-button:focus-visible {
  outline: 2px solid var(--accent, #f39321);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ---- ACTIVE / LISTENING STATE ----
   The plugin paints this WordPress admin red (#d63638), which is jarring on a
   navy-and-gold site and reads as an error rather than "listening".

   IMPORTANT: the colour must be set on the SVG as well as the button. The
   plugin's rule is `.relevanssi-mic-button.is-active { color: #d63638 }` and
   the icon inherits via `currentColor` — but Elementor and the theme both
   emit svg fill/colour rules, so a button-only override loses on some
   templates. Set both, and target `fill`/`stroke` explicitly. */
.ht-search .relevanssi-mic-button.is-active,
.ht-search .relevanssi-mic-button.is-talking,
.ht-search .relevanssi-mic-button:active {
  color: var(--accent, #f39321) !important;
  opacity: 1;
}
.ht-search .relevanssi-mic-button.is-active svg,
.ht-search .relevanssi-mic-button.is-talking svg,
.ht-search .relevanssi-mic-button:active svg,
.ht-search .relevanssi-mic-button.is-active svg *,
.ht-search .relevanssi-mic-button.is-talking svg * {
  color: var(--accent, #f39321) !important;
  fill: currentColor !important;
  stroke: currentColor;
}

/* Permission-denied is the one state that SHOULD stay red — it is a genuine
   warning, and recolouring it to the brand accent would hide a real failure.
   Tone it off the raw WP admin red to something that sits with the palette. */
.ht-search .relevanssi-mic-button:disabled .relevanssi-svg-mic-blocked,
.ht-search .relevanssi-mic-button:disabled .relevanssi-svg-mic-blocked * {
  color: #b3261e !important;
  fill: currentColor !important;
  opacity: 0.55;
}

/* Respect reduced motion — the plugin pulses the icon while listening. */
@media (prefers-reduced-motion: reduce) {
  .ht-search .relevanssi-mic-button.is-talking svg {
    animation: none !important;
  }
}/* End custom CSS */