@import url("https://fonts.googleapis.com/css2?family=Baloo+2:wght@600;700;800&family=Berkshire+Swash&family=Bevan&family=Cabin+Sketch:wght@400;700&family=Cormorant+Garamond:wght@500;600;700&family=Creepster&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Fredoka:wght@500;600;700&family=Limelight&family=Nunito:wght@400;600;700;800&family=Orbitron:wght@500;600;700&family=Pacifico&family=Playfair+Display:wght@600;700&family=Special+Elite&family=Yeseva+One&display=swap");

/*
 * Global Resort & Park Style Guide — refined pass
 *
 * Design intent per theme:
 *   Global default ......... "Vintage attraction poster": soft sky paper, deep
 *                            navy ink, Disney red used as ink (not paint), gold
 *                            reserved for small moments.
 *   .park-disneyland ....... 1950s Main Street marquee: cream ticket-stock paper,
 *                            midnight-navy hero with gold Limelight lettering,
 *                            Special Elite "typewritten itinerary" details.
 *   .park-california-adventure  Pixar-sunset warmth (now a real scoped theme).
 *   .theme-oogie-boogie-bash    Itinerary: moonlit burlap, purple-black
 *                            canvas, orange stitching, lime for data.
 *                            Food & Wine: rebuilt on a light parchment
 *                            ground -- the dark surface was hard to read --
 *                            deep purple stands in for lime as the data
 *                            color there. See the food-mode block after
 *                            the shared/itinerary rules in section 4.
 *   WDW park classes ....... each of the four parks (EPCOT, Magic Kingdom,
 *                            Hollywood Studios, Animal Kingdom) now forks
 *                            into two signature looks via a second body
 *                            class -- .page-itinerary (a bolder, after-dark
 *                            wayfinding mood) and .page-food (a warmer,
 *                            appetite-appealing mood) -- see section 3b.
 *                            .park-travel (transit days) keeps the single
 *                            generic treatment; it has no food guide.
 *   .theme-epcot-festival .. EPCOT Food & Wine Festival's own standalone
 *                            theme (booth-guide passport, not a reskinned
 *                            EPCOT dining page) -- see section 3c.
 *
 * Rules of the file:
 *   - Every selector from the previous version is preserved; HTML/JS untouched.
 *   - Themes override tokens first, component rules second, decoration last.
 */

/* ==========================================================================
   1. GLOBAL DEFAULTS (CLASSIC DISNEY — SKY, NAVY & RED)
   ========================================================================== */
:root {
  --page: #eef6fe; /* Soft morning sky */
  --surface: #ffffff;
  --surface-strong: #ffffff;
  --ink: #16233b; /* Deep navy ink */
  --muted: #5b6b82; /* Cool slate */
  --brand: #cf2233; /* Poster red */
  --brand-hover: #a91a29;
  --accent: #e8a512; /* Gold — small moments only */
  --line: #cfe4f7; /* Sky border */
  --line-subtle: #e4edf6;
  --hero-from: #143a72; /* Royal navy */
  --hero-to: #2a63b4; /* Royal blue */
  --radius: 16px;
  --radius-pill: 999px;
  --shadow: 0 8px 24px rgba(20, 40, 80, 0.08);
  --shadow-hover: 0 14px 32px rgba(20, 40, 80, 0.14);
  --font-display: "Fredoka", sans-serif;
  --font-body: "Nunito", sans-serif;
  --font-detail: var(--font-body); /* eyebrows, pills, badges */
}

* {
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
}
body {
  margin: 0;
  min-height: 100vh;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
a {
  color: inherit;
}
button,
input {
  font: inherit;
}

/* Accessibility focus ring */
a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* Disneyland Resort home canvas — faint sunburst, quieter than before */
.theme-disneyland-resort {
  background:
    radial-gradient(
      circle at 50% -8%,
      rgba(232, 165, 18, 0.14),
      transparent 34rem
    ),
    radial-gradient(
      circle at 90% 104%,
      rgba(207, 34, 51, 0.06),
      transparent 26rem
    ),
    var(--page);
}

.theme-walt-disney-world-resort {
  --page: #edf6fb;
  --brand: #1a5d9c;
  --brand-hover: #134a7e;
  --accent: #c9962c;
  --line: #c9dded;
  --hero-from: #123f6e;
  --hero-to: #3f8dae;
  background:
    radial-gradient(
      circle at 50% -8%,
      rgba(63, 141, 174, 0.14),
      transparent 34rem
    ),
    var(--page);
}

.container {
  width: min(960px, calc(100% - 32px));
  margin: 0 auto;
}

/* ==========================================================================
   2. HOME PAGE & CORE COMPONENTS (INDEX.HTML)
   ========================================================================== */
.status-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  padding: 9px 16px;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
}
.status-bar [data-kind="online"] {
  color: #178a4c;
  font-weight: 700;
}
.status-bar [data-kind="offline"] {
  color: var(--brand);
  font-weight: 700;
}
.status-bar button {
  border: 1.5px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 6px 12px;
  background: var(--surface);
  color: var(--ink);
  font-weight: 700;
  font-size: 13.5px;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease,
    background 0.15s ease;
}
.status-bar button:hover {
  border-color: var(--brand);
  color: var(--brand);
}
.page-toolbar {
  position: static;
  flex-wrap: wrap;
  gap: 10px;
  padding: 18px 16px 32px;
  background: transparent;
  backdrop-filter: none;
  border-bottom: none;
  border-top: 1px solid var(--line);
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Homepage entry point into the (unthemed-page) Utilidors admin console —
   deliberately fixed dark/amber colors rather than CSS variables, since it
   renders on top of whichever resort theme index.html is using. True
   black + a bright hazard-yellow (not the trip-picker marquee's muted
   gold, so the two read as distinctly different buttons) with a caution-
   tape striped bar top and bottom -- overflow:hidden clips both bars to
   the pill's own rounded corners (border-image can't follow a
   border-radius, hence the pseudo-element bars instead of a striped
   border). */
.utilidors-link {
  position: relative;
  overflow: hidden;
  display: block;
  width: min(360px, calc(100% - 32px));
  margin: 0 auto 40px;
  padding: 16px 20px 14px;
  border-radius: var(--radius-pill);
  background: #0a0a0a;
  border: 2px solid #f5da42;
  color: #f5da42;
  text-align: center;
  text-decoration: none;
  font-weight: 800;
  font-size: 14px;
  letter-spacing: 0.03em;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
  transition:
    transform 0.15s ease,
    box-shadow 0.15s ease;
}
.utilidors-link::before,
.utilidors-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 6px;
  background: repeating-linear-gradient(
    135deg,
    #f5da42 0 8px,
    #0a0a0a 8px 16px
  );
}
.utilidors-link::before {
  top: 0;
}
.utilidors-link::after {
  bottom: 0;
}
.utilidors-link:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5);
}

.trip-home-nav {
  padding-top: 24px;
}
/* Trip-picker page only (site/assets/js/app.js's renderTripPicker) -- a
   fixed 3x2 mosaic (1,2,3 top row; 4,5,6 bottom row), photos supplied by
   Kyle directly into site/assets/images/home-grid/. */
.home-photo-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  padding-top: 20px;
}
.home-photo-grid img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.site-header {
  padding: 56px 0 24px;
  text-align: center;
}
.site-title {
  margin: 10px 0 4px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(40px, 8.5vw, 68px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  color: var(--ink);
}
.site-title::after {
  /* Poster underline: red rule with a gold center notch */
  content: "";
  display: block;
  width: 96px;
  height: 4px;
  margin: 16px auto 0;
  border-radius: 999px;
  background: linear-gradient(
    90deg,
    var(--brand) 0 38%,
    var(--accent) 38% 62%,
    var(--brand) 62% 100%
  );
}
.subtitle {
  margin: 14px 0 4px;
  color: var(--muted);
  font-size: 18px;
  font-weight: 600;
}
.dates {
  display: inline-block;
  margin-top: 2px;
  color: var(--brand);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-family: var(--font-detail);
}
.section-title {
  margin: 34px 0 16px;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 26px;
  text-align: center;
  letter-spacing: -0.01em;
}

/* Trip homepage weather widget -- always the resort's own park weather
   (see scripts/lib/resort-weather.js), never the visitor's location.
   Ported from a prior project's Open-Meteo-based widget, remapped onto
   this site's shared tokens (--ink/--muted/--accent/--line/--surface) so
   it inherits every park/resort theme automatically, same as .pill and
   .day-card already do. */
.weather-widget {
  display: block;
  width: 100%;
  margin: 20px 0 0;
  padding: 0;
  border: 1.5px solid var(--card-line, var(--line));
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition:
    transform 0.18s ease,
    box-shadow 0.18s ease;
}
.weather-widget:hover,
.weather-widget:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--shadow-hover);
}
.weather-widget-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  padding: 16px 20px;
}
.weather-main {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.weather-icon {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
}
.weather-copy {
  min-width: 0;
}
.weather-kicker {
  grid-column: 1 / -1;
  display: block;
  margin-bottom: 8px;
  font-family: var(--font-detail);
  font-weight: 800;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--card-ink, var(--accent));
}
.weather-description {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 21px;
  line-height: 1.1;
  color: var(--ink);
}
.weather-guidance {
  display: block;
  margin-top: 5px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
}
.weather-stats {
  display: grid;
  grid-template-columns: repeat(4, auto);
  gap: 10px;
  align-items: stretch;
}
.weather-stat {
  min-width: 52px;
  padding: 4px 8px;
  border-left: 1px solid var(--line);
  text-align: center;
}
.weather-stat-label {
  display: block;
  font-family: var(--font-detail);
  font-weight: 800;
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--card-ink, var(--accent));
}
.weather-stat-value {
  display: block;
  margin-top: 4px;
  font-family: var(--font-display);
  font-size: 18px;
  line-height: 1;
  color: var(--ink);
}
.weather-widget-pending,
.weather-widget-unavailable {
  grid-template-columns: 1fr;
}
/* Sunset is a fact of the day (a time), not a numeric condition like the
   stat tiles above it, so it gets its own full-width footer line rather
   than a 5th cramped grid column -- spans both .weather-widget-inner
   columns at desktop width, sits as a normal block once that grid
   collapses to one column on mobile (see breakpoint below). */
.weather-sunset {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  font-size: 16.5px;
  color: var(--muted);
}
.weather-sunset-icon {
  width: 32px;
  height: 32px;
  border-radius: 6px;
  object-fit: cover;
}
@media (max-width: 560px) {
  .weather-widget-inner {
    grid-template-columns: 1fr;
    gap: 12px;
    padding: 14px 16px;
  }
  .weather-stats {
    grid-template-columns: repeat(4, 1fr);
    gap: 0;
    border-top: 1px solid var(--line);
    padding-top: 10px;
  }
  .weather-stat {
    min-width: 0;
    padding: 4px 5px;
  }
  .weather-stat:first-child {
    border-left: 0;
  }
  .weather-description {
    font-size: 20px;
  }
}

/* Trip homepage header: trip emoji + countdown pill next to the dates.
   Countdown reuses trip-utils.js's countdownDays()/countdownLabel(), the
   same source of truth as the trip-picker card's own badge -- just a plain
   inline pill here rather than that badge's glowing circle, since this
   sits in a single full-width header rather than on a card corner. */
/* Trip home header: a large icon to the left of the trip tagline (now the
   headline, styled via .site-title), sized to roughly match the height of
   a two-line title -- matching other page elements that pair a big icon
   with headline-weight text. Font sizes step down top to bottom: tagline
   (.site-title, biggest) -> trip dates (.home-dates-line, bumped up from
   the plain .dates size) -> resort name (year stripped, see renderHome()'s
   resortName) + countdown pill (.home-meta-row, smallest). Trip home pages
   also drop the poster underline -- the icon already anchors the header.
   Scoped via .home-title-row rather than a body class, since renderHome()
   doesn't add one of its own. */
.home-title-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  /* Center, not left: the icon+tagline unit is already centered as a
     block by justify-content above (its bounding box lands at the exact
     same x as the centered dates/resort lines below), but flush-left text
     inside a box sized to its longest wrapped line reads left-heavy --
     any shorter line leaves blank space on the right of its own box, so
     the drawn "ink" skews left even though the box doesn't. Centering the
     text fixes that; text-wrap: balance below keeps the residual gap on
     an uneven line small. */
  text-align: center;
}
.trip-home-icon {
  display: block;
  flex: 0 0 auto;
  font-size: clamp(80px, 17vw, 136px);
  line-height: 1;
}
.home-title-row .site-title::after {
  display: none;
}
.home-title-row .site-title {
  /* Zeroed here (rather than in the shared .site-title rule) so the gap
     down to .home-dates-line is controlled by one margin, not two. */
  margin-bottom: 0;
  /* Same script face as "Happily Ever After" on the trip-picker page
     (body.page-trip-picker .site-title above) -- reused here rather than
     the shared --font-display token, so it scopes to just the header
     headline. Berkshire Swash is single-weight (400 only), so pin that
     here too rather than inherit the shared 600, which would just
     fake-bold it. Its glyphs run noticeably wider than Fredoka's at the
     same font-size, so the shared .site-title clamp wrapped a 4-word
     tagline to 4 lines against an icon sized for ~2 -- sized down here
     to keep that ~2-line balance. */
  font-family: "Berkshire Swash", cursive;
  font-weight: 400;
  font-size: clamp(30px, 6.2vw, 50px);
  /* Balances the wrapped lines' widths (e.g. 2+2 words instead of 3+1)
     instead of the default greedy wrap. Supported in current
     Chrome/Safari/Firefox; unsupported browsers just keep the default
     wrap, so this is a safe progressive enhancement. */
  text-wrap: balance;
  /* This element's width is also set inline by fitHomeTaglineWidth()
     (app.js) after render. A flex item's auto width and text-wrap:
     balance disagree on how wide this box needs to be -- measured it
     landing ~55px wider than the actual longest rendered line, even with
     an explicit `width: max-content` here. With text-align: center that
     oversized box pushed the text noticeably right of the icon instead
     of hugging it, so the actual fix has to happen in JS, after the
     balanced lines have rendered and can be measured. */
}
/* Dates + resort name/countdown: Baloo 2 instead of the shared
   --font-detail (Nunito), which read flat and businesslike next to the
   script tagline above. Baloo 2 is rounded and friendly without being a
   true script/cursive face -- already used elsewhere in the theme matrix
   (e.g. the Hollywood Studios itinerary theme) for the same "soften it
   up" reason. .countdown-pill sets its own font-family explicitly, so it
   needs the override named directly rather than just inheriting. */
.home-dates-line,
.home-meta-row,
.home-meta-row .countdown-pill {
  font-family: "Baloo 2", sans-serif;
}
.home-dates-line {
  /* margin set as a full shorthand, not just margin-top, so it overrides
     both the plain .dates rule's margin-top and the paragraph's default
     UA bottom margin -- otherwise this row and .home-meta-row below it
     end up with mismatched gaps. */
  margin: 7px 0 0;
  font-size: 20px;
}
.home-meta-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  /* Half of .home-dates-line's 7px again -- deliberately tighter than the
     gap above it now, so the resort name/countdown pill read as a closer
     pair with the dates line than either does with the tagline above. */
  margin-top: 3.5px;
}
.home-meta-row .subtitle {
  margin: 0;
  font-size: 17px;
}
.countdown-pill {
  display: inline-block;
  padding: 4px 12px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  font-family: var(--font-detail);
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
/* The default --accent text reads too close to the pill's own
   accent-tinted background. Only two resort themes render this pill
   today (Disneyland, Walt Disney World), so pin each to the *other*
   resort's brand color -- distinct from both the pill background and
   .dates' own --brand color right next to it: Disneyland's date is red
   (global --brand), so its pill text is WDW's blue; WDW's date is blue
   (its own --brand), so its pill text is the global red. */
.theme-disneyland-resort .countdown-pill {
  color: #1a5d9c;
}
.theme-walt-disney-world-resort .countdown-pill {
  color: #cf2233;
}

/* Trip homepage Food & Drink -- two columns; an odd guide out (EPCOT Food &
   Wine Festival alongside WDW's four parks) spans both columns and centers
   rather than leaving a lopsided empty cell. :nth-child(odd) on the last
   child is true exactly when the total count is odd, so this needs no
   count logic in app.js. */
.food-drink-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding-bottom: 48px;
}
.food-drink-grid .pill {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin: 0;
}
.food-drink-grid .pill:last-child:nth-child(odd) {
  grid-column: 1 / -1;
  /* Wide enough to keep a long name (e.g. "EPCOT Food & Wine Festival")
     on 2 lines next to the 38px icon rather than wrapping to 3 -- the
     200px cap this replaced was sized for the icon's original 19px. */
  width: min(280px, 100%);
  justify-self: center;
}
.food-drink-grid .park-icon,
.pill .park-icon {
  width: 38px;
  height: 38px;
  flex: none;
}

/* Trip homepage "Trip Itinerary" -- a connected path rather than a stack of
   unrelated cards: a line down the left links standalone park icons to each
   day, echoing itinerary.html's own .timeline/.timeline-node motif. The
   node and the .day-card below share the same day.theme class, so both
   read the park's real --card-ink/--card-line tokens (and, for Oogie
   Boogie Bash, the full dark-surface reskin) with no duplicated per-theme
   CSS. */
.trip-timeline {
  position: relative;
  padding-bottom: 12px;
}
.trip-timeline::before {
  content: "";
  position: absolute;
  /* Centered under the 96px icon column (48px half-width), not a medallion
     circle's center -- v22 dropped the circular background/border so the
     icon itself, at its enlarged size, needs to read clearly on its own. */
  left: 48px;
  top: 6px;
  bottom: 6px;
  width: 2px;
  background: var(--line);
}
/* A 2-column grid (node, then card) rather than an absolutely-positioned
   node overlaid on a full-width card -- centers the node against the
   card via the grid row's own cross-axis alignment for free. The node is
   a fixed size (not a percentage of the card's height, tried and reverted
   -- a tall two-line card grew its medallion large enough to overlap its
   neighbors), at 96px so a detailed icon (e.g. Animal Kingdom's Tree of
   Life) reads clearly standing alone with no circular backing. */
.trip-timeline-item {
  position: relative;
  display: grid;
  grid-template-columns: 96px 1fr;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}
.trip-timeline-item:last-child {
  margin-bottom: 0;
}
.trip-timeline-node {
  justify-self: center;
  width: 96px;
  height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.trip-timeline-node .park-icon {
  width: 88px;
  height: 88px;
  color: var(--card-ink, var(--brand));
}

/* Cards & grids */
.day-card {
  position: relative;
  display: block;
  padding: 22px 22px 20px;
  border: 1.5px solid var(--card-line, var(--line));
  border-top: 4px solid var(--card-ink, var(--brand));
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  text-decoration: none;
  transition:
    transform 0.18s ease,
    box-shadow 0.18s ease,
    border-color 0.18s ease;
}
.day-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-hover);
  border-color: var(--card-ink, var(--brand));
}
.day-card .date {
  font-family: var(--font-detail);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.12em;
  /* Matches the Food & Drink pills: the park name carries the park's own
     accent color (below), so the date stays plain ink instead. */
  color: var(--ink);
  text-transform: uppercase;
}
.day-card h2 {
  margin: 6px 0 8px;
  color: var(--card-ink, var(--brand));
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.15;
}
.day-card p {
  margin: 0;
  color: var(--muted);
  font-size: 14.5px;
}
/* One guide per row, same grid idiom as .day-grid (defined rows/gap
   rather than a wrapping chip cloud) -- just a single column instead of
   two, since each .pill is now sized close to full mobile width. */
.food-links {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  padding-bottom: 48px;
}
/* .pill (trip homepage Food & Wine links, the index.html Style Guide
   link) and .action-link (itinerary/food page nav) share one pill-button
   size so nothing on the site reads as an unintentionally smaller variant
   of the other -- stretched close to full mobile width like
   .utilidors-link, rather than shrink-to-fit-content, per Kyle's
   follow-up on issue #73/PR #74 (the previous, still-compact size still
   read as too small next to it). */
.pill,
.action-link {
  display: block;
  width: min(360px, calc(100% - 32px));
  margin: 0 auto;
  padding: 14px 26px;
  border-radius: var(--radius-pill);
  font-weight: 800;
  font-size: 16px;
  text-align: center;
  text-decoration: none;
  transition:
    transform 0.15s ease,
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.pill {
  border: 1.5px solid var(--card-line, var(--line));
  background: var(--surface);
  box-shadow: 0 4px 12px rgba(20, 40, 80, 0.06);
  color: var(--card-ink, var(--brand));
}
.pill:hover {
  transform: translateY(-2px);
  border-color: var(--card-ink, var(--brand));
  box-shadow: var(--shadow);
}

/* Trip picker (index.html with no trip selected) -- each card carries its
   own trip's resortTheme class directly, since multiple trips/themes are
   shown together with no single theme on <body> to scope from. */
.trip-picker-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  padding-bottom: 44px;
}
.trip-picker-card {
  position: relative;
  display: block;
  padding: 22px 22px 20px;
  border: 1.5px solid var(--card-line, var(--line));
  border-top: 4px solid var(--card-ink, var(--brand));
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  text-decoration: none;
  transition:
    transform 0.18s ease,
    box-shadow 0.18s ease,
    border-color 0.18s ease;
}
.trip-picker-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-hover);
  border-color: var(--card-ink, var(--brand));
}
.trip-picker-card h2 {
  margin: 6px 0 8px;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.15;
}
.trip-picker-card .subtitle,
.trip-picker-card .dates {
  margin: 0;
  color: var(--muted);
  font-size: 14.5px;
}
.trip-picker-countdown {
  margin: 10px 0 0;
  font-family: var(--font-detail);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--card-ink, var(--brand));
  text-transform: uppercase;
}
.footer {
  padding: 20px 0 44px;
  color: var(--muted);
  font-size: 13.5px;
  text-align: center;
  font-weight: 600;
}

/* Default food guide layout */
.food-page {
  background: var(--page);
  color: var(--ink);
}
.food-hero {
  padding: 34px 20px 30px;
  background: linear-gradient(160deg, var(--hero-from), var(--hero-to));
  color: #fff;
  text-align: center;
  border-bottom: 4px solid var(--accent);
}
.food-hero-inner {
  width: min(920px, 100%);
  margin: 0 auto;
}
/* Same contrast-first approach as the restaurant-name/category-title pass:
   a light translucent tint (previously rgba(255,255,255,0.12)) only reads
   against a dark hero -- several themes' food-hero gradients run light-to-
   light (Magic Kingdom's is barely off-white end to end), so the button
   nearly vanished there. A dark scrim behind white text guarantees real
   contrast against every theme's hero regardless of its own color/
   lightness (verified against the lightest hero in the set, Magic
   Kingdom's #fdf6f0, at ~6:1) while still reading as "glass on the photo"
   rather than an opaque box. */
.food-back-link {
  display: inline-block;
  margin-bottom: 14px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid rgba(255, 255, 255, 0.55);
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-weight: 700;
  font-size: 13.5px;
  text-decoration: none;
  backdrop-filter: blur(4px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  transition:
    background 0.15s ease,
    border-color 0.15s ease;
}
.food-back-link:hover {
  background: rgba(0, 0, 0, 0.72);
  border-color: rgba(255, 255, 255, 0.75);
}
.food-hero h1 {
  margin: 4px 0 8px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(32px, 7vw, 50px);
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.food-hero p {
  margin: 0;
  font-size: 15.5px;
  opacity: 0.88;
}

.food-toolbar {
  position: sticky;
  top: 0;
  z-index: 20;
  padding: 12px 16px;
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 4px 16px rgba(20, 40, 80, 0.06);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.food-toolbar-inner {
  display: flex;
  flex-direction: column;
  width: min(920px, 100%);
  gap: 10px;
  margin: 0 auto;
}
.search-input {
  width: 100%;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 11px 18px;
  font-size: 15px;
  color: var(--ink);
  background: var(--surface);
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.search-input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 16%, transparent);
  outline: none;
}
/* Fixed 2-column grid -- 3 rows of intentionally-paired buttons (Alcohol/
   Seasonal, Favorites/Already Tasted, Hide Restaurant Categories/Expand
   All), one grid item per button in that exact source order, rather than
   flex-wrap's width-dependent wrapping (which left an uneven "row of 3
   then a lone button" layout). Every button stretches to fill its column
   (.filter-btn's width: 100% below) so the whole block reads as one
   uniform, thematic control instead of pill-shaped buttons of varying
   width. */
.filter-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.filter-btn {
  width: 100%;
  box-sizing: border-box;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 6px 14px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ink);
  text-align: center;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    background 0.15s ease,
    color 0.15s ease;
}
.filter-btn:hover {
  border-color: var(--brand);
  color: var(--brand);
}
.filter-btn.active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
.filter-btn.utility-btn {
  background: transparent;
  border-style: dashed;
  color: var(--muted);
  font-weight: 600;
}
.filter-btn.utility-btn:hover {
  border-color: var(--brand);
  color: var(--brand);
}
/* Default (no restaurants hidden) is deliberately just a plain .filter-btn
   -- same color palette, font, and outline as every other filter-row
   button, no custom rule needed here. Once any category is actually
   hidden, .has-hidden fills with --hero-from -- the same token anchoring
   the .food-hero band directly above (linear-gradient(--hero-from,
   --hero-to)), specifically the FROM end since it's the darker of the two
   stops in every theme except Magic Kingdom's (overridden below) -- rather
   than plain --ink, so the flipped state reads as a themed color pulled
   from the page's own hero instead of a generic near-black every theme's
   --ink independently converges on.

   Scoped through the always-present .category-filter-wrap ancestor
   (bumping specificity to 0,4,0) rather than left at .filter-btn.category-
   toggle-btn.has-hidden alone (0,3,0) -- Oogie Boogie's own
   `.theme-oogie-boogie-bash .filter-btn:not(.utility-btn)` rule ties at
   0,3,0 and sits later in this file, so without the extra scope it silently
   won on that one theme and the hidden state never visibly changed color
   there at all. Found by screenshotting every food-page theme, not by
   inspection -- the same class of bug the "audit every reader of a shared
   custom property" guidance elsewhere in this file exists to catch, just
   on a whole-ruleset level instead of one property. */
.category-filter-wrap .filter-btn.category-toggle-btn.has-hidden {
  background: var(--hero-from);
  border-color: var(--hero-from);
  color: var(--surface);
}
.category-filter-wrap .filter-btn.category-toggle-btn.has-hidden:hover {
  background: var(--hero-from);
  border-color: var(--hero-from);
  color: var(--surface);
}
.category-toggle-icon {
  width: 14px;
  height: 14px;
  vertical-align: -2px;
  margin-right: 2px;
}
.category-filter-wrap {
  position: relative;
  width: 100%;
}
.category-filter-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 20;
  min-width: 220px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.category-filter-panel[hidden] {
  display: none;
}
.category-filter-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 8px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}
.category-filter-option:hover {
  background: var(--line-subtle, var(--line));
}
.category-filter-option input {
  cursor: pointer;
}

.food-content {
  width: min(920px, calc(100% - 28px));
  margin: 0 auto;
  padding: 24px 0 56px;
}
.location-divider {
  margin: 34px 0 14px;
  display: flex;
  align-items: center;
  gap: 14px;
  color: var(--ink);
  font-family: var(--font-detail);
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: 13.5px;
}
.location-divider::before,
.location-divider::after {
  content: "";
  flex: 1;
  height: 2px;
  border-radius: 999px;
  background: var(--card-line, var(--line));
}

.restaurant-card {
  background: var(--surface);
  border: 1.5px solid var(--card-line, var(--line));
  border-radius: var(--radius);
  box-shadow: 0 4px 14px rgba(20, 40, 80, 0.05);
  overflow: hidden;
  margin-bottom: 12px;
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.restaurant-card:hover {
  border-color: var(--brand);
  box-shadow: var(--shadow);
}
.restaurant-header {
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 15px 18px;
  background: var(--surface);
}
.restaurant-name-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.restaurant-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 22px;
  color: var(--ink);
  margin: 0;
  line-height: 1.2;
}
.restaurant-favorite-badge {
  display: none;
  color: var(--accent);
  font-size: 15px;
  line-height: 1;
}
.restaurant-card.has-favorite-item .restaurant-favorite-badge {
  display: inline;
}
.category-badge {
  display: inline-block;
  background: var(--line-subtle);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 2px 8px;
  font-family: var(--font-detail);
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--muted);
  text-transform: uppercase;
}
/* A restaurant/booth pulled in from the EPCOT Food & Wine Festival guide
   (app.js's buildRestaurant(), entry.is_festival_booth) needs its own
   per-card marker on the merged EPCOT page -- .theme-epcot-festival above
   is a whole-page theme keyed off a body class and can't apply here,
   since this page's body theme stays park-epcot. Deliberately plain,
   non-body-scoped selectors (same exception class as the park-icon theme
   tokens, style-guide.css Section 3's own note) applied directly to
   elements carrying the class/badge themselves. Colors are literal,
   reused from .theme-epcot-festival's own gold/wine tokens above rather
   than introduced fresh, so a merged festival card still reads as "this
   theme" even though the surrounding page isn't festival-themed.
   A genuine festival-only booth already gets "FESTIVAL BOOTH" as its
   plain .category-badge text (its raw `category` field) -- this chip is
   for the 9 merged same-venue restaurants, whose .category-badge shows
   their real service type instead, so they'd otherwise carry no visible
   festival marker at all. */
.restaurant-card.is-festival-booth {
  border-left: 4px solid #d4af37;
}
/* Same idea, EPCOT Flower & Garden Festival (issue #150) -- its own
   green/pink border, reused from .theme-epcot-flower-garden's own
   tokens above, so a merged Flower & Garden card reads as "this
   festival" the same way a Food & Wine card does with its gold border.
   Every current Flower & Garden entry is booth-only (no same-venue
   merge, see mergeFlowerGardenBoothsIntoEpcot()), so .festival-booth-badge
   never actually fires for one today -- its "FESTIVAL BOOTH" .category-badge
   text already covers it -- but the badge's title text still branches on
   festival_id (app.js) in case a future same-venue merge needs it. */
.restaurant-card.is-flower-garden-booth {
  border-left: 4px solid #7a9c4a;
}
.festival-booth-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: #fbf3df;
  border: 1px solid #d4af37;
  border-radius: 6px;
  padding: 2px 8px;
  font-family: var(--font-detail);
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #5b2140;
  text-transform: uppercase;
}
.restaurant-meta {
  margin-top: 4px;
  font-size: 14px;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.menu-link {
  color: var(--brand);
  font-weight: 700;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--brand) 35%, transparent);
  text-underline-offset: 2px;
  transition: text-decoration-color 0.15s ease;
}
.menu-link:hover {
  text-decoration-color: var(--brand);
}
.chevron {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--line-subtle);
  color: var(--brand);
  display: grid;
  place-items: center;
  font-size: 14px;
  font-weight: 800;
  transition:
    transform 0.2s ease,
    background 0.2s ease,
    color 0.2s ease;
}
.restaurant-card.open .chevron {
  transform: rotate(180deg);
  background: var(--brand);
  color: #fff;
}
.restaurant-body {
  display: none;
  padding: 10px 18px 18px;
  border-top: 1.5px dashed var(--line);
  background: var(--surface);
}
.restaurant-card.open .restaurant-body {
  display: block;
}
/* Outlined stamp -- option #8 of "The Category Lineup" comparison, picked
   after a light-background-chip pass read as too close to .category-badge.
   No fill, just a themed-accent border + accent-colored text, so it reads
   as its own labeled section without competing with the badge next to the
   restaurant name above it. Text is --accent darkened toward --ink rather
   than raw --accent -- several themes' accents (Disneyland/Magic Kingdom/
   EPCOT/Festival gold tones) sit under 4.5:1 against a light card at this
   size as plain text; the border alone only needs the lower ~3:1 UI-
   component threshold, so it stays the pure accent color. */
.category-title {
  display: inline-block;
  background: transparent;
  border: 1.5px solid var(--accent);
  color: color-mix(in srgb, var(--accent) 65%, var(--ink) 35%);
  border-radius: 6px;
  padding: 5px 14px;
  font-family: var(--font-detail);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.menu-item {
  display: block;
  padding: 10px 8px 10px 2px;
  margin: 0 -6px;
  border-bottom: 1px solid var(--line-subtle);
  border-left: 3px solid transparent;
  border-radius: 6px;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  touch-action: pan-y;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    transform 0.1s ease;
}
.menu-item:last-child {
  border-bottom: none;
}
.menu-item.is-done {
  background: color-mix(in srgb, var(--brand) 6%, transparent);
}
.menu-item.is-favorite {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-left-color: var(--accent);
  padding-left: 8px;
}
.menu-item.is-pressing {
  transform: scale(0.98);
  background: color-mix(in srgb, var(--accent) 20%, transparent);
}
.favorite-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.item-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
}
/* Two columns: the name (which can wrap onto multiple lines) and price sit
   in the left column; the favorite/seasonal tags and photo thumbnail stack
   in a fixed-width right column, tags on top and the photo directly under
   them as a second row -- keeps the tags/photo from getting pushed onto
   their own full-width line underneath a wrapped name. */
.item-left {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.item-name-wrap {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.item-right {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}
.item-tags {
  display: flex;
  align-items: center;
  gap: 6px;
}
.item-photo-thumb {
  display: block;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}
.item-photo-thumb img {
  display: block;
  width: 88px;
  height: 88px;
  border: 1px solid var(--line);
  border-radius: 5px;
  object-fit: cover;
}
.photo-lightbox {
  padding: 0;
  border: none;
  border-radius: var(--radius);
  background: none;
  overflow: visible;
  max-width: 90vw;
  max-height: 90vh;
}
.photo-lightbox::backdrop {
  background: rgba(0, 0, 0, 0.7);
}
.photo-lightbox img {
  display: block;
  max-width: 90vw;
  max-height: 90vh;
  border-radius: var(--radius);
}
.photo-lightbox-close {
  position: absolute;
  top: -14px;
  right: -14px;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* Hot dog rating popup -- opened by a long press on a menu item (replaces
   the old plain eaten checkbox). Same dialog/backdrop/close-button
   structure as .photo-lightbox above, sized for the 5-icon row + clear
   button instead of an image. */
.rating-popup {
  width: min(320px, 90vw);
  padding: 22px 20px 20px;
  border: none;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-hover);
  overflow: visible;
  color: var(--ink);
  text-align: center;
}
.rating-popup::backdrop {
  background: rgba(0, 0, 0, 0.7);
}
.rating-popup-close {
  position: absolute;
  top: -14px;
  right: -14px;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.rating-popup-item-name {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 17px;
  color: var(--brand);
}
.rating-hotdogs {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-bottom: 18px;
}
.rating-hotdog {
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 6px;
}
.rating-hotdog img {
  display: block;
  width: 44px;
  height: 44px;
  object-fit: contain;
  border-radius: 6px;
  /* Greyed out by default; .is-filled (set by wireRatingPopup()'s
     paint()) switches a hotdog on -- coloring in icons 1..N left to
     right as the user picks a score. */
  filter: grayscale(1) opacity(0.35);
  transition: filter 0.15s ease;
  /* Suppresses the OS's native long-press image callout (Save/Share/Copy
     Image on iOS Safari, the same on Android Chrome) -- these icons sit
     right where a long press already means something else on this page
     (open the rating popup / pick a score), so the native menu is just
     noise here. Paired with draggable="false" on the <img> and a
     contextmenu preventDefault() in wireRatingPopup(). */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}
.rating-hotdog.is-filled img {
  filter: none;
}
.rating-hotdog:focus-visible img {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.rating-popup-clear {
  padding: 8px 16px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
/* Trip forecast dialog -- day-by-day breakdown opened by tapping the
   .weather-widget button. Same dialog/backdrop/close-button structure as
   .photo-lightbox above, sized for a scrolling text list instead of an
   image. */
.weather-forecast-dialog {
  width: min(420px, 90vw);
  max-height: 80vh;
  padding: 20px;
  border: none;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-hover);
  overflow: visible;
  color: var(--ink);
}
.weather-forecast-dialog::backdrop {
  background: rgba(0, 0, 0, 0.7);
}
.weather-forecast-close {
  position: absolute;
  top: -14px;
  right: -14px;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.weather-forecast-kicker {
  display: block;
  font-family: var(--font-detail);
  font-weight: 800;
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}
.weather-forecast-title {
  margin: 4px 0 16px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 24px;
  color: var(--ink);
}
.weather-forecast-days {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: calc(80vh - 90px);
  overflow-y: auto;
}
.weather-forecast-loading {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}
.weather-forecast-day {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
}
.weather-forecast-day-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.weather-forecast-day-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 16px;
  color: var(--ink);
}
.weather-forecast-day-date {
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.weather-forecast-day-description {
  display: block;
  margin-top: 4px;
  font-size: 13px;
  color: var(--muted);
}
.weather-forecast-day-unavailable {
  display: block;
  margin-top: 4px;
  font-size: 13px;
  font-style: italic;
  color: var(--muted);
}
.weather-forecast-day-stats {
  display: flex;
  gap: 16px;
  margin-top: 8px;
  font-size: 13px;
  color: var(--ink);
}
.weather-forecast-day-stats strong {
  font-family: var(--font-display);
  font-weight: 600;
}
.weather-forecast-day-sunset {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font-size: 16.5px;
  color: var(--muted);
}
/* Visual-only checkmark shown when an item's rating > 0 -- same
   position/size/style as the original .item-check-mark, before the plain
   eaten checkbox was retired in favor of the hot dog rating. Toggled by
   applyRatings() in JS (a rating is a 0-5 int, not a boolean, so there's
   no checkbox :checked sibling selector to drive this off of any more). */
.rating-check-mark {
  display: none;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  border-radius: 4px;
  background: var(--brand);
  color: #fff;
  font-size: 10px;
  font-weight: 800;
}
.rating-check-mark:not([hidden]) {
  display: inline-flex;
}
/* The actual score, as N repeated hot dog icons -- replaces the old text
   "🌭 N" badge. A block-level row of its own (left-aligned, between the
   item name and price -- .item-left is a flex column, see above) rather
   than sitting inline after the name: at inline size a long item name
   pushed the icons into an awkward wrap alongside the photo thumbnail.
   `hidden` fully collapses the row's space when there's no rating. Each
   icon is the same fixed pixel size regardless of the score. */
.rating-score-icons {
  display: none;
  align-items: center;
  gap: 2px;
}
.rating-score-icons:not([hidden]) {
  display: flex;
}
.rating-score-icon {
  display: block;
  width: 42px;
  height: 42px;
  object-fit: contain;
  /* Same OS-native-long-press-callout suppression as .rating-hotdog img
     above -- these icons sit inside the same .menu-item a long press
     opens the rating popup from, so an accidental image callout here is
     especially disruptive mid-gesture. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}
.favorite-badge {
  display: none;
  flex: none;
  color: var(--accent);
  font-size: 13px;
  line-height: 1;
}
.favorite-input:checked ~ .item-top .favorite-badge {
  display: inline;
}
/* Flipped from an earlier pass: item names now carry the full brand
   color (they're what a diner is actually scanning the list for) and
   item prices take the quieter ink/brand blend -- reads closer to black
   than colored, which is deliberate here. Between the two, this is what
   actually needed the contrast help. */
.item-name {
  font-weight: 700;
  font-size: 16px;
  color: var(--brand);
}
.item-price {
  white-space: nowrap;
  font-weight: 800;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--ink) 60%, var(--brand) 40%);
}
.item-desc {
  margin-top: 3px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted);
}
.no-results {
  padding: 28px;
  text-align: center;
  border: 1.5px dashed var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--muted);
  font-weight: 600;
}

/* ==========================================================================
   2a. TRIP PICKER PAGE THEME -- "MARQUEE UNDER A NIGHT SKY"
   --------------------------------------------------------------------------
   Scoped to body.page-trip-picker (set by renderTripPicker() in app.js)
   rather than the shared .site-title/.site-header/.trip-picker-card
   selectors directly -- a selected trip's own home page renders through
   those same classes and is deliberately untouched here. Structure is
   unchanged from before this pass (photo grid, "Our Trips", the trip
   list, Style Guide, Utilidors) -- only color/type/iconography/countdown
   presentation.

   A plain deep-navy night-sky page (no firework decoration) behind the
   trip cards, which keep their own separate "classic ticket/marquee"
   identity untouched from the page around them: white card, warm-cream
   border, solid red top accent, Limelight title, warm brown-gold
   subtitle, red all-caps dates, and a plain emoji icon -- all still
   driven by this scope's own --ink/--muted/--line/--brand tokens exactly
   as the shared .trip-picker-card rules in Section 2 already render them,
   so there's very little card-specific CSS below beyond the icon and the
   countdown badge. */
body.page-trip-picker {
  --page: #0b1b3a; /* Deep navy night sky, plain -- no firework decoration */
  --ink: #17213a;
  --muted: #8a6a3a; /* Warm brown-gold, not cool slate -- matches the cards' warm cream/white */
  --accent: #f4c430; /* True marigold */
  --line: #f0dcae;
  --line-subtle: #f7ecd3;
  --font-display: "Limelight", cursive;
}
/* Limelight is single-weight (Google only ships it at 400) -- pin
   font-weight here rather than inherit the shared base's 700, which
   would just fake-bold it. */
body.page-trip-picker .trip-picker-card h2 {
  font-weight: 400;
}
/* .dates fell back to var(--muted) (this scope's warm brown-gold) same as
   everywhere else on the site -- Option 1 specifically wanted it red,
   distinct from the subtitle above it. Card top accent (border-top) is
   also pinned to the same red for every card regardless of resort theme --
   .theme-walt-disney-world-resort sets its own --brand (blue), which was
   winning on the two WDW trip cards and leaving only the Disneyland card
   red. Both bypass the --brand/--card-ink indirection entirely rather
   than fighting it. */
body.page-trip-picker .trip-picker-card {
  border-top-color: #cf2233;
}
body.page-trip-picker .trip-picker-card .dates {
  color: #cf2233;
}
.trip-picker-icon {
  display: block;
  font-size: 22px;
  line-height: 1;
}
/* "Happily Ever After" now IS the site-title (see renderTripPicker() in
   app.js -- it replaced "Our Trips" rather than sitting above it), so it
   keeps its script font but grows to the shared .site-title size instead
   of the smaller tagline size it had before. Sits directly on the navy
   page background, so it needs a light color instead of the cards' dark
   --ink -- a muted gold ties it to the ticket-gold accent used inside the
   cards below. Berkshire Swash is single-weight (only 400 is loaded), so
   font-weight is pinned rather than inheriting the shared base's 600. */
body.page-trip-picker .site-title {
  font-family: "Berkshire Swash", cursive;
  font-weight: 400;
  color: #e3c17a;
}
body.page-trip-picker .site-title::after {
  content: none;
}
/* Only reachable via the empty-trips fallback now (see renderTripPicker()
   in app.js) -- the normal path puts "Happily Ever After" directly into
   .site-title above instead of using this as a separate tagline over
   "Our Trips". Kept for that fallback rather than removed. */
.trip-picker-tagline {
  margin: 28px 0 0;
  font-family: "Berkshire Swash", cursive;
  font-weight: 400;
  font-size: 24px;
  text-align: center;
  letter-spacing: 0.01em;
  color: #e3c17a;
}
/* Style Guide button: gold outline + gold text to match "Happily Ever
   After" above, on a dark fill so the gold stays legible (the same
   light-gold-on-white problem that made .dates hard to read otherwise). */
body.page-trip-picker .food-links .pill {
  background: #0b1b3a;
  border-color: #e3c17a;
  color: #e3c17a;
}
body.page-trip-picker .food-links .pill:hover {
  border-color: #f4c430;
  color: #f4c430;
}
/* Countdown badge -- a numeric "N days" trip gets a glowing circle pinned
   to the card's top-right corner; a trip with no numeric day count
   (happening now, already over, no days added yet) falls back to
   .trip-picker-countdown's plain caption text instead (unchanged from
   before this pass), set by renderTripPicker() in app.js. Ring color is
   white/var(--surface), not var(--page) -- the badge sits mostly over the
   card's white background, not the navy page behind it. */
.trip-picker-badge {
  position: absolute;
  top: -12px;
  right: 14px;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fff6da, #f4c430 70%);
  box-shadow:
    0 0 14px rgba(244, 196, 48, 0.75),
    0 0 0 3px var(--surface);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.trip-picker-badge-num {
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 800;
  color: #4a2f06;
  line-height: 1;
}
.trip-picker-badge-label {
  font-family: var(--font-body);
  font-size: 8px;
  font-weight: 800;
  color: #4a2f06;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ==========================================================================
   2b. ITINERARY PAGE (static, non-interactive timeline)
   ========================================================================== */
.itinerary-shell {
  max-width: 640px;
  margin: 0 auto;
  padding: 24px 20px 56px;
}
.back-link {
  display: inline-block;
  margin-bottom: 16px;
  color: var(--brand);
  text-decoration: none;
  font-weight: 700;
  font-size: 14.5px;
}
.back-link:hover {
  text-decoration: underline;
}
.itinerary-head {
  text-align: center;
  padding: 26px 18px 22px;
  border-radius: var(--radius);
  background: linear-gradient(160deg, var(--hero-from), var(--hero-to));
  color: #fff;
  border-bottom: 4px solid var(--accent);
  box-shadow: var(--shadow);
  margin-bottom: 8px;
}
.itinerary-head h1 {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(26px, 5vw, 36px);
  letter-spacing: -0.01em;
  line-height: 1.1;
}
.itinerary-head p {
  margin: 0;
  color: rgba(255, 255, 255, 0.85);
  font-size: 15px;
}
.schedule-link {
  text-align: center;
  margin: 14px 0 0;
}
.schedule-link a {
  color: rgba(255, 255, 255, 0.95);
  font-weight: 700;
  font-size: 13.5px;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--accent);
}
.schedule-link a:hover {
  color: #fff;
}

.timeline {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 26px 0;
  padding-left: 22px;
  border-left: 2px solid var(--card-line, var(--line));
}
.timeline-event {
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 12px;
  padding: 13px 16px;
  background: var(--surface);
  border: 1.5px solid var(--card-line, var(--line));
  border-radius: var(--radius);
  box-shadow: 0 3px 10px rgba(20, 40, 80, 0.05);
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.timeline-event:hover {
  border-color: var(--brand);
  box-shadow: var(--shadow);
}
.timeline-node {
  position: absolute;
  left: -29px;
  top: 20px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--brand);
  border: 2px solid var(--page);
  box-shadow: 0 0 0 2px var(--card-line, var(--line));
}
.event-copy {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.event-copy h2 {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16.5px;
  font-weight: 700;
  line-height: 1.3;
}
.event-copy h2 a {
  color: var(--brand);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--brand) 35%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s ease;
}
.event-copy h2 a:hover {
  text-decoration-color: var(--brand);
}
.time-pill {
  align-self: flex-start;
  font-family: var(--font-detail);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.05em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--line-subtle);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 2px 9px;
  white-space: nowrap;
}

/* Category tinting — quiet, node + pill only */
.timeline-event--hours .timeline-node {
  background: var(--accent);
}
.timeline-event--hours .time-pill {
  border-color: var(--accent);
}
.timeline-event--dining .timeline-node {
  background: #178a4c;
}
.timeline-event--fireworks .timeline-node,
.timeline-event--event .timeline-node {
  background: var(--hero-to);
}

.page-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}
.itinerary-food-action {
  margin-top: 18px;
}
/* A plain --surface fill blended into the page on themes where --surface
   sits close to --page (most itinerary pages) -- tinted with the active
   theme's own --brand instead, so it stays "light" while still standing
   apart from the page behind it, on every theme automatically. */
.action-link {
  background: color-mix(in srgb, var(--brand) 10%, var(--surface));
  border: 1.5px solid
    color-mix(in srgb, var(--brand) 35%, var(--card-line, var(--line)));
  color: var(--brand);
}
.action-link:hover {
  background: color-mix(in srgb, var(--brand) 16%, var(--surface));
  border-color: var(--brand);
  box-shadow: var(--shadow);
  transform: translateY(-1px);
}

/* ==========================================================================
   3. SCOPED PARK THEMES
   ========================================================================== */

/* --- Home-page card accents ------------------------------------------- */
.park-disneyland {
  --card-line: #ecc9a3;
  --card-ink: #a5271d;
}
.park-california-adventure {
  --card-line: #f3c98b;
  --card-ink: #c2571f;
}
/* Dark slate gray (not green) -- EPCOT's home-page card color previously
   read too close to Animal Kingdom's olive green (below) to tell the two
   apart at a glance. Themed to Spaceship Earth's brushed-metal geosphere
   and the entry plaza's concrete instead: a cool, slightly blue-leaning
   charcoal against a light steel-gray line/border, both distinct from
   every other park's hue family here. Scoped to home-page cards only
   (pills/day-cards/timeline nodes) -- body.park-epcot's own itinerary/food
   page theme below keeps its green palette untouched. */
.park-epcot {
  --card-line: #cbd3d6;
  --card-ink: #3c4a52;
}
.park-magic-kingdom {
  --card-line: #d3c3e8;
  --card-ink: #5b3a9b;
}
.park-hollywood-studios {
  --card-line: #b9cbe8;
  --card-ink: #1f4e9c;
}
.park-animal-kingdom {
  --card-line: #cdd6ae;
  --card-ink: #4d6b1f;
}
.park-travel {
  --card-line: #b9d4e8;
  --card-ink: #14649c;
}
/* Oogie Boogie Bash (California Adventure's Halloween overlay event) --
   the only entry here that isn't a park itself, so it didn't get one of
   these when v21 introduced this section; it fell back to inheriting a
   stray bleed from the full page-reskin selector instead (see that
   theme's section 4 below for the bug this caused). --card-ink reuses
   this theme's own light-mode --brand (#b8481a, from its .page-food
   palette below) rather than the neon #f97316 used on its dark
   itinerary page -- that neon orange has poor contrast on the white
   trip-home cards (~2.8:1), which is exactly why the theme's own food
   page already carries a separate, darker "orange for light
   backgrounds" color. --card-line reuses that same palette's --line. */
.theme-oogie-boogie-bash {
  --card-line: #ecdcc4;
  --card-ink: #b8481a;
}

/* --- Disneyland: 1950s Main Street marquee ------------------------ */
body.park-disneyland {
  --page: #faf4e6; /* Cream ticket stock */
  --surface: #fffdf7;
  --ink: #33241a; /* Warm sepia ink */
  --muted: #7a6a58;
  --brand: #a5271d; /* Ticket-booth red */
  --brand-hover: #832015;
  --accent: #c8871a; /* Marquee gold */
  --line: #e5d5b8;
  --line-subtle: #efe5d0;
  --card-line: #e5d5b8;
  --card-ink: var(--brand);
  --hero-from: #121a2e; /* Midnight over Main Street */
  --hero-to: #23304e;
  --radius: 12px;
  --shadow: 0 5px 16px rgba(60, 40, 20, 0.1);
  --shadow-hover: 0 10px 26px rgba(60, 40, 20, 0.16);
  --font-display: "Limelight", cursive;
  --font-body: "DM Sans", sans-serif;
  --font-detail: "Special Elite", cursive;
  background:
    /* faint halftone paper grain */
    radial-gradient(rgba(165, 39, 29, 0.035) 1px, transparent 1px), var(--page);
  background-size:
    22px 22px,
    auto;
  font-family: var(--font-body);
}

body.park-disneyland .food-hero,
body.park-disneyland .itinerary-head {
  background: linear-gradient(170deg, var(--hero-from), var(--hero-to));
  border-bottom: none;
  /* Marquee double rule: gold over red */
  box-shadow:
    inset 0 -4px 0 var(--brand),
    inset 0 -7px 0 var(--hero-from),
    inset 0 -10px 0 var(--accent),
    var(--shadow);
  padding-bottom: 32px;
}
body.park-disneyland .food-hero h1,
body.park-disneyland .itinerary-head h1,
body.park-disneyland .restaurant-name,
body.park-disneyland .site-title,
body.park-disneyland .section-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.02em;
}
body.park-disneyland .food-hero h1,
body.park-disneyland .itinerary-head h1 {
  color: #f3d69a; /* Incandescent gold lettering */
  text-shadow:
    0 1px 0 #7c5c19,
    0 0 22px rgba(243, 214, 154, 0.35);
  font-size: clamp(34px, 7vw, 56px);
}
body.park-disneyland .restaurant-name {
  color: var(--brand);
}
body.park-disneyland .location-divider {
  font-family: var(--font-detail);
  font-weight: 400;
  font-size: 15px;
  letter-spacing: 0.14em;
  color: var(--brand);
}
body.park-disneyland .location-divider::before,
body.park-disneyland .location-divider::after {
  height: 1px;
  background: var(--accent);
  box-shadow: 0 3px 0 var(--accent);
}
body.park-disneyland .food-hero p,
body.park-disneyland .itinerary-head p,
body.park-disneyland .category-title,
body.park-disneyland .food-footer,
body.park-disneyland .time-pill,
body.park-disneyland .dates,
body.park-disneyland .day-card .date {
  font-family: var(--font-detail);
  font-weight: 400;
}
body.park-disneyland .food-hero p,
body.park-disneyland .itinerary-head p {
  color: #cbb98f;
}
body.park-disneyland .schedule-link a {
  color: #f3d69a;
  text-decoration-color: var(--accent);
}

.hero-graphics-row {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 8px auto 12px;
}
body.park-disneyland .castle-png {
  height: 240px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  filter: drop-shadow(0 8px 20px rgba(0, 0, 0, 0.45));
  transition: transform 0.2s ease;
}

body.park-disneyland .restaurant-card,
body.park-disneyland .timeline-event {
  border-radius: var(--radius);
  border: 1.5px solid var(--line);
  box-shadow: var(--shadow);
}
body.park-disneyland .restaurant-card:hover,
body.park-disneyland .timeline-event:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-hover);
}
body.park-disneyland .timeline {
  border-left-color: var(--accent);
}
body.park-disneyland .timeline-node {
  /* Marquee bulb */
  background: var(--accent);
  border-color: var(--page);
  box-shadow:
    0 0 0 2px var(--accent),
    0 0 8px rgba(200, 135, 26, 0.55);
}
body.park-disneyland .time-pill {
  background: #f6ecd7;
  border-color: var(--accent);
  color: #6c4b12;
  border-radius: 4px;
}
body.park-disneyland .chevron {
  background: #f6ecd7;
  color: var(--brand);
}
body.park-disneyland .restaurant-card.open .chevron {
  background: var(--brand);
  color: #fffdf7;
}
body.park-disneyland .category-badge {
  /* Warmed to match the ticket-stock cream/red/gold family used everywhere
     else on this theme (time-pill, chevron) -- was a stray cool blue. */
  background: #f6ecd7;
  color: #a5271d;
  border: 1px solid rgba(200, 135, 26, 0.4);
  border-radius: 4px;
}
body.park-disneyland .search-input:focus {
  box-shadow: 0 0 0 3px rgba(165, 39, 29, 0.14);
}
body.park-disneyland .food-toolbar {
  background: rgba(250, 244, 230, 0.94);
  border-bottom-color: var(--line);
}

/* Food mode: Carnation Plaza Daylight -- same ticket-stock cream/red/gold
   identity, moved from the marquee's midnight hero to a golden-hour sky,
   evoking Main Street's confectionery side (Gibson Girl, Jolly Holiday)
   rather than its marquee-at-night side. */
body.park-disneyland.page-food {
  --hero-from: #4f7fae;
  --hero-to: #e7a13c;
}
body.park-disneyland.page-food .food-hero h1 {
  color: #fff8ea;
  text-shadow:
    0 1px 0 rgba(124, 92, 25, 0.6),
    0 0 18px rgba(255, 248, 234, 0.35);
}
body.park-disneyland.page-food .food-hero p {
  color: #fdefd2;
}
/* Text-role differentiation: .restaurant-name had no page-food color
   override, so it fell back to body.park-disneyland .restaurant-name's
   color: var(--brand) -- the exact same variable .item-name always uses,
   making the two literally identical. Given its own warm sepia here (ink
   blended with this theme's marquee-gold accent) instead. category-title
   moves from a muddy computed accent/ink mix to a genuinely vivid marquee
   gold; item-desc cools toward grey. item-name/--brand is untouched. */
body.park-disneyland.page-food .restaurant-name {
  font-family: "Pacifico", cursive;
  font-weight: 400;
  letter-spacing: 0;
  color: #513a1a;
}
body.park-disneyland.page-food .category-title {
  color: #9b691a;
  border-color: #9b691a;
}
body.park-disneyland.page-food .item-desc {
  color: #6d6151;
}
body.park-disneyland.page-food .location-divider::before,
body.park-disneyland.page-food .location-divider::after {
  height: 4px;
  background: repeating-linear-gradient(
    45deg,
    var(--brand) 0 6px,
    var(--page) 6px 12px
  );
  box-shadow: none;
  border-radius: 999px;
}
/* This food mode's --hero-from (#4f7fae, golden-hour sky blue) only just
   misses readable contrast against white text (~4.15:1, short of ~4.5:1) --
   falls back to --brand (this park's own ticket-booth red, already used at
   full saturation elsewhere on the page) instead, same reasoning as Magic
   Kingdom's override above. Found via an actual computed-contrast check
   across every food-page theme, not by eye. */
body.park-disneyland.page-food
  .category-filter-wrap
  .filter-btn.category-toggle-btn.has-hidden {
  background: var(--brand);
  border-color: var(--brand);
}

/* --- California Adventure: Pixar sunset -------------------------- */
body.park-california-adventure {
  --page: #fff6ec;
  --surface: #fffdf9;
  --ink: #3a2417;
  --muted: #8a6a55;
  --brand: #c2571f; /* Sunset ember */
  --brand-hover: #9e4517;
  --accent: #f0a02e; /* Pier gold */
  --line: #f0dcc4;
  --line-subtle: #f7ead9;
  --card-line: #f0dcc4;
  --card-ink: var(--brand);
  --hero-from: #7c2d4e; /* Dusk plum */
  --hero-to: #d96b2f; /* Sunset orange */
  --radius: 16px;
  --shadow: 0 5px 16px rgba(120, 60, 20, 0.1);
  --shadow-hover: 0 10px 26px rgba(120, 60, 20, 0.16);
  --font-display: "Fredoka", sans-serif;
  --font-body: "DM Sans", sans-serif;
  background: var(--page);
  font-family: var(--font-body);
}
body.park-california-adventure .food-hero,
body.park-california-adventure .itinerary-head {
  background: linear-gradient(165deg, var(--hero-from), var(--hero-to));
  border-bottom: 4px solid var(--accent);
}
body.park-california-adventure .timeline {
  border-left-color: var(--accent);
}
body.park-california-adventure .timeline-node {
  background: var(--accent);
}
body.park-california-adventure .time-pill {
  background: #fdeed7;
  border-color: var(--accent);
  color: #8a5510;
}
body.park-california-adventure .category-badge {
  background: #fdeed7;
  color: #8a5510;
  border-color: #f0dcc4;
}
body.park-california-adventure .search-input:focus {
  box-shadow: 0 0 0 3px rgba(194, 87, 31, 0.15);
}
body.park-california-adventure .food-toolbar {
  background: rgba(255, 246, 236, 0.94);
}

/* Itinerary mode: Pixar Pier at Dusk -- keeps the existing sunset gradient
   as-is, adds the one motif this theme was missing: the timeline becomes a
   light string, its node a warm glow bulb instead of a flat dot. */
body.park-california-adventure.page-itinerary .timeline {
  border-left: 2px dashed var(--line);
}
body.park-california-adventure.page-itinerary .timeline-node {
  width: 13px;
  height: 13px;
  background: radial-gradient(circle at 35% 30%, #fff6da, var(--accent) 70%);
  border: none;
  box-shadow: 0 0 8px rgba(240, 160, 46, 0.65);
}

/* Food mode: Pacific Wharf Market -- shifts from the Pier's dusk plum to a
   wharf-morning teal-into-cannery-orange, with a second accent (teal)
   borrowed from the cannery/coastal setting rather than the boardwalk. */
body.park-california-adventure.page-food {
  --accent: #2f8f92;
  --hero-from: #2f6f78;
  --hero-to: #e2903a;
  /* Darkened from the base theme's #8a6a55 -- item descriptions in that
     lighter shade read as hard to read in focus-group feedback. */
  --muted: #6b4f3a;
}
body.park-california-adventure.page-food .item-desc {
  font-weight: 500;
}
/* Text-role differentiation: restaurant-name had no override, so it fell
   back to plain --ink -- not a bug (nothing collided), just an unclaimed
   color slot while category-title/item-name/item-desc already read as
   three distinct colors. Given this park's own dusk-plum (the itinerary
   hero's signature color -- hardcoded rather than var(--hero-from), since
   that token itself is repurposed to a teal in food mode and would clash
   with category-title's teal). */
body.park-california-adventure.page-food .restaurant-name {
  color: #7c2d4e;
}
body.park-california-adventure.page-food .category-badge {
  background: #e9f2f0;
  color: #215a5e;
  border: 1.5px solid #bcdcd9;
  border-radius: 3px;
  letter-spacing: 0.05em;
}
body.park-california-adventure.page-food .location-divider::before,
body.park-california-adventure.page-food .location-divider::after {
  height: 3px;
  background: linear-gradient(
    to right,
    transparent,
    #2f8f92 15%,
    #2f8f92 85%,
    transparent
  );
}
body.park-california-adventure.page-food .search-input:focus {
  box-shadow: 0 0 0 3px rgba(47, 143, 146, 0.18);
}

/* --- Walt Disney World parks: generic tokens-plus-component treatment --- */
/* Each park below gets the same shape of decorative pass DCA has (hero
   gradient, timeline, time-pill, category-badge, search focus ring,
   toolbar tint) driven entirely by its own tokens -- deliberately generic,
   not yet a signature look like .park-disneyland's marquee or
   .theme-oogie-boogie-bash's stitched-seam motif. Fine-tune per park as
   each is actually used. */
body.park-epcot {
  --page: #f2f8f4;
  --ink: #1c2b24;
  --muted: #5c7268;
  --brand: #1d6b4f;
  --brand-hover: #155238;
  --accent: #b08a2e;
  --line: #cfe2d6;
  --line-subtle: #e3efe8;
  --hero-from: #123c2d;
  --hero-to: #2e7d5f;
  --font-display: "Playfair Display", serif;
  background: var(--page);
}
body.park-epcot .food-hero,
body.park-epcot .itinerary-head {
  background: linear-gradient(165deg, var(--hero-from), var(--hero-to));
  border-bottom: 4px solid var(--accent);
}
body.park-epcot .timeline {
  border-left-color: var(--accent);
}
body.park-epcot .timeline-node {
  background: var(--accent);
}
body.park-epcot .time-pill {
  background: var(--line-subtle);
  border-color: var(--accent);
  color: var(--brand-hover);
}
body.park-epcot .category-badge {
  background: var(--line-subtle);
  color: var(--brand-hover);
  border-color: var(--line);
}
body.park-epcot .restaurant-name {
  color: var(--brand);
}
body.park-epcot .search-input:focus {
  box-shadow: 0 0 0 3px rgba(29, 107, 79, 0.15);
}
body.park-epcot .food-toolbar {
  background: rgba(242, 248, 244, 0.94);
}

body.park-magic-kingdom {
  --page: #f7f4fc;
  --ink: #261c3a;
  --muted: #6b5f85;
  --brand: #5b3a9b;
  --brand-hover: #472b7e;
  --accent: #c9962c;
  --line: #ded2f0;
  --line-subtle: #ece5f7;
  --hero-from: #2c1a55;
  --hero-to: #5b3a9b;
  background: var(--page);
}
body.park-magic-kingdom .food-hero,
body.park-magic-kingdom .itinerary-head {
  background: linear-gradient(165deg, var(--hero-from), var(--hero-to));
  border-bottom: 4px solid var(--accent);
}
body.park-magic-kingdom .timeline {
  border-left-color: var(--accent);
}
body.park-magic-kingdom .timeline-node {
  background: var(--accent);
}
body.park-magic-kingdom .time-pill {
  background: var(--line-subtle);
  border-color: var(--accent);
  color: var(--brand-hover);
}
body.park-magic-kingdom .category-badge {
  background: var(--line-subtle);
  color: var(--brand-hover);
  border-color: var(--line);
}
body.park-magic-kingdom .search-input:focus {
  box-shadow: 0 0 0 3px rgba(91, 58, 155, 0.15);
}
body.park-magic-kingdom .food-toolbar {
  background: rgba(247, 244, 252, 0.94);
}

body.park-hollywood-studios {
  --page: #f0f4fa;
  --ink: #141d2e;
  --muted: #55627a;
  --brand: #1f4e9c;
  --brand-hover: #173c79;
  --accent: #2ec4d6;
  --line: #cddaee;
  --line-subtle: #e2eaf5;
  --hero-from: #0c1930;
  --hero-to: #1f4e9c;
  --font-display: "Orbitron", sans-serif;
  background: var(--page);
}
body.park-hollywood-studios .food-hero,
body.park-hollywood-studios .itinerary-head {
  background: linear-gradient(165deg, var(--hero-from), var(--hero-to));
  border-bottom: 4px solid var(--accent);
}
body.park-hollywood-studios .timeline {
  border-left-color: var(--accent);
}
body.park-hollywood-studios .timeline-node {
  background: var(--accent);
}
body.park-hollywood-studios .time-pill {
  background: var(--line-subtle);
  border-color: var(--accent);
  color: var(--brand-hover);
}
body.park-hollywood-studios .category-badge {
  background: var(--line-subtle);
  color: var(--brand-hover);
  border-color: var(--line);
}
body.park-hollywood-studios .search-input:focus {
  box-shadow: 0 0 0 3px rgba(31, 78, 156, 0.15);
}
body.park-hollywood-studios .food-toolbar {
  background: rgba(240, 244, 250, 0.94);
}

body.park-animal-kingdom {
  --page: #f6f6ec;
  --ink: #26301a;
  --muted: #6b7355;
  --brand: #4d6b1f;
  --brand-hover: #3a5216;
  --accent: #c1701f;
  --line: #dcdfc2;
  --line-subtle: #ebedd9;
  --hero-from: #26330f;
  --hero-to: #56732a;
  background: var(--page);
}
body.park-animal-kingdom .food-hero,
body.park-animal-kingdom .itinerary-head {
  background: linear-gradient(165deg, var(--hero-from), var(--hero-to));
  border-bottom: 4px solid var(--accent);
}
body.park-animal-kingdom .timeline {
  border-left-color: var(--accent);
}
body.park-animal-kingdom .timeline-node {
  background: var(--accent);
}
body.park-animal-kingdom .time-pill {
  background: var(--line-subtle);
  border-color: var(--accent);
  color: var(--brand-hover);
}
body.park-animal-kingdom .category-badge {
  background: var(--line-subtle);
  color: var(--brand-hover);
  border-color: var(--line);
}
body.park-animal-kingdom .search-input:focus {
  box-shadow: 0 0 0 3px rgba(77, 107, 31, 0.15);
}
body.park-animal-kingdom .food-toolbar {
  background: rgba(246, 246, 236, 0.94);
}

body.park-travel {
  --page: #f0f6fa;
  --ink: #12283a;
  --muted: #567285;
  --brand: #14649c;
  --brand-hover: #0f4d78;
  --accent: #e8a512;
  --line: #cde0ee;
  --line-subtle: #e2eef6;
  --hero-from: #0d3a5e;
  --hero-to: #2a7db4;
  background: var(--page);
}
body.park-travel .food-hero,
body.park-travel .itinerary-head {
  background: linear-gradient(165deg, var(--hero-from), var(--hero-to));
  border-bottom: 4px solid var(--accent);
}
body.park-travel .timeline {
  border-left-color: var(--accent);
}
body.park-travel .timeline-node {
  background: var(--accent);
}
body.park-travel .time-pill {
  background: var(--line-subtle);
  border-color: var(--accent);
  color: var(--brand-hover);
}
body.park-travel .category-badge {
  background: var(--line-subtle);
  color: var(--brand-hover);
  border-color: var(--line);
}
body.park-travel .search-input:focus {
  box-shadow: 0 0 0 3px rgba(20, 100, 156, 0.15);
}
body.park-travel .food-toolbar {
  background: rgba(240, 246, 250, 0.94);
}

/* ==========================================================================
   3b. WDW PARK PAGE-MODE FORKS -- ITINERARY VS. FOOD & WINE
   --------------------------------------------------------------------------
   Each park keeps its shared identity (brand hue, icon, instant
   recognizability) on body.park-X above, then forks the hero mood,
   headline face, and one signature motif depending on which body class
   app.js adds alongside it: .page-itinerary (itinerary.html) or
   .page-food (food.html). See app.js's two setTheme() call sites.
   ========================================================================== */

/* --- Magic Kingdom: Castle at Dusk vs. Main Street Bakery --------------- */
body.park-magic-kingdom.page-itinerary {
  --hero-from: #190f30;
  --hero-to: #3d2569;
  --font-display: "Cormorant Garamond", serif;
}
body.park-magic-kingdom.page-itinerary .itinerary-head {
  border-bottom: none;
  padding-bottom: 34px;
  position: relative;
}
body.park-magic-kingdom.page-itinerary .itinerary-head::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 12px;
  background-image:
    linear-gradient(135deg, var(--accent) 25%, transparent 25%),
    linear-gradient(225deg, var(--accent) 25%, transparent 25%);
  background-position:
    0 0,
    9px 0;
  background-size: 18px 12px;
  background-repeat: repeat-x;
  opacity: 0.9;
}
body.park-magic-kingdom.page-itinerary .timeline-node {
  background: var(--accent);
  clip-path: polygon(
    50% 0%,
    61% 35%,
    98% 35%,
    68% 57%,
    79% 91%,
    50% 70%,
    21% 91%,
    32% 57%,
    2% 35%,
    39% 35%
  );
  border-radius: 0;
  border: none;
  box-shadow: 0 0 6px rgba(201, 150, 44, 0.6);
}

body.park-magic-kingdom.page-food {
  --page: #fdf6f0;
  --ink: #3a2a1a;
  --muted: #8a7358;
  --hero-from: #f3d9e6;
  --hero-to: #fdf6f0;
  --line: #f0d9c8;
  --line-subtle: #fbe9d8;
  --font-display: "Berkshire Swash", cursive;
}
body.park-magic-kingdom.page-food .food-hero {
  color: #5b3a1f;
  border-bottom: none;
  padding-bottom: 34px;
  position: relative;
}
body.park-magic-kingdom.page-food .food-hero p {
  opacity: 0.75;
}
/* Berkshire Swash is single-weight (Google only ships it at 400) -- this
   selector had no override at all, so it was inheriting the shared base
   .food-hero h1's 600, the same fake-bold issue already pinned around it
   on .restaurant-name below. */
body.park-magic-kingdom.page-food .food-hero h1 {
  font-weight: 400;
}
body.park-magic-kingdom.page-food .food-hero::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 12px;
  background-image: radial-gradient(
    circle at 8px -4px,
    transparent 8px,
    #d94f79 9px
  );
  background-size: 16px 12px;
  background-repeat: repeat-x;
}
/* Berkshire Swash is single-weight (Google only ships it at 400), so pin
   font-weight here rather than inherit the shared base's 700 -- that would
   just fake-bold it, which reads blurrier, not bolder. */
body.park-magic-kingdom.page-food .restaurant-name {
  color: #a13d63;
  font-weight: 400;
}
body.park-magic-kingdom.page-food .category-badge {
  background: #fbe4ec;
  color: #a13d63;
  border-color: #f3c9d9;
  border-radius: 14px;
}
body.park-magic-kingdom.page-food .search-input:focus {
  box-shadow: 0 0 0 3px rgba(217, 79, 121, 0.16);
}
/* This food mode's --hero-from/--hero-to (#f3d9e6 -> #fdf6f0, a "castle in
   daylight" pastel pink-into-cream) is the one hero gradient on the site
   with neither stop dark enough to hold white text -- both come in under
   1.5:1 contrast, nowhere near the ~4.5:1 the rest of the .has-hidden rule
   assumes. Falls back to --brand (this park's own marquee purple, already
   used at full saturation everywhere else on the page) instead of a new
   hardcoded color -- still "a color from the page's own palette," just not
   literally off the hero gradient like every other park manages. Found via
   an actual computed-contrast check across every food-page theme, not by
   eye -- see the base .has-hidden rule's comment above for the general
   rule this overrides. */
body.park-magic-kingdom.page-food
  .category-filter-wrap
  .filter-btn.category-toggle-btn.has-hidden {
  background: var(--brand);
  border-color: var(--brand);
}

/* --- EPCOT: Spaceship Earth vs. World Showcase Passport ------------------
   Itinerary mode reuses Hollywood Studios' navy/cyan retro-space palette --
   it reads closer to EPCOT's own retro-futurism than the everyday green
   EPCOT hero, and previously the itinerary hero was easy to mistake for the
   food guide's hero since both leaned on the same green tokens. */
body.park-epcot.page-itinerary {
  --page: #f0f4fa;
  --ink: #141d2e;
  --muted: #55627a;
  --brand: #1f4e9c;
  --brand-hover: #173c79;
  --accent: #2ec4d6;
  --line: #cddaee;
  --line-subtle: #e2eaf5;
  --hero-from: #0c1930;
  --hero-to: #1f4e9c;
  --font-display: "Orbitron", sans-serif;
}
body.park-epcot.page-itinerary .itinerary-head {
  border-bottom: none;
  padding-bottom: 32px;
  position: relative;
}
body.park-epcot.page-itinerary .itinerary-head::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 10px;
  background-image:
    linear-gradient(
      135deg,
      var(--accent) 25%,
      transparent 25%,
      transparent 75%,
      var(--brand) 75%
    ),
    linear-gradient(
      45deg,
      var(--accent) 25%,
      transparent 25%,
      transparent 75%,
      var(--brand) 75%
    );
  background-position:
    0 0,
    7px 0;
  background-size: 14px 10px;
  background-repeat: repeat-x;
  opacity: 0.85;
}
body.park-epcot.page-itinerary .timeline-node {
  border-radius: 2px;
  transform: rotate(45deg);
}

body.park-epcot.page-food {
  --page: #faf6ec;
  --ink: #332711;
  --muted: #8a7a58;
  --accent: #c2571f;
  --line: #e6dcc2;
  --line-subtle: #f3e6cc;
}
body.park-epcot.page-food .food-hero {
  border-bottom: 3px dashed var(--accent);
}
/* Text-role differentiation: .restaurant-name had no page-food override, so
   it fell back to body.park-epcot .restaurant-name's color: var(--brand) --
   the exact same variable .item-name always uses, making the two literally
   identical. Given its own warm umber here (ink blended with this theme's
   rust accent) instead. category-title moves from a muddy computed accent/
   ink mix to a genuinely vivid burnt orange; item-desc cools toward grey so
   it reads as supporting copy rather than a third brown. item-name/--brand
   is untouched. */
body.park-epcot.page-food .restaurant-name {
  color: #503114;
}
body.park-epcot.page-food .category-title {
  color: #a54d1c;
  border-color: #a54d1c;
}
body.park-epcot.page-food .item-desc {
  color: #7a6f5e;
}
body.park-epcot.page-food .category-badge {
  border-radius: 999px;
  border-style: dotted;
  border-width: 1.5px;
}
body.park-epcot.page-food .search-input:focus {
  box-shadow: 0 0 0 3px rgba(194, 87, 31, 0.15);
}

/* --- Hollywood Studios: Slinky Dog Skyway vs. Brown Derby Glamour --------
   Itinerary mode is a new Toy Story-inspired look: a daytime toy-box blue
   instead of a night hero, a scattered-cloud page texture, a candy-twist
   "coil" rule under the header nodding at Slinky Dog without needing a
   raster image (no image asset added here -- see project rule against
   adding icon/image assets without being asked), and toy-block timeline
   nodes cycling red/blue/yellow per event via :nth-of-type. */
body.park-hollywood-studios.page-itinerary {
  --page: #cfe9fb;
  --ink: #1f3a52;
  --muted: #4d7392;
  --brand: #d64536;
  --brand-hover: #b93a2d;
  --accent: #3f7fc4;
  --line: #a9d4ec;
  --line-subtle: #dff0fb;
  --hero-from: #7fc3ea;
  --hero-to: #cdeaf9;
  --font-display: "Baloo 2", cursive;
  background-image:
    radial-gradient(
      circle at 15% 20%,
      rgba(255, 255, 255, 0.9) 0 26px,
      transparent 27px
    ),
    radial-gradient(
      circle at 32% 12%,
      rgba(255, 255, 255, 0.9) 0 18px,
      transparent 19px
    ),
    radial-gradient(
      circle at 78% 32%,
      rgba(255, 255, 255, 0.85) 0 30px,
      transparent 31px
    ),
    radial-gradient(
      circle at 60% 8%,
      rgba(255, 255, 255, 0.85) 0 16px,
      transparent 17px
    ),
    radial-gradient(
      circle at 92% 62%,
      rgba(255, 255, 255, 0.8) 0 22px,
      transparent 23px
    ),
    radial-gradient(
      circle at 8% 68%,
      rgba(255, 255, 255, 0.8) 0 20px,
      transparent 21px
    );
  background-size: 280px 240px;
}
body.park-hollywood-studios.page-itinerary .itinerary-head {
  border-bottom: none;
  padding-bottom: 34px;
  position: relative;
  color: #1f3a52;
}
body.park-hollywood-studios.page-itinerary .itinerary-head p {
  color: #35577a;
}
body.park-hollywood-studios.page-itinerary .itinerary-head::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 10px;
  background-image: repeating-linear-gradient(
    45deg,
    var(--brand) 0 8px,
    #f4f9fd 8px 16px,
    var(--accent) 16px 24px,
    #f4f9fd 24px 32px
  );
  opacity: 0.9;
}
body.park-hollywood-studios.page-itinerary .schedule-link a {
  color: #1f3a52;
  text-decoration-color: var(--brand);
}
body.park-hollywood-studios.page-itinerary .schedule-link a:hover {
  color: #0f2233;
}
body.park-hollywood-studios.page-itinerary .timeline {
  border-left-style: dashed;
}
body.park-hollywood-studios.page-itinerary .timeline-node {
  width: 15px;
  height: 15px;
  left: -31px;
  top: 17px;
  border: none;
  border-radius: 3px;
  box-shadow:
    inset -2px -2px 0 rgba(0, 0, 0, 0.2),
    inset 2px 2px 0 rgba(255, 255, 255, 0.4),
    0 2px 4px rgba(20, 40, 60, 0.25);
}
body.park-hollywood-studios.page-itinerary
  .timeline-event:nth-of-type(3n + 1)
  .timeline-node {
  background: #d64536;
}
body.park-hollywood-studios.page-itinerary
  .timeline-event:nth-of-type(3n + 2)
  .timeline-node {
  background: #3f7fc4;
}
body.park-hollywood-studios.page-itinerary
  .timeline-event:nth-of-type(3n)
  .timeline-node {
  background: #ffcc33;
}

body.park-hollywood-studios.page-food {
  --page: #f7f0e4;
  --ink: #241a12;
  --muted: #8a7458;
  --accent: #b8860b;
  --hero-from: #4a1620;
  --hero-to: #8a4a1f;
  --line: #e6d6bd;
  --line-subtle: #f2e6ce;
  /* Was Poiret One -- too thin/small to read even at 700 (browser can only
     fake-bold a font Google only ships at weight 400). Limelight is a real
     single-weight marquee face already loaded site-wide (Disneyland's
     itinerary/site-title font), so it reads bold without faux-bold blur. */
  --font-display: "Limelight", cursive;
}
body.park-hollywood-studios.page-food .food-hero {
  position: relative;
  overflow: hidden;
}
body.park-hollywood-studios.page-food .food-hero::before {
  content: "";
  position: absolute;
  top: -40%;
  left: 50%;
  width: 220px;
  height: 220px;
  transform: translateX(-50%);
  background: radial-gradient(
    circle,
    rgba(255, 224, 168, 0.35),
    transparent 70%
  );
  pointer-events: none;
}
/* Color-only fix, unrelated to the font swap above: --brand stays this
   theme's itinerary navy even in food mode (never overridden here), which
   read as an arbitrary, mismatched color on a brass/burgundy card --
   swapped for the hero's own warm brass-brown endpoint instead, so it ties
   back into the food mode's actual palette. Limelight is single-weight, so
   font-weight stays 400 here (matches Disneyland's use of the same font)
   rather than inheriting the shared base's 700, which would just fake-bold
   it. */
body.park-hollywood-studios.page-food .restaurant-name {
  color: #8a4a1f;
  font-weight: 400;
}
body.park-hollywood-studios.page-food .food-hero h1 {
  font-weight: 400;
  letter-spacing: 0.02em;
}
body.park-hollywood-studios.page-food .category-badge {
  border-radius: 2px;
  display: inline-block;
}
/* Text-role differentiation pass: restaurant-name (brass, above), category-
   title, and item-desc were all landing as near-identical mid-tone browns
   (category-title's computed accent/ink mix, item-desc's plain --muted) --
   only item-name's inherited --brand blue read as its own color. category-
   title moves to a true crimson-burgundy (blended from this theme's own
   hero-from maroon + accent gold, not a new hue for the theme) so it reads
   as its own tag rather than a duller echo of restaurant-name; item-desc
   cools toward grey so it recedes as supporting copy instead of competing
   as a fourth brown. item-name/--brand and item-price are untouched. */
body.park-hollywood-studios.page-food .category-title {
  color: #a3273f;
  border-color: #a3273f;
}
body.park-hollywood-studios.page-food .item-desc {
  color: #75695c;
}
body.park-hollywood-studios.page-food .search-input:focus {
  box-shadow: 0 0 0 3px rgba(184, 134, 11, 0.18);
}

/* --- Animal Kingdom: Tree of Life Trail vs. Harambe Market --------------- */
body.park-animal-kingdom.page-itinerary {
  --font-display: "Cabin Sketch", cursive;
}
body.park-animal-kingdom.page-itinerary .itinerary-head {
  border-bottom: none;
  padding-bottom: 32px;
  position: relative;
}
body.park-animal-kingdom.page-itinerary .itinerary-head::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 12px;
  background-image: radial-gradient(
    circle at 8px -5px,
    transparent 8px,
    var(--accent) 9px
  );
  background-size: 16px 12px;
  background-repeat: repeat-x;
  opacity: 0.75;
}

body.park-animal-kingdom.page-food {
  --page: #faf3e6;
  --ink: #2e2410;
  --muted: #8a7455;
  --hero-from: #5c2f12;
  --hero-to: #b3701f;
  --line: #e8d9bd;
  --line-subtle: #f3e6cc;
  --accent: #4d6b1f;
  /* Food mode had no --font-display override, so it fell back to the
     global default (Fredoka) -- the same font California Adventure uses.
     First tried reusing Cabin Sketch (this park's own itinerary-mode
     font), but its hand-drawn double-stroke style read as washed-out/
     light-grey at 22px on a phone even at a very dark hex value -- a
     rendering issue, not a color one. Baloo 2 is a solid, chunky,
     no-hairline face (already loaded, used today only by Hollywood
     Studios' itinerary mode) that keeps AK's restaurant-name off both
     Fredoka (California Adventure) and Cabin Sketch (this park's own
     itinerary mode) without the sketch font's legibility problem. */
  --font-display: "Baloo 2", cursive;
}
body.park-animal-kingdom.page-food .restaurant-card {
  border-top: 4px solid transparent;
  border-image: repeating-linear-gradient(45deg, #c1701f 0 4px, #f3e6cc 4px 8px)
    4;
}
/* Text-role differentiation: --accent and --brand both resolve to the same
   green (#4d6b1f) in food mode, so category-title's computed accent/ink mix
   landed only a few RGB steps from item-name's plain --brand -- both read
   as "olive green." category-title moves onto this theme's own rust/amber
   hero gradient (already defined, previously unused for text) instead.
   item-desc cools toward grey. item-name/--brand is untouched.
   restaurant-name was first a rich dark umber (#372610), but per Kyle's
   phone review that measured-dark color still rendered washed-out/light
   in Cabin Sketch's hand-drawn double-stroke style -- moved to a vivid
   burnt orange instead (also matches Kyle's request for an animal-theme
   yellow/orange), distinct enough from category-title's more muted amber
   (#9f651d) to stay two different roles rather than two shades of the
   same thing. */
body.park-animal-kingdom.page-food .restaurant-name {
  color: #c2571f;
}
body.park-animal-kingdom.page-food .category-title {
  color: #9f651d;
  border-color: #9f651d;
}
body.park-animal-kingdom.page-food .item-desc {
  color: #7a6f5c;
}
body.park-animal-kingdom.page-food .category-badge {
  background: #f3e6cc;
  color: #7a4c12;
  border: none;
  border-left: 3px solid #c1701f;
  border-radius: 3px;
}
body.park-animal-kingdom.page-food .search-input:focus {
  box-shadow: 0 0 0 3px rgba(193, 112, 31, 0.16);
}

/* ==========================================================================
   3c. THEME: EPCOT FOOD & WINE FESTIVAL (STANDALONE, NOT park-epcot)
   --------------------------------------------------------------------------
   Deliberately its own theme rather than a page-mode fork of .park-epcot --
   a seasonal festival booth guide should read as an occasion, not a
   reskinned version of EPCOT's everyday dining guide. Wired in by giving
   the "epcot-festival" foodGuide a "theme": "theme-epcot-festival" instead
   of "park-epcot" (see resort-food-guides.js).
   ========================================================================== */
.theme-epcot-festival {
  --page: #f7f0e8;
  --surface: #ffffff;
  --ink: #2e1b22;
  --muted: #8a6a58;
  --brand: #5b2140;
  --brand-hover: #451831;
  --accent: #d4af37;
  --line: #e6d6c4;
  --line-subtle: #f2e2c9;
  --card-line: #e6d6c4;
  --card-ink: var(--brand);
  --hero-from: #3a1220;
  --hero-to: #6b2a44;
  --radius: 10px;
  --shadow: 0 5px 16px rgba(60, 20, 35, 0.12);
  --shadow-hover: 0 10px 26px rgba(60, 20, 35, 0.18);
  /* Was "Caveat", then "Fredericka the Great" -- settled on Bevan (option
     #8 of the "Festival Restaurant-Name Fonts" comparison), a bold slab
     serif with real poster presence. */
  --font-display: "Bevan", serif;
  background: var(--page);
}
.theme-epcot-festival .food-hero {
  border-bottom: none;
  padding-bottom: 32px;
  position: relative;
}
/* Bevan is single-weight (Google only ships it at 400) -- pinned rather
   than left at the shared base .food-hero h1's 600, and specifically not
   raised to 700, which would just fake-bold it. */
.theme-epcot-festival .food-hero h1 {
  font-weight: 400;
}
.theme-epcot-festival .food-hero::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 9px;
  background-image: radial-gradient(
    circle at 7px -3px,
    transparent 7px,
    var(--accent) 8px
  );
  background-size: 14px 9px;
  background-repeat: repeat-x;
  opacity: 0.85;
}
.theme-epcot-festival .restaurant-card {
  border-radius: var(--radius);
}
/* "Booth · " used to run inline before the name in a disliked small caps
   label -- removed in favor of .category-badge (already present, already
   themed below), the same tag component every other guide already uses
   for its service type (Table/Quick Service, Snack, Cart, Kiosk). */
/* Bevan is single-weight (Google only ships it at 400), so pin font-weight
   here rather than inherit the shared base's 700 -- that would just
   fake-bold it, which reads blurrier, not bolder. */
/* Text-role differentiation: restaurant-name was explicitly set to
   var(--brand) -- the exact same variable .item-name always uses, making
   the two literally identical. Given its own deep wine-black here (ink
   blended with --brand) instead. A second pass then pushed the remaining
   roles further: item-name gets its own more saturated wine/magenta
   (rather than plain --brand, which reads muddy/brownish at this
   saturation) and category-title moves off a muted olive-gold onto a
   fully-saturated marigold -- both explicitly sharpened past what --brand/
   --accent give at their default saturation, since the theme was reading
   as uniformly muted. item-desc cools toward grey. */
.theme-epcot-festival .restaurant-name {
  color: #371c28;
  font-weight: 400;
}
.theme-epcot-festival .item-name {
  color: #861350;
}
.theme-epcot-festival .category-title {
  color: #996800;
  border-color: #996800;
}
.theme-epcot-festival .item-desc {
  color: #7a6c5c;
}
.theme-epcot-festival .category-badge {
  background: var(--line-subtle);
  color: var(--brand);
  border-color: var(--accent);
  border-radius: 3px;
}
.theme-epcot-festival .search-input:focus {
  box-shadow: 0 0 0 3px rgba(91, 33, 64, 0.18);
}
.theme-epcot-festival .food-toolbar {
  background: rgba(247, 240, 232, 0.94);
}

/* ==========================================================================
   3d. THEME: EPCOT FLOWER & GARDEN FESTIVAL (STANDALONE, NOT park-epcot)
   --------------------------------------------------------------------------
   Same standalone-seasonal-guide pattern as 3c above (own theme, not a
   park-epcot fork) -- but its own identity: a spring garden palette (moss
   green + cherry-blossom pink) instead of Food & Wine's wine/gold, and
   Yeseva One (a single-weight, Google-only-ships-400 display serif, same
   pinning caution as Bevan above) instead of Bevan. Wired in by giving
   the "epcot-flower-garden" foodGuide a "theme": "theme-epcot-flower-garden"
   (see resort-food-guides.js). Issue #150.
   ========================================================================== */
.theme-epcot-flower-garden {
  --page: #fbf5f2;
  --surface: #ffffff;
  --ink: #2c3324;
  --muted: #7c8a6a;
  --brand: #a83b64;
  --brand-hover: #872c4f;
  --accent: #7a9c4a;
  --line: #ecdde3;
  --line-subtle: #f5e9ee;
  --card-line: #dce8cf;
  --card-ink: #3f6b34;
  --hero-from: #22381c;
  --hero-to: #5c8a41;
  --radius: 10px;
  --shadow: 0 5px 16px rgba(40, 60, 30, 0.12);
  --shadow-hover: 0 10px 26px rgba(40, 60, 30, 0.18);
  --font-display: "Yeseva One", serif;
  background: var(--page);
}
.theme-epcot-flower-garden .food-hero {
  border-bottom: none;
  padding-bottom: 32px;
  position: relative;
}
.theme-epcot-flower-garden .food-hero h1 {
  font-weight: 400;
}
.theme-epcot-flower-garden .food-hero::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 9px;
  background-image: radial-gradient(
    circle at 7px -3px,
    transparent 7px,
    var(--accent) 8px
  );
  background-size: 14px 9px;
  background-repeat: repeat-x;
  opacity: 0.85;
}
.theme-epcot-flower-garden .restaurant-card {
  border-radius: var(--radius);
}
.theme-epcot-flower-garden .restaurant-name {
  color: #3a2430;
  font-weight: 400;
}
.theme-epcot-flower-garden .item-name {
  color: #a03a63;
}
.theme-epcot-flower-garden .category-title {
  color: #4f6b30;
  border-color: #4f6b30;
}
.theme-epcot-flower-garden .item-desc {
  color: #6b7864;
}
.theme-epcot-flower-garden .category-badge {
  background: var(--line-subtle);
  color: var(--brand);
  border-color: var(--accent);
  border-radius: 3px;
}
.theme-epcot-flower-garden .search-input:focus {
  box-shadow: 0 0 0 3px rgba(168, 59, 100, 0.18);
}
.theme-epcot-flower-garden .food-toolbar {
  background: rgba(251, 245, 242, 0.94);
}

/* ==========================================================================
   4. THEME: OOGIE BOOGIE BASH (NIGHTMARE BEFORE CHRISTMAS)
   ==========================================================================
   Signature: a single "stitched burlap seam" — dashed thread borders that
   ignite orange on hover. Everything else stays quiet: Creepster for H1s
   only, lime reserved for data (times & prices), purple moonlight canvas.

   Body-scoped only (unlike most rules below, which target descendants of
   this body class) -- v21's park-icon system started tagging trip-home
   pill/day-card/timeline-node elements directly with day.theme/guide.theme
   classes (Section 16), and a stray bare `.theme-oogie-boogie-bash` here
   used to match those too, bleeding this whole dark page reskin
   (near-black background, cream ink) onto 2 of the 3 -- see the real
   home-card accent block in Section 3 for the fix. */
body.theme-oogie-boogie-bash {
  --page: #0c0a12; /* Moonless purple-black */
  --surface: #17141f;
  --surface-strong: #211c2c;
  --ink: #f2eef8;
  --muted: #a99fbc;
  --brand: #f97316; /* Oogie neon orange */
  --brand-hover: #fb8c33;
  --accent: #a3e635; /* Slime lime — data only */
  --line: #3a3348; /* Quiet seam (was loud orange) */
  --line-subtle: #2a2536;
  --card-line: #3a3348;
  --card-ink: var(--brand);
  --thread: rgba(249, 115, 22, 0.45); /* Burlap stitching */
  --hero-from: #08060d;
  --hero-to: #241333; /* Deep witching purple */
  --radius: 8px;
  --shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  --shadow-hover:
    0 8px 24px rgba(0, 0, 0, 0.5), 0 0 18px rgba(249, 115, 22, 0.25);
  --font-display: "Creepster", cursive;
  --font-body: "DM Sans", sans-serif;
  --font-detail: "Special Elite", cursive;

  font-family: var(--font-body);
  color: var(--ink);

  /* Burlap weave, barely-there */
  background-color: var(--page);
  background-image:
    radial-gradient(rgba(148, 130, 180, 0.06) 1px, transparent 1px),
    linear-gradient(to right, rgba(249, 115, 22, 0.025) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(249, 115, 22, 0.025) 1px, transparent 1px);
  background-size:
    22px 22px,
    44px 44px,
    44px 44px;
}

/* Spooky accessibility focus state */
.theme-oogie-boogie-bash a:focus-visible,
.theme-oogie-boogie-bash button:focus-visible,
.theme-oogie-boogie-bash input:focus-visible {
  outline: 3px dashed var(--accent);
  outline-offset: 3px;
}

/* Typography: Creepster for headline moments ONLY */
.theme-oogie-boogie-bash .site-title,
.theme-oogie-boogie-bash .food-hero h1,
.theme-oogie-boogie-bash .itinerary-head h1 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--brand);
  text-shadow:
    0 2px 0 #000,
    0 0 24px rgba(249, 115, 22, 0.45);
}
.theme-oogie-boogie-bash .section-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--ink);
}
.theme-oogie-boogie-bash .restaurant-name {
  font-family: var(--font-body);
  font-weight: 700;
  color: var(--ink);
}

.theme-oogie-boogie-bash .subtitle,
.theme-oogie-boogie-bash .dates,
.theme-oogie-boogie-bash .food-hero p,
.theme-oogie-boogie-bash .itinerary-head p,
.theme-oogie-boogie-bash .category-title,
.theme-oogie-boogie-bash .footer,
.theme-oogie-boogie-bash .time-pill,
.theme-oogie-boogie-bash .location-divider {
  font-family: var(--font-detail);
  font-weight: 400;
}
.theme-oogie-boogie-bash .food-hero p,
.theme-oogie-boogie-bash .itinerary-head p {
  color: var(--muted);
}
.theme-oogie-boogie-bash .dates {
  color: var(--accent);
}

/* Section dividers — a rotating cast of Halloween icons, one per location
   group, centered on a visible "stitched thread" rule (the theme's own
   card-border signature) instead of the old spider-web line art, whose
   stroke color sat too close to the page background to actually read.
   :nth-of-type counts only this element's div siblings (restaurant-card is
   an <article>), so it cycles cleanly once per location on the page. Icon
   colors stay inside the theme's existing palette -- lime stays reserved
   for data (times & prices) per the theme's own rule, so icons live in the
   cream/orange family already used by the ghost and jack-o'-lantern. */
.theme-oogie-boogie-bash .location-divider {
  color: var(--brand);
  font-size: 21px;
  letter-spacing: 0.1em;
  margin: 42px 0 22px;
  text-shadow: 0 0 12px rgba(249, 115, 22, 0.5);
}
.theme-oogie-boogie-bash .location-divider::before,
.theme-oogie-boogie-bash .location-divider::after {
  content: "";
  flex: 1;
  height: 22px;
  /* Neutralize the global default rule's solid pill fill + border-radius
     (.location-divider::before/::after, background: var(--card-line);
     border-radius: 999px) -- this rule only replaces background-image
     below, so without this reset the icon/rule sit on top of a visible
     rounded var(--card-line) bar. */
  background-color: transparent;
  border-radius: 0;
  background-repeat: no-repeat, no-repeat;
  background-position:
    center center,
    center center;
  background-size:
    20px 20px,
    100% 2px;
}
.theme-oogie-boogie-bash .location-divider::before {
  background-image:
    var(--divider-icon),
    linear-gradient(
      to right,
      transparent,
      var(--thread) 15%,
      var(--thread) 85%,
      transparent
    );
}
.theme-oogie-boogie-bash .location-divider::after {
  background-image:
    var(--divider-icon),
    linear-gradient(
      to left,
      transparent,
      var(--thread) 15%,
      var(--thread) 85%,
      transparent
    );
}
.theme-oogie-boogie-bash .location-divider:nth-of-type(5n + 1) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23e9e2f5'%3E%3Cpath d='M12 2A8 8 0 0 0 4 10v11l3-2 3 2 2-2 2 2 3-2 3 2V10a8 8 0 0 0-8-8zm-3 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm6 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z'/%3E%3C/svg%3E");
}
.theme-oogie-boogie-bash .location-divider:nth-of-type(5n + 2) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23f97316'%3E%3Cpath d='M12 2c.8 0 1.5.5 1.8 1.2.6 0 1.2.2 1.7.5 2.5 1.4 4.5 4.3 4.5 7.8 0 4.4-3.6 8-8 8s-8-3.6-8-8c0-3.5 2-6.4 4.5-7.8.5-.3 1.1-.5 1.7-.5C10.5 2.5 11.2 2 12 2zm-3 8l1.5 2h3L15 10l2 1-1 3-4-1-4 1-1-3 2-1z'/%3E%3C/svg%3E");
}
.theme-oogie-boogie-bash .location-divider:nth-of-type(5n + 3) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a99fbc' stroke-width='1.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Ccircle cx='12' cy='12' r='5.5'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Cpath d='M12 3v18M3 12h18M5.5 5.5l13 13M18.5 5.5l-13 13'/%3E%3C/svg%3E");
}
.theme-oogie-boogie-bash .location-divider:nth-of-type(5n + 4) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23f97316'%3E%3Cpath d='M6 10l-1-4 4 3zM18 10l1-4-4 3z'/%3E%3Cellipse cx='12' cy='14' rx='6.5' ry='5.5'/%3E%3Cpath d='M18.5 15c2.3-.2 3.6-2.2 3.2-5-1.8.6-3 2.1-3.2 4' fill='none' stroke='%23f97316' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
}
.theme-oogie-boogie-bash .location-divider:nth-of-type(5n) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23e9e2f5'%3E%3Cpath d='M2 9l7.5 3-7.5 2.2z'/%3E%3Cpath d='M22 9l-7.5 3 7.5 2.2z'/%3E%3Cellipse cx='12' cy='13.5' rx='3.2' ry='3.6'/%3E%3Cpath d='M9 10.5l1.2-2 1.8 2 1.8-2 1.2 2z'/%3E%3C/svg%3E");
}

/* List bullets — jack-o'-lantern */
.theme-oogie-boogie-bash ul {
  list-style: none;
  padding-left: 28px;
}
.theme-oogie-boogie-bash ul li {
  position: relative;
  margin-bottom: 10px;
}
.theme-oogie-boogie-bash ul li::before {
  content: "";
  position: absolute;
  left: -26px;
  top: 3px;
  width: 18px;
  height: 18px;
  background-repeat: no-repeat;
  background-size: contain;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23f97316'%3E%3Cpath d='M12 2c.8 0 1.5.5 1.8 1.2.6 0 1.2.2 1.7.5 2.5 1.4 4.5 4.3 4.5 7.8 0 4.4-3.6 8-8 8s-8-3.6-8-8c0-3.5 2-6.4 4.5-7.8.5-.3 1.1-.5 1.7-.5C10.5 2.5 11.2 2 12 2zm-3 8l1.5 2h3L15 10l2 1-1 3-4-1-4 1-1-3 2-1z'/%3E%3C/svg%3E");
}

/* Timeline nodes — floating ghost */
.theme-oogie-boogie-bash .timeline {
  border-left: 2px dashed var(--line);
}
.theme-oogie-boogie-bash .timeline-node {
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 0;
  width: 22px;
  height: 22px;
  left: -34px;
  top: 16px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23e9e2f5'%3E%3Cpath d='M12 2A8 8 0 0 0 4 10v11l3-2 3 2 2-2 2 2 3-2 3 2V10a8 8 0 0 0-8-8zm-3 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm6 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
  filter: drop-shadow(0 0 6px rgba(233, 226, 245, 0.35));
}

/* Cards: the stitched seam. Quiet thread at rest, ignites on hover. */
.theme-oogie-boogie-bash .restaurant-card,
.theme-oogie-boogie-bash .day-card,
.theme-oogie-boogie-bash .timeline-event {
  background: var(--surface);
  border: 2px dashed var(--thread);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.theme-oogie-boogie-bash .day-card {
  border-top-width: 2px; /* undo global 4px cap — seam is uniform */
}
.theme-oogie-boogie-bash .restaurant-card:hover,
.theme-oogie-boogie-bash .day-card:hover,
.theme-oogie-boogie-bash .timeline-event:hover {
  border-style: dashed;
  border-color: var(--brand);
  box-shadow: var(--shadow-hover);
}
.theme-oogie-boogie-bash .day-card h2 {
  color: var(--ink);
}
.theme-oogie-boogie-bash .day-card .date {
  color: var(--brand);
}
.theme-oogie-boogie-bash .event-copy h2 a {
  color: var(--ink);
  text-decoration-color: rgba(249, 115, 22, 0.5);
}
.theme-oogie-boogie-bash .event-copy h2 a:hover {
  color: var(--brand);
  text-decoration-color: var(--brand);
}

.theme-oogie-boogie-bash .category-badge {
  background: #241a10;
  color: #fdba74;
  border: 1px solid rgba(249, 115, 22, 0.4);
  border-radius: 4px;
}
.theme-oogie-boogie-bash .item-desc {
  color: var(--muted);
}
.theme-oogie-boogie-bash .item-price {
  color: var(--accent);
  font-family: var(--font-detail);
  font-weight: 400;
  font-size: 16px;
}
.theme-oogie-boogie-bash .menu-item {
  border-color: var(--line-subtle);
}

.theme-oogie-boogie-bash .chevron {
  background: var(--surface-strong);
  color: var(--brand);
  border-radius: 4px;
}
.theme-oogie-boogie-bash .restaurant-card.open .chevron {
  background: var(--brand);
  color: #0c0a12;
}
.theme-oogie-boogie-bash .restaurant-header,
.theme-oogie-boogie-bash .restaurant-body {
  background: var(--surface);
}
.theme-oogie-boogie-bash .restaurant-body {
  border-top: 2px dashed var(--thread);
}

/* Hero: pitch black into witching purple, stitched hem */
.theme-oogie-boogie-bash .food-hero,
.theme-oogie-boogie-bash .itinerary-head {
  background:
    radial-gradient(
      ellipse at 50% 120%,
      rgba(132, 204, 22, 0.12),
      transparent 60%
    ),
    linear-gradient(180deg, var(--hero-from), var(--hero-to));
  border-bottom: 3px dashed var(--thread);
  color: var(--ink);
}
.theme-oogie-boogie-bash .food-back-link {
  background: rgba(249, 115, 22, 0.12);
  border-color: rgba(249, 115, 22, 0.4);
  color: #fdba74;
}
.theme-oogie-boogie-bash .food-back-link:hover {
  background: rgba(249, 115, 22, 0.24);
}
body.theme-oogie-boogie-bash .pumpkin-png {
  height: 240px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  filter: drop-shadow(0 8px 20px rgba(0, 0, 0, 0.45));
  transition: transform 0.2s ease;
}

/* Dark toolbars & status bar */
.theme-oogie-boogie-bash .status-bar,
.theme-oogie-boogie-bash .food-toolbar {
  background: rgba(12, 10, 18, 0.92);
  border-color: var(--line-subtle);
  color: var(--ink);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
}
.theme-oogie-boogie-bash .search-input {
  background-color: var(--surface);
  color: var(--ink);
  border-color: var(--line);
}
.theme-oogie-boogie-bash .search-input::placeholder {
  color: var(--muted);
}
.theme-oogie-boogie-bash .search-input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.2);
}
/* :not(.utility-btn) keeps this from tying in specificity with (and, by
   later source order, winning over) the base .filter-btn.utility-btn rule
   above -- without it, the "Collapse All" button loses its dashed/
   transparent/muted styling and looks like a regular filter pill on this
   theme. */
.theme-oogie-boogie-bash .filter-btn:not(.utility-btn),
.theme-oogie-boogie-bash .status-bar button {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line);
}
.theme-oogie-boogie-bash .filter-btn:not(.utility-btn):hover,
.theme-oogie-boogie-bash .status-bar button:hover {
  border-color: var(--brand);
  color: var(--brand);
}
.theme-oogie-boogie-bash .filter-btn.active {
  background: var(--brand);
  border-color: var(--brand);
  color: #0c0a12;
}

.theme-oogie-boogie-bash .action-link {
  background: var(--surface);
  border: 2px dashed var(--thread);
  color: var(--brand);
}
.theme-oogie-boogie-bash .action-link:hover {
  background: var(--brand);
  color: #0c0a12;
  border-color: var(--brand);
}
.theme-oogie-boogie-bash .back-link {
  color: var(--brand);
}
.theme-oogie-boogie-bash .schedule-link a {
  color: var(--accent);
  text-decoration-color: rgba(163, 230, 53, 0.5);
}
.theme-oogie-boogie-bash .time-pill {
  background: #1a2410;
  color: var(--accent);
  border: 1px solid rgba(163, 230, 53, 0.4);
  border-radius: 4px;
  letter-spacing: 0.03em;
}
.theme-oogie-boogie-bash .timeline-event--hours .time-pill {
  color: #fdba74;
  background: #241a10;
  border-color: rgba(249, 115, 22, 0.4);
}
.theme-oogie-boogie-bash .no-results {
  background: var(--surface);
  border: 2px dashed var(--thread);
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   Food & Wine mode -- rebuilt from scratch on a light ground. The dark
   moonlit-purple surface worked for the itinerary timeline, but made the
   restaurant list hard to read; every other theme on the site pairs a
   colorful/dark hero with a light page and light cards, so this brings
   Oogie Boogie's food guide in line with that pattern instead of carrying
   the itinerary's dark surface onto it. The hero band above (background
   gradient, Creepster glow) is untouched -- only the body and cards below
   change. "Data" purple replaces "data" lime here specifically because
   lime text has no usable contrast on a light ground; lime stays exactly
   as it was for the (unchanged) itinerary mode. */
body.theme-oogie-boogie-bash.page-food {
  --page: #fbf3e6;
  --surface: #ffffff;
  --surface-strong: #fdece0;
  --ink: #2b1f30;
  /* Darkened from #6b5a72 -- item descriptions in that lighter shade read
     as hard to read in focus-group feedback; this keeps the same hue but
     improves contrast against the white cards. */
  --muted: #52425c;
  --brand: #b8481a;
  --brand-hover: #96380f;
  --accent: #6b2fa0;
  --line: #ecdcc4;
  --line-subtle: #f5ead9;
  --thread: rgba(184, 72, 26, 0.4);
  --radius: 10px;
  --shadow: 0 6px 18px rgba(80, 40, 15, 0.12);
  --shadow-hover:
    0 10px 26px rgba(80, 40, 15, 0.18), 0 0 14px rgba(184, 72, 26, 0.18);
}
/* The hero's subtitle text would otherwise pick up the new light-mode
   --muted and vanish against the still-dark hero background. */
body.theme-oogie-boogie-bash.page-food .food-hero p {
  color: #d8cbe8;
}
body.theme-oogie-boogie-bash.page-food .location-divider {
  text-shadow: none;
}
body.theme-oogie-boogie-bash.page-food .category-badge {
  background: #fbe4d3;
  color: #8a3a10;
  border: 1px solid rgba(184, 72, 26, 0.35);
  border-radius: 4px;
}
/* Text-role differentiation, food mode only: restaurant-name/category-title/
   item-desc were all purple-family values at different lightness (near-
   black purple, mid purple, purple-grey) -- readable as shades of one
   thing rather than three roles. restaurant-name warms toward a wine-black
   (blended with --brand) instead of staying purple; category-title becomes
   a genuinely vivid amethyst; item-desc goes neutral grey with no purple
   tint. item-name/--brand is untouched. Scoped to .page-food since the
   itinerary mode's --ink is a light color on a dark page (see the base
   .theme-oogie-boogie-bash .restaurant-name rule above). */
body.theme-oogie-boogie-bash.page-food .restaurant-name {
  color: #4e292b;
}
body.theme-oogie-boogie-bash.page-food .category-title {
  color: #652d95;
  border-color: #652d95;
}
body.theme-oogie-boogie-bash.page-food .item-desc {
  font-weight: 500;
  color: #6a6258;
}
body.theme-oogie-boogie-bash.page-food .food-toolbar {
  background: rgba(255, 250, 240, 0.94);
  border-color: var(--line);
  box-shadow: 0 4px 16px rgba(80, 40, 15, 0.08);
}
body.theme-oogie-boogie-bash.page-food .status-bar {
  background: rgba(255, 250, 240, 0.94);
  border-color: var(--line);
  color: var(--ink);
  box-shadow: none;
}
body.theme-oogie-boogie-bash.page-food .restaurant-card.open .chevron,
body.theme-oogie-boogie-bash.page-food .filter-btn.active,
body.theme-oogie-boogie-bash.page-food .action-link:hover {
  color: #fff8ea;
}

/* Divider icons recolored for a light ground -- same five shapes as the
   itinerary-shared set above, darker fills so the ghost and bat (pale
   cream, meant to glow against near-black) don't disappear against
   parchment. */
body.theme-oogie-boogie-bash.page-food .location-divider:nth-of-type(5n + 1) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236b5a72'%3E%3Cpath d='M12 2A8 8 0 0 0 4 10v11l3-2 3 2 2-2 2 2 3-2 3 2V10a8 8 0 0 0-8-8zm-3 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm6 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z'/%3E%3C/svg%3E");
}
body.theme-oogie-boogie-bash.page-food .location-divider:nth-of-type(5n + 2) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23c1541c'%3E%3Cpath d='M12 2c.8 0 1.5.5 1.8 1.2.6 0 1.2.2 1.7.5 2.5 1.4 4.5 4.3 4.5 7.8 0 4.4-3.6 8-8 8s-8-3.6-8-8c0-3.5 2-6.4 4.5-7.8.5-.3 1.1-.5 1.7-.5C10.5 2.5 11.2 2 12 2zm-3 8l1.5 2h3L15 10l2 1-1 3-4-1-4 1-1-3 2-1z'/%3E%3C/svg%3E");
}
body.theme-oogie-boogie-bash.page-food .location-divider:nth-of-type(5n + 3) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a3a5c' stroke-width='1.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Ccircle cx='12' cy='12' r='5.5'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Cpath d='M12 3v18M3 12h18M5.5 5.5l13 13M18.5 5.5l-13 13'/%3E%3C/svg%3E");
}
body.theme-oogie-boogie-bash.page-food .location-divider:nth-of-type(5n + 4) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%232b1f30'%3E%3Cpath d='M6 10l-1-4 4 3zM18 10l1-4-4 3z'/%3E%3Cellipse cx='12' cy='14' rx='6.5' ry='5.5'/%3E%3Cpath d='M18.5 15c2.3-.2 3.6-2.2 3.2-5-1.8.6-3 2.1-3.2 4' fill='none' stroke='%232b1f30' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
}
body.theme-oogie-boogie-bash.page-food .location-divider:nth-of-type(5n) {
  --divider-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%232b1f30'%3E%3Cpath d='M2 9l7.5 3-7.5 2.2z'/%3E%3Cpath d='M22 9l-7.5 3 7.5 2.2z'/%3E%3Cellipse cx='12' cy='13.5' rx='3.2' ry='3.6'/%3E%3Cpath d='M9 10.5l1.2-2 1.8 2 1.8-2 1.2 2z'/%3E%3C/svg%3E");
}

/* ==========================================================================
   4b. THEME: THE UTILIDORS (BACK-OF-HOUSE ADMIN CONSOLE)
   ==========================================================================
   Signature: painted concrete + hazard tape. A single amber warning-light
   accent does all the work; everything else stays flat industrial gray.
   Only ever applied to utilidors.html, never a park/day theme. */
.theme-utilidors,
body.theme-utilidors {
  --page: #1b1d20;
  --surface: #24272b;
  --surface-strong: #2c3034;
  --ink: #e9e7e2;
  --muted: #9aa0a6;
  --brand: #f5a623;
  --brand-hover: #ffb84d;
  --accent: #f5a623;
  --line: #3a3f44;
  --line-subtle: #303439;
  --card-line: #3a3f44;
  --card-ink: var(--brand);
  --hero-from: #202225;
  --hero-to: #2e3236;
  --radius: 10px;
  --shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  --shadow-hover: 0 10px 28px rgba(0, 0, 0, 0.5);
  --font-display: "Special Elite", cursive;
  --font-detail: "Special Elite", cursive;

  font-family: var(--font-body);
  color: var(--ink);
  background-color: var(--page);
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
    linear-gradient(to right, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
  background-size: 28px 28px;
  min-height: 100vh;
}
.theme-utilidors a:focus-visible,
.theme-utilidors button:focus-visible,
.theme-utilidors input:focus-visible,
.theme-utilidors select:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
.theme-utilidors .back-link {
  display: inline-block;
  margin: 20px 0 0 20px;
  color: var(--brand);
}
.utilidors-head {
  max-width: 720px;
  margin: 18px auto 0;
  padding: 26px 22px 22px;
  text-align: center;
}
.utilidors-head::before {
  content: "";
  display: block;
  height: 6px;
  max-width: 240px;
  margin: 0 auto 20px;
  border-radius: 3px;
  background: repeating-linear-gradient(
    45deg,
    var(--brand) 0 10px,
    #1b1d20 10px 20px
  );
}
.utilidors-head h1 {
  margin: 0 0 10px;
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.04em;
  font-size: clamp(30px, 6vw, 44px);
  color: var(--brand);
}
.utilidors-head p {
  margin: 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.5;
}
.utilidors-section {
  max-width: 720px;
  margin: 22px auto 0;
  padding: 20px 22px;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow-x: auto;
}
.utilidors-section .section-title {
  margin: 0 0 12px;
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.03em;
  font-size: 20px;
  text-align: left;
  color: var(--ink);
}
.utilidors-section p {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.5;
}
.utilidors-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.utilidors-section input[type="text"],
.utilidors-section input[type="password"],
.utilidors-section select {
  flex: 1 1 220px;
  min-width: 0;
  padding: 9px 12px;
  border: 1.5px solid var(--line);
  border-radius: 8px;
  background: var(--surface-strong);
  color: var(--ink);
  font-size: 14px;
}
.utilidors-section button {
  border: 1.5px solid var(--brand);
  border-radius: 8px;
  padding: 9px 16px;
  background: transparent;
  color: var(--brand);
  font-weight: 700;
  font-size: 13.5px;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease;
}
.utilidors-section button:hover:not(:disabled) {
  background: var(--brand);
  color: #1b1d20;
}
.utilidors-section button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.utilidors-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.utilidors-table th,
.utilidors-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
}
.utilidors-table th {
  color: var(--muted);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 11.5px;
  letter-spacing: 0.06em;
}
.utilidors-table td:last-child {
  text-align: right;
}
.utilidors-trip-row {
  cursor: pointer;
  transition: background 0.15s ease;
}
.utilidors-trip-row:hover {
  background: var(--surface-strong);
}
.utilidors-trip-row.is-selected {
  background: color-mix(in srgb, var(--brand) 14%, transparent);
}
.utilidors-trip-row.is-selected td:first-child {
  color: var(--brand);
  font-weight: 700;
}
.utilidors-trip-detail {
  margin: 12px 0 0;
  padding: 10px 12px;
  border: 1.5px dashed var(--line);
  border-radius: 8px;
  color: var(--ink);
  font-size: 13.5px;
}
.danger-zone {
  position: relative;
  border-color: var(--brand);
  background: color-mix(in srgb, var(--brand) 8%, var(--surface));
}
.danger-zone::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 6px;
  border-radius: var(--radius) var(--radius) 0 0;
  background: repeating-linear-gradient(
    45deg,
    var(--brand) 0 10px,
    #1b1d20 10px 20px
  );
}
.danger-zone .section-title {
  color: var(--brand);
}
.danger-zone button {
  background: color-mix(in srgb, var(--brand) 18%, transparent);
}
.utilidors-output {
  max-width: 720px;
  margin: 20px auto 60px;
  min-height: 20px;
  padding: 14px 22px;
  text-align: center;
  color: var(--muted);
  font-weight: 700;
  font-size: 13.5px;
}
.utilidors-output[data-kind="online"] {
  color: #7cd992;
}
.utilidors-output[data-kind="offline"] {
  color: #ff8a65;
}
.utilidors-output[data-kind="loading"] {
  color: var(--brand);
}

/* ==========================================================================
   4c. STYLE GUIDE PAGE CHROME
   --------------------------------------------------------------------------
   Layout only -- style-guide.html's actual theme swatches are rendered by
   style-guide-frame.html inside an <iframe>, applying the real park/theme
   body classes to itself and loading this same stylesheet, so every swatch
   below is driven by the tokens above rather than a hand-copied palette.
   Editing a .park-*/
.theme-*
  rule
  anywhere
  in
  this
  file
  updates
  the
  swatch
  here
  and
  the
  live
  itinerary/food
  pages
  together.
  */
  .sg-theme {
  margin-bottom: 40px;
}
.sg-theme-title {
  margin: 0 0 4px;
}
.sg-theme-resort {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 13.5px;
  font-weight: 600;
}
.sg-mode-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
}
.sg-mode {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow);
}
.sg-mode-head {
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
}
.sg-mode-label {
  margin: 0;
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.sg-mode-name {
  margin: 2px 0 0;
  font-weight: 700;
  font-size: 15.5px;
}
.sg-mode-desc {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--muted);
}
.sg-frame {
  display: block;
  width: 100%;
  height: 420px;
  border: none;
}
[data-style-guide] {
  padding-bottom: 60px;
}

/* Trip Itinerary timeline's .day-card intentionally drops the 4px accent
   stripe every other .day-card use doesn't have to worry about -- the
   medallion beside it already carries the park color, so a matching top
   border would just repeat it. Placed after every per-theme .day-card
   override above (in particular Oogie Boogie Bash's own border-top-width
   tweak) so this wins the specificity tie via source order, same as the
   rest of this file's cascade discipline. */
.trip-timeline .day-card {
  border-top: 1.5px solid var(--card-line, var(--line));
}

/* ==========================================================================
   5. RESPONSIVE ADJUSTMENTS
   ========================================================================== */
@media (max-width: 680px) {
  .trip-picker-grid {
    grid-template-columns: 1fr;
  }
  .site-header {
    padding-top: 36px;
  }
  body.park-disneyland .castle-png {
    height: 150px;
  }
  body.theme-oogie-boogie-bash .pumpkin-png {
    height: 150px;
  }
  .timeline {
    padding-left: 18px;
  }
  .timeline-node {
    left: -25px;
  }
  .theme-oogie-boogie-bash .timeline-node {
    left: -30px;
  }
  .utilidors-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .utilidors-section input[type="text"],
  .utilidors-section input[type="password"],
  .utilidors-section select,
  .utilidors-section button {
    flex: 1 1 auto;
    width: 100%;
  }
}
