/* ============================================================================
   COASTAL ESCAPE UI KIT — the reusable design system for cometowestport.com
   ----------------------------------------------------------------------------
   🔴 READ THIS BEFORE YOU EDIT: ONE FILE, MANY PAGES, A SEPARATE CACHE KEY ON
   EACH. Editing this file changes it for every page that links it — but a
   browser only RECEIVES the change on a page whose own `?v=` you bumped,
   because two `?v=` values are two different Cloudflare cache entries of the
   same file, held up to 4h each.

   HOW MANY PAGES, AND WHICH KEYS: `python tools/check-analytics.py` prints it.
   Do not keep a count here. This header used to say "FIFTEEN PAGES, FIFTEEN
   SEPARATE CACHE KEYS" and so did CLIENT-MAP.md and CLAUDE.md; on 2026-08-29 it
   was 19 pages sharing ?v=25 with photowalk.html stranded on ?v=3 — and because
   the hand-written count was the only record, FIVE other shared assets had
   drifted the same way unnoticed (map.widget.js sat on three keys at once).
   A comment is the right home for WHY this bites. It is never a home for a
   count: the count rots and then it lies with the authority of a warning.

   Two ways that bites, both real, both hit on 2026-08-14:

   a) YOU SHIP THE FILE AND NOTHING CHANGES. The bytes are on the box; every
      page still asks for its old key and Cloudflare answers from cache. It is
      not a deploy failure and nothing errors — verifying with `curl` on the
      raw path (no `?v=`) will happily show you the new file that no visitor is
      getting. Verify by loading the PAGE and reading what it actually linked.

   b) THE DANGEROUS ONE — A BUMP RELEASES OTHER PEOPLE'S WORK. Because the keys
      are per page, this file can sit CHANGED on the box while 14 pages keep
      serving the old bytes. The next person who bumps one of those pages ships
      every accumulated edit to it at once — work they did not write, did not
      test on that page, and probably does not know is there.

   STATE AS OF 2026-08-29 (keep this current when you bump):
      ALL 19 linking pages ... coastal.css?v=25  ← current, UNIFIED
        (v25 = 2026-08-29 AUTHOR PROSE: the block shapes CEmd.html() can emit
        (h3/h4, ul/ol, a, blockquote, code, hr) styled once for all three
        cinematic detail pages, which previously styled only `.body p`. Link
        colour is the load-bearing one — default blue is unreadable on navy.)
        (v24 = 2026-08-29 .ce-mosaic: the photo-mosaic backdrop promoted out of
        join.html/members.html into one primitive, so events.html could use it
        for the Signature rail instead of forking it a third time. v23 was only
        ever on photowalk.html — v24 skips past it so no page reuses a live key.)
        (v22 = 2026-08-28 theme polish: residual one-off darks/mists tokenized
        (+45 :root tokens — pins, footer, menu, page panels), gradcards/tabs/
        hero re-pointed. Same pass bumped style.css v11 (variables.css?v=3
        re-pointed to ce tokens), map.css v27 (pin gradients + fonts),
        footer-loader.js da13 / bottom-nav.js svg3 / event-showcase.js v15
        (injected styles now ride var(--ce-*, fallback)).)
        (v21 = 2026-08-28 THEME-SYSTEM: extended --ce-* token vocabulary +
        site-wide token sweep; 404/attraction/event/member now link this file
        too, and every page also links data/theme-overrides.css right after it.
        Shipped as one structural deploy, so all pages+css landed together and
        the old per-page key drift (v5..v9 on style.css etc.) was unified.)
      photowalk.html ......... coastal.js?v=3   ← js STALE (19 keys behind —
        bumping it releases everything since; read the diff first)
      the other pages ........ coastal.js?v=25  ← current
        (v25 = 2026-08-29 CEmd: author copy may carry a markdown subset, so the
        search index, the trait seeds and the trading-card flavour paragraph now
        strip markers via ceMdText. CEmd is an OPTIONAL dependency here — the
        pages that render no author copy (about/privacy/contact/…) do not load
        js/utils/markdown.js and fall through to the raw string, unchanged.)
        (v24 = 2026-08-29 CE.mosaic — behavior half of the .ce-mosaic primitive)
        (v23 = 2026-08-28 Photo Studio focal points)

   So: bump the key on every page whose rendering your change can reach, ship
   THIS FILE BEFORE the HTML that references the new key (the reverse order lets
   a request for the new key miss at the origin and Cloudflare caches that 404
   for 4h), and load a real page to confirm. Same rules apply to js/coastal.js.
   Full incident + verification recipe: KNOWN_ERRORS.md, CHANGELOG 2026-08-14.
   ----------------------------------------------------------------------------
   THE METHOD (see docs/ui-kit.md):
   1. Every public page links this AFTER css/style.css:
        <link rel="stylesheet" href="css/coastal.css?v=1">
   2. Page markup uses these `ce-` primitives for anything that could ever
      appear on a second page (sections, heads, cards, CTAs, bands, heroes).
      Page-SPECIFIC one-offs stay in that page's inline <style>.
   3. Colors/spacing come from the --ce-* tokens below — never re-hardcode.
   4. New reusable pattern? Add it HERE (one home), not inline. Bump the ?v=.
   5. Companion behaviors (hero rotation, live member counts) auto-init from
      js/coastal.js — include it once, no per-page wiring.
   Breakpoints: 980px (grid collapse) · 768px (site chrome) · 640px (phones).
   Locked direction: "Coastal Escape" (GRANT-BUILD-PLAN.md) — Playfair Display
   display type, Inter body, ocean-navy + coral + teal on warm sand.
   ========================================================================== */

:root {
  /* palette (locked — chamber brand) */
  --ce-ocean: #1e40af;   /* primary blue */
  --ce-deep: #13315c;    /* footer navy */
  --ce-navy: #0a1a30;    /* cinematic dark (page-hero) */
  --ce-coral: #e8743b;   /* warm accent / primary CTA (decorative fills, large text only) */
  --ce-coral-hot: #ff7a45;
  --ce-coral-deep: #c2410c; /* WCAG-AA coral: small text on light + fills carrying white text */
  --ce-teal: #1b9aaa;
  --ce-teal-deep: #0e7490;  /* WCAG-AA teal: fills carrying white text (chips) */
  --ce-sand: #faf6ee;    /* warm section background */
  --ce-cream: #fffdf8;   /* alt section background */
  --ce-ink: #23303d;     /* body text on light */
  --ce-muted: #5d6a79;   /* secondary text on light (AA ≥4.5:1 on sand/cream) */
  --ce-peach: #ffd9b0;   /* eyebrow/kicker on dark */
  --ce-mist: #dce6f6;    /* body text on navy */

  /* extended palette (THEME-SYSTEM sweep 2026-08-27 — values identical to the legacy
     hard-coded colors they replace; the Design Studio derives them from the core choices) */
  --ce-ocean-bright: #2563eb;   /* legacy primary (old style.css system) */
  --ce-ocean-light: #3b82f6;
  --ce-ocean-soft: #60a5fa;
  --ce-ocean-deeper: #1d4ed8;
  --ce-ocean-deepest: #1e3a8a;
  --ce-navy-alt: #1a1a2e;       /* old chrome dark (header/footer legacy) */
  --ce-navy-soft: #14243a;
  --ce-deep-2: #143a63;
  --ce-deep-3: #0e2747;
  --ce-slate-blue: #33566f;
  --ce-coral-bright: #ff6b4a;
  --ce-coral-soft: #ff9166;
  --ce-teal-light: #5eb8c4;
  --ce-teal-ice: #7ad3e0;
  --ce-teal-sky: #6fd3e0;
  --ce-mist-2: #b8c9dd;
  --ce-mist-soft: #eaf2fb;
  --ce-mist-muted: #8fa3bb;
  --ce-mist-slate: #6b7c93;
  --ce-line: #efe7d8;           /* warm hairline (matches --ce-border-warm color) */

  /* page-local dialect anchors (attraction/event/member heroes, countdown, map chrome) —
     same sweep, same rule: values identical to the page-local colors they replace */
  --ce-navy-hero: #0e2238;
  --ce-navy-hero-2: #15314f;
  --ce-steel: #8695a3;
  --ce-aqua: #36c5c0;
  --ce-rust: #9a3412;
  --ce-mist-3: #9fb1c6;
  --ce-mist-4: #dbe3ee;
  --ce-mist-5: #c4cedb;
  --ce-mist-6: #cdd6e2;
  --ce-frost: #eef3f9;
  --ce-frost-2: #eef1f5;

  /* neutral scale (legacy tailwind slates/grays — follow the Ink choice in the studio) */
  --ce-slate: #64748b;
  --ce-slate-dark: #475569;
  --ce-slate-line: #e2e8f0;
  --ce-slate-bg: #f8fafc;
  --ce-slate-bg-2: #f1f5f9;
  --ce-gray: #6b7280;
  --ce-gray-soft: #9ca3af;
  --ce-gray-mid: #4b5563;
  --ce-gray-dark: #374151;
  --ce-gray-deep: #1f2937;
  --ce-gray-deepest: #111827;   /* legacy gray-900 (variables.css dialect) */
  --ce-line-gray: #d1d5db;
  --ce-line-soft: #e5e7eb;
  --ce-bg-soft: #f3f4f6;
  --ce-bg-softer: #f9fafb;

  /* polish pass 2026-08-28 — residual one-off darks/mists tokenized (owner feedback:
     visible areas still carried literal dark navy). Values identical to the literals
     they replace; the Design Studio derives them all from the core choices. */
  --ce-navy-hero-3: #0d2040;   /* ce-hero fallback backdrop */
  --ce-navy-menu: #11294a;     /* mobile nav overlay gradient, top */
  --ce-navy-menu-2: #06111d;   /* mobile nav overlay gradient, bottom */
  --ce-navy-card: #16293a;     /* trading-card edge gradient mid */
  --ce-navy-panel: #0e1622;    /* event/member side map-card backdrop */
  --ce-navy-night: #0e2140;    /* 404 backdrop gradient mid */
  --ce-navy-theater: #03080f;  /* webcams theater-mode backdrop */
  --ce-navy-sea: #050d1b;      /* sounds hero gradient end */
  --ce-navy-spot: #0f2a4a;     /* homepage spotlight avatar fallback */
  --ce-navy-pin: #16283f;      /* map: photowalk pin dark stop */
  --ce-navy-pin-2: #1d4470;    /* map: photowalk pin bright stop */
  --ce-navy-pin-3: #12325a;    /* map: hot pin dark stop */
  --ce-slate-pin: #3a5470;     /* map: pending pin light stop */
  --ce-ocean-pin: #2f6ea8;     /* map: hot pin bright stop */
  --ce-ocean-sky: #4a90e2;     /* event card category fallback fill */
  --ce-ocean-wash: #e0f2fe;    /* today-section gradient wash */
  --ce-foot-ink: #dfe7f2;      /* footer body text (js/footer-loader.js) */
  --ce-foot-link: #cdd8ea;     /* footer links */
  --ce-foot-soft: #aebbd0;     /* footer brand blurb + address */
  --ce-foot-label: #9fb0c8;    /* footer sponsor label + legal bar */
  --ce-menu-ink: #eef5ff;      /* mobile nav link text */
  --ce-hero-lede: #c8d3e2;     /* page-hero lede on navy */
  --ce-hero-fine: #9db0c9;     /* page-hero fine print */
  --ce-hero-link: #7fd3e0;     /* page-hero fine-print links */
  --ce-tab-dim: #93a8bf;       /* ce-tab resting text on dark */
  --ce-tab-lit: #cfe0f2;       /* ce-tab hover text on dark */
  --ce-rail-label: #9db2cc;    /* contact rail headers on navy */
  --ce-wash-blue: #e8eef6;     /* contact page top wash */
  --ce-line-cool: #dde3ec;     /* cool input hairline (contact form) */
  --ce-mist-7: #cfd8e4;        /* attraction tips/link text on dark */
  --ce-coral-2: #f08549;       /* footer/consent CTA hover */
  --ce-peach-2: #ffb78f;       /* map: mystery pin text + ring */
  --ce-peach-3: #ffd9a8;       /* map: pending pin stroke, cluster text */
  --ce-rust-2: #7a2e1c;        /* gradcard rust, stop 1 */
  --ce-wine: #4a1f2b;          /* gradcard rust, stop 2 */
  --ce-teal-sea: #155e75;      /* gradcard teal, deep stop */
  --ce-teal-tint: #e7f2f4;     /* trading-card flavor well */
  --ce-slate-ink: #3d4d5e;     /* trading-card flavor text */
  --ce-slate-mid: #4a5568;     /* footer social icon hover */
  --ce-slate-deep: #334155;    /* btn-secondary hover fill */
  --ce-cream-2: #f3f0ea;       /* ce-hero lede text (warm off-white) */
  --ce-line-2: #e6dfd2;        /* warm hairline, darker (trading cards) */
  --ce-line-3: #ece3d3;        /* warm dashed hairline (homepage countdown) */
  --ce-line-4: #f2ecdd;        /* warm hairline (accessibility/sitemap) */

  /* type */
  --ce-font-display: 'Playfair Display', Georgia, serif;
  --ce-font-body: 'Inter', system-ui, sans-serif;

  /* shape + elevation */
  --ce-r-card: 16px;
  --ce-r-card-lg: 18px;
  --ce-r-band: 22px;
  --ce-r-pill: 999px;
  --ce-shadow-card: 0 8px 26px rgba(20, 40, 70, .10);
  --ce-shadow-photo: 0 12px 30px rgba(20, 40, 70, .16);
  --ce-border-warm: 1px solid #efe7d8;

  /* glow + on-navy glass (added for the interactive map + any dark surface).
     Glow color is swappable per element via --ce-glow; teal is the default. */
  --ce-glow-teal: rgba(27, 154, 170, .40);
  --ce-glow-coral: rgba(232, 116, 59, .38);
  --ce-glow-peach: rgba(255, 217, 176, .26);
  --ce-glass-dark: rgba(19, 49, 92, .42);
  --ce-glass-dark-border: rgba(94, 184, 196, .26);
  --ce-glass-dark-border-warm: rgba(255, 217, 176, .30);
  --ce-focus-ring: 0 0 0 3px rgba(27, 154, 170, .48);
  --ce-shadow-float: 0 12px 36px rgba(4, 10, 20, .45);
}

/* ---- scope: put class="ce" on <main> ---------------------------------- */
main.ce { font-family: var(--ce-font-body); color: var(--ce-ink); background: var(--ce-sand); }
.ce h1, .ce h2, .ce h3 { font-family: var(--ce-font-display); letter-spacing: -.01em; }

.ce-wrap { max-width: 1180px; margin: 0 auto; padding: 0 24px; }

/* ---- sections ---------------------------------------------------------- */
.ce-sec { padding: clamp(46px, 7vw, 74px) 0; }
.ce-sec--alt { background: var(--ce-cream); }

.ce-head { text-align: center; max-width: 640px; margin: 0 auto clamp(30px, 4.5vw, 44px); }
.ce-head .kicker { text-transform: uppercase; letter-spacing: .2em; font-size: 13px; font-weight: 600; color: var(--ce-coral-deep); }
.ce-head h2 { font-size: clamp(30px, 3.6vw, 44px); margin: 10px 0 12px; color: var(--ce-deep); }
.ce-head p { color: var(--ce-muted); font-size: clamp(16px, 1.8vw, 18px); line-height: 1.6; margin: 0; }

/* ---- CTAs (pill buttons) ---------------------------------------------- */
.ce-cta { display: inline-flex; align-items: center; gap: 10px; background: var(--ce-coral-deep); color: #fff;
  font-family: var(--ce-font-body); font-weight: 600; padding: 15px 28px; border-radius: var(--ce-r-pill);
  text-decoration: none; box-shadow: 0 10px 30px color-mix(in srgb, var(--ce-coral) 40%, transparent); transition: transform .15s; }
.ce-cta:hover { transform: translateY(-2px); }
.ce-cta--ghost { background: rgba(255, 255, 255, .12); border: 1.5px solid rgba(255, 255, 255, .6); box-shadow: none; }
.ce-cta--ocean { background: var(--ce-ocean); box-shadow: 0 10px 30px rgba(30, 64, 175, .32); }

/* ---- responsive card grids --------------------------------------------
   4-up → 2-up (≤980) → 1-up (≤640) · 3-up → 1-up (≤980) · 2-up → 1-up (≤980) */
.ce-grid { display: grid; gap: clamp(16px, 2.2vw, 22px); }
.ce-grid--4 { grid-template-columns: repeat(4, 1fr); }
.ce-grid--3 { grid-template-columns: repeat(3, 1fr); }
.ce-grid--2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 980px) {
  /* --3 steps through 2 columns before collapsing — straight to 1fr made tablet-width cards
     span the whole page (home "Upcoming" 2026-08-10). */
  .ce-grid--4, .ce-grid--3 { grid-template-columns: repeat(2, 1fr); }
  .ce-grid--2 { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .ce-grid--4, .ce-grid--3 { grid-template-columns: 1fr; }
}

/* ---- photo card (image bg + label; used for trip picks, seasons) ------- */
.ce-photocard { position: relative; border-radius: var(--ce-r-card-lg); overflow: hidden; min-height: 320px;
  display: flex; align-items: flex-end; color: #fff; text-decoration: none; box-shadow: var(--ce-shadow-photo);
  transition: transform .2s; }
.ce-photocard:hover { transform: translateY(-5px); }
.ce-photocard img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform .4s; }
.ce-photocard:hover img { transform: scale(1.06); }
.ce-photocard::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(13, 32, 64, 0) 35%, rgba(13, 32, 64, .85) 100%); }
.ce-photocard .lbl { position: relative; z-index: 2; padding: 22px; }
.ce-photocard .lbl small { text-transform: uppercase; letter-spacing: .16em; font-size: 11px; color: var(--ce-peach); font-weight: 600; }
.ce-photocard .lbl h3 { font-size: 24px; margin: 6px 0 0; color: #fff; }
.ce-photocard--sm { min-height: 230px; border-radius: 14px; box-shadow: none; }
.ce-photocard--sm .lbl h3 { font-size: 19px; }

/* ---- surface card (white; events, generic content cards) --------------- */
.ce-card { background: #fff; border-radius: var(--ce-r-card); overflow: hidden; box-shadow: var(--ce-shadow-card);
  border: var(--ce-border-warm); display: flex; flex-direction: column; }
/* 16:9 keeps the photo composed at any column width — a fixed 160px turned 1-col/2-col cards
   into a blurry letterbox strip (home "Upcoming" 2026-08-10). Applies to <img> and gradient divs. */
.ce-card__ph { aspect-ratio: 16 / 9; height: auto; object-fit: cover; width: 100%; }
.ce-card__body { padding: 20px 20px 22px; }
.ce-card__body h3 { font-size: 20px; margin: 0 0 8px; color: var(--ce-deep); }
.ce-card__body p { color: var(--ce-muted); font-size: 14.5px; line-height: 1.55; margin: 0; }

/* small colored pill (dates, tags) */
.ce-chip { display: inline-block; background: var(--ce-teal-deep); color: #fff; font-size: 12px; font-weight: 600;
  padding: 4px 12px; border-radius: var(--ce-r-pill); margin-bottom: 10px; }

/* ---- gradient→photo reveal card (About towns; any "place" card) --------
   Tint via modifier or set --gc1/--gc2/--gc-shade (shade = "r,g,b").       */
.ce-gradcard { position: relative; border-radius: var(--ce-r-card-lg); overflow: hidden; padding: 30px 28px 28px;
  color: #fff; min-height: 300px; display: flex; flex-direction: column; justify-content: flex-end;
  box-shadow: var(--ce-shadow-photo);
  --gc1: var(--ce-deep-2); --gc2: var(--ce-deep-3); --gc-shade: 10, 26, 48; background: var(--gc2);
  /* longhands after the shorthand on purpose: a card with no <img class="photo"> can still take a
     photo as its own background (content-apply.js's non-IMG `media`/`focal` branch), and then it
     needs to cover and to honour the focal pair. Inert on the cards that carry an <img>. */
  background-size: cover; background-position: center; }
.ce-gradcard > * { position: relative; z-index: 2; }
.ce-gradcard .photo { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: right center; }
.ce-gradcard::before { content: ""; position: absolute; inset: 0; z-index: 1; background:
  linear-gradient(180deg, rgba(var(--gc-shade), 0) 34%, rgba(var(--gc-shade), .82) 88%),
  linear-gradient(100deg, var(--gc1) 0%, var(--gc2) 30%, color-mix(in srgb, var(--gc2) 70%, transparent) 50%, transparent 80%); }
.ce-gradcard::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; z-index: 2;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--ce-coral-hot) 50%, transparent) 30%, rgba(255, 255, 255, .5) 50%, color-mix(in srgb, var(--ce-coral-hot) 50%, transparent) 70%, transparent);
  opacity: .7; }
.ce-gradcard small { text-transform: uppercase; letter-spacing: .16em; font-size: 11px; color: var(--ce-peach); font-weight: 600; }
.ce-gradcard h3 { font-size: 26px; margin: 6px 0 10px; color: #fff; }
.ce-gradcard p { color: var(--ce-mist); font-size: 14.5px; line-height: 1.6; margin: 0; }
.ce-gradcard small, .ce-gradcard h3, .ce-gradcard p { text-shadow: 0 1px 14px rgba(0, 0, 0, .4); }
.ce-gradcard .motif { position: absolute; top: 18px; right: 20px; opacity: .34; filter: drop-shadow(0 1px 6px rgba(0, 0, 0, .5)); }
.ce-gradcard .motif svg { width: 52px; height: 52px; fill: none; stroke: var(--ce-peach); stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round; }
/* brand tints */
.ce-gradcard--navy { --gc1: var(--ce-deep-2); --gc2: var(--ce-deep-3); --gc-shade: 10, 26, 48; }
.ce-gradcard--rust { --gc1: var(--ce-rust-2); --gc2: var(--ce-wine); --gc-shade: 38, 17, 24; }
.ce-gradcard--teal { --gc1: var(--ce-teal-deep); --gc2: var(--ce-teal-sea); --gc-shade: 11, 42, 55; }
/* The fourth tint (Ocosta). Deliberately the neutral of the set rather than a fourth hue — blue,
   rust and teal are the brand's three, and a near-miss fourth reads as a mistake. Both stops are
   tokens the Design Studio actually re-tones (checked against the live theme_bake output), which
   --ce-slate-blue is not: the studio turns that one LIGHT and it would fail as a gradient stop. */
.ce-gradcard--graphite { --gc1: var(--ce-navy-alt); --gc2: var(--ce-navy-panel); --gc-shade: 14, 22, 34; }

/* ---- CTA band (inset rounded card) ------------------------------------ */
.ce-band { background: linear-gradient(115deg, var(--ce-deep), var(--ce-ocean)); color: #fff;
  border-radius: var(--ce-r-band); padding: clamp(38px, 5vw, 54px); text-align: center; }
.ce-band h2 { color: #fff; font-size: clamp(28px, 3vw, 34px); margin: 0 0 12px; }
.ce-band p { color: var(--ce-mist); font-size: clamp(16px, 1.8vw, 18px); max-width: 54ch; margin: 0 auto 26px; }

/* ---- Closing CTA (full-bleed — join-page treatment, kit-shared) ---------
   Photo + navy scrim + slow aurora. Use as the LAST section before the navy
   footer so the seam blends. Markup:
     <section class="ce-close">
       <span class="ce-close__photo" aria-hidden="true"></span>
       <span class="ce-close__scrim" aria-hidden="true"></span>
       <div class="ce-close__inner">…</div>
     </section> */
.ce-close { position: relative; overflow: hidden; text-align: center; color: #fff;
  background: linear-gradient(180deg, var(--ce-navy), var(--ce-deep));
  padding: clamp(62px, 9vw, 104px) 24px; }
.ce-close__photo { position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: url('../images/coast/grayland-coast.webp') center 58% / cover no-repeat;
  opacity: .30; filter: saturate(.7);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 66%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 66%, transparent 100%); }
.ce-close__scrim { position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, color-mix(in srgb, var(--ce-navy) 86%, transparent) 0%, color-mix(in srgb, var(--ce-navy) 72%, transparent) 42%, rgba(13,35,64,.88) 100%); }
.ce-close__inner { position: relative; z-index: 2; max-width: 760px; margin: 0 auto; }
.ce-close__eyebrow { display: inline-flex; align-items: center; gap: 10px; text-transform: uppercase;
  letter-spacing: .26em; font-size: 12px; font-weight: 700; color: var(--ce-coral-hot); margin-bottom: 22px; }
.ce-close__eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ce-coral-hot);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--ce-coral-hot) 22%, transparent); }
.ce-close h2 { font-family: var(--ce-font-display); font-weight: 900; color: #fff;
  font-size: clamp(30px, 4.4vw, 52px); margin: 0 0 14px; letter-spacing: -.015em; }
.ce-close p { color: var(--ce-mist); font-size: 17px; max-width: 52ch; margin: 0 auto 30px; line-height: 1.6; }
.ce-close__cta { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
.ce-close__foot { margin: 26px auto 0; font-size: 14.5px; color: color-mix(in srgb, var(--ce-mist) 70%, transparent); }
.ce-close__foot a { color: var(--ce-coral-hot); font-weight: 600; text-decoration: none; }
.ce-close__foot a:hover { text-decoration: underline; }
/* Slow aurora so the last screen isn't a flat rectangle */
.ce-close::before { content: ""; position: absolute; inset: -40% -20%; z-index: 0; pointer-events: none;
  background: radial-gradient(38% 46% at 22% 32%, color-mix(in srgb, var(--ce-teal) 30%, transparent), transparent 70%),
              radial-gradient(34% 42% at 78% 62%, color-mix(in srgb, var(--ce-coral-hot) 26%, transparent), transparent 70%);
  animation: ceCloseAurora 26s ease-in-out infinite alternate; }
@keyframes ceCloseAurora {
  from { transform: translate3d(-3%, -2%, 0) scale(1); }
  to { transform: translate3d(4%, 3%, 0) scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
  .ce-close::before { animation: none; }
}

/* ---- hero (rotating photo crossfade under a fixed gradient) -------------
   Markup: <section class="ce-hero"><img class="bg on" ...><img class="bg" ...>
           <div class="ce-wrap">…</div></section>
   Rotation auto-inits from js/coastal.js (data-rotate optional interval ms). */
.ce-hero { position: relative; min-height: 560px; display: flex; align-items: center; color: #fff;
  overflow: hidden; background: var(--ce-navy-hero-3); }
.ce-hero img.bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 1.8s ease-in-out; }
.ce-hero img.bg.on { opacity: 1; }
.ce-hero::after { content: ""; position: absolute; inset: 0; z-index: 2;
  background: linear-gradient(105deg, rgba(13, 32, 64, .82) 0%, rgba(13, 32, 64, .45) 55%, color-mix(in srgb, var(--ce-coral) 25%, transparent) 100%); }
.ce-hero .ce-wrap { position: relative; z-index: 3; padding-top: 64px; padding-bottom: 64px; }
.ce-hero .eyebrow { font-family: var(--ce-font-body); text-transform: uppercase; letter-spacing: .22em;
  font-size: 13px; font-weight: 600; color: var(--ce-peach); margin-bottom: 14px; }
.ce-hero h1 { font-size: clamp(38px, 5.4vw, 68px); line-height: 1.04; font-weight: 800; max-width: 14ch;
  margin: 0 0 18px; text-shadow: 0 2px 24px rgba(0, 0, 0, .35); }
.ce-hero .lede { font-size: clamp(17px, 2.2vw, 21px); max-width: 46ch; color: var(--ce-cream-2); margin: 0 0 30px; line-height: 1.5; }
.ce-hero .ce-cta--ghost { margin-left: 12px; }

/* hero search pill */
.ce-hero-search { margin-top: 30px; display: flex; max-width: 520px; background: #fff;
  border-radius: var(--ce-r-pill); padding: 7px 7px 7px 22px; box-shadow: 0 14px 40px rgba(0, 0, 0, .22); }
.ce-hero-search input { flex: 1; min-width: 0; border: 0; outline: 0; font-size: 16px; color: #333; font-family: var(--ce-font-body); }
.ce-hero-search button { background: var(--ce-ocean); color: #fff; border: 0; border-radius: var(--ce-r-pill);
  padding: 11px 22px; font-weight: 600; cursor: pointer; flex-shrink: 0; }

@media (max-width: 640px) {
  .ce-hero { min-height: 520px; }
  .ce-hero .ce-wrap { padding-top: 48px; padding-bottom: 48px; }
  .ce-hero .ce-cta { padding: 13px 22px; }
  .ce-hero .ce-cta--ghost { margin-left: 8px; }
  .ce-hero-search { max-width: 100%; }
  .ce-band { border-radius: 16px; }
}

/* Hero search pill doubles as the opener for the site search overlay
   (js/coastal.js CE.mountHeroSearch → header-loader CE.openSiteSearch). The
   overlay itself is styled in the "search overlay" section below. */
.ce-hero-search { cursor: text; }
.ce-hero-search input { cursor: text; }

/* ============================================================================
   ATMOSPHERE — glow, on-navy glass, loading shimmer, fog canvas
   Opt-in utilities (never global). Used by the interactive map + any dark
   surface. The fog CANVAS is driven by CE.fog in js/coastal.js.
   ========================================================================== */

/* soft brand glow — pins, buttons, featured ribbon, focus states.
   Set --ce-glow to any color; teal is the default interactive glow. */
.ce-glow { box-shadow: 0 0 0 1px rgba(255, 255, 255, .05), 0 6px 22px var(--ce-glow, var(--ce-glow-teal)); }

/* one dark-glass recipe so every floating surface over the map reads as one object */
.ce-glass {
  background: var(--ce-glass-dark);
  border: 1px solid var(--ce-glass-dark-border);
  border-radius: var(--ce-r-card); box-shadow: var(--ce-shadow-float);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}

/* branded loading shimmer — sea-mist sweep while tiles/pins arrive (no blank OSM flash) */
.ce-shimmer {
  background:
    linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--ce-teal) 16%, transparent) 45%, color-mix(in srgb, var(--ce-peach) 12%, transparent) 55%, transparent 80%),
    var(--ce-navy);
  background-size: 220% 100%; animation: ce-shimmer 1.4s ease-in-out infinite;
}
@keyframes ce-shimmer { from { background-position: 180% 0; } to { background-position: -80% 0; } }

/* ambient fog-mote canvas (CE.fog) — sits behind hero content, pointer-inert */
.ce-fog { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }

/* photo-mosaic backdrop (CE.mosaic) — a drifting tile wall of REAL site
   photography behind a dark section, so a second navy block reads as texture
   instead of another slab of blue. Three surfaces use it: the join hero and the
   directory hero (member photos) and the events Signature rail (event photos).
   Promoted here 2026-08-29 after the events page needed a third copy.

   The host is ONLY the tile grid. The navy wash that keeps type at AA contrast
   stays with the section — each one carries different content over it and wants
   a different weight — as does the opacity, because two of the three fade in.
   Tile size drives BOTH the grid and the tile count CE.mosaic asks for, so
   override the two vars; never re-declare the grid. */
.ce-mosaic {
  --ce-mosaic-tile-w: 118px;
  --ce-mosaic-tile-h: 96px;
  position: absolute; inset: 0; display: grid; gap: 6px;
  grid-template-columns: repeat(auto-fill, minmax(var(--ce-mosaic-tile-w), 1fr));
  grid-auto-rows: var(--ce-mosaic-tile-h);
  opacity: .42; filter: saturate(.75); pointer-events: none;
}
.ce-mosaic img { width: 100%; height: 100%; object-fit: cover; border-radius: 8px; display: block; }
/* drift is a transform on a clipped, inset:0 layer — it can never widen the document */
.ce-mosaic.is-drift { animation: ce-mosaic-drift 64s linear infinite alternate; will-change: transform; }
@keyframes ce-mosaic-drift {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to { transform: scale(1.14) translate3d(-2%, -1.5%, 0); }
}
@media (prefers-reduced-motion: reduce) { .ce-mosaic.is-drift { animation: none; } }

/* on-brand keyboard focus for coastal chrome */
.ce-focus:focus-visible { outline: none; box-shadow: var(--ce-focus-ring); }

/* ============================================================================
   SITE CHROME — mobile compaction (overrides css/style.css)
   On phones the two-tier header stacked hours/email/call full-width and ate
   more than a viewport before content. Compact it: small logo + one slim
   email·phone row; hours live on the Contact page / footer.
   ========================================================================== */
@media (max-width: 768px) {
  .header-top { padding: .55rem 0; }
  .header-top-content { flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: .35rem .9rem; padding: 0 .75rem; }
  .header-logo { width: auto; }
  .header-logo img { max-height: 54px; }
  .header-contact { width: auto; flex-direction: row; flex-wrap: wrap; justify-content: center; gap: .3rem 1.1rem; }
  .contact-item { width: auto; flex-direction: row; align-items: center; gap: .35rem; }
  .contact-item:first-child { display: none; } /* chamber hours — too bulky for phones */
  .contact-label { display: none; }
  .contact-value { font-size: .8rem; font-weight: 600; text-transform: none; }
  .header-search { position: static; }
  .search-btn { padding: .35rem; }
}

/* ---- motion preferences ------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .ce-cta, .ce-photocard, .ce-photocard img, .ce-hero img.bg { transition: none; }
  .ce-shimmer { animation: none; }
}

/* ============================================================================
   SITE HEADER — unified top bar (utility strip + sticky main bar + mega nav
   + search overlay). Rendered by js/header-loader.js from
   data/site-settings.json + data/navigation.json. Namespaced .ce-util/.ce-bar/
   .ce-nav so it never collides with the retired .header-top/.nav-menu rules.
   Signature: a coral→teal "lighthouse beam" underline + scroll-shrink.
   ========================================================================== */
:root { --ce-hdr-h: 78px; --ce-hdr-h-sm: 60px; --ce-hdr-max: 1280px; --ce-hdr-bp: 1080px;
        --ce-logo-h: 90px; --ce-logo-h-sm: 70px; --ce-logo-h-mob: 64px;
        /* Breathing room above+below the mark, and the ONLY thing that couples the bar's
           height to the logo's. It was 24/20/18px in three places, so raising the logo
           72 -> 90px in the admin also made the bar 96 -> 114px on every page -- the owner
           asked for a bigger logo and got a taller header (2026-09-09). At 8px the logo
           uses the bar it already has: 90px mark in a 98px bar, 2px off the original 96.
           Raise this only to fix real crowding, and know it moves every page's header. */
        --ce-logo-pad: 8px; }

/* pre-hydration: kill the legacy bare `header{}` white bar/border before header-loader adds .ce-hdr */
#site-header { background: transparent; border: 0; }
#site-header.ce-hdr { position: sticky; top: 0; z-index: 1000; background: transparent; border: 0;
  font-family: var(--ce-font-body); }

/* ---- utility strip (navy) --------------------------------------------- */
.ce-util { background: var(--ce-navy); color: var(--ce-mist); font-size: 13px; overflow: hidden;
  max-height: 60px; opacity: 1; border-bottom: 1px solid rgba(255,255,255,.06);
  transition: max-height .3s ease, opacity .25s ease; }
.ce-util__in { max-width: var(--ce-hdr-max); margin: 0 auto; padding: 8px 24px; display: flex;
  align-items: center; justify-content: space-between; gap: 16px; }
.ce-util__hours { display: inline-flex; align-items: center; gap: 7px; color: var(--ce-peach);
  font-weight: 500; letter-spacing: .01em; }
.ce-util__hours .ce-ic { width: 14px; height: 14px; opacity: .9; }
.ce-util__right { display: flex; align-items: center; gap: 18px; }
.ce-util__link { display: inline-flex; align-items: center; gap: 7px; color: var(--ce-mist);
  text-decoration: none; transition: color .18s ease; }
.ce-util__link .ce-ic { width: 14px; height: 14px; opacity: .75; }
.ce-util__link:hover { color: #fff; }
.ce-util__soc-wrap { display: flex; align-items: center; gap: 8px; padding-left: 16px;
  border-left: 1px solid rgba(255,255,255,.14); }
/* Language toggle (EN ⇄ ES) — lives in the utility bar; behavior in header-loader.js */
.ce-lang { display: inline-flex; align-items: center; gap: 6px; background: transparent;
  border: 1px solid rgba(255,255,255,.3); color: var(--ce-mist); border-radius: var(--ce-r-pill);
  padding: 3px 11px; font: 600 12px/1.5 var(--ce-font-body); letter-spacing: .08em; cursor: pointer;
  transition: color .18s, border-color .18s; }
.ce-lang:hover, .ce-lang.on { color: #fff; border-color: rgba(255,255,255,.65); }
.ce-lang .ce-ic { width: 13px; height: 13px; opacity: .85; }
/* Google Translate chrome suppression — WE drive translation from .ce-lang; Google's
   injected banner/tooltip UI would otherwise shove the page down. Don't remove.
   Scoped :not(.ce-noscroll) so it can't out-!important the negative `top` the
   scroll-lock sets while the mobile menu / search overlay is open. */
body:not(.ce-noscroll) { top: 0 !important; }
iframe.skiptranslate, body > .skiptranslate { display: none !important; }
#google_translate_element { display: none; }
.ce-util__soc { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%;
  color: var(--ce-mist); background: rgba(255,255,255,.06); transition: background .18s, color .18s, transform .18s; }
.ce-util__soc .ce-ic { width: 15px; height: 15px; }
.ce-util__soc:hover { background: var(--ce-teal); color: #fff; transform: translateY(-1px); }
#site-header.ce-hdr.is-scrolled .ce-util { max-height: 0; opacity: 0; }

/* ---- main bar (frosted white, sticky, shrinks on scroll) -------------- */
.ce-bar { background: rgba(255,255,255,.86); -webkit-backdrop-filter: saturate(1.4) blur(14px);
  backdrop-filter: saturate(1.4) blur(14px); border-bottom: 1px solid color-mix(in srgb, var(--ce-deep) 8%, transparent);
  transition: box-shadow .25s ease, background .25s ease; }
#site-header.ce-hdr.is-scrolled .ce-bar { background: rgba(255,255,255,.95); box-shadow: 0 8px 30px rgba(20,40,70,.12); }
.ce-bar__in { max-width: var(--ce-hdr-max); margin: 0 auto; padding: 0 24px;
  height: max(var(--ce-hdr-h), calc(var(--ce-logo-h) + var(--ce-logo-pad)));
  display: flex; align-items: center; gap: 18px; transition: height .25s ease; }
#site-header.ce-hdr.is-scrolled .ce-bar__in { height: max(var(--ce-hdr-h-sm), calc(var(--ce-logo-h-sm) + var(--ce-logo-pad))); }

/* ---- brand mark -------------------------------------------------------
   THE HEIGHT IS THE ADMIN'S. Settings -> Branding -> "Logo Height" / "Mobile
   Logo Height" are written onto #site-header by applyLogoHeight() in
   header-loader.js as --ce-logo-h / --ce-logo-h-mob; --ce-logo-h-sm (scrolled)
   is derived from the first at ~78%. The values in :root are the fallback, used
   when the setting is missing or outside the catalog's ranges. To change how
   big the logo is, change it in the admin -- not here.

   The bar takes its height FROM the logo rather than pinning it, so raising
   that number in the admin can never clip the mark or crop it against a fixed
   bar.

   The height sits on the LINK, not the <img>, for two reasons. The anchor
   reserves the vertical box before an admin-uploaded logo has loaded, so there
   is no layout shift -- those files carry no width/height attributes (see
   logoDims(), which only knows the packaged one). And it lets the img shrink
   inside it on its own ratio, which is load-bearing: measured 2026-09-08, the
   nav row (765px) + search (42px) + gaps leave the brand only ~190px at the
   narrowest desktop width, and CSS cannot know the ratio of a logo the admin
   uploaded. `flex: 0 1 auto` + `max-width: 100%` therefore let a big logo get
   quietly smaller in the 1081-1280px band instead of wrapping the nav -- which
   is also what keeps a careless 200px setting from breaking the header. */
.ce-bar__brand { flex: 0 1 auto; min-width: 0; display: flex; align-items: center;
  height: var(--ce-logo-h); transition: height .25s ease; }
.ce-bar__brand img { max-height: 100%; max-width: 100%; width: auto; height: auto; display: block; }
#site-header.ce-hdr.is-scrolled .ce-bar__brand { height: var(--ce-logo-h-sm); }

/* ---- primary nav ------------------------------------------------------ */
.ce-nav { margin-left: auto; }
.ce-nav__list { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: 1px; }
.ce-nav__item { position: relative; }
.ce-nav__link { display: inline-flex; align-items: center; gap: 5px; font: 600 14px/1 var(--ce-font-body);
  text-transform: uppercase; letter-spacing: .05em; color: var(--ce-ink); background: none; border: 0;
  cursor: pointer; padding: 10px 13px; border-radius: 10px; text-decoration: none; white-space: nowrap; position: relative; }
.ce-nav__caret { width: 14px; height: 14px; opacity: .55; transition: transform .2s ease; }
.ce-nav__item.is-open .ce-nav__caret { transform: rotate(180deg); }
.ce-nav__link:hover { color: var(--ce-ocean); }
.ce-nav__link:focus-visible { outline: none; box-shadow: var(--ce-focus-ring); }
/* signature: lighthouse-beam underline */
.ce-nav__link::after { content: ""; position: absolute; left: 13px; right: 13px; bottom: 3px; height: 2px;
  border-radius: 2px; background: linear-gradient(90deg, var(--ce-coral), var(--ce-teal));
  transform: scaleX(0); opacity: 0; transition: transform .22s ease, opacity .22s ease;
  box-shadow: 0 0 10px var(--ce-glow-teal); }
.ce-nav__link:hover::after,
.ce-nav__item.is-open > .ce-nav__link::after,
.ce-nav__link.is-active::after,
.ce-nav__item.is-active-parent > .ce-nav__link::after { transform: scaleX(1); opacity: 1; }
.ce-nav__link.is-active, .ce-nav__item.is-active-parent > .ce-nav__link { color: var(--ce-deep); }

/* ---- mega dropdown (left-anchored to its item) ------------------------ */
.ce-mega { position: absolute; top: calc(100% + 10px); left: 0; min-width: 280px; background: #fff;
  border-radius: var(--ce-r-card); box-shadow: var(--ce-shadow-float); border: 1px solid color-mix(in srgb, var(--ce-deep) 8%, transparent);
  padding: 12px; opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(8px);
  transition: opacity .18s ease, transform .18s ease, visibility .18s; z-index: 50;
  max-width: calc(100vw - 32px); }
.ce-mega::before { content: ""; position: absolute; top: -12px; left: 0; right: 0; height: 12px; } /* hover bridge */
.ce-nav__item.is-open .ce-mega { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0); }
.ce-mega__links { display: grid; gap: 2px; }
.ce-mega--grid .ce-mega__links { grid-template-columns: 1fr 1fr; gap: 2px 6px; min-width: 460px; }
.ce-mega--wide { display: grid; grid-template-columns: 1fr 236px; gap: 14px; min-width: 640px; }
.ce-mega--wide .ce-mega__links { grid-template-columns: 1fr 1fr; }
.ce-mega__link { display: flex; align-items: flex-start; gap: 12px; padding: 11px 12px; border-radius: 12px;
  text-decoration: none; color: var(--ce-ink); transition: background .15s ease; }
.ce-mega__link:hover { background: var(--ce-sand); }
.ce-mega__ic { flex-shrink: 0; display: grid; place-items: center; width: 38px; height: 38px; border-radius: 10px;
  background: color-mix(in srgb, var(--ce-teal) 10%, transparent); color: var(--ce-teal); transition: background .15s, color .15s; }
.ce-mega__link:hover .ce-mega__ic { background: var(--ce-coral); color: #fff; }
.ce-mega__ic .ce-ic { width: 18px; height: 18px; }
.ce-mega__txt { display: flex; flex-direction: column; gap: 2px; }
.ce-mega__t { font-weight: 600; font-size: 14.5px; color: var(--ce-deep); }
.ce-mega__d { font-size: 12.5px; color: var(--ce-muted); line-height: 1.35; }
.ce-mega__feature { display: flex; flex-direction: column; justify-content: flex-end; gap: 6px; padding: 18px;
  border-radius: var(--ce-r-card); text-decoration: none; color: #fff; position: relative; overflow: hidden;
  background: linear-gradient(150deg, var(--ce-deep), var(--ce-navy)); }
.ce-mega__feature::after { content: ""; position: absolute; inset: 0;
  background: radial-gradient(140px 90px at 85% 8%, var(--ce-glow-coral), transparent 70%); }
.ce-mega__feature > * { position: relative; }
.ce-mega__eyebrow { font-size: 11px; text-transform: uppercase; letter-spacing: .16em; color: var(--ce-peach); font-weight: 600; }
.ce-mega__ftitle { font-family: var(--ce-font-display); font-size: 20px; line-height: 1.15; }
.ce-mega__ftext { font-size: 12.5px; color: var(--ce-mist); line-height: 1.45; }
.ce-mega__fcta { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; font-size: 13px; color: #fff; margin-top: 4px; }
.ce-mega__fcta .ce-ic { width: 15px; height: 15px; }

/* ---- actions (search + burger) ---------------------------------------- */
.ce-bar__actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.ce-iconbtn { display: grid; place-items: center; width: 42px; height: 42px; border-radius: 12px; border: 0;
  cursor: pointer; background: none; color: var(--ce-deep); transition: background .15s ease, color .15s ease; }
.ce-iconbtn:hover { background: var(--ce-sand); color: var(--ce-ocean); }
.ce-iconbtn:focus-visible { outline: none; box-shadow: var(--ce-focus-ring); }
.ce-iconbtn .ce-ic { width: 20px; height: 20px; }

/* burger — three <i> bars that morph into an X. NOT a swapped-in SVG: replacing
   the icon markup on open detached the tapped node, and the outside-click test
   then read the tap as "outside" and shut the menu in the same tick (the whole
   "the hamburger doesn't work on mobile" bug). pointer-events:none keeps every
   tap on the <button> itself, so no descendant can ever become the target. */
.ce-burger { display: none; color: var(--ce-deep); }
.ce-burger__box { position: relative; display: block; width: 22px; height: 16px; pointer-events: none; }
.ce-burger__box i { position: absolute; left: 0; height: 2px; width: 100%; border-radius: 2px; background: currentColor;
  transition: transform .34s cubic-bezier(.22,1,.36,1), opacity .18s ease, width .3s ease; }
.ce-burger__box i:nth-child(1) { top: 0; }
.ce-burger__box i:nth-child(2) { top: 7px; width: 70%; }
.ce-burger__box i:nth-child(3) { top: 14px; }
.ce-burger:hover .ce-burger__box i:nth-child(2) { width: 100%; }
#site-header.ce-hdr.is-open .ce-burger__box i:nth-child(1) { transform: translateY(7px) rotate(45deg); }
#site-header.ce-hdr.is-open .ce-burger__box i:nth-child(2) { opacity: 0; transform: translateX(-10px); }
#site-header.ce-hdr.is-open .ce-burger__box i:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* sheet-only chrome (mobile menu head + footer) — off on desktop */
.ce-nav__head, .ce-nav__foot { display: none; }

/* ---- search overlay --------------------------------------------------- */
.ce-search { position: fixed; inset: 0; z-index: 2000; }
.ce-search[hidden] { display: none; }
.ce-search__scrim { position: absolute; inset: 0; background: color-mix(in srgb, var(--ce-navy) 62%, transparent);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); opacity: 0; transition: opacity .2s ease; }
.ce-search.is-open .ce-search__scrim { opacity: 1; }
.ce-search__panel { position: relative; width: min(680px, 92vw); margin: 12vh auto 0; background: #fff;
  border-radius: 18px; box-shadow: var(--ce-shadow-float); overflow: hidden; opacity: 0;
  transform: translateY(-14px) scale(.985); transition: transform .22s ease, opacity .22s ease; }
.ce-search.is-open .ce-search__panel { opacity: 1; transform: none; }
.ce-search__bar { display: flex; align-items: center; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--ce-sand); }
.ce-search__mag { width: 22px; height: 22px; color: var(--ce-teal); flex-shrink: 0; }
.ce-search__input { flex: 1; border: 0; outline: none; background: none; font: 500 19px var(--ce-font-body); color: var(--ce-ink); }
.ce-search__close { border: 0; background: var(--ce-sand); color: var(--ce-muted); width: 34px; height: 34px;
  border-radius: 10px; cursor: pointer; display: grid; place-items: center; }
.ce-search__close:hover { color: var(--ce-ink); }
.ce-search__results { max-height: 52vh; overflow: auto; padding: 8px; }
.ce-res__group { font-size: 11px; text-transform: uppercase; letter-spacing: .14em; color: var(--ce-muted);
  font-weight: 600; padding: 12px 12px 6px; }
.ce-res { display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: 12px; text-decoration: none; color: var(--ce-ink); }
.ce-res.is-sel, .ce-res:hover { background: var(--ce-sand); }
.ce-res__ic { flex-shrink: 0; display: grid; place-items: center; width: 36px; height: 36px; border-radius: 10px;
  background: color-mix(in srgb, var(--ce-teal) 10%, transparent); color: var(--ce-teal); }
.ce-res--go .ce-res__ic { background: color-mix(in srgb, var(--ce-coral) 12%, transparent); color: var(--ce-coral); }
.ce-res__ic .ce-ic { width: 18px; height: 18px; }
.ce-res__txt { display: flex; flex-direction: column; min-width: 0; }
.ce-res__t { font-weight: 600; font-size: 14.5px; color: var(--ce-deep); }
.ce-res__d { font-size: 12.5px; color: var(--ce-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ce-search__hint { padding: 12px 18px; border-top: 1px solid var(--ce-sand); font-size: 12px; color: var(--ce-muted); }
.ce-search__hint kbd { font: 600 11px var(--ce-font-body); background: var(--ce-sand); border-radius: 5px; padding: 2px 6px; color: var(--ce-ink); }
.ce-search__didyou { padding: 10px 18px 0; font-size: 12.5px; color: var(--ce-muted); }
.ce-search__didyou b { color: var(--ce-teal); font-weight: 600; }
/* Local-answer rows (area knowledge) — gold accent so they read as "info", distinct from a business. */
.ce-res--info .ce-res__ic { background: rgba(245, 158, 11, .14); color: #d97706; }
/* Scroll lock for the menu sheet + search overlay. `overflow:hidden` alone does
   not hold iOS Safari — the page scrolls behind the overlay and you lose your
   place — so the body is pinned; header-loader.js sets `top:-<scrollY>` and
   restores the position on release. */
body.ce-noscroll { position: fixed; left: 0; right: 0; width: 100%; overflow: hidden; }
/* The fixed bottom app-nav lives in the ROOT stacking context at z-index 9999,
   so it paints OVER the header's sheet no matter what z-index the sheet takes —
   it was covering the last 64px of the menu (and of the search overlay). Drop it
   out of the way while either is open. */
body.ce-noscroll .mobile-bottom-nav { opacity: 0; transform: translateY(100%); pointer-events: none;
  transition: transform .3s cubic-bezier(.22,1,.36,1), opacity .2s ease; }

/* ---- responsive: the mobile MENU SHEET (≤ 1080px) ----------------------
   A full-screen "coastal night" panel, not a side drawer: navy gradient with a
   coral/teal glow, a beam that sweeps the top edge on open, nav rows that
   stagger up, accordion sub-menus, and a one-thumb action footer pinned at the
   bottom. Markup + behavior: js/header-loader.js. ---------------------------- */
@media (max-width: 1080px) {
  /* Historical: the old off-canvas nav parked at translateX(105%) and dragged a
     ~378px horizontal overflow across every page (measured 2026-07-28: scrollWidth
     1300 in a 922px viewport). The sheet no longer translates off-screen, but
     `overflow-x: clip` stays as the cheap guard — it removes overflow WITHOUT
     making html a scroll container, so the sticky header keeps working
     (`hidden` would break it). */
  html, body { overflow-x: clip; }
  .ce-burger { display: grid; }
  .ce-iconbtn { width: 44px; height: 44px; }   /* ≥44px touch target */
  /* one constant height on phones -- the logo does not shrink on scroll here,
     so neither does the bar (it used to drop 64px -> 60px on its own). */
  .ce-bar__in, #site-header.ce-hdr.is-scrolled .ce-bar__in { height: max(64px, calc(var(--ce-logo-h-mob) + var(--ce-logo-pad))); }
  .ce-bar__brand, #site-header.ce-hdr.is-scrolled .ce-bar__brand { height: var(--ce-logo-h-mob); }
  .ce-bar__actions { margin-left: auto; }
  .ce-util__link span { display: none; }       /* icons-only on the slim mobile utility bar */

  /* NO backdrop-filter here. A filtered ancestor becomes the containing block
     for its position:fixed descendants, so the sheet resolved `top:0` against
     the BAR — it opened 125px down the screen and ran 125px off the bottom, and
     its last items were unreachable. Opaque white costs nothing on mobile and
     puts the sheet back on the viewport. */
  .ce-bar { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(255,255,255,.97); }

  .ce-nav { position: fixed; inset: 0; width: 100%; height: 100dvh; margin: 0; z-index: 1500;
    display: flex; flex-direction: column; color: #fff;
    background:
      radial-gradient(115% 55% at 92% -8%, color-mix(in srgb, var(--ce-coral) 26%, transparent), transparent 62%),
      radial-gradient(100% 55% at 0% 106%, color-mix(in srgb, var(--ce-teal) 28%, transparent), transparent 68%),
      linear-gradient(168deg, var(--ce-navy-menu) 0%, var(--ce-navy) 48%, var(--ce-navy-menu-2) 100%);
    opacity: 0; visibility: hidden; pointer-events: none; transform: scale(1.04);
    transition: opacity .28s ease, transform .42s cubic-bezier(.22,1,.36,1), visibility .42s;
    overflow: hidden; }
  #site-header.ce-hdr.is-open .ce-nav { opacity: 1; visibility: visible; pointer-events: auto; transform: none; }
  /* signature: the lighthouse beam sweeps the top edge as the sheet lands */
  .ce-nav::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; z-index: 2;
    background: linear-gradient(90deg, transparent, var(--ce-coral), var(--ce-teal), transparent);
    box-shadow: 0 0 18px var(--ce-glow-teal); transform: scaleX(0);
    transition: transform .7s cubic-bezier(.22,1,.36,1) .08s; }
  #site-header.ce-hdr.is-open .ce-nav::before { transform: scaleX(1); }

  /* --- sheet head: brand chip + close ---------------------------------- */
  .ce-nav__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex: 0 0 auto;
    padding: calc(12px + env(safe-area-inset-top)) 16px 10px; }
  .ce-nav__brand { display: inline-flex; background: #fff; border-radius: 12px; padding: 7px 11px;
    box-shadow: 0 10px 26px rgba(0,0,0,.34); }
  .ce-nav__brand img { display: block; height: 28px; width: auto; }
  .ce-nav__close { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 14px; cursor: pointer;
    color: #fff; background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.16);
    transition: background .18s ease, transform .18s ease; }
  .ce-nav__close:hover { background: rgba(255,255,255,.14); }
  .ce-nav__close:active { transform: scale(.93); }
  .ce-nav__close .ce-ic { width: 22px; height: 22px; }

  /* --- the rows --------------------------------------------------------- */
  .ce-nav__list { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch; flex-direction: column; align-items: stretch; gap: 6px;
    padding: 6px 16px 20px; }
  .ce-nav__item { opacity: 0; transform: translateY(18px);
    transition: opacity .4s ease, transform .5s cubic-bezier(.22,1,.36,1); }
  #site-header.ce-hdr.is-open .ce-nav__item { opacity: 1; transform: none;
    transition-delay: calc(var(--i, 0) * 45ms + 110ms); }   /* stagger */
  .ce-nav__link { position: relative; justify-content: space-between; width: 100%; overflow: hidden;
    text-transform: none; letter-spacing: .01em; color: var(--ce-menu-ink); font: 600 18px/1.25 var(--ce-font-body);
    padding: 16px 15px 16px 18px; border-radius: 14px;
    background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.09); }
  .ce-nav__link::after { display: none; }
  .ce-nav__link::before { content: ""; position: absolute; left: 0; top: 13px; bottom: 13px; width: 3px;
    border-radius: 0 3px 3px 0; background: linear-gradient(180deg, var(--ce-coral), var(--ce-teal));
    box-shadow: 0 0 12px var(--ce-glow-coral); opacity: 0; transform: scaleY(.3);
    transition: opacity .22s ease, transform .3s cubic-bezier(.22,1,.36,1); }
  .ce-nav__item.is-open > .ce-nav__link::before,
  .ce-nav__link.is-active::before,
  .ce-nav__item.is-active-parent > .ce-nav__link::before { opacity: 1; transform: scaleY(1); }
  .ce-nav__link:hover, .ce-nav__link.is-active,
  .ce-nav__item.is-active-parent > .ce-nav__link { color: #fff; background: rgba(255,255,255,.1); }
  .ce-nav__item.is-open > .ce-nav__link { background: rgba(255,255,255,.1); }
  .ce-nav__link:active { transform: scale(.99); }
  .ce-nav__caret { width: 20px; height: 20px; opacity: .65; }

  /* --- accordion sub-menu ----------------------------------------------- */
  .ce-mega { position: static; transform: none !important; opacity: 1; visibility: visible; pointer-events: auto;
    background: none; box-shadow: none; border: 0; padding: 0; min-width: 0 !important; max-width: none;
    display: block; max-height: 0; overflow: hidden; transition: max-height .36s cubic-bezier(.4,0,.2,1); }
  .ce-mega::before { display: none; }
  .ce-nav__item.is-open .ce-mega { max-height: 1200px; }
  .ce-mega__links { padding: 8px 0 2px 10px; gap: 2px; }
  .ce-mega--wide, .ce-mega--grid .ce-mega__links, .ce-mega--wide .ce-mega__links { grid-template-columns: 1fr !important;
    min-width: 0 !important; display: block; }
  .ce-mega__link { align-items: center; gap: 12px; padding: 10px; border-radius: 12px; color: var(--ce-mist); }
  .ce-mega__link:hover, .ce-mega__link:active { background: rgba(255,255,255,.07); }
  .ce-mega__ic { width: 36px; height: 36px; background: color-mix(in srgb, var(--ce-teal) 18%, transparent); color: var(--ce-teal-ice);
    border: 1px solid rgba(255,255,255,.08); }
  .ce-mega__ic .ce-ic { width: 17px; height: 17px; }
  .ce-mega__link:hover .ce-mega__ic { background: var(--ce-coral); color: #fff; }
  .ce-mega__t { color: #fff; font-size: 15px; }
  .ce-mega__d { color: color-mix(in srgb, var(--ce-mist) 62%, transparent); font-size: 12.5px; }
  .ce-mega__feature { margin: 10px 0 4px 10px; padding: 16px;
    background: linear-gradient(150deg, rgba(255,255,255,.12), rgba(255,255,255,.03));
    border: 1px solid rgba(255,255,255,.14); }

  /* --- action footer (thumb zone) --------------------------------------- */
  .ce-nav__foot { display: grid; gap: 10px; flex: 0 0 auto;
    padding: 12px 16px calc(14px + env(safe-area-inset-bottom));
    border-top: 1px solid rgba(255,255,255,.1); background: rgba(4,12,24,.4);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    opacity: 0; transform: translateY(12px);
    transition: opacity .4s ease .22s, transform .45s cubic-bezier(.22,1,.36,1) .22s; }
  #site-header.ce-hdr.is-open .ce-nav__foot { opacity: 1; transform: none; }
  .ce-nav__acts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .ce-nav__act { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
    padding: 12px 6px; border-radius: 14px; cursor: pointer; text-decoration: none; color: var(--ce-mist-soft);
    background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.11);
    font: 600 11.5px/1 var(--ce-font-body); letter-spacing: .07em; text-transform: uppercase;
    transition: background .18s ease, border-color .18s ease, transform .18s ease; }
  .ce-nav__act .ce-ic { width: 19px; height: 19px; color: var(--ce-teal-ice); }
  .ce-nav__act:hover { background: rgba(255,255,255,.12); border-color: rgba(122,211,224,.4); }
  .ce-nav__act:active { transform: scale(.96); }
  .ce-nav__hours { margin: 0; display: flex; align-items: center; justify-content: center; gap: 7px;
    font-size: 12.5px; color: var(--ce-peach); }
  .ce-nav__hours .ce-ic { width: 14px; height: 14px; }
  .ce-nav__meta { display: flex; align-items: center; justify-content: center; gap: 10px; }
  .ce-nav__meta .ce-util__soc { width: 40px; height: 40px; background: rgba(255,255,255,.07);
    border: 1px solid rgba(255,255,255,.11); }
  .ce-nav__meta .ce-util__soc .ce-ic { width: 17px; height: 17px; }
  .ce-nav__meta .ce-lang { padding: 9px 15px; font-size: 12.5px; }
}
@media (max-width: 400px) {
  .ce-nav__link { font-size: 17px; padding: 14px 13px 14px 16px; }
  .ce-nav__act { font-size: 10.5px; letter-spacing: .05em; }
}
@media (max-width: 560px) {
  .ce-util__in, .ce-bar__in { padding-left: 16px; padding-right: 16px; }
  .ce-util__hours span { font-size: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  #site-header.ce-hdr *, .ce-search, .ce-search * { transition: none !important; }
}

/* ============================================================================
   Motion primitives — spotlight · tilt · sheen · count-up
   Lifted from the cluster's **ui-foundry** component gallery
   (http://192.168.8.101:38420/gallery.html § Motion tricks) so we use the house
   implementations instead of re-inventing them. Its own summary is the brief:
   "cheap effects that make an interface read as expensive".

   All are OPT-IN by class and inert until used. Behaviour lives in coastal.js
   (CE.motion, auto-initialised). Every one is disabled under reduced motion.
   ========================================================================== */

/* --- spotlight: a radial highlight that follows the cursor ---------------- */
/* Host needs position:relative + overflow:hidden. --mx/--my written by JS.    */
.ce-spot { position: relative; }
.ce-spot::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0; z-index: 0;
  /* follow the host's corners — otherwise the radial squares off the rounded card.
     `border-radius: inherit` beats putting overflow:hidden on .ce-spot, which would
     clip anything a card deliberately hangs outside itself. */
  border-radius: inherit;
  transition: opacity .3s ease;
  background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%),
              color-mix(in srgb, var(--ce-coral-hot) 20%, transparent), transparent 65%);
}
.ce-spot:hover::before { opacity: 1; }
.ce-spot > * { position: relative; z-index: 1; }

/* --- 3D tilt: wrapper tracks the pointer, child rotates ------------------- */
/* Markup: <div class="ce-tilt-wrap"><div class="ce-tilt">…</div></div>       */
.ce-tilt-wrap { perspective: 900px; }
.ce-tilt { transition: transform .12s linear, box-shadow .3s ease;
  transform-style: preserve-3d; will-change: transform; }
/* anything marked .ce-pop lifts off the card face as it tilts (parallax)     */
.ce-tilt .ce-pop { transform: translateZ(34px); }

/* --- sheen: a light sweep across the surface on hover --------------------- */
.ce-sheen { position: relative; overflow: hidden; }
.ce-sheen::after {
  content: ''; position: absolute; top: -50%; bottom: -50%; left: -70%; width: 45%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .16), transparent);
  transform: skewX(-22deg); pointer-events: none;
}
.ce-sheen:hover::after { animation: ce-sweep .75s cubic-bezier(.2, .7, .2, 1); }
@keyframes ce-sweep { to { left: 130%; } }

/* --- count-up: reserve the digits' width so the layout can't jump --------- */
.ce-count { font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .ce-spot::before { transition: none; }
  .ce-tilt { transition: none; }
  .ce-sheen:hover::after { animation: none; }
}

/* --- skip link: visually hidden until focused (WCAG 2.4.1 bypass blocks) ----
   Hidden by CLIPPING, not by parking it at a negative offset. `top: -60px`
   quietly assumed this link's containing block began at the top of the viewport
   — but the containing block is #site-header (position:sticky establishes one),
   and whenever the announcement bar is running the header starts 70px down. So
   -60px resolved to y=10 and the link sat permanently on top of the announcement
   bar, on every page, for every visitor (reported from the field 2026-08-13:
   34px of overlap, measured). It only looked correct while no announcement was
   live and the header sat at y=0, which is why it shipped.
   A clip cannot drift: it hides the link wherever the header happens to be, and
   the link stays focusable and in the accessibility tree — which is the entire
   point of a bypass-blocks link. Do NOT "fix" this back to an offset, and do not
   delete it: accessibility.html publicly commits this site to WCAG 2.1 AA, and
   2.4.1 is a Level A prerequisite of that claim. */
.ce-skip { position: absolute; left: 8px; top: 0; z-index: 2000;
  background: var(--ce-deep); color: #fff; padding: 10px 16px; border-radius: 0 0 10px 10px;
  font: 700 14px/1 var(--ce-font-body); text-decoration: none;
  clip-path: inset(50%); }
/* No transition to disable any more, so the prefers-reduced-motion rule that
   used to sit here went with the offset — the reveal is now instant. */
.ce-skip:focus { clip-path: none; outline: 3px solid var(--ce-peach); outline-offset: 2px; }

/* ============================================================================
   COLLECTIBLE TRADING CARDS (.ce-tcard) — MOVED to css/ce-card.css 2026-08-28.

   Not deleted, not duplicated: the member portal needs the card but cannot load
   this file (two :root blocks here, 11 tokens collide with the admin palette and
   re-tint the whole portal). So the card became independently linkable.

   Every surface that draws a card must link css/ce-card.css itself —
   coastal.css no longer carries it. Renderer is still CE.memberCard() in
   js/coastal.js, which is unchanged.
   ========================================================================== */

/* ============================================================================
   TABS (.ce-tabs) — one tab primitive for the whole project.
   Promoted from the music player's `mp-tabs`, which was a hardcoded two-button
   row with bespoke switch logic per element. Anything that needs tabs uses this;
   do not write a third one. (The music player still runs its own copy — it works,
   and rewriting a live shared component for tidiness alone is not worth the risk.)

   Markup contract — CE.tabs() wires it, no per-page JS:
     <div class="ce-tabs" role="tablist">
       <button class="ce-tab" role="tab" data-panel="deck">Deck</button> …
     </div>
     <div data-ce-panel="deck"> … </div>

   Colours come from --ce-tab-* so a dark surface (the walk book) and a light one
   (the site) both work without forking the component.
   ========================================================================== */
.ce-tabs {
  display: flex; gap: 6px; margin: 16px 0 12px; overflow-x: auto; min-width: 0;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.ce-tabs::-webkit-scrollbar { display: none; }
.ce-tab {
  flex: 1 0 auto; min-width: 0; padding: 9px 14px; border: 0; cursor: pointer;
  border-radius: var(--ce-r-pill); font: 600 13px/1 var(--ce-font-body);
  background: var(--ce-tab-bg, rgba(255, 255, 255, .07));
  color: var(--ce-tab-fg, var(--ce-tab-dim));
  display: flex; align-items: center; justify-content: center; gap: 6px;
  white-space: nowrap; transition: background .15s, color .15s;
}
/* `display:flex` above beats the [hidden] attribute's display:none, so a tab
   hidden in markup rendered anyway — the empty "Yours" tab showed for a player
   who had never uploaded. */
.ce-tab[hidden] { display: none; }
.ce-tab:hover { color: var(--ce-tab-fg-hover, var(--ce-tab-lit)); }
.ce-tab[aria-selected="true"] {
  background: var(--ce-tab-on-bg, var(--ce-teal)); color: var(--ce-tab-on-fg, #fff);
}
.ce-tab:focus-visible { outline: none; box-shadow: var(--ce-focus-ring); }
/* count badge — the reason a tab is worth opening */
.ce-tab i {
  font-style: normal; font-size: 11px; font-weight: 700; padding: 1px 6px;
  border-radius: var(--ce-r-pill); background: rgba(0, 0, 0, .22);
}
.ce-tab[aria-selected="true"] i { background: rgba(255, 255, 255, .22); }
/* a tab wearing a dot has something new behind it */
.ce-tab--new::after {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--ce-coral-hot); flex: 0 0 auto;
}
@media (prefers-reduced-motion: reduce) { .ce-tab { transition: none; } }


/* ============================================================================
   AUTHOR PROSE — the shapes CEmd.html() can emit (js/utils/markdown.js).
   ONE home for all three cinematic detail pages (event / member / attraction);
   each of them already carries `.about .body{font-size;line-height;color}` and
   `.about .body p{margin}` inline, and this only adds the shapes those two rules
   never anticipated. Keep it to what the renderer can actually produce — every
   selector below maps to a marker a director can type, and nothing else.
   ========================================================================== */
.about .body h3, .about .body h4 {
  color: #fff; line-height: 1.3; margin: 30px 0 12px; font-weight: 700;
}
.about .body h3 { font-size: 1.28em; }
.about .body h4 { font-size: 1.1em; }
.about .body > :first-child { margin-top: 0; }
.about .body ul, .about .body ol { margin: 0 0 18px; padding-left: 1.35em; }
.about .body li { margin: 0 0 8px; }
.about .body li::marker { color: var(--ce-coral-hot); }
/* Default link blue is unreadable on the ocean-navy these pages are built on. */
.about .body a {
  color: var(--ce-coral-hot); text-decoration: underline;
  text-underline-offset: 2px; text-decoration-thickness: 1px;
}
.about .body a:hover { color: #fff; }
.about .body a:focus-visible { outline: none; box-shadow: var(--ce-focus-ring); border-radius: 2px; }
.about .body strong { color: #fff; font-weight: 700; }
.about .body blockquote {
  margin: 0 0 18px; padding: 2px 0 2px 18px;
  border-left: 3px solid var(--ce-teal); color: var(--ce-mist-4, inherit);
}
.about .body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .9em; padding: 1px 5px; border-radius: var(--ce-r-sm, 4px);
  background: rgba(255, 255, 255, .09);
}
.about .body hr {
  border: 0; height: 1px; margin: 26px 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .28), transparent);
}
