:root {
  --bg: #f4f5f7;
  --card-bg: #ffffff;
  --text: #1c1e21;
  --muted: #6b7280;
  --accent: #0057b8;
  --save: #c0392b;
  --border: #e2e4e8;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.4;
  /* min-height:100vh first as a fallback for anything that doesn't know
     dvh; 100dvh (dynamic viewport height) is what actually tracks iOS
     Safari's toolbar as it shows/hides during scroll, which 100vh does
     not -- this is the underlying reason a position:fixed bottom bar can
     visually vanish mid-scroll. Making the CTA bar position:sticky below
     instead of fixed sidesteps that whole class of bug, but this still
     matters so body/main can stretch to fill the real visible height on
     short pages. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.app-header {
  background: var(--accent);
  padding: 14px 16px;
  position: sticky;
  top: 0;
  z-index: 10;
  flex-shrink: 0;
}
.app-header .brand {
  color: #fff;
  font-weight: 700;
  font-size: 1.1rem;
  text-decoration: none;
}
.globe-link {
  display: inline-block;
  vertical-align: middle;
  font-size: 1.2rem;
  line-height: 1;
  margin-right: 8px;
  text-decoration: none;
}
.version-badge {
  display: inline-block;
  font-weight: 400;
  font-size: 0.75rem;
  color: #fff;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 999px;
  padding: 2px 8px;
  margin-left: 6px;
  vertical-align: middle;
}

/* ---- hamburger menu widget (sort menu on results.php, tabs menu on
   deal.php -- any number of these can exist independently) ----
   A plain <button>, pinned to the header's right edge with position:
   absolute -- not flexbox, not a native <details> disclosure widget, not a
   checkbox hack. Nothing here for any browser to reinterpret. When more
   than one menu-widget sits in the same header, stack them with CSS. */
.menu-widget {
  position: absolute;
  top: 50%;
  right: 16px;
  transform: translateY(-50%);
}
.hamburger-btn {
  display: block;
  background: none;
  border: none;
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  padding: 6px 8px;
  cursor: pointer;
}

.dropdown-menu {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: #ffffff;
  color: #1c1e21;
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
  list-style: none;
  margin: 0;
  padding: 6px 0;
  min-width: 230px;
  max-height: 70vh;
  overflow-y: auto;
  z-index: 20;
}
.dropdown-menu.open { display: block; }

.dropdown-menu li a {
  display: block;
  padding: 10px 16px;
  color: #1c1e21;
  text-decoration: none;
  font-size: 0.95rem;
  white-space: nowrap;
}
.dropdown-menu li a.active {
  background: #eef1f5;
  font-weight: 700;
}
.dropdown-menu li a:active { background: #eef1f5; }

main {
  padding: 16px;
  max-width: 600px;
  margin: 0 auto;
  width: 100%;
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

/* ---- FastDeal # quick-jump box ---- */
.fastdeal-lookup {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 16px;
  margin-bottom: 16px;
}
.fastdeal-label {
  display: block;
  font-size: 0.85rem;
  color: var(--muted);
  margin-bottom: 8px;
}
.fastdeal-row {
  display: flex;
  gap: 8px;
}
.fastdeal-row input {
  flex: 1;
  min-width: 0;
  font-size: 1rem;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}
.btn-secondary {
  flex-shrink: 0;
  font-size: 1rem;
  font-weight: 700;
  padding: 10px 20px;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
}

/* ---- search form ---- */
.search-form {
  flex: 0 0 auto; /* keep its natural size within main's flex column -- the CTA bar below is what stretches/sticks */
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
  margin-bottom: 16px;
}
.search-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.85rem;
  color: var(--muted);
}
.search-form select {
  font-size: 1rem;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  width: 100%;
}

/* Two fields per row (From/To, Region/Line, Ship/Nights, Departure/Visit)
   instead of one long stack -- roughly halves the form's height on
   mobile, where vertical space (not width) is the scarce thing. */
.form-row {
  display: flex;
  gap: 10px;
}
.form-row > label,
.form-row > .picker-field {
  flex: 1;
  min-width: 0; /* lets the ellipsis on long labels/trigger text actually kick in instead of forcing the row to overflow */
}

/* ---- pick-list field (region/line/ship/departure port/visit port) ----
   A button, not a text input -- tapping it opens #picker-overlay (a
   full-screen list + A-Z jump bar), populated by assets/app.js. No typing,
   no keyboard, just scroll or jump to a letter. */
.picker-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.picker-label {
  font-size: 0.85rem;
  color: var(--muted);
}
.picker-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 1rem;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  color: var(--text);
  width: 100%;
  text-align: left;
  font-family: inherit;
}
.picker-trigger-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.picker-trigger-arrow { color: var(--muted); flex-shrink: 0; }

/* ---- full-screen picker overlay ----
   "Full-screen" means top-to-bottom, not edge-to-edge on a wide window --
   the panel matches main's own max-width (600px) and sits centered, same
   as the rest of the app. The backdrop still dims the full viewport behind
   it, same idea as main being centered on a page-colored background. */
.picker-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 100;
}
.picker-overlay.open { display: block; }
.picker-panel {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 600px;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
.picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  background: var(--accent);
  color: #fff;
  flex-shrink: 0;
}
.picker-header-title { font-weight: 700; font-size: 1.1rem; }
.picker-close {
  background: none;
  border: none;
  color: #fff;
  font-size: 1.3rem;
  line-height: 1;
  padding: 4px 8px;
  cursor: pointer;
}
.picker-body {
  flex: 1;
  display: flex;
  overflow: hidden;
}
.picker-list {
  /* Makes this the offsetParent for its <li> children, so app.js can read
     each group header's true offsetTop (unaffected by position:sticky --
     see app.js for why that distinction actually matters here). */
  position: relative;
  flex: 1;
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.picker-list li {
  padding: 13px 16px;
  font-size: 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--card-bg);
}
.picker-list li:active { background: #eef1f5; }
.picker-list li.picker-selected { font-weight: 700; color: var(--accent); }
.picker-list .picker-group-label {
  padding: 6px 16px;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--muted);
  background: var(--bg);
  border-bottom: none;
  position: sticky;
  top: 0;
}

/* The A-Z index -- one narrow column of tappable letters down the right
   edge, like the iOS Contacts app. Letters with no matching entries in
   this particular field are still shown (consistent layout across fields)
   but dimmed and inert. */
.picker-az-bar {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 32px;
  flex-shrink: 0;
  padding: 4px 2px;
  background: var(--bg);
  /* This whole strip is a drag surface (see app.js) -- without this, the
     browser tries to scroll/pan the page on touchmove instead of letting
     our pointermove handler track the drag. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.picker-az-bar button {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.4;
  padding: 0;
  cursor: pointer;
  pointer-events: none; /* the bar itself owns pointer events, not each tiny letter -- see app.js */
}
.picker-az-bar button:disabled {
  color: var(--border);
}
.picker-az-bar button.picker-az-active {
  color: #fff;
  background: var(--accent);
  border-radius: 4px;
}

/* Deliberately NOT position:fixed. Two attempts at fixing iOS Safari's
   dynamic-toolbar-during-scroll bug on a fixed bottom bar (forcing a
   compositing layer, then an iOS-safe body scroll-lock) both failed --
   because fixed positioning itself is the actual problem, not something
   layered on top of it. position:sticky is computed as part of normal
   layout/scroll in the same pass as the browser's own toolbar resize,
   not as a separately composited overlay, so it doesn't have this class
   of bug at all.

   margin-top:auto is what makes it sit at the bottom even on a short page
   with room to spare: .search-form (flex:0 0 auto) takes its natural
   size, and this bar's auto margin eats whatever's left in main's flex
   column, pushing itself down to the bottom of the viewport with no
   sticky/scroll trickery needed yet. Only once the form is tall enough to
   push this bar below the fold does "sticky" actually start doing
   anything -- keeping it pinned as you scroll instead of letting it
   scroll away. */
.cta-bar {
  margin-top: auto;
  /* main has its own 16px padding-bottom (shared by every page). Pulling
     through by the full 16px put the button dead flush against Safari's
     own bottom toolbar with zero gap -- the two blues touched with no
     visible seam between "our button" and "the browser's own UI". Leaving
     2px of the page background showing gives them a visible seam. */
  margin-bottom: -14px;
  position: sticky;
  bottom: 0;
  z-index: 40;
}
.btn-primary {
  display: block;
  width: 100%;
  font-size: 1rem;
  font-weight: 700;
  padding: 16px;
  border: none;
  /* All 4 corners now that there's a couple px of gap below the button
     (.cta-bar's margin-bottom) -- squared-off bottom corners against that
     gap looked like a mistake, not a design choice. */
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.15);
}
.hint { color: var(--muted); font-size: 0.85rem; }

/* ---- results list ---- */
.result-count { color: var(--muted); margin: 0 0 12px; }

.deal-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.deal-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.deal-card a {
  position: relative;
  display: block;
  padding: 14px;
  color: var(--text);
  text-decoration: none;
}
.deal-card.sold-out { opacity: 0.55; }
.deal-id {
  position: absolute;
  bottom: 6px;
  right: 10px;
  font-size: 0.7rem;
  color: var(--muted);
}

.deal-card-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-weight: 600;
  margin-bottom: 4px;
}
.deal-rating { color: var(--muted); font-weight: 400; font-size: 0.9rem; }

.deal-card-mid {
  display: flex;
  gap: 12px;
  color: var(--muted);
  font-size: 0.9rem;
  margin-bottom: 6px;
}

.deal-card-ports {
  font-size: 0.9rem;
  margin-bottom: 10px;
}

.deal-card-bottom {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.deal-price { font-size: 1.15rem; font-weight: 700; color: var(--accent); }
.deal-brochure { color: var(--muted); font-size: 0.9rem; }
.deal-save { color: var(--save); font-weight: 600; font-size: 0.9rem; }
.deal-status {
  margin-left: auto;
  background: #eee;
  color: #444;
  font-size: 0.75rem;
  padding: 3px 8px;
  border-radius: 999px;
}

/* ---- deal detail ---- */
.deal-title { margin-bottom: 4px; }
.deal-headline { font-weight: 600; margin: 0 0 2px; }
.deal-subline { color: var(--muted); margin: 0 0 16px; }

.cabin-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 20px;
}
.cabin-panel {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.cabin-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: none;
  border: none;
  padding: 14px 16px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.cabin-type {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}
.cabin-arrow {
  color: var(--muted);
  transition: transform 0.15s ease;
}
.cabin-toggle[aria-expanded="true"] .cabin-arrow { transform: rotate(180deg); }

.cabin-body {
  display: none;
  padding: 0 16px 14px;
}
.cabin-body.open { display: block; }

/* Section-level collapse (Itinerary, when a hamburger tab is active) --
   same idea as the cabin toggle above but styled as a heading, not a card,
   since it's a top-level page section rather than one of several peers. */
.section-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.section-arrow {
  color: var(--muted);
  font-size: 1rem;
  transition: transform 0.15s ease;
}
.section-toggle[aria-expanded="true"] .section-arrow { transform: rotate(180deg); }

.section-body { display: none; }
.section-body.open { display: block; }

.price-row {
  display: flex;
  justify-content: space-between;
  padding: 6px 0;
}
.price-row.highlight { font-size: 1.2rem; }
.save-pct { color: var(--save); font-weight: 600; }

.route-map {
  display: block;
  width: 100%;
  max-width: 100%;
  border-radius: 10px;
  margin-bottom: 20px;
}

.itinerary-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.itinerary-stop {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
}
.stop-date { font-size: 0.8rem; color: var(--muted); }
.stop-port { font-weight: 600; }
.stop-times { display: flex; gap: 12px; font-size: 0.85rem; color: var(--muted); }

/* ---- Ship/Deck Plans/Weather/Ports/Dining/Wifi/Special Needs tabs ---- */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.photo-grid img {
  width: 100%;
  height: 120px;
  object-fit: cover;
  border-radius: 8px;
  background: var(--border);
}

/* Deck Plans reuses .photo-grid but with one big image per row instead of
   a 2-up thumbnail grid -- deal.php only ever puts 1-2 images through it,
   and a deck plan diagram needs to be legible, not thumbnail-sized. */
.deckplan-grid {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.deckplan-grid img {
  width: 100%;
  border-radius: 8px;
}

/* Generic embed for content we sanitize rather than fully re-parse. Not
   trying to match VTG's desktop design -- just keeping it readable and
   from overflowing a phone screen. */
.raw-tab-content {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  overflow-x: auto;
}
.raw-tab-content img { max-width: 100%; height: auto; }
.raw-tab-content table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.raw-tab-content td, .raw-tab-content th { padding: 6px 8px; border-bottom: 1px solid var(--border); text-align: left; }
.raw-tab-content a { color: var(--accent); }
.raw-tab-content h1, .raw-tab-content h2, .raw-tab-content h3, .raw-tab-content h4 {
  font-size: 1rem;
  margin: 12px 0 6px;
}

.notice, .error {
  background: #fff8e1;
  border: 1px solid #f0d98a;
  border-radius: 8px;
  padding: 12px 14px;
}
.error { background: #fdecea; border-color: #f5c2c0; }
