/* ============================================================
   cebutravelguide.com - Phase 3 Design System
   IDENTITY: "Mangrove Green and Lechon Amber"
   A dark mangrove green (the brand/structural colour, after Cebu's mangrove-lined coastline) and
   a warm lechon amber accent (after the roasted-pork skin colour Cebu is famous for), on a warm
   sand-paper ground. Approved by Oleg at the Phase C gate, 2026-09-25 (research/layout-approval.md).
   Support tokens are DERIVED from the approved cores by build/lib/palette-apply.mjs,
   which measures every contrast pair and refuses to write when one misses its floor.
   ============================================================ */
/* ---- COLOR TOKENS (light, purposeful) ---- */
:root {
  /* ---- Palette "MANGROVE GREEN AND LECHON AMBER" (research/layout-approval.md; approved by
     Oleg at the Phase C gate 2026-09-25, verbatim answer "Mangrove Green + Lechon Amber").
     The ground is a warm sand paper, the brand is a dark mangrove green (Cebu's coastal
     mangroves), the accent is a golden lechon amber (roast-pork skin, a Cebu icon, CTA only).
     The APPROVED values are fixed; everything else in this block is DERIVED from them, and
     build/check-contrast.mjs recomputes every ratio and fails the build, so it is the gate:

       --paper   #F2ECD9  page ground            --paper-2 #E9DFC4  alt band
       --ink     #1A2420  body text               --ink-soft #4B5850 muted text
       --brand   #19571B  links, structure (8.68:1 on --paper, white on it 8.68:1)
       --accent  #816A0E  CTA, white text (5.25:1 on white)

     COLLISION CHECK (build/D1a, 2026-09-25) against the 6 most recent city-guide siblings'
     :root primaries (ljubljanatravelguide #245C4B/#9E3B2F, freiburgtravelguide #1F3B2D/#9E3B2E,
     nantestravelguide #19571B/#816A0E, santiagodecompostelatravelguide #2F4A3A/#A15420,
     timisoaratravelguide #7A5D12/#0A7A6D, coimbratravelguide #2B3A55/#96601C): every sibling
     brand/accent hue is >=15deg from these two (measured in HSL; nearest brand neighbour is
     santiagodecompostela's moss green at 22deg away, nearest accent neighbour is coimbra's
     bronze at 15deg away, both at materially different saturation/lightness). Full working
     recorded in research/PHASE-D1A.md.

     A PALETTE SWAP TOUCHES THREE LAYERS: these tokens, the .band-* definitions further down, and
     the rgb TRIPLETS inside rgba() calls, which a hex sweep cannot see. This swap patched token
     VALUES only, by exact value, and asserted what SURVIVED: the same count of declared tokens
     before and after, and five distinct band grounds. SCRIMS ARE BUILT FROM A FIXED DARK
     (14,22,28), never from --ink. ---- */
  --ink:        #1A2420;   /* APPROVED - primary text */
  --ink-soft:   #4B5850;   /* APPROVED - muted text */
  --paper:      #F2ECD9;   /* APPROVED - page ground: warm sand */
  --paper-2:    #E9DFC4;   /* APPROVED - alt band and raised panels */
  --surface:    #FFFFFF;   /* cards */
  --surface-2:  #F6F1E5;   /* derived: inputs, one step off --paper */
  --line:       #DACD9E;   /* derived: hairline borders on light */
  --brand:      #19571B;   /* APPROVED - mangrove green: links, structural text */
  --brand-bright:#2E7A2E;  /* derived: lifted green for FILLS ON LIGHT */
  --signature:  #B89A2E;   /* derived: gilt lechon-amber wash. DARK BANDS ONLY, NEVER TEXT ON
                              LIGHT (2.6:1 on --paper; well over 4.5:1 on the inverse band, where
                              it is the link colour). */
  --brand-deep: #12351A;   /* derived: nav/footer fills, the inverse band ground */
  --accent:     #816A0E;   /* APPROVED - lechon amber, CTA (white text) */
  --accent-warm:#9C8020;   /* derived: lifted amber, wash and hover ONLY */
  --accent-deep:#5E4C09;   /* derived: CTA hover */
  --accent-ink: #FFFFFF;   /* text colour that sits on --accent */
  --gold:       #77590E;   /* derived: REAL RATINGS ONLY. Darkened at the contrast gate: #8C6D12
                              cleared --paper (4.5+:1) but missed on the zebra-striped compare-table
                              row (#F5F1E4) at 4.31:1, bold 14.72px text does not meet the "large
                              text" size threshold. 5.5-5.8:1 on both grounds now. */
  --gold-soft:  #DCC989;   /* derived: amber wash for badge backgrounds (DARK text on top) */
  --gold-ink:   #211A05;
  /* CANONICAL ALIASES required by build/lib/palette-apply.mjs. The tool derives a fixed token set
     (sea, sea-deep, slate, footer, gold-light, gold-deep, focus) and refuses to write unless every
     one is declared in :root, so each is seeded with the value of the sibling token it aliases. */
  --sea:        #B89A2E;   /* alias of --signature */
  --focus:      #19571B;   /* alias of --brand, referenced by the focus ring */
  --sea-deep:   #2E7A2E;   /* alias of --brand-bright */
  --slate:      #4B5850;   /* alias of --ink-soft */
  --footer:     #12351A;   /* alias of --brand-deep */
  --gold-light: #DCC989;   /* alias of --gold-soft */
  --gold-deep:  #211A05;   /* alias of --gold-ink */
  /* map base, derived: Cebu is a real coastal island province, not the donor's inland river
     city, so the water reads as tropical sea, not a canal. (The basemap GEOMETRY itself, i.e.
     drawing real coastline polygons, is tracked separately as a PENDING item in
     build/preflight.sh COASTAL_FLAGS; this is the colour tokens only.) */
  --map-sea:    #6E9BB0;   /* derived: tropical sea blue-teal */
  --map-land:   #E9E0C5;   /* derived: pale sand, matches --paper-2 */
  --map-shore:  #19571B;   /* derived: --brand, for the shoreline */
  --ok:         #19571B;   /* derived: same hue as --brand */
  --warn:       #9A4213;   /* derived: warm warn red-orange, distinct hue from --accent */

  /* ---- TYPE - assertive sans display + neutral sans body. System stacks, no webfont
     (protects LCP); contrast comes from weight and scale, an editorial feel. ---- */
  --display: "Helvetica Neue", "Segoe UI", system-ui, Arial, sans-serif;
  --body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* modular scale */
  --step--1: clamp(.83rem, .8rem + .15vw, .92rem);
  --step-0:  clamp(1rem, .96rem + .2vw, 1.12rem);
  --step-1:  clamp(1.2rem, 1.1rem + .5vw, 1.5rem);
  --step-2:  clamp(1.45rem, 1.25rem + 1vw, 2.1rem);
  --step-3:  clamp(1.85rem, 1.5rem + 1.8vw, 3.1rem);
  --step-4:  clamp(2.4rem, 1.8rem + 3vw, 4.4rem);

  /* spacing scale */
  --s1:.4rem; --s2:.7rem; --s3:1.1rem; --s4:1.7rem; --s5:2.6rem; --s6:4rem; --s7:6rem;
  --maxw: 72rem;
  /* soft-square: reads kitchen-clean, not scenic-rustic */
  --radius: 8px;
  --radius-sm: 5px;
  --shadow: 0 1px 2px rgba(28,22,14,.05), 0 10px 28px rgba(28,22,14,.09);
}

/* ---- RESET-ISH ---- */
*,*::before,*::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: var(--body); font-size: var(--step-0); line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: var(--brand); text-underline-offset: 3px; }
h1,h2 { font-family: var(--display); line-height: 1.05; letter-spacing: -.025em; font-weight: 800; margin: 0 0 var(--s3); color: var(--ink); }
h3 { font-family: var(--display); line-height: 1.2; letter-spacing: -.01em; font-weight: 700; margin: 0 0 var(--s3); color: var(--ink); }
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); margin-top: var(--s6); }
h3 { font-size: var(--step-1); margin-top: var(--s4); }
p { margin: 0 0 var(--s3); max-width: 64ch; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* ---- LAYOUT ---- */
.wrap { width: min(100% - 2rem, var(--maxw)); margin-inline: auto; }
.wrap-narrow { width: min(100% - 2rem, 50rem); margin-inline: auto; }
.section { padding-block: var(--s6); }
.section + .section { padding-top: 0; }
.skip-link { position:absolute; left:-999px; top:0; background:var(--brand); color:var(--accent-ink); padding:.6rem 1rem; z-index:50; font-weight:700; }
.skip-link:focus { left:8px; top:8px; }

/* ---- CTA ---- */
.btn {
  display:inline-flex; align-items:center; gap:.5rem; justify-content:center;
  font-family: var(--display); font-weight:700; font-size: var(--step-0);
  padding: .85rem 1.4rem; border-radius: 999px; text-decoration:none; border:0; cursor:pointer;
  min-height: 48px; transition: transform .08s ease, background .15s ease;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color:var(--accent-ink); }
.btn-primary:hover { background: var(--accent-deep); color:var(--accent-ink); }
.btn-brand { background: var(--brand); color:var(--accent-ink); }
.btn-brand:hover { background: var(--brand-deep); }
.btn-ghost { background: transparent; color: var(--ink); border:2px solid var(--line); }
.btn-ghost:hover { border-color: var(--ink-soft); }

/* ---- HEADER / NAV ---- */
.site-header { position: sticky; top:0; z-index:40; background: rgba(242,236,217,.9); backdrop-filter: blur(10px); border-bottom:1px solid var(--line); }
/* HAND PATCH (contrast gate): the rgba() above is a literal, never inverted by prefers-color-scheme,
   so a dark-mode visitor got near-white nav text (var(--ink), correctly inverted) sitting on a
   header background frozen at the light sand colour: the single most visible defect on the site,
   present on every page from first paint. Pinned to --paper dark (#141C13) at the same opacity. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-header { background: rgba(20,28,19,.9); }
}
:root[data-theme="dark"] .site-header { background: rgba(20,28,19,.9); }
/* NAV SIZING (rebuilt 2026-09-09). The previous pass added `white-space:nowrap` and stopped
   there. Measured over HTTP, that fix was treating the wrong thing: nowrap keeps a LABEL off a
   second line, but it cannot keep the ROW inside the content column, and the row had no room
   left. At 1440/1360/1280 the brand (326px) plus the ten items (810px) plus the gap came to
   exactly 1152px in a 1152px column: SLACK = 0. At 1100 it was -39px and at 1024 it was -105px,
   which pushed real horizontal page scroll (documentElement.scrollWidth 1114 on a 1024 viewport).
   With zero slack, anything that widens the row by a few pixels (browser zoom, a wider fallback
   face before the display font settles, a longer label) tips it over, which is what the
   screenshot shows. The old 1023px collapse point made it worse: the row already failed at
   about 1150px, so 1024-1150 was a dead zone, too narrow for the row and too wide for the menu.

   The row is now sized to FIT with real slack instead of being told not to wrap:
   the brand and the link type scale down between 1024 and 1440, the inter-item gap is fluid,
   the nav CTA is a compact pill rather than a full-size button, the brand never shrinks below
   its own text (so it can no longer be squeezed into the links), and the collapse point moved
   to 1023px only because the row genuinely fits from 1024 up now. Verified at 1024-1600 in 8px
   steps: minimum slack 44px. nowrap stays as a second line of defence. */
.nav { display:flex; align-items:center; justify-content:space-between; gap:clamp(.75rem, 1.4vw, 1.5rem); padding-block:.7rem; flex-wrap:nowrap; }
.brand { font-family:var(--display); font-weight:800; font-size:clamp(1.02rem, .62rem + .62vw, 1.35rem); color:var(--ink); text-decoration:none; letter-spacing:-.02em; display:inline-flex; align-items:center; gap:.45rem; flex:0 0 auto; white-space:nowrap; }
.brand-logo { width:28px; height:28px; border-radius:7px; display:block; flex:0 0 auto; }
.brand b { color: var(--brand); }
.nav-links { display:flex; gap:clamp(.62rem, .12rem + .78vw, 1.2rem); align-items:center; list-style:none; margin:0; padding:0; flex:0 1 auto; min-width:0; }
/* nowrap: "Day Trips" broke onto a second line at 1440 and pushed the whole row out of
   alignment, on all 398 pages. A nav label is never a wrapping phrase. */
.nav-links li { white-space:nowrap; flex:0 0 auto; }
.nav-links a { color:var(--ink); text-decoration:none; font-weight:600; font-size:clamp(.8rem, .68rem + .19vw, .92rem); white-space:nowrap; }
.nav-links a:hover { color:var(--brand); }
.nav-links a.btn-brand { color:var(--accent-ink); }
.nav-links a.btn-primary { color:var(--accent-ink); }
/* The shortlist pill was 159x51 in a row with no room to give. It stays the only filled target
   in the header, just sized for a nav bar rather than for a page body. */
.nav-links .btn { padding:.5rem clamp(.62rem, .2rem + .62vw, 1.05rem); min-height:0; border-radius:9px; line-height:1.15; }
.nav-toggle { display:none; background:none; border:0; font-size:1.6rem; min-height:48px; min-width:48px; cursor:pointer; color:var(--ink); }
/* Below 1024 the row cannot fit at any honest type size, so it becomes the menu. */
@media (max-width: 1023px) {
  .nav-toggle { display:block; }
  .nav-links { position:absolute; inset:100% 0 auto 0; flex-direction:column; align-items:flex-start; background:var(--paper-2); border-bottom:1px solid var(--line); padding:1rem; gap:1rem; display:none; }
  .nav-links[data-open="true"] { display:flex; }
  /* In the collapsed menu the links were 18px-tall tap targets. */
  .nav-links a { font-size:1rem; display:flex; align-items:center; min-height:44px; width:100%; }
  .nav-links .btn { padding:.7rem 1.1rem; justify-content:center; }
}
/* Belt and braces: even if a future nav item overruns the budget, the header clips instead of
   giving all 398 pages a horizontally scrolling body. */
.site-header { overflow-x: clip; }

/* ---- HTML SITEMAP: 398 links, so they read as columns rather than one long ribbon ---- */
.sitemap-list { list-style:none; margin:0 0 var(--s5); padding:0; columns: 2; column-gap: var(--s5); }
.sitemap-list li { break-inside:avoid; margin:0 0 .35rem; font-size:var(--step--1); line-height:1.45; }
.sitemap-list a { color:var(--ink); text-decoration:none; }
.sitemap-list a:hover { color:var(--brand); text-decoration:underline; }
@media (max-width: 640px) { .sitemap-list { columns: 1; } }

/* ---- BREADCRUMB ---- */
.crumbs { font-size: var(--step--1); color: var(--ink-soft); padding-block: var(--s3); }
.crumbs a { color: var(--ink-soft); }
.crumbs span[aria-current] { color: var(--ink); font-weight:600; }

/* ---- HERO: FULL-SCREEN BACKGROUND (this site's first screen, approved 2026-07-25:
        blue ice glittering on black sand, headline overlaid) ---- */
/* Vertically CENTRED, not bottom-anchored (Oleg, 2026-09-09). `align-items:flex-end` pinned the
   headline, the lede, the proof line and the shortlist button to the bottom edge of an 88svh
   band, leaving a large empty stripe under the header and putting the CTA within a few pixels of
   the fold. Centring moves the whole block up: at 390 the button's bottom goes from 676px to
   about 565px in an 844px viewport, so it clears the fold by a wider margin than before. */
.hero-full {
  min-height: 88svh;
  background-size: cover; background-position: center;
  display: flex; align-items: center;
  color: #fff;
  border-bottom: 3px solid var(--accent);
}
/* The padding that used to hold the copy off the bottom edge would now bias a centred block
   downwards, so it is balanced. */
.hero-full .hero-inner { padding-block: var(--s6); }
.hero-full-inner { padding-block: var(--s7) var(--s6); }
.hero-full h1 { color: #fff; max-width: 21ch; }
.hero-full .lede { color: rgba(255,255,255,.9); max-width: 56ch; font-size: var(--step-1); }
.hero-full .author-hook { color: rgba(255,255,255,.85); display:flex; align-items:center; gap:.6rem; font-size:var(--step--1); margin: var(--s3) 0 var(--s4); }
.hero-full .author-hook a { color: #fff; }
.hero-full .author-hook img { width:38px; height:38px; border-radius:50%; object-fit:cover; border:2px solid rgba(255,255,255,.5); }
.hero-full-ghost { color:#fff; border-color: rgba(255,255,255,.55); }
.hero-full-ghost:hover { border-color:#fff; }
.hero-full .cta-proof { color: rgba(255,255,255,.92); }
.hero-full .cta-proof .gold { color:#96BAF0; }
.hero-cta { margin: var(--s3) 0 0; }
/* 72svh, not 78: on a 390px screen the hero used most of the first screen and the shortlist CTA
   still fell below it. */
@media (max-width: 640px) { .hero-full { min-height: 72svh; background-position: 64% center !important; } .hero-cta .btn-xl { width:100%; text-align:center; } }

/* ---- HERO (money) - asymmetric split ---- */
.hero { display:grid; grid-template-columns: 1.15fr .85fr; gap: var(--s5); align-items:center; padding-top: var(--s5); }
/* this site's signature: media on the LEFT, taller than wide never; text column right */
.hero--flip { grid-template-columns: .9fr 1.1fr; }
.hero--flip .hero-media { order:-1; }
.eyebrow { font-family:var(--display); text-transform:uppercase; letter-spacing:.14em; font-size:var(--step--1); color:var(--gold); font-weight:700; margin-bottom:var(--s2); }
.hero h1 { margin-bottom: var(--s3); }
.hero .author-hook { display:flex; align-items:center; gap:.6rem; font-size:var(--step--1); color:var(--ink-soft); margin-bottom:var(--s4); }
.hero .author-hook img { width:38px; height:38px; border-radius:50%; object-fit:cover; border:2px solid var(--line); }
.hero-media { aspect-ratio:16/9; border-radius:var(--radius); overflow:hidden; background:var(--surface); box-shadow:var(--shadow); }
.hero-media img { width:100%; height:100%; object-fit:cover; }
@media (max-width: 820px){ .hero{ grid-template-columns:1fr; align-items:start; } .hero--flip .hero-media { order:0; } }

/* ---- QUICK ANSWER (answer-first) ---- */
.quick-answer { background: var(--surface); border:1px solid var(--line); border-left:5px solid var(--accent); color: var(--ink); border-radius: var(--radius); padding: var(--s4) var(--s5); margin-top: var(--s5); box-shadow: var(--shadow); }
.quick-answer p { color:var(--ink); font-size: var(--step-1); max-width: 60ch; margin:0; }
.quick-answer .qa-label { font-family:var(--display); text-transform:uppercase; letter-spacing:.14em; font-size:.72rem; color:var(--gold); margin-bottom:var(--s2); font-weight:700; }

/* ---- KEY FACTS TABLE ---- */
.keyfacts { width:100%; border-collapse:collapse; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; }
.keyfacts th, .keyfacts td { text-align:left; padding:.8rem 1rem; border-bottom:1px solid var(--line); vertical-align:top; }
.keyfacts th { font-family:var(--display); font-weight:700; color:var(--ink); background:var(--paper-2); }
/* width:42% IS A TWO-COLUMN RULE (city-guide skill §11b, defect 6). Applied to every .keyfacts
   table it starves the last column of a wider one until a sentence wraps roughly one word per
   line and the row grows to ~380px tall. build/qa-layout.py measures that and fails the deploy,
   which is the right backstop but a late one: the cause is here, so it is fixed here.
   Scoped with :has() to rows that genuinely have ONE data cell. Where :has() is unsupported the
   rule simply does not apply and the browser sizes the columns automatically, which is the safe
   direction to fail: no starvation, just a less deliberate label column. */
.keyfacts tr:not(:has(td ~ td)) th { width:42%; }
.keyfacts tr:last-child th, .keyfacts tr:last-child td { border-bottom:0; }
@media (max-width:640px){
  .keyfacts { display:block; overflow-x:auto; -webkit-overflow-scrolling:touch; }
  .keyfacts th { min-width: 9rem; }
}

/* ---- PRODUCT CARD (money component) ---- */
.product-card { display:grid; grid-template-columns: 1fr 1.2fr; gap:0; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; box-shadow:var(--shadow); }
.product-card .pc-media { background:var(--paper-2); overflow:hidden; }
.product-card .pc-media img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.product-card .pc-body { padding: var(--s4); display:flex; flex-direction:column; gap:var(--s2); }
.pc-tag { align-self:flex-start; background:var(--gold-soft); color:var(--gold-ink); font-weight:700; font-size:.72rem; text-transform:uppercase; letter-spacing:.06em; padding:.25rem .6rem; border-radius:999px; }
.pc-rating { font-weight:700; color:var(--ink); display:flex; align-items:center; gap:.45rem; flex-wrap:wrap; }
.pc-rating .src { font-weight:500; color:var(--ink-soft); font-size:var(--step--1); }

/* ---- STAR RATING (dependency-free) - set fill width inline: ratingValue/5*100% ---- */
.stars { position:relative; display:inline-block; vertical-align:middle; line-height:1; white-space:nowrap; font-size:1.05em; }
.stars::before { content:"★★★★★"; color:var(--line); letter-spacing:2px; }
.stars .stars-fill { position:absolute; top:0; left:0; overflow:hidden; white-space:nowrap; }
.stars .stars-fill::before { content:"★★★★★"; color:var(--gold); letter-spacing:2px; }
.stars-num { font-weight:700; color:var(--ink); }
.trust .stars { font-size:1.15rem; margin-top:.2rem; }
.pc-price { font-family:var(--display); font-size:var(--step-2); font-weight:800; color:var(--ink); }
.pc-price small { font-size:var(--step--1); color:var(--ink-soft); font-weight:500; }
@media (max-width:680px){ .product-card{ grid-template-columns:1fr; } .product-card .pc-media{ aspect-ratio:4/3; } }

/* ---- PRICING & INCLUSIONS ---- */
.incl { display:grid; grid-template-columns:1fr 1fr; gap:var(--s4); }
.incl ul { list-style:none; padding:0; margin:0; }
.incl li { padding:.35rem 0 .35rem 1.6rem; position:relative; }
.incl .yes::before { content:"✓"; position:absolute; left:0; color:var(--ok); font-weight:800; }
.incl .no::before  { content:"✕"; position:absolute; left:0; color:var(--brand); font-weight:800; }
@media (max-width:600px){ .incl{ grid-template-columns:1fr; } }

/* ---- ITINERARY ---- */
.timeline { list-style:none; margin:0; padding:0; border-left:3px solid var(--line); }
.timeline li { position:relative; padding:0 0 var(--s4) var(--s4); }
.timeline li::before { content:""; position:absolute; left:-9px; top:4px; width:15px; height:15px; border-radius:50%; background:var(--accent); border:3px solid var(--paper); }
.timeline .t { font-family:var(--display); font-weight:700; }

/* ---- PROS / CONS ---- */
.proscons { display:grid; grid-template-columns:1fr 1fr; gap:var(--s4); }
.proscons .col { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:var(--s4); }
.proscons h3 { margin-top:0; }
.proscons ul { padding-left:1.1rem; margin:0; }
.proscons li { margin-bottom:.5rem; }
.proscons .pros { border-top:4px solid var(--ok); }
.proscons .cons { border-top:4px solid var(--accent); }
@media (max-width:600px){ .proscons{ grid-template-columns:1fr; } }

/* ---- AUTHOR EXPERIENCE ---- */
/* BOTH TRACKS BOUND. `auto 1fr` lets the first track size itself from content with no upper
   bound, so one long unbreakable word in it (a URL, a long place name) pushes the flexible
   track to zero and the layout collapses sideways. minmax(0,...) on both ends that. */
.author-block { background:var(--paper-2); border:1px solid var(--line); border-radius:var(--radius); padding:var(--s5); display:grid; grid-template-columns:minmax(0,max-content) minmax(0,1fr); gap:var(--s4); align-items:start; }
.author-block img.avatar { width:84px; height:84px; border-radius:50%; object-fit:cover; border:3px solid var(--surface); box-shadow:var(--shadow); }
.author-block .updated { font-size:var(--step--1); color:var(--ink-soft); margin-top:var(--s3); }
@media (max-width:600px){ .author-block{ grid-template-columns:1fr; } }

/* ---- TRUST STRIP ---- */
.trust { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--s3); text-align:center; background:var(--paper-2); border:1px solid var(--line); border-radius:var(--radius); padding:var(--s4); }
.trust .num { font-family:var(--display); font-size:var(--step-2); font-weight:800; color:var(--gold); }
.trust .lbl { font-size:var(--step--1); color:var(--ink-soft); }
@media (max-width:640px){ .trust{ grid-template-columns:repeat(2,1fr); gap:var(--s4); } }

/* ---- FAQ (FAQPage) ----
   UX-SWEEP 2026-09-25: the homepage FAQ block renders as `.home-faq details`, not `.faq details`,
   so every rule below was silently dead on the homepage: no card border/background, no +/- toggle
   icon, and the native details marker (a plain triangle bullet) leaked through instead. Same
   template, two different class names; selector list widened to cover both. */
.faq details, .home-faq details { border:1px solid var(--line); border-radius:var(--radius-sm); background:var(--surface); padding:.4rem 1rem; margin-bottom:.7rem; }
.faq summary, .home-faq summary { font-family:var(--display); font-weight:700; cursor:pointer; padding:.6rem 0; list-style:none; color:var(--ink); }
.faq summary::-webkit-details-marker, .home-faq summary::-webkit-details-marker{ display:none; }
.faq summary::after, .home-faq summary::after { content:"+"; float:right; color:var(--brand); font-weight:800; }
.faq details[open] summary::after, .home-faq details[open] summary::after { content:"−"; }

/* ---- RELATED TOURS ---- */
.related { display:grid; grid-template-columns:repeat(2,1fr); gap:var(--s4); }
.related .rcard { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; box-shadow:var(--shadow); }
.related .rcard .rc-media { aspect-ratio:4/3; background:var(--paper-2); }
.related .rcard .rc-media img { width:100%; height:100%; object-fit:cover; }
.related .rcard .rc-body { padding:var(--s3) var(--s4); }
@media (max-width:600px){ .related{ grid-template-columns:1fr; } }
/* 3-up card grid (homepage / hubs) */
.cards-3 { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s4); }
.cards-3 .rcard { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; box-shadow:var(--shadow); display:flex; flex-direction:column; }
.cards-3 .rcard .rc-media { aspect-ratio:4/3; background:var(--paper-2); }
.cards-3 .rcard .rc-media img { width:100%; height:100%; object-fit:cover; }
.cards-3 .rcard .rc-body { padding:var(--s3) var(--s4) var(--s4); display:flex; flex-direction:column; gap:var(--s2); flex:1; }
.cards-3 .rcard .rc-body .btn { margin-top:auto; }
@media (max-width:820px){ .cards-3{ grid-template-columns:1fr; } }

/* Product card upgrades: "best for" frame, benefit bullets, social proof, popular badge */
.pc-reviews { font-weight:500; color:var(--ink-soft); font-size:var(--step--1); }
.pc-bestfor { align-self:flex-start; margin:0; background:var(--gold-soft); color:var(--gold-ink);
  font-weight:700; font-size:.7rem; text-transform:uppercase; letter-spacing:.05em; padding:.28rem .65rem; border-radius:999px; }
.pc-points { list-style:none; padding:0; margin:.15rem 0 0; display:flex; flex-direction:column; gap:.4rem; }
.pc-points li { position:relative; padding-left:1.45rem; font-size:var(--step--1); color:var(--ink); line-height:1.4; }
.pc-points li::before { content:"✓"; position:absolute; left:0; top:-.02em; color:var(--brand); font-weight:800; }
.rc-media, .pc-media { position:relative; }
.pc-badge { position:absolute; top:.6rem; left:.6rem; z-index:1; background:var(--gold-soft); color:var(--gold-ink);
  font-weight:800; font-size:.7rem; text-transform:uppercase; letter-spacing:.05em; padding:.32rem .7rem; border-radius:999px; box-shadow:var(--shadow); }
.cards-3 .rcard.is-popular, .product-card.is-popular { border-color:var(--gold); box-shadow:0 0 0 2px var(--gold), var(--shadow); }

/* ---- CTA BANNER ---- */
.cta-banner { background:linear-gradient(120deg,#2E7A2E,#12351A); border:1px solid #12351A; color:#fff; border-radius:var(--radius); padding:var(--s5); text-align:center; }
.cta-banner h2, .cta-banner h3 { color:#fff; margin-top:0; }
.cta-banner p { color:rgba(255,255,255,.82); max-width:52ch; margin-inline:auto; }

/* ---- AVAILABILITY WIDGET (date -> affiliate check) ---- */
.availability { display:flex; gap:.7rem; align-items:center; flex-wrap:wrap; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:var(--s3) var(--s4); box-shadow:var(--shadow); }
.availability .av-label { font-family:var(--display); font-weight:700; color:var(--ink); }
.availability .av-date { padding:.7rem .8rem; border:1px solid var(--line); border-radius:var(--radius-sm); font:inherit; min-height:48px; background:var(--surface-2); color:var(--ink); color-scheme:light; }
.availability .av-go, .availability .av-check { margin-left:auto; }
.availability .av-msg { width:100%; margin:.3rem 0 0; color:var(--ok); font-weight:600; }
@media (max-width:560px){ .availability .av-go, .availability .av-check { margin-left:0; width:100%; } }

/* ---- FOOTER (the one deepest surface, near-black glacier navy) ---- */
.site-footer { background:#12351A; color:#C6B6A9; margin-top:var(--s7); padding-block:var(--s6) var(--s4); border-top:1px solid var(--line); }
.footer-grid { display:grid; grid-template-columns:2fr 1fr 1fr; gap:var(--s5); }
.site-footer a { color:#F2ECD9; text-decoration:none; }
.site-footer a:hover { text-decoration:underline; }
.site-footer h4, .site-footer .footer-h { font-family:var(--display); font-weight:700; font-size:var(--step-0); color:#fff; margin:0 0 var(--s2); }
.footer-nav ul { list-style:none; margin:0; padding:0; }
.footer-nav li { margin-bottom:.4rem; }
.socials { display:flex; gap:.8rem; margin-top:var(--s3); }
.socials a { width:40px; height:40px; display:grid; place-items:center; border:1px solid #56462C; border-radius:50%; }
.socials a:hover { border-color:#DCC989; color:#DCC989; }
.disclosure { font-size:var(--step--1); color:#BAAB9F; border-top:1px solid #56462C; margin-top:var(--s5); padding-top:var(--s3); }
.disclosure p { max-width:none; }
@media (max-width:740px){ .footer-grid{ grid-template-columns:1fr; gap:var(--s4); } }

/* ---- BLOG ---- */
.blog-hero { margin:var(--s5) 0 0; }
.blog-hero img { width:100%; height:auto; aspect-ratio:16/9; object-fit:cover; border-radius:var(--radius); box-shadow:var(--shadow); }
.blog-post .author-hook { display:flex; align-items:center; gap:.6rem; font-size:var(--step--1); color:var(--ink-soft); margin-top:var(--s3); }
.blog-post .author-hook img { width:38px; height:38px; border-radius:50%; object-fit:cover; border:2px solid var(--line); }
.prose { margin-top:var(--s5); }
.prose > * { max-width:64ch; }
.prose h2 { margin-top:var(--s6); }
.prose h3 { margin-top:var(--s5); }
.prose img { width:100%; max-width:100%; height:auto; border-radius:var(--radius); margin:var(--s4) 0; box-shadow:var(--shadow); }
.prose figure { margin:var(--s4) 0; }
.prose figcaption { font-size:var(--step--1); color:var(--ink-soft); margin-top:.4rem; }
.prose ul, .prose ol { padding-left:1.3rem; }
.prose li { margin-bottom:.4rem; }
.prose blockquote { margin:var(--s4) 0; padding:.4rem 0 .4rem var(--s4); border-left:4px solid var(--accent); color:var(--ink-soft); font-style:italic; }
/* EVERY TABLE ON THE SITE, not only the ones inside article prose.
   `.prose table` is a DESCENDANT selector, so it styles a table only when an ancestor carries
   .prose. compile.mjs wraps EVERY markdown table as
   `<div class="table-wrap"><table class="datatable">`, and `.datatable` had ZERO rules: inside
   prose the element selector below still caught them, but every table on the homepage, a hub or
   a rendered block shipped as a bare browser default. That is the exact defect the skill records
   from a sibling, where a "When to Go" block emitted `.table-wrap` + `.datatable`, neither class
   existed, and the table shipped with no border, no header tint, no zebra and a clipped last
   column instead of a scrollable one. Valid markup, passing build, passing qa-dist, visibly
   broken, and found by Oleg opening the page.
   Keyed to `main table` rather than to a wrapper class, because keying the fix to a wrapper
   misses any donor that uses a different one. The .prose rules below still win on specificity
   where they differ, so article tables are unchanged. */
main table, table.datatable {
  width:100%; max-width:100%; border-collapse:collapse; background:var(--surface);
  border:1px solid var(--line); border-radius:var(--radius); overflow:hidden;
  margin:var(--s4) 0; font-size:var(--step--1);
}
main th, main td, table.datatable th, table.datatable td {
  text-align:left; padding:.7rem .9rem; border-bottom:1px solid var(--line); vertical-align:top;
}
main thead th, table.datatable thead th {
  background:var(--paper-2); font-family:var(--display); color:var(--ink);
}
main tbody tr:nth-child(even) td, table.datatable tbody tr:nth-child(even) td {
  background:color-mix(in srgb, var(--paper-2) 45%, transparent);
}
main tbody tr:last-child td, table.datatable tbody tr:last-child td { border-bottom:0; }
/* A wide table must scroll INSIDE its own container. The page body must never scroll sideways. */
.table-wrap { overflow-x:auto; -webkit-overflow-scrolling:touch; max-width:100%; }
.table-wrap > table { min-width:min(640px, 100%); }

.prose table { width:100%; max-width:100%; border-collapse:collapse; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; margin:var(--s4) 0; font-size:var(--step--1); }
.prose th, .prose td { text-align:left; padding:.7rem .9rem; border-bottom:1px solid var(--line); vertical-align:top; }
.prose thead th { background:var(--paper-2); font-family:var(--display); color:var(--ink); }
.prose tbody tr:last-child td { border-bottom:0; }
@media (max-width:640px){
  .prose table { display:block; overflow-x:auto; -webkit-overflow-scrolling:touch; }
.table-scroll { overflow-x:auto; -webkit-overflow-scrolling:touch; }
.table-scroll > table { min-width: 640px; }
}
.prose a { color:var(--brand); }
/* CRITICAL: .prose a (0,1,1) out-specifies .btn-primary (0,1,0); without these overrides a
   button inside an article body renders accent-on-accent = INVISIBLE TEXT. */
.prose a.btn-primary, .prose a.btn-primary:hover { color:var(--accent-ink); }
.prose a.btn-brand { color:var(--accent-ink); }
.prose a.btn-ghost { color:var(--ink); }
/* Hotel affiliate pill (Expedia via Travelpayouts): deliberately amber + outline so it reads as a
   secondary lodging action, distinct from the cyan GetYourGuide tour buttons. Explicit colors
   defeat the .prose a override trap above. */
.hotel-cta, .prose a.hotel-cta { display:inline-flex; align-items:center; gap:.35rem; font-family:var(--display); font-weight:800; font-size:var(--step--1); line-height:1; padding:.6rem 1.1rem; border-radius:10px; border:1px solid var(--gold); color:var(--accent-ink); background:var(--gold); text-decoration:none; white-space:nowrap; box-shadow:var(--shadow); }
.hotel-cta:hover, .prose a.hotel-cta:hover { background:#99420E; color:#fff; text-decoration:none; }
.hotel-row { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:.6rem .9rem; margin:.2rem 0 var(--s3); padding:.7rem .95rem; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-sm); }
.hotel-row .hr-name { font-weight:700; color:var(--ink); }
.blog-cta { background:var(--paper-2); border:1px solid var(--line); border-left:4px solid var(--accent); border-radius:var(--radius); padding:var(--s4) var(--s5); margin:var(--s6) 0 0; }
.blog-cta h2 { margin-top:0; }
.blog-cta p { margin-bottom:var(--s3); }
.blog-cta-btns { display:flex; gap:.6rem; flex-wrap:wrap; align-items:center; }

/* ---- INFOGRAPHIC (generated SVG) ---- */
.infographic { margin:var(--s4) 0; }
.infographic img, .infographic svg { width:100%; height:auto; border-radius:var(--radius); border:1px solid var(--line); background:var(--surface); display:block; }
.infographic figcaption { margin-top:.6rem; text-align:center; color:var(--ink-soft); }
.embed + p, .embed + p.small, .video-grid + p { max-width:none; }

/* information-gain block: fresh, sourced data competitors don't carry */
.infogain { background:var(--paper-2); border:1px solid var(--line); border-left:5px solid var(--gold); border-radius:var(--radius); padding:var(--s4) var(--s4) var(--s3); margin:var(--s5) 0; }
.infogain .infogain-h { display:flex; align-items:center; flex-wrap:wrap; gap:.55rem; font-family:var(--display); font-weight:800; font-size:var(--step-1); line-height:1.1; margin:0 0 var(--s3); max-width:none; color:var(--ink); }
.infogain .tag { font-family:var(--body); font-size:var(--step--1); font-weight:700; color:var(--gold-ink); background:var(--gold-soft); padding:.18rem .55rem; border-radius:999px; letter-spacing:.03em; text-transform:uppercase; }
.infogain ul { list-style:none; margin:0; padding:0; display:grid; gap:var(--s3); }
.infogain li { position:relative; padding-left:1.5rem; max-width:66ch; }
.infogain li::before { content:""; position:absolute; left:0; top:.5em; width:.55rem; height:.55rem; background:var(--gold); border-radius:50%; }
.infogain .src { display:block; font-size:var(--step--1); color:var(--ink-soft); margin-top:.2rem; }
.infogain .src a { color:var(--ink-soft); }
.infogain .infogain-note { font-size:var(--step--1); color:var(--ink-soft); margin:var(--s3) 0 0; max-width:none; }

/* ---- EMBEDS (interactive map + videos) ---- */
.embed { position:relative; width:100%; aspect-ratio:16/9; border-radius:var(--radius); overflow:hidden; border:1px solid var(--line); box-shadow:var(--shadow); background:var(--surface); }
.embed iframe { position:absolute; inset:0; width:100%; height:100%; border:0; }
.video-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s4); }
.video-grid .embed { box-shadow:none; }
@media (max-width:820px){ .video-grid{ grid-template-columns:1fr; } }

/* ---- CONVERSION COMPONENTS (conversion-optimizer skill) ---- */
.btn-xl { font-size: var(--step-1); padding: 1.05rem 1.9rem; }
.cta-proof { display:block; font-size:var(--step--1); color:var(--ink-soft); margin:.55rem 0 0; max-width:none; }
.cta-proof .gold { color: var(--gold); font-weight:700; }
.cta-box { background:var(--paper-2); border:1px solid var(--line); border-top:3px solid var(--accent);
  border-radius:var(--radius); padding:var(--s5); margin:var(--s5) 0; max-width:none; text-align:center; }
.cta-box .cb-h { font-family:var(--display); font-weight:800; font-size:var(--step-2); color:var(--ink); margin:0 0 .5rem; max-width:none; }
.cta-box p { max-width:44ch; margin-inline:auto; }
.cta-box p:last-child { margin-bottom:0; max-width:none; }
.cta-box .btn { margin-top:.5rem; }
.cta-box a.btn-primary, .cta-box a.btn-primary:hover { color:var(--accent-ink); }
@media (max-width:640px){ .cta-box { padding:var(--s4); } .cta-box .btn { width:100%; } }
/* sticky bar: fixed overlay (zero CLS), thin, revealed after first screen */
.sticky-cta { position:fixed; z-index:45; left:0; right:0; bottom:0; display:flex; align-items:center;
  justify-content:center; gap:.9rem; padding:.55rem .9rem calc(.55rem + env(safe-area-inset-bottom));
  background:rgba(255,255,255,.97); backdrop-filter:blur(8px); border-top:1px solid var(--line);
  transform:translateY(110%); transition:transform .25s ease; }
.sticky-cta.visible { transform:translateY(0); }
.sticky-cta .sc-proof { font-size:var(--step--1); color:var(--ink); white-space:nowrap; flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; }
/* Show the long proof only where it actually fits; below 560px the short form carries the
   count and the from-price instead of letting the sentence be sliced mid-phrase. */
.sticky-cta .sc-short { display:none; }
@media (max-width: 420px) { .sticky-cta .sc-count { display:none; } }
@media (max-width: 560px) {
  .sticky-cta .sc-long { display:none; }
  .sticky-cta .sc-short { display:inline; }
}
.sticky-cta .sc-proof .gold { color:var(--gold); font-weight:700; }
.sticky-cta .btn { min-height:44px; padding:.6rem 1.3rem; }
@media (min-width: 761px) {
  .sticky-cta { left:auto; right:1.2rem; bottom:1.2rem; border:1px solid var(--line);
    border-radius:999px; padding:.5rem .6rem .5rem 1.1rem; box-shadow:var(--shadow); }
  /* article pages (blog/guides): full-width bottom bar on desktop too, like mobile */
  body.article .sticky-cta { left:0; right:0; bottom:0; border-radius:0; border:0;
    border-top:1px solid var(--line); box-shadow:none; padding:.55rem .9rem; }
}
@media (prefers-reduced-motion: reduce) { .sticky-cta { transition:none; } }

/* ---- TESTIMONIALS (real GetYourGuide/Tripadvisor reviews, verbatim) ---- */
.reviews { display:grid; grid-template-columns:repeat(2,1fr); gap:var(--s4); }
.review-card { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:var(--s4); display:flex; flex-direction:column; gap:var(--s2); }
.review-card .stars { font-size:.95rem; }
.review-card blockquote { margin:0; font-size:var(--step-0); color:var(--ink); max-width:none; }
.review-card blockquote p { max-width:none; margin:0; }
.review-meta { margin-top:auto; font-size:var(--step--1); color:var(--ink-soft); }
.review-meta strong { color:var(--ink); }
@media (max-width:760px){ .reviews{ grid-template-columns:1fr; } }

/* utility */
.lede { font-size:var(--step-1); color:var(--ink-soft); }
.small { font-size:var(--step--1); color:var(--ink-soft); }
.mt-0{margin-top:0}.mb-0{margin-bottom:0}.text-center{text-align:center}

/* ============================================================
   SITE-SPECIFIC LAYER , "Arctic Rust" additions for an ancestor sitetours.org
   ============================================================ */

/* ---- FLIPPED SPLIT HERO (this site's first screen, approved 2026-08-07).
        Tall photo LEFT, headline + proof + XL CTA RIGHT. On mobile the H1 comes first
        and the photo drops below, so the primary-keyword H1 is above the fold. ---- */
.hero--split { display:grid; grid-template-columns: .85fr 1.15fr; gap: var(--s5);
  align-items:center; padding-block: var(--s5) var(--s6); }
.hero--split .hero-media { order:-1; aspect-ratio:3/4; border-radius:var(--radius);
  overflow:hidden; background:var(--paper-2); box-shadow:var(--shadow); }
.hero--split .hero-media img { width:100%; height:100%; object-fit:cover; }
.hero--split h1 { margin-bottom: var(--s3); max-width: 16ch; }
.hero--split .lede { max-width: 46ch; margin-bottom: var(--s4); }
.hero--split .hero-actions { display:flex; flex-wrap:wrap; gap:.7rem; align-items:center; }
.hero--split .author-hook { display:flex; align-items:center; gap:.6rem;
  font-size:var(--step--1); color:var(--ink-soft); margin-top:var(--s4); }
.hero--split .author-hook img { width:38px; height:38px; border-radius:50%; object-fit:cover; border:2px solid var(--line); }
@media (max-width: 860px) {
  .hero--split { grid-template-columns:1fr; gap:var(--s4); padding-block:var(--s4) var(--s5); }
  /* The media div is FIRST in the DOM so it can sit left on desktop. On mobile it has to
     drop BELOW the text, or the primary-keyword H1 is pushed off the first screen. */
  .hero--split .hero-media { order:2; aspect-ratio:4/3; }
  .hero--split h1 { max-width:none; }
}

/* ---- Editorial hairline under section headings (the industrial detail) ---- */
.section > h2:first-child, .rule-h2 { padding-bottom: var(--s2); border-bottom: 2px solid var(--ink);
  border-image: repeating-linear-gradient(90deg, var(--ink) 0 14px, var(--accent) 14px 18px, var(--ink) 18px 32px) 1; }

/* ---- CATEGORY GRID (8 activity hubs on the homepage) ---- */
.cat-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s3); }
.cat-card { display:flex; flex-direction:column; gap:.3rem; background:var(--surface);
  border:1px solid var(--line); border-left:4px solid var(--brand); border-radius:var(--radius-sm);
  padding:var(--s3) var(--s4); text-decoration:none; color:var(--ink); transition:border-color .15s ease, transform .08s ease; }
.cat-card:hover { border-left-color:var(--accent); transform:translateY(-2px); }
.cat-card .cc-name { font-family:var(--display); font-weight:800; font-size:var(--step-0); line-height:1.2; }
.cat-card .cc-meta { font-size:var(--step--1); color:var(--ink-soft); }
@media (max-width:900px){ .cat-grid{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:520px){ .cat-grid{ grid-template-columns:1fr; } }

/* ---- PLATFORM PILL (which marketplace a listing lives on) ---- */
.pc-platform { font-size:var(--step--1); font-weight:700; color:var(--ink-soft); }
.pc-platform .pf { display:inline-block; padding:.12rem .5rem; border-radius:999px;
  border:1px solid var(--line); background:var(--paper-2); color:var(--ink); font-size:.72rem;
  letter-spacing:.03em; text-transform:uppercase; }

/* ---- HONESTY CALLOUT (used wherever the site corrects a common claim) ---- */
.honesty { background:var(--surface); border:1px solid var(--line); border-left:5px solid var(--accent);
  border-radius:var(--radius); padding:var(--s4); margin:var(--s5) 0; }
.honesty .h-h { font-family:var(--display); font-weight:800; font-size:var(--step-1);
  margin:0 0 var(--s2); max-width:none; color:var(--ink); }
.honesty p:last-child { margin-bottom:0; }
.prose .honesty p { max-width:none; }

/* ---- TOUR LIST (category hubs: a dense, scannable row per product) ---- */
.tour-list { display:grid; gap:var(--s3); }
.tour-row { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,max-content); gap:var(--s3) var(--s4); align-items:start;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:var(--s4); }
.tour-row.is-lead { border-color:var(--gold); box-shadow:0 0 0 2px var(--gold-soft), var(--shadow); }
.tour-row h3 { margin:0 0 .35rem; font-size:var(--step-1); }
.tour-row h3 a { color:var(--ink); text-decoration:none; }
.tour-row .tr-meta { font-size:var(--step--1); color:var(--ink-soft); margin:0 0 .5rem; max-width:none; }
.tour-row .tr-desc { margin:0; max-width:58ch; }
.tour-row .tr-cta { display:flex; flex-direction:column; align-items:flex-end; gap:.4rem; text-align:right; }
.tr-price { font-family:var(--display); font-weight:800; font-size:var(--step-1); white-space:nowrap; }
.tr-price small { display:block; margin-top:2px; font-family:var(--body); font-size:var(--step--1); font-weight:500; color:var(--ink-soft); white-space:normal; }
@media (max-width:760px){
  .tour-row { grid-template-columns:1fr; }
  .tour-row .tr-cta { align-items:stretch; text-align:left; }
  .tour-row .tr-cta .btn { width:100%; }
}

/* ============================================================
   TOUR-PICKS GRID (depth-cro conversion layer, ported from niagarafallsboattours.org
   2026-08-15 and re-tokened for "Arctic Rust"). A 3-card grid dropped into an article body
   before its FAQ. Whole card converts: image, title and button all carry the sponsored link.
   ============================================================ */
.tour-picks {
  background:var(--paper-2); border:1px solid var(--line); border-radius:var(--radius);
  padding:var(--s4); margin:var(--s5) 0;
}
.tour-picks .tp-season {
  font-size:var(--step--1); color:var(--ink-soft); margin:0 0 var(--s3);
  border-left:3px solid var(--accent); padding-left:.7rem;
}
.tour-picks .tp-grid { display:grid; gap:var(--s3); grid-template-columns:1fr; }
@media (min-width:700px) { .tour-picks .tp-grid { grid-template-columns:repeat(3,1fr); } }
.tour-picks .tp-card {
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-sm);
  overflow:hidden; display:flex; flex-direction:column;
}
.tour-picks .tp-media { display:block; aspect-ratio:4/3; overflow:hidden; }
.tour-picks .tp-media img { width:100%; height:100%; object-fit:cover; }
.tour-picks .tp-body { padding:var(--s3); display:flex; flex-direction:column; gap:.5rem; flex:1; }
.tour-picks .tp-chips { margin:0; display:flex; gap:.35rem; flex-wrap:wrap; }
.pc-chip { display:inline-block; font-size:.7rem; font-weight:700; letter-spacing:.02em;
  padding:.2rem .55rem; border-radius:999px; background:var(--paper-2); color:var(--ink-soft);
  border:1px solid var(--line); }
/* nowrap REMOVED 2026-09-17. This selector is (0,3,0) and the ported chip-wrap fix below
   is (0,1,0), so the fix lost on specificity and was inert: the chips in this band still
   could not wrap. A chip here carries a product one-liner, which is a SENTENCE, inside a
   card with overflow:hidden, which is how "Best value for first-time visitors set on the
   heavy hi" shipped. Wrapping is the honest failure mode: the card grows a line instead
   of hiding words. */
.tour-picks .tp-chips .pc-chip:first-child { color:var(--ink); }
.tour-picks .tp-title { font-weight:700; color:var(--ink); font-size:var(--step--1); line-height:1.35; margin:0; }
.tour-picks .tp-title a { color:var(--ink); text-decoration:none; }
.tour-picks .tp-title a:hover { color:var(--brand); text-decoration:underline; }
.tour-picks .tp-proof { font-size:var(--step--1); color:var(--ink-soft); margin:0; }
.tour-picks .tp-proof .gold { color:var(--gold); font-weight:700; }
.tour-picks .tp-proof-none { font-style:italic; }
.tour-picks .tp-reassure { margin:0; font-size:.74rem; color:var(--ink-soft); }
.tour-picks .tp-body .btn { margin-top:auto; width:100%; white-space:nowrap; font-size:var(--step--1); padding:.7rem .8rem; }
.tour-picks a.btn-primary, .tour-picks a.btn-primary:hover { color:var(--accent-ink); }
/* BREAKOUT: .prose > * and .wrap-narrow cap children at ~64ch/50rem, and max-width beats width,
   so a 3-card grid gets crushed to ~150px columns unless the panel is lifted out of the measure
   (same pattern as .cta-box / .infogain). This is the CSS gotcha the depth-cro skill flags. */
.wrap-narrow .tour-picks, .prose .tour-picks, .blog-post .tour-picks {
  max-width:none;
  width:min(100vw - 2rem, 68rem);
  margin-left:50%;
  transform:translateX(-50%);
}
@media (max-width:700px) {
  .wrap-narrow .tour-picks, .prose .tour-picks, .blog-post .tour-picks { width:100%; margin-left:0; transform:none; }
}

/* ---- v2.1: card-style mid-article CTA (image + body) ---- */
.cta-box.cta-card { display:grid; grid-template-columns:230px 1fr; gap:var(--s4); align-items:center; max-width:none; }
.cta-box.cta-card .cb-media { display:block; }
.cta-box.cta-card .cb-media img { width:100%; height:100%; min-height:170px; object-fit:cover; border-radius:var(--radius-sm); display:block; }
.cta-box.cta-card .cb-body p { margin:0 0 var(--s2); max-width:none; margin-inline:0; text-align:left; }
.cta-box.cta-card .tp-proof { color:var(--ink-soft); font-size:var(--step--1); }
@media (max-width: 700px) { .cta-box.cta-card { grid-template-columns:1fr; } }
/* category card: who-it's-for line */
.cat-card .cc-who { display:block; margin-top:.35rem; color:var(--ink-soft); font-size:var(--step--1); font-weight:600; }


/* ---- v2.2 (Oleg, 2026-08-18): section intros span the container, rows + cat cards carry images.
   UX-SWEEP 2026-09-25: "span the container" at 1152px was rendering 140+ characters per line
   (measure-sections.mjs flagged 9-11 intro paragraphs per page over the 90ch readability cap).
   Capped to 75ch: wider than card copy (64ch) so it still reads as a section intro, but short
   enough that the eye can track a line at desktop width. ---- */
.section.wrap > p { max-width: 75ch; }
/* THE THIRD COLUMN MUST BE CAPPED. It was `auto`, which sizes to content, so a long price note
   grew the CTA column until the middle column had almost no room: the lead card rendered its
   title one word per line with the note taking half the card. `auto` is safe only while every
   note is short, and 45 of 46 ran past 120 characters. A max width makes the layout independent
   of the copy, which is the property it needed all along. */
.tour-row.has-media { grid-template-columns: 220px minmax(0, 1fr) minmax(9rem, 15rem); }
.tour-row { grid-template-columns: minmax(0, 1fr) minmax(9rem, 15rem); }
.tour-row .tr-cta { min-width: 0; }
.tour-row .tr-price small { display:block; max-width: 15rem; margin-left:auto; }
.tour-row .tr-media { display:block; align-self:stretch; }
.tour-row .tr-media img { width:100%; height:100%; min-height:150px; object-fit:cover; border-radius:var(--radius-sm); display:block; }
@media (max-width: 860px) {
  .tour-row.has-media { grid-template-columns: 1fr; }
  .tour-row .tr-media img { min-height:0; max-height:210px; }
}
.cat-card { padding-top:0; overflow:hidden; }
.cat-card .cc-media { display:block; margin:0 calc(-1 * var(--s4)) var(--s2); }
.cat-card .cc-media img { width:100%; height:130px; object-fit:cover; display:block; }

/* homepage per-category anchor blocks */
.cat-block { margin-top: var(--s5); scroll-margin-top: 5rem; }
.cat-block > h3 { margin-bottom: var(--s1); }
.cat-block > p.small { margin-top: 0; color: var(--ink-soft); }

/* single mid-article conversion card (gradual blog placements) */
.tp-solo { margin: var(--s5) 0; }
.tp-solo .tp-grid { grid-template-columns: 1fr; max-width: 34rem; margin-inline: auto; }

/* ---- TOUR (MONEY) PAGES: booking panel above the fold (tour-page-cro spec) ---- */
.tour-hero { padding-top: var(--s4); }
.tour-hero-grid { display: grid; gap: var(--s4); align-items: start; }
@media (min-width: 860px) { .tour-hero-grid { grid-template-columns: 1.15fr 1fr; } }
.tour-hero .hero-media img { width: 100%; height: auto; border-radius: var(--radius); box-shadow: var(--shadow); }
.booking-panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--s4); box-shadow: var(--shadow); }
.booking-panel h1 { font-size: var(--step-2); margin: 0 0 var(--s2); line-height: 1.15; }
.bp-rating { margin: 0 0 var(--s2); color: var(--ink-soft); font-size: var(--step--1); }
.bp-rating .gold { color: var(--gold); font-weight: 700; }
.bp-reason { margin: 0 0 var(--s2); font-size: var(--step-0); }
.bp-price { margin: 0 0 var(--s3); font-size: var(--step-1); font-family: var(--display); }
.bp-price small { display: block; font-size: var(--step--1); color: var(--ink-soft); font-family: var(--body); font-weight: 400; }
.btn-block { display: block; width: 100%; text-align: center; }
.bp-next { color: var(--ink-soft); margin: var(--s2) 0 var(--s3); }
.bp-facts { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2) var(--s3); margin: 0; border-top: 1px solid var(--line); padding-top: var(--s3); }
.bp-facts div { min-width: 0; }
.bp-facts dt { font-size: var(--step--1); color: var(--ink-soft); }
.bp-facts dd { margin: 0; font-size: var(--step--1); font-weight: 600; }

/* ============================================================
   CITY-GUIDE additions: free-entry treatment + wide comparison table
   ============================================================ */
.pc-free { font-weight:700; color:var(--ok); margin:.1rem 0; }
.bp-free { font-family:var(--display); font-weight:800; color:var(--ok); font-size:var(--step-1); margin:0 0 var(--s2); }
.table-scroll { overflow-x:auto; -webkit-overflow-scrolling:touch; margin:var(--s3) 0; }
.keyfacts.compare { min-width:680px; }
.keyfacts.compare th, .keyfacts.compare td { width:auto; white-space:nowrap; vertical-align:middle; }
.keyfacts.compare thead th { white-space:nowrap; }
.keyfacts.compare td:nth-child(2), .keyfacts.compare th:nth-child(2) { white-space:normal; min-width:12rem; }
.keyfacts.compare th[scope="row"] { background:var(--surface); font-weight:700; }
/* UX-SWEEP 2026-09-25: the link was an inline anchor around the tour name only, so the tappable
   area was a 16px text line inside a padded cell; padding around it looked clickable but was not.
   The link now fills the whole padded cell (negative-margin trick), so the real tap target
   matches what it visually looks like: the full row header, min 40px tall at mobile widths. */
.keyfacts.compare th[scope="row"] a { display:block; margin:-.8rem -1rem; padding:.8rem 1rem; min-height:40px; color:var(--ink); text-decoration:none; }
.keyfacts.compare th[scope="row"] a:hover { color:var(--brand); text-decoration:underline; }
.keyfacts.compare .gold { color:var(--gold); font-weight:700; }
/* free-entry card / passes shell */
.passes-shell { background:var(--paper-2); border:1px solid var(--line); border-left:5px solid var(--accent); border-radius:var(--radius); padding:var(--s4) var(--s5); margin:var(--s4) 0; }
.passes-shell h2 { margin-top:0; }

/* ---- DECISION PICKER (generic, build/launch-v2/gen-decision-picker.mjs) ---- */
.decision-picker { --dp-key: var(--brand, var(--sea, #19571B)); --dp-line: var(--line, #DACD9E);
  --dp-surface: var(--surface, #fff); --dp-surface-2: var(--surface-2, var(--paper-2, #F6F1E5));
  --dp-ink: var(--ink, #1A2420); --dp-soft: var(--ink-soft, #4B5850);
  background:var(--dp-surface); border:1px solid var(--dp-line); border-radius:var(--radius, 10px);
  padding:var(--s4, 1.5rem); box-shadow:var(--shadow, 0 1px 2px rgba(33,26,5,.06)); }
.decision-picker .dp-q { border:0; padding:0; margin:0 0 var(--s3, 1rem); min-width:0; }
.decision-picker .dp-q legend { font-family:var(--display, inherit); font-weight:800;
  font-size:var(--step-0, 1rem); color:var(--dp-ink); padding:0 0 .45rem; }
.decision-picker .dp-opts { display:flex; flex-wrap:wrap; gap:.5rem; }
.decision-picker .dp-opt { font-family:var(--body, inherit); font-size:var(--step--1, .9rem); font-weight:600;
  color:var(--dp-ink); background:var(--dp-surface); border:1.5px solid var(--dp-line); border-radius:999px;
  padding:.5rem .9rem; cursor:pointer; line-height:1.25; min-height:40px;
  transition:border-color .15s ease, background .15s ease, color .15s ease; }
.decision-picker .dp-opt:hover { border-color:var(--dp-key); color:var(--dp-key); }
.decision-picker .dp-opt.is-on { background:var(--dp-key); border-color:var(--dp-key); color:var(--accent-ink); }
.decision-picker .dp-opt:focus-visible { outline:3px solid var(--accent, var(--dp-key)); outline-offset:2px; }
.decision-picker .dp-controls { margin:0 0 var(--s3, 1rem); }
.decision-picker .dp-summary { margin:0 0 var(--s3, 1rem); padding:.6rem .85rem; border-radius:var(--radius-sm, 6px);
  background:var(--dp-surface-2); color:var(--dp-ink); font-size:var(--step--1, .9rem); font-weight:600; max-width:none; }
.decision-picker .dp-results { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s3, 1rem); }
.decision-picker .dp-card { display:flex; flex-direction:column; border:1px solid var(--dp-line);
  border-radius:var(--radius, 10px); overflow:hidden; background:var(--dp-surface-2); }
.decision-picker[data-state="picked"] .dp-card { border-color:var(--dp-key); box-shadow:0 0 0 2px rgba(33,26,5,.06); }
.decision-picker .dp-card.dp-fold { display:none; }
/* [hidden] alone loses to the .dp-card display:flex rule above (author styles beat the UA stylesheet), so a
   card the script hides stays on screen: pin it, same fix as the exit popup's dismissal trap. */
.decision-picker .dp-card[hidden] { display:none !important; }

.decision-picker .dp-media { display:block; aspect-ratio:4/3; background:var(--dp-surface-2); }
.decision-picker .dp-media img { width:100%; height:100%; object-fit:cover; display:block; }
.decision-picker .dp-body { padding:var(--s3, 1rem); display:flex; flex-direction:column; gap:.4rem; flex:1; }
.decision-picker .dp-name { margin:0; font-size:var(--step-0, 1rem); line-height:1.25; }
.decision-picker .dp-name a { color:var(--dp-ink); text-decoration:none; }
.decision-picker .dp-name a:hover { color:var(--dp-key); text-decoration:underline; }
/* Rule 33 floor applies to the card's title LINK too, not only to the chips. Measured at
   39.2px on a 390px viewport (kualalumpuraquarium.com, 2026-09-05) while every chip sat at
   exactly 40px, so the highest-intent target in the block was the one under the floor. */
@media (max-width: 760px) {
  .decision-picker .dp-name a { display:block; min-height:44px; line-height:1.35; padding-block:9px; }
}
.decision-picker .dp-facts { margin:0; display:flex; flex-wrap:wrap; gap:.3rem; max-width:none; }
.decision-picker .dp-facts span { font-size:.72rem; font-weight:600; background:var(--dp-surface);
  color:var(--dp-soft); border:1px solid var(--dp-line); border-radius:999px; padding:.2rem .55rem; }
.decision-picker .dp-price { margin:0; font-size:var(--step--1, .9rem); max-width:none; }
.decision-picker .dp-price strong { font-family:var(--display, inherit); font-size:var(--step-0, 1rem); }
.decision-picker .dp-rev { color:var(--dp-soft); }
.decision-picker .dp-body .btn { margin-top:auto; text-align:center; }
@media (max-width:900px){ .decision-picker .dp-results { grid-template-columns:repeat(2,1fr); } }
@media (max-width:560px){
  .decision-picker { padding:var(--s3, 1rem); }
  .decision-picker .dp-results { grid-template-columns:1fr; }
  .decision-picker .dp-card { flex-direction:row; }
  .decision-picker .dp-media { width:38%; flex:none; aspect-ratio:1/1; }
}

/* ============================================================
   D1 BLOCK LAYER (compile tokens added in Phase D1)
   Count-aware card grid (rule 30) + photo collage (rule 32) +
   testimonials and hotels (homepage blueprint rule 26).
   Every colour is a palette token, so nothing here re-tunes the approved palette.
   ============================================================ */

/* ---- COUNT-AWARE CARD GRID (rule 30 / block library 4.5c.A) ----
   Two leftover cards sit two-per-row and one sits in a capped single column, so a short
   group never stretches across a three-column track and reads as "everything looks the same". */
.cards-3.cards-n2 { grid-template-columns:repeat(2,1fr); }
.cards-3.cards-n1 { grid-template-columns:minmax(0,1fr); max-width:420px; }
@media (max-width:1040px){ .cards-3, .cards-3.cards-n2 { grid-template-columns:repeat(2,1fr); } }
@media (max-width:760px){
  .cards-3, .cards-3.cards-n1, .cards-3.cards-n2 { grid-template-columns:1fr; max-width:none; }
}

/* ---- PHOTO COLLAGE (rule 32 / block library 4.5c.C) ---- */
.photo-collage { display:grid; grid-template-columns:repeat(4,1fr); grid-auto-rows:130px; gap:.6rem; margin:var(--s3) 0 var(--s4); }
.photo-collage .pcol-tile { position:relative; display:block; overflow:hidden; border-radius:var(--radius-sm); background:var(--paper-2); }
.photo-collage .pcol-tile.pcol-hero { grid-column:span 2; grid-row:span 2; }
.photo-collage .pcol-tile.pcol-wide { grid-column:span 2; }
.photo-collage .pcol-tile img { width:100%; height:100%; object-fit:cover; display:block; transition:transform .3s ease; }
.photo-collage .pcol-tile:hover img { transform:scale(1.04); }
.photo-collage .pcol-cap { position:absolute; left:0; right:0; bottom:0; padding:1.4rem .6rem .5rem; font-size:.78rem; font-weight:700; color:#fff;
  background:linear-gradient(to top, rgba(28,22,14,.78), rgba(28,22,14,0)); line-height:1.25; }
@media (max-width:900px){
  .photo-collage { grid-template-columns:repeat(3,1fr); grid-auto-rows:110px; }
  .photo-collage .pcol-tile.pcol-wide { grid-column:span 1; }
}
@media (max-width:560px){
  .photo-collage { grid-template-columns:repeat(2,1fr); grid-auto-rows:100px; }
  .photo-collage .pcol-tile.pcol-wide { grid-column:span 2; }
  .photo-collage .pcol-tile:nth-child(n+7) { display:none; }
}
@media (prefers-reduced-motion: reduce){ .photo-collage .pcol-tile img { transition:none; } .photo-collage .pcol-tile:hover img { transform:none; } }

/* ---- TESTIMONIALS ({{ testimonials }}, real reviews only) ---- */
.testimonials-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s3); }
.testimonial-card { background:var(--surface); border:1px solid var(--line); border-top:3px solid var(--gold);
  border-radius:var(--radius); padding:var(--s4); display:flex; flex-direction:column; gap:var(--s2); }
.testimonial-card .tc-stars { margin:0; color:var(--gold); letter-spacing:.08em; font-size:.95rem; }
.testimonial-card blockquote { margin:0; max-width:none; color:var(--ink); }
.testimonial-card .tc-attr { margin:auto 0 0; font-size:var(--step--1); color:var(--ink-soft); }
.testimonials-disclaimer { margin-top:var(--s3); font-size:var(--step--1); color:var(--ink-soft); }
@media (max-width:980px){ .testimonials-grid { grid-template-columns:repeat(2,1fr); } }
@media (max-width:640px){ .testimonials-grid { grid-template-columns:1fr; } }

/* ---- HOTELS ({{ hotels }}, minted Travelpayouts links) ---- */
.hotel-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s3); }
.hotel-card { background:var(--surface); border:1px solid var(--line); border-left:4px solid var(--brand);
  border-radius:var(--radius); padding:var(--s4); display:flex; flex-direction:column; gap:.45rem; }
.hotel-card h3 { margin:0; font-size:var(--step-0); line-height:1.25; }
.hotel-card .hc-tier { align-self:flex-start; font-size:.72rem; font-weight:800; letter-spacing:.04em; text-transform:uppercase;
  color:var(--gold-ink); background:var(--gold-soft); border-radius:999px; padding:.14rem .6rem; }
.hotel-card .hc-area, .hotel-card .hc-rating { margin:0; font-size:var(--step--1); color:var(--ink-soft); }
.hotel-card .hc-rating .gold { color:var(--gold); font-weight:700; }
.hotel-card p { margin:0; font-size:var(--step--1); }
.hotel-card .btn { margin-top:auto; align-self:flex-start; }
@media (max-width:980px){ .hotel-grid { grid-template-columns:repeat(2,1fr); } }
@media (max-width:640px){ .hotel-grid { grid-template-columns:1fr; } }

/* === BEGIN rule37 section bands (build/launch-v2/apply-section-bands.mjs) === */
/* rule37:bands {"band-paper":{"key":"paper","bg":"#F2ECD9","fg":"#1A2420","link":"#19571B"},"band-tint":{"key":"tint","bg":"#E9DFC4","fg":"#1A2420","link":"#19571B"},"band-wash":{"key":"wash","bg":"#ECE1E2","fg":"#1A2420","link":"#19571B"},"band-edge":{"key":"edge","bg":"#FFFFFF","fg":"#1A2420","link":"#19571B"},"band-inverse":{"key":"inverse","bg":"#12351A","fg":"#F2ECD9","link":"#DCC989"}} */
/* Rule 37: adjacent sections never share a ground. The colour lives on the OUTER
   full-width <section>; .wrap moved to an inner div that only constrains width.
   Never reintroduce a box-shadow 0 0 0 100vmax full-bleed here: an outer box-shadow
   paints only outside the border box, so none of it lands behind the content. */
.section[class*="band-"]{background:var(--band-bg);color:var(--band-fg);position:relative;isolation:isolate;overflow-x:clip}
.section[class*="band-"]>.wrap{position:relative;z-index:1}
/* a banded section needs air on both sides, so the usual collapsed top padding is restored */
.section[class*="band-"]+.section[class*="band-"]{padding-top:var(--s6,4rem)}
.section[class*="band-"] a:not(.btn):not(.nav-link){color:var(--band-link)}
.section[class*="band-"] a:not(.btn):not(.nav-link):hover{color:var(--band-link-hover)}
.section[class*="band-"] :where(h1,h2,h3,h4,h5,h6){color:var(--band-fg)}
.band-edge{--band-bg:#FFFFFF;--band-fg:#1A2420;--band-muted:#4B5850;--band-line:#DACD9E;--band-link:#19571B;--band-link-hover:#12351A;--band-rule:#B89A2E;--band-cta-bg:#816A0E;--band-cta-fg:#FFFFFF;--band-surface:#FFFFFF;--paper:#FFFFFF;--surface:#F2ECD9;--surface-2:#F6F1E5}
.band-inverse :where(hr,table,th,td){border-color:var(--band-line)}
.band-inverse :where(.card,.rcard,.tcard,.stat-tile,.quick-answer-box,details,.tp-card){background:var(--band-surface);border-color:var(--band-line)}

/* the 5 treatments, driven only by this site's own palette tokens.
   HAND PATCH (contrast gate, 2026-09-25, cebutravelguide.com): a device in prefers-color-scheme
   dark inverts EVERY base token at :root (--ink, --brand, --surface, --accent-ink...), but these
   four "light" bands still self-paint their own SECTION background from a fixed --band-bg, never
   from the theme. A child that reaches past the --band-* set and reads a BASE token directly (a
   table, a card, `.tex-table a`) got the section's fixed light card sitting under the device's
   dark-mode ink/brand/surface values: dark-on-dark table cells and #19571B links rendered over a
   #1E2A1C table fill that only the surrounding band, not the table itself, knew was "really" light.
   Fix: pin the full base-token set to the same light values every time, so anything inside these
   bands resolves consistently regardless of device theme. This block is machine-generated by
   build/launch-v2/apply-section-bands.mjs (shared pipeline script, not edited here to avoid
   changing every site's output); regenerating this file will need this patch re-applied, tracked
   in research/ux/CONTRAST.md. */
.band-paper,.band-tint,.band-wash,.band-edge{--paper:#F2ECD9;--paper-2:#E9DFC4;--surface:#FFFFFF;--surface-2:#F6F1E5;--line:#DACD9E;--ink:#1A2420;--ink-soft:#4B5850;--brand:#19571B;--brand-bright:#2E7A2E;--brand-deep:#12351A;--signature:#B89A2E;--accent:#816A0E;--accent-warm:#9C8020;--accent-deep:#5E4C09;--accent-ink:#FFFFFF;--gold:#77590E;--gold-soft:#DCC989;--gold-ink:#211A05}
.band-paper{--band-bg:#F2ECD9;--band-fg:#1A2420;--band-muted:#4B5850;--band-line:#DACD9E;--band-link:#19571B;--band-link-hover:#12351A;--band-rule:#B89A2E;--band-cta-bg:#816A0E;--band-cta-fg:#FFFFFF;--band-surface:#FFFFFF}
.band-tint{--band-bg:#E9DFC4;--band-fg:#1A2420;--band-muted:#4B5850;--band-line:#DACD9E;--band-link:#19571B;--band-link-hover:#12351A;--band-rule:#B89A2E;--band-cta-bg:#816A0E;--band-cta-fg:#FFFFFF;--band-surface:#FFFFFF}
.band-wash{--band-bg:#E9E1CE;--band-fg:#1A2420;--band-muted:#4B5850;--band-line:#DACD9E;--band-link:#19571B;--band-link-hover:#12351A;--band-rule:#B89A2E;--band-cta-bg:#816A0E;--band-cta-fg:#FFFFFF;--band-surface:#FFFFFF;--surface:#FFFFFF}
.band-edge{--band-bg:#FFFFFF;--band-fg:#1A2420;--band-muted:#4B5850;--band-line:#DACD9E;--band-link:#19571B;--band-link-hover:#12351A;--band-rule:#B89A2E;--band-cta-bg:#816A0E;--band-cta-fg:#FFFFFF;--band-surface:#FFFFFF;--paper:#FFFFFF;--surface:#F2ECD9;--surface-2:#F6F1E5}
.band-inverse{--band-bg:#12351A;--band-fg:#F2ECD9;--band-muted:#A8A18F;--band-line:#3D4D56;--band-link:#DCC989;--band-link-hover:#5D9CCB;--band-surface:#3B2C2A;--band-rule:#DCC989;--band-cta-bg:#B89A2E;--band-cta-fg:#1A2420;--ink:#F2ECD9;--ink-soft:#BDBAA9;--paper:#1A2420;--paper-2:#362818;--surface:#362818;--surface-2:#362818;--line:#48442E;--brand:#B89A2E;--brand-bright:#B89A2E;--brand-deep:#B89A2E;--accent:#B89A2E;--accent-warm:#B89A2E;--accent-deep:#B89A2E;--accent-ink:#1A2420;--gold:#96BAF0;--gold-soft:#362818;--gold-ink:#F2ECD9;--shadow:none}

/* selectors that used to match the combined .section.wrap element, re-pointed at the split form */
.section > .wrap > h2:first-child{padding-bottom: var(--s2); border-bottom: 2px solid var(--ink); border-image: repeating-linear-gradient(90deg, var(--ink) 0 14px, var(--accent) 14px 18px, var(--ink) 18px 32px) 1;}
.section > .wrap > p{max-width: 75ch;}

/* ---- motion layer. Both effects are decoration only: nothing here can leave real
   content hidden if the animation never runs (memory: a broad opacity:0 scroll reveal
   stays invisible forever for any renderer that does not scroll). ---- */
@keyframes r37-drift{from{transform:translate3d(-4%,0,0) scale(1.02);opacity:.5}to{transform:translate3d(4%,0,0) scale(1.09);opacity:.95}}
.band-wash::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;border-radius:inherit;background:radial-gradient(38% 60% at 22% 28%,rgba(140,109,18,0.16) 0%,transparent 70%),radial-gradient(34% 56% at 78% 74%,rgba(25,87,27,0.12) 0%,transparent 72%);animation:r37-drift 22s ease-in-out infinite alternate;will-change:transform,opacity}
@keyframes r37-pulse{0%{transform:scale(.55);opacity:.8}70%{transform:scale(2);opacity:0}100%{transform:scale(2);opacity:0}}
.map-pin,.spot-pin,.pin,[data-pulse]{position:relative}
.map-pin::after,.spot-pin::after,.pin::after,[data-pulse]::after{content:"";position:absolute;left:50%;top:50%;width:18px;height:18px;margin:-9px 0 0 -9px;border-radius:50%;border:2px solid rgba(140,109,18,0.85);pointer-events:none;animation:r37-pulse 2.6s ease-out infinite}
[data-countup],.st-num,.stat-num,.kpi-num{font-variant-numeric:tabular-nums}
/* reduced motion: animation off, END STATE shown, nothing hidden */
@media (prefers-reduced-motion: reduce){
  .band-wash::before{animation:none;transform:none;opacity:.75}
  .map-pin::after,.spot-pin::after,.pin::after,[data-pulse]::after{animation:none;transform:translate(0,0) scale(1);opacity:.5}
  [data-countup],.st-num,.stat-num,.kpi-num{transition:none}
}
/* === END rule37 section bands === */

/* === BEGIN crowd calendar (homepage #when, build/compile.mjs > crowdCalendarHtml) ===
   The block sits on the inverse band, so every colour resolves from the band tokens with a
   light-band fallback: moving the section to another treatment needs no edit here. */
.crowd{--cw-fg:var(--band-fg,var(--ink));--cw-muted:var(--band-muted,var(--ink-soft));
  --cw-line:var(--band-line,var(--line));--cw-surface:var(--band-surface,var(--surface));
  --cw-accent:var(--band-rule,var(--gold));--cw-bar:rgba(28,22,14,.30);
  display:grid;gap:var(--s4);margin-top:var(--s4)}
.band-inverse .crowd{--cw-bar:rgba(255,255,255,.42)}

.crowd-fig{margin:0;background:var(--cw-surface);border:1px solid var(--cw-line);border-radius:var(--radius);padding:var(--s3)}
.crowd-fig figcaption{margin-top:var(--s2);font-size:var(--step--1);color:var(--cw-muted);max-width:76ch}
.crowd-chart{display:block;width:100%;height:auto;overflow:visible}
.crowd-chart .ch-grid{stroke:var(--cw-line);stroke-width:1;opacity:.55}
.crowd-chart .ch-axis{stroke:var(--cw-line);stroke-width:1.5}
.crowd-chart .ch-bar{fill:var(--cw-bar)}
.crowd-chart .ch-bar.is-peak{fill:var(--cw-accent)}
.crowd-chart .ch-ylab,.crowd-chart .ch-xlab{fill:var(--cw-muted);font-size:15px;font-family:var(--body)}
.crowd-chart .ch-val{fill:var(--cw-fg);font-size:16px;font-weight:700;font-family:var(--body)}
.crowd-chart .ch-cap{stroke:var(--cw-accent);stroke-width:1.5;stroke-dasharray:6 5}
.crowd-chart .ch-caplab{fill:var(--cw-accent);font-size:14px;font-weight:700;font-family:var(--body)}

.crowd-now{background:var(--cw-surface);border:1px solid var(--cw-line);border-radius:var(--radius);padding:var(--s3)}
/* min-height reserves the tallest wording BEFORE the fetch resolves, so replacing the text
   with the live reading cannot shift a single pixel of the page below it. */
.cn-live{margin:0;font-size:var(--step-0);font-weight:600;min-height:5.4em}
.cn-refresh{margin:.5rem 0 0;font-size:var(--step--1);color:var(--cw-muted)}
.cn-live[data-state="live"]{font-weight:700}
.cn-gauge{margin-top:var(--s2);height:14px;border-radius:999px;background:var(--cw-bar);overflow:hidden}
.cn-gauge span{display:block;height:100%;width:var(--pct,2%);border-radius:inherit;background:var(--cw-accent);
  transition:width .6s ease;animation:cw-fill .9s cubic-bezier(.2,.7,.3,1) both;transform-origin:left center}
@keyframes cw-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.cn-scale{display:flex;justify-content:space-between;margin:.35rem 0 0;font-size:var(--step--1);color:var(--cw-muted)}
.cn-next{margin:var(--s3) 0 0;padding-top:var(--s2);border-top:1px solid var(--cw-line);font-size:var(--step--1)}

.crowd-cal{background:var(--cw-surface);border:1px solid var(--cw-line);border-radius:var(--radius);padding:var(--s3)}
.cc-lede{margin:0 0 var(--s3);font-size:var(--step--1);max-width:78ch}
.cc-controls{display:flex;flex-wrap:wrap;gap:.5rem}
.cc-chip{min-height:44px;padding:.5rem .95rem;border-radius:999px;border:1px solid var(--cw-line);
  background:transparent;color:var(--cw-fg);font:inherit;font-size:var(--step--1);font-weight:600;cursor:pointer}
.cc-chip:hover{border-color:var(--cw-accent)}
.cc-chip:focus-visible{outline:3px solid var(--cw-accent);outline-offset:2px}
.cc-chip.is-on{background:var(--cw-accent);border-color:var(--cw-accent);color:var(--band-cta-fg,#1A2420)}
.cc-status{margin:var(--s2) 0 var(--s3);font-size:var(--step--1);color:var(--cw-muted);min-height:1.5em}
.cc-month + .cc-month{margin-top:var(--s3)}
.cc-mname{margin:0 0 .5rem;font-size:var(--step-0);letter-spacing:.02em}
.cc-grid{list-style:none;margin:0;padding:0;display:grid;gap:.4rem;grid-template-columns:repeat(auto-fill,minmax(88px,1fr))}
.cd-day{border:1px solid var(--cw-line);border-radius:var(--radius-sm);padding:.4rem .45rem;
  display:flex;flex-direction:column;gap:.1rem;font-size:.78rem;line-height:1.25;min-height:74px}
.cd-dnum{font-weight:800;font-size:1rem}
.cd-dow{color:var(--cw-muted);font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}
.cd-ships{font-weight:600}
.cd-quiet{color:var(--cw-muted);font-weight:500}
.cd-pax{color:var(--cw-muted);font-variant-numeric:tabular-nums}
.cd-bar{display:block;height:4px;margin-top:auto;border-radius:999px;background:var(--cw-bar)}
.cd-bar::before{content:"";display:block;height:100%;width:var(--w,0%);border-radius:inherit;background:var(--cw-accent)}
.cd-none{opacity:.72}
.cd-busy{border-color:var(--cw-accent);border-width:2px}
@media (max-width:520px){
  .cc-grid{grid-template-columns:repeat(auto-fill,minmax(74px,1fr))}
  .cd-day{min-height:68px;font-size:.72rem}
}
@media (prefers-reduced-motion: reduce){
  .cn-gauge span{animation:none;transition:none}
}
/* === END crowd calendar === */

/* === BEGIN pin-map schematic + tour explorer (/map/, build/compile.mjs) ===
   NOTE ON SVG STYLING: these rules live HERE, in the site stylesheet, and never in a <style>
   element inside the SVG. A <style> inside an SVG is not scoped and leaks to the whole
   document, which is how a chart ends up restyling the nav. */
.map-embed{position:relative;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:var(--surface-2)}
.map-embed iframe{display:block;width:100%;height:min(62vh,520px);border:0}

.pin-panel{margin-top:var(--s4)}
.pin-panel .pm-title{margin:0 0 .2rem;font-size:var(--step-1)}
.pin-panel .pm-sub{margin:0 0 var(--s3);color:var(--ink-soft);font-size:var(--step--1);max-width:74ch}
.pm-grid-2{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);gap:var(--s3);align-items:start}
.pin-map{display:block;width:100%;height:auto;border:1px solid var(--line);border-radius:var(--radius);background:var(--surface)}
/* Base geography. .pm-sea is the whole frame; .pm-land is painted over it with fill-rule
   evenodd so a lake inside an island reads as water again. There is no .pm-bg fallback any more:
   a build with no research/geo/coastline.json now FAILS rather than shipping pins on a blank
   tinted box, which is the exact defect this layer exists to end. */
.pin-map .pm-sea{fill:var(--map-sea)}
.pin-map .pm-land{fill:var(--map-land)}
.pin-map .pm-shore{fill:none;stroke:var(--map-shore);stroke-width:1.1;stroke-linejoin:round;stroke-linecap:round}
.pin-map .pm-border{fill:none;stroke:var(--ink-soft);stroke-width:1.4;stroke-dasharray:7 5;opacity:.55}
.pin-map .pm-sea-lab{fill:var(--map-shore);font-size:17px;font-weight:600;letter-spacing:.14em;
  font-family:var(--body);text-transform:uppercase;opacity:.75}
.pin-map .pm-grid{stroke:var(--ink-soft);stroke-width:.8;opacity:.28}
/* A badge may be nudged off its place to stop two numbers covering each other; .pm-true is
   the real coordinate and .pm-leader ties the badge back to it. */
.pin-map .pm-true{fill:var(--brand);stroke:var(--surface);stroke-width:1.4}
.pin-map .pm-leader{stroke:var(--brand);stroke-width:1.6;opacity:.75}
.pin-map .pm-scale line,.pin-map .pm-north line,.pin-map .pm-north path{stroke:var(--ink-soft);stroke-width:1.6;fill:var(--ink-soft)}
.pin-map .pm-scale-lab{fill:var(--ink-soft);font-size:14px;font-family:var(--body)}
.pin-map .pm-anchor circle{fill:var(--ink);opacity:.85}
.pin-map .pm-anchor-lab{fill:var(--ink);font-size:15px;font-weight:700;font-family:var(--body)}
.pin-map .pm-dot{fill:var(--brand);stroke:var(--surface);stroke-width:2.5;transition:fill .18s ease}
.pin-map .pm-num{fill:#fff;font-size:15px;font-weight:800;font-family:var(--body);pointer-events:none}
.pin-map .pm-halo{fill:none;stroke:var(--gold);stroke-width:2;opacity:0;transform-box:fill-box;transform-origin:center;
  animation:pm-pulse 3s ease-out infinite}
.pin-map .pm-pin:hover .pm-dot,.pin-map .pm-pin:focus .pm-dot{fill:var(--accent)}
.pin-map .pm-pin:focus{outline:none}
.pin-map .pm-pin:focus-visible .pm-dot{stroke:var(--accent-deep);stroke-width:4}
@keyframes pm-pulse{0%{opacity:.7;transform:scale(.7)}70%{opacity:0;transform:scale(1.5)}100%{opacity:0;transform:scale(1.5)}}

.pm-legend{list-style:none;margin:0;padding:0;display:grid;gap:.35rem}
.pm-item{display:block;font-size:var(--step--1);line-height:1.4}
.pm-item > a{display:inline-flex;align-items:center;gap:.5rem;min-height:40px;font-weight:700;text-decoration:none}
.pm-item > a:hover{text-decoration:underline}
.pm-badge{display:inline-grid;place-items:center;width:26px;height:26px;border-radius:50%;
  background:var(--brand);color:#fff;font-size:.78rem;font-weight:800;flex:none}
.pm-note{color:var(--ink-soft)}
.pm-credit{color:var(--ink-soft);margin-top:var(--s3);max-width:80ch}
@media (max-width:820px){ .pm-grid-2{grid-template-columns:1fr} }
@media (prefers-reduced-motion: reduce){ .pin-map .pm-halo{animation:none;opacity:0} }

/* ---- tour explorer ---- */
.tex{margin-top:var(--s3)}
.tex-controls{display:grid;gap:var(--s3);margin-bottom:var(--s2)}
.tex-facet{border:1px solid var(--line);border-radius:var(--radius);padding:.7rem .9rem 1rem;margin:0;background:var(--surface)}
.tex-facet legend{padding:0 .35rem;font-size:var(--step--1);font-weight:800;letter-spacing:.02em}
.tex-chips{display:flex;flex-wrap:wrap;gap:.45rem}
.tex-chip{min-height:44px;padding:.5rem .9rem;border-radius:999px;border:1px solid var(--line);
  background:var(--surface-2);color:var(--ink);font:inherit;font-size:var(--step--1);font-weight:600;cursor:pointer}
.tex-chip:hover{border-color:var(--brand)}
.tex-chip:focus-visible{outline:3px solid var(--brand);outline-offset:2px}
.tex-chip.is-on{background:var(--brand);border-color:var(--brand);color:var(--accent-ink)}
.tex-chip .tex-n{opacity:.7;font-weight:700;font-size:.75em}
.tex-sortwrap{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem}
.tex-sortwrap label{font-size:var(--step--1);font-weight:700}
.tex-sort{min-height:44px;padding:.45rem .7rem;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--ink);font:inherit;font-size:var(--step--1)}
.tex-clear{min-height:44px}
.tex-note{color:var(--ink-soft);margin:.2rem 0 0;max-width:78ch}
.tex-status{margin:.5rem 0 var(--s2);font-size:var(--step--1);color:var(--ink-soft);min-height:1.5em}
.tex-table{min-width:720px}
.tex-table th[scope="col"]{width:auto;white-space:nowrap}
.tex-table .tex-name{width:30%}
.tex-table td,.tex-table th{padding:.6rem .8rem;font-size:var(--step--1)}
.tex-price{font-variant-numeric:tabular-nums;white-space:nowrap}
.tex-rev{color:var(--ink-soft)}
.tex-na{color:var(--ink-soft)}
.tex-empty{margin:var(--s3) 0 0;padding:var(--s3);border:1px dashed var(--line);border-radius:var(--radius);
  background:var(--surface-2);font-weight:600}
@media (min-width:820px){ .tex-controls{grid-template-columns:1fr 1fr;align-items:start} .tex-sortwrap{grid-column:1 / -1} }
/* === END pin-map schematic + tour explorer === */

/* ---- SECTION LINK LIST (homepage #kids / #rainy) --------------------------------------------
   These two approved sections shipped as a heading over a single paragraph that named articles
   it never linked to. They deliver a route onward, not a seventh copy of the product roster:
   one scannable line per article, title then what it is for. */
/* A TABLE-LIKE LIST ALIGNS ACROSS ROWS, SO THE GRID GOES ON THE LIST.
   Each row used to own its own `1fr auto`, which means every row measured its own note column
   and none of them lined up: a list of twelve links rendered twelve different column positions.
   The columns are declared once, here, and each row opts into them with subgrid. */
.section-links { list-style:none; margin:var(--s4) 0 0; padding:0;
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,max-content); gap:.5rem; }
.section-links li { margin:0; grid-column:1 / -1; }
.section-links a {
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,max-content); align-items:baseline; gap:.35rem 1.2rem;
  padding:.7rem .95rem; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--radius-sm); text-decoration:none; color:var(--ink);
}
/* AFTER the base rule, never before: a subgrid declaration that comes first is simply overridden
   by the explicit track list below it and is silently discarded, which is how this "fix" has
   shipped inert before. The @supports guard keeps the bound two-track fallback for browsers
   without subgrid. */
@supports (grid-template-columns: subgrid) {
  .section-links li { display:grid; grid-template-columns:subgrid; }
  .section-links a { grid-column:1 / -1; grid-template-columns:subgrid; }
}
.section-links a:hover { border-color:var(--brand); background:var(--paper-2); }
.section-links .sl-name { font-family:var(--display); font-weight:700; font-size:var(--step-0); line-height:1.3; }
.section-links .sl-note { color:var(--ink-soft); font-size:var(--step--1); line-height:1.4; text-align:right; }
@media (max-width:760px) {
  .section-links a { grid-template-columns:1fr; }
  .section-links .sl-note { text-align:left; }
}

/* ---- HOMEPAGE FAQ ---- */
.home-faq { margin-top:var(--s4); }
.home-faq .faq-more { margin:.35rem 0 .6rem; font-size:var(--step--1); }

/* DECISION PICKER: the compact server-rendered list (city-guide SKILL §11).
   The picker used to server-render a full image card per product, which on the donor site made
   the block 98 KB and a quarter of the homepage, duplicating the kinds grid directly below it.
   Every product is still here, still linked, still readable with scripting off; it is a row
   until the visitor answers a question, and only the matched few become cards. */
.decision-picker .dp-list { list-style:none; margin:0; padding:0; display:flex; flex-direction:column;
  border:1px solid var(--dp-line); border-radius:var(--radius-sm, 6px); overflow:hidden; background:var(--dp-surface); }
.decision-picker .dp-list[hidden] { display:none !important; }
.decision-picker .dp-row { display:grid; grid-template-columns:minmax(0,1.5fr) minmax(0,1.4fr) minmax(0,max-content) minmax(0,max-content);
  align-items:center; gap:.5rem .9rem; padding:.62rem .85rem; border-top:1px solid var(--dp-line); font-size:var(--step--1, .9rem); }
.decision-picker .dp-row:first-child { border-top:0; }
.decision-picker .dp-row:nth-child(even) { background:var(--dp-surface-2); }
.decision-picker .dp-row-name { color:var(--dp-ink); font-weight:700; text-decoration:none; min-width:0; }
.decision-picker .dp-row-name:hover { text-decoration:underline; }
.decision-picker .dp-row-facts { color:var(--dp-muted, inherit); min-width:0; display:flex; flex-wrap:wrap; gap:.5rem; }
.decision-picker .dp-row-facts span + span::before { content:"·"; margin-right:.5rem; opacity:.6; }
.decision-picker .dp-row-price { white-space:nowrap; }
.decision-picker .dp-row-cta { white-space:nowrap; font-weight:700; color:var(--dp-key); text-decoration:none;
  border:1px solid var(--dp-key); border-radius:999px; padding:.28rem .7rem; }
.decision-picker .dp-row-cta:hover { background:var(--dp-key); color:var(--accent-ink); }
/* The results grid is empty and hidden until a question is answered, so it must not reserve space. */
.decision-picker .dp-results[hidden] { display:none !important; }
@media (max-width: 860px) {
  .decision-picker .dp-row { grid-template-columns:minmax(0,1fr) minmax(0,max-content); row-gap:.3rem; }
  .decision-picker .dp-row-facts { grid-column:1 / -1; }
  .decision-picker .dp-row-cta { grid-column:2; grid-row:1; }
}

/* FLAGSHIP: the shore-conditions block. The live line RESERVES ITS HEIGHT so a successful fetch
   swaps text without moving anything below it. §12 is explicit that a blocked or slow API must
   produce zero layout shift, and a one-line paragraph that grows to two lines is a layout shift,
   so the reservation is two lines at the narrowest supported width. */
.surf { margin: var(--s4, 1.25rem) 0 0; }
.surf-table { width: 100%; border-collapse: collapse; font-size: var(--step--1, .9rem); }
.surf-table caption { text-align: left; padding-bottom: .5rem; color: var(--band-muted, var(--ink-soft)); }
.surf-table th, .surf-table td { padding: .55rem .7rem; border-bottom: 1px solid var(--band-line, var(--line)); text-align: left; vertical-align: top; }
.surf-table thead th { font-weight: 700; border-bottom-width: 2px; white-space: nowrap; }
.surf-table tbody th { font-weight: 700; white-space: nowrap; }
.surf-table td:nth-child(2), .surf-table td:nth-child(3) { white-space: nowrap; font-variant-numeric: tabular-nums; }
.surf-table td:last-child { min-width: 18ch; }
.surf-live {
  margin: var(--s3, 1rem) 0 .35rem;
  font-weight: 700;
  min-height: 3.1em;            /* two lines at 390px, so the live swap never reflows the page */
  display: flex; align-items: center;
}
.surf-src { margin: 0; color: var(--band-muted, var(--ink-soft)); }
@media (max-width: 640px) {
  .surf-table td:last-child { min-width: 0; }
  .surf-live { min-height: 4.2em; }
}

/* WHEN TO GO: the monthly sea-temperature chart. Hand-authored SVG, so it is styled here rather
   than inline, and it inherits the band tokens so it reads correctly on any section background.
   Note the SVG carries no <style> block of its own: an SVG <style> is NOT scoped and leaks into
   the whole page, which has broken sites in this pipeline before. */
.wtg-lead { font-size: var(--step-0); }
.wtg-fig { margin: var(--s4, 1.25rem) 0 .6rem; }
.wtg-chart { width: 100%; height: auto; display: block; }
.wtg-bar { fill: var(--band-link, var(--brand)); }
.wtg-bar.is-peak { fill: var(--band-cta-bg, var(--accent)); }
.wtg-val { font-size: 11px; font-weight: 700; fill: var(--band-fg, var(--ink)); }
.wtg-mon { font-size: 11px; fill: var(--band-muted, var(--ink-soft)); }
.wtg-ax  { font-size: 10px; fill: var(--band-muted, var(--ink-soft)); }
.wtg-grid { stroke: var(--band-line, var(--line)); stroke-width: 1; }
/* ---- Monthly data figures: the sea-temperature block and the when-to-go block.
   These two charts emitted class names that had NO CSS AT ALL, so twelve bars rendered as bare
   stacked numbers and the reader saw a broken figure. Both are now real SVG and every class they
   emit is defined here. If a chart class is ever added to a renderer, add its rule in the same
   commit: unstyled SVG does not error, it just looks wrong.
   Colours come from the band tokens so the figures stay legible on every section background. */
.wtg-rainbar { fill: var(--band-line, var(--line)); opacity: .85; }
.wtg-line { stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.wtg-air { stroke: var(--band-cta-bg, var(--accent)); }
.wtg-sea { stroke: var(--band-link, var(--brand)); }
.wtg-dot { stroke: var(--band-bg, var(--paper)); stroke-width: 1.5; }
.wtg-air-dot { fill: var(--band-cta-bg, var(--accent)); }
.wtg-sea-dot { fill: var(--band-link, var(--brand)); }
.wtg-bar.is-now { stroke: var(--band-fg, var(--ink)); stroke-width: 1.5; }
.wtg-key { display: inline-flex; align-items: center; gap: .35rem; margin-right: .9rem; white-space: nowrap; }
.wtg-key::before { content: ""; width: .85rem; height: .2rem; border-radius: .1rem; background: currentColor; }
.wtg-key-air { color: var(--band-cta-bg, var(--accent)); }
.wtg-key-sea { color: var(--band-link, var(--brand)); }
.wtg-key-rain { color: var(--band-muted, var(--ink-soft)); }
.wtg-key-rain::before { height: .6rem; width: .5rem; border-radius: .1rem; }
.st-live { font-size: var(--step-1, 1.15rem); margin-bottom: var(--s3, 1rem); }
.st-read { margin-top: var(--s3, 1rem); }
.wtg-rainfall, .wtg-light { margin-top: var(--s3, 1rem); }
.seatemp .wtg-fig { margin: var(--s3, 1rem) 0; }
@media (max-width: 640px) { .wtg-key { margin-right: .6rem; font-size: .8rem; } }

.wtg-fig figcaption { font-size: var(--step--1, .9rem); color: var(--band-muted, var(--ink-soft)); margin-top: .5rem; }
.wtg-src { color: var(--band-muted, var(--ink-soft)); margin: 0; }
.hotel-more { margin-top: var(--s3, 1rem); }
@media (max-width: 640px) { .wtg-val { font-size: 9px; } .wtg-mon { font-size: 9px; } }

/* ---- Dark-mode CORE PALETTE (Mangrove Green + Lechon Amber, dark variant). Added at D1a,
   2026-09-25: the donor only carried dark tokens for the map (--mp-*, below); the site body never
   had a dark ground at all, which is its own gap since prefers-color-scheme is device-level, not
   opt-in. Ground goes to a near-black mangrove green rather than a neutral grey, so the identity
   still reads in dark mode; brand and accent lift in lightness (a saturated colour needs less
   fill to read against near-black than it does against a pale paper). All four pairs measured
   >=7:1 against --paper: ink 13.68:1, brand 7.7:1, accent 8.16:1. ---- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink:        #E9E4D2;
    --ink-soft:   #B7B29C;
    --paper:      #141C13;
    --paper-2:    #1B2519;
    --surface:    #1E2A1C;
    --surface-2:  #253321;
    --line:       #33452E;
    --brand:      #6FBF5A;
    --brand-bright:#8ED679;
    --brand-deep: #0D140B;
    --signature:  #E0A83A;
    --accent:     #E0A83A;
    --accent-warm:#EEC167;
    --accent-deep:#B8862A;
    --accent-ink: #14180B;
    --gold:       #E0A83A;
    --gold-soft:  #4A3B18;
    --gold-ink:   #F2E4B9;
    --sea:        #E0A83A;
    --focus:      #8ED679;
    --sea-deep:   #8ED679;
    --slate:      #B7B29C;
    --footer:     #0D140B;
    --gold-light: #EEC167;
    --gold-deep:  #F2E4B9;
  }
}
:root[data-theme="dark"] {
  --ink:        #E9E4D2;
  --ink-soft:   #B7B29C;
  --paper:      #141C13;
  --paper-2:    #1B2519;
  --surface:    #1E2A1C;
  --surface-2:  #253321;
  --line:       #33452E;
  --brand:      #6FBF5A;
  --brand-bright:#8ED679;
  --brand-deep: #0D140B;
  --signature:  #E0A83A;
  --accent:     #E0A83A;
  --accent-warm:#EEC167;
  --accent-deep:#B8862A;
  --accent-ink: #14180B;
  --gold:       #E0A83A;
  --gold-soft:  #4A3B18;
  --gold-ink:   #F2E4B9;
  --sea:        #E0A83A;
  --focus:      #8ED679;
  --sea-deep:   #8ED679;
  --slate:      #B7B29C;
  --footer:     #0D140B;
  --gold-light: #EEC167;
  --gold-deep:  #F2E4B9;
}



/* ---- PORTED LAYOUT FIXES (2026-09-14) ---- */
/* Each rule below fixes a defect that shipped live and passed every text gate.
   build/qa-layout.py is the gate that now catches this whole class. */

/* Chips carry SENTENCES on these sites, not one-word labels, so they must wrap. Left at nowrap a
   chip rendered 609px wide inside a 332px card and its tail was cut off. */
.pc-chip,
/* A CHIP IS A LABEL. This rule used to let a chip wrap to any number of lines, which was the
   accommodation for putting a SENTENCE in one. The sentence moved to .tp-note, so the chip goes
   back to being a single-line pill. */
.tour-picks .tp-chips .pc-chip { white-space: normal; max-width: 100%; overflow-wrap: anywhere; }
/* The product's own one-liner: prose, in a paragraph, clamped to three lines so a long one
   cannot push the price and the CTA off the bottom of a card in a fixed-height grid row. */
.tour-picks .tp-note { margin:.3rem 0 .45rem; color:var(--ink-soft); font-size:var(--step--1);
  line-height:1.45; display:-webkit-box; -webkit-line-clamp:3; line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }

/* A link-card whose inner layout is two columns (name left, note right) must stack when the CARD
   is narrow, which is not the same question as when the WINDOW is narrow. Keyed to the viewport
   it never fired inside a 275px card at a 1440px window, and titles wrapped one word per line. */
.section-links li { container-type: inline-size; }
@container (max-width: 360px) {
  .section-links a { grid-template-columns: 1fr; }
  .section-links .sl-note { text-align: left; }
}

/* .btn-ghost is styled for a light ground. On a dark hero band its ink is the same colour as the
   overlay behind it and the button is invisible. */
.hero-full .btn-ghost, .band-dark .btn-ghost, [data-band="dark"] .btn-ghost {
  color: #fff; border-color: rgba(255,255,255,.55); background: rgba(255,255,255,.06);
}
.hero-full .btn-ghost:hover, .band-dark .btn-ghost:hover, [data-band="dark"] .btn-ghost:hover {
  border-color: #fff; background: rgba(255,255,255,.14);
}

/* Article tables are styled by `.prose table`. Nothing on a homepage is inside .prose, so a
   homepage table shipped with no border, no radius and a transparent header. */
/* Scoped to `main table` on purpose, NOT to a wrapper class. The first attempt keyed off
   `.table-scroll`, and the donor wraps its homepage tables in `.table-wrap` instead, so two
   unstyled tables sailed straight through. An element-only selector cannot miss a wrapper it has
   not heard of, and it is weak enough (0,0,2) that every existing class rule still wins:
   `.prose table` (0,1,1) keeps styling article tables and `.keyfacts` (0,1,0) keeps its own. */
main table {
  width: 100%; border-collapse: collapse; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
main table > thead > tr > th, main table > tr > th {
  background: var(--paper-2); color: var(--ink); text-align: left;
}

/* `.keyfacts th { width:42% }` is written for a TWO-column key/value table. Applied to a wide
   data table it starves the last column and one cell wraps one word per line. */
.keyfacts[class*="-table"] th, .keyfacts[class*="-table"] td { width: auto; vertical-align: top; }

/* Picker rows: each row is its own grid, so `auto` tracks made every row compute different
   column widths and nothing lined up. A product with no duration renders NO facts cell, which
   shifted its price and button into the wrong columns entirely. Pin each cell to its column. */
@media (min-width: 861px) {
  .decision-picker .dp-row { grid-template-columns: minmax(0,1.5fr) minmax(0,.9fr) 16rem 15.5rem; }
}
.decision-picker .dp-row-name  { grid-column: 1; }
.decision-picker .dp-row-facts { grid-column: 2; overflow-wrap: anywhere; }
.decision-picker .dp-row-price { grid-column: 3; justify-self: end; text-align: right;
  white-space: normal; overflow-wrap: anywhere; }
.decision-picker .dp-row-cta   { grid-column: 4; justify-self: stretch; text-align: center; }
@media (max-width: 860px) {
  /* Explicit ROWS as well as columns: two cells sharing a column with no row named let grid
     auto-placement drop them into the SAME cell, printing one on top of the other. */
  .decision-picker .dp-row { grid-template-columns: minmax(0,1fr) minmax(0,max-content); grid-template-rows: auto auto auto; row-gap: .3rem; }
  .decision-picker .dp-row-name  { grid-column: 1 / -1; grid-row: 1; }
  .decision-picker .dp-row-facts { grid-column: 1; grid-row: 2; }
  .decision-picker .dp-row-price { grid-column: 1; grid-row: 3; justify-self: start; text-align: left; }
  .decision-picker .dp-row-cta   { grid-column: 2; grid-row: 2 / span 2; justify-self: end; align-self: center; }
}

/* ============================================================================================
   LIVE DATA BLOCKS, lane D1e. Every class below is EMITTED by a renderer in this repo and is
   registered in build/check-styled.mjs. A renderer that invents a class name ships its CSS in the
   same change: on the donor build 15 of 17 emitted chart classes had no rule at all, so both data
   blocks rendered as bare stacked numbers, nothing errored, and the section was reported working
   twice because its TEXT was being read rather than the figure looked at.
   ============================================================================================ */

/* ---- {{ sea_temp_now }} : the live block, build/render-live-blocks.mjs -------------------- */
.boranow { margin: var(--s3, 1rem) 0 0; }
.bn-lead { font-size: var(--step-0); margin: 0 0 var(--s2, .6rem); }
/* THE SWAPPABLE SENTENCE RESERVES ITS HEIGHT. The live and cached strings are written to the same
   length by one skeleton function, and the box holds two lines at the narrowest layout, so neither
   a shorter nor a longer replacement can move anything below it. This is the CLS guarantee, and
   build/verify-live-blocks.py measures it with the upstream host blocked. */
.bn-live { font-size: var(--step-1, 1.15rem); line-height: 1.45; margin: 0 0 var(--s3, 1rem);
  min-height: calc(2 * 1.45em); }
.bn-num { font-variant-numeric: tabular-nums; }
.bn-disc { border-top: 1px solid var(--band-line, var(--line)); margin: 0; }
.bn-disc > summary { cursor: pointer; padding: .55rem 0; font-weight: 600;
  color: var(--band-link, var(--brand)); list-style-position: inside; }
.bn-disc > summary::marker { color: var(--band-muted, var(--ink-soft)); }
.bn-body { padding-bottom: .5rem; }
.bn-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.bn-table { border-collapse: collapse; width: 100%; min-width: 520px; font-size: var(--step--1, .9rem); }
.bn-table caption { text-align: left; color: var(--band-muted, var(--ink-soft));
  font-size: var(--step--1, .9rem); padding-bottom: .4rem; }
.bn-table th, .bn-table td { text-align: left; padding: .4rem .6rem; border-bottom: 1px solid var(--band-line, var(--line)); }
.bn-table thead th { background: var(--paper-2); font-weight: 700; white-space: nowrap; }
.bn-table tbody th { font-weight: 600; white-space: nowrap; }
.bn-table td { font-variant-numeric: tabular-nums; }
.bn-na { color: var(--band-muted, var(--ink-soft)); font-style: italic; }
.bn-read { margin: 0; }
.bn-src { color: var(--band-muted, var(--ink-soft)); margin: var(--s2, .6rem) 0 0; }
/* On a screen with room, the disclosures are open by default. Two mechanisms, because browsers
   disagree about how a closed <details> hides its content: the newer ::details-content box and the
   older "display:none on every non-summary child". Where neither applies the panel simply stays
   collapsed, which is a correct state and never a broken one. */
@media (min-width: 760px) {
  .bn-disc::details-content { content-visibility: visible; block-size: auto; }
  .bn-disc:not([open]) > .bn-body { display: block; }
  .bn-disc > summary { color: var(--band-muted, var(--ink-soft)); font-weight: 600; }
}

/* ---- {{ when_to_go }} : the information-gain block, build/blocks/climate-year.mjs ------------- */
.wtg { margin: var(--s3, 1rem) 0 0; }
.by-year { margin: var(--s3, 1rem) 0 0; }
.by-claim { font-size: var(--step-1, 1.15rem); line-height: 1.5; margin: 0 0 var(--s3, 1rem); }
.by-fig { margin: var(--s4, 1.25rem) 0 .6rem; }
.by-fig figcaption { font-size: var(--step--1, .9rem); color: var(--band-muted, var(--ink-soft)); margin-top: .5rem; }
.by-chart { width: 100%; height: auto; display: block; }
.by-bar { fill: var(--band-link, var(--brand)); }
.by-bar-low { fill: var(--band-cta-bg, var(--accent)); }
.by-val { font-size: 11px; font-weight: 700; fill: var(--band-fg, var(--ink)); font-variant-numeric: tabular-nums; }
.by-mon { font-size: 11px; fill: var(--band-muted, var(--ink-soft)); }
.by-ax  { font-size: 10px; fill: var(--band-muted, var(--ink-soft)); }
.by-grid { stroke: var(--band-line, var(--line)); stroke-width: 1; }
.by-floor { stroke: var(--band-cta-bg, var(--accent)); stroke-width: 1.5; stroke-dasharray: 5 4; }
.by-floorlab { font-size: 10px; font-weight: 700; fill: var(--band-cta-bg, var(--accent)); }
.by-note { margin: var(--s3, 1rem) 0 0; }
.by-src { color: var(--band-muted, var(--ink-soft)); margin: var(--s2, .6rem) 0 0; }
.by-disc { border-top: 1px solid var(--band-line, var(--line)); margin-top: var(--s3, 1rem); }
.by-disc > summary { cursor: pointer; padding: .55rem 0; font-weight: 600; color: var(--band-link, var(--brand)); list-style-position: inside; }
.by-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.by-table { border-collapse: collapse; width: 100%; min-width: 620px; font-size: var(--step--1, .9rem); }
.by-table caption { text-align: left; color: var(--band-muted, var(--ink-soft)); font-size: var(--step--1, .9rem); padding-bottom: .4rem; }
.by-table th, .by-table td { text-align: left; padding: .4rem .6rem; border-bottom: 1px solid var(--band-line, var(--line)); }
.by-table thead th { background: var(--paper-2); font-weight: 700; }
.by-table tbody th { font-weight: 600; white-space: nowrap; }
.by-table td { font-variant-numeric: tabular-nums; }
@media (max-width: 640px) { .by-val { font-size: 9px; } .by-mon { font-size: 9px; } .by-floorlab { font-size: 9px; } }
@media (min-width: 760px) {
  .by-disc::details-content { content-visibility: visible; block-size: auto; }
  .by-disc:not([open]) > .by-scroll { display: block; }
  .by-disc > summary { color: var(--band-muted, var(--ink-soft)); }
}

/* ---- {{ region_map }} : the day-trip panel, build/blocks/region-map.mjs --------------------
   The region tier SHIPS its derived water fill here, on this frame's own audits rather than on the
   inherited decision: gen-basemap.mjs disagreed with the surveyed coastline on 0.11% of its 1,296
   sample points and audit-basemap.mjs on 0.56% of 1,600 more, both well inside the 1.5% ceiling.
   The donor turned the fill off because its frame held a lagoon, a peninsula and 54 islands and
   missed by 2.78%. There is no international border in this frame, so .bm-border draws nothing at
   this tier. .bm-water, .bm-coast and .bm-river are the city panel's own layer rules, reused
   rather than duplicated. */
.rgn-block { margin: var(--s3, 1rem) 0 0; }
.rgn-wrap { margin: 0 0 var(--s3, 1rem); }
.rgn-map { width: 100%; height: auto; display: block; }
.rgn-frame { fill: var(--mp-land); stroke: var(--mp-edge); stroke-width: 1.25; }
.rgn-pin { cursor: pointer; }
.rgn-dot { fill: var(--band-link, var(--brand)); stroke: var(--mp-land); stroke-width: 1.5; }
.rgn-pin:hover .rgn-dot, .rgn-pin:focus .rgn-dot { fill: var(--band-cta-bg, var(--accent)); }
.rgn-num { font-size: 10px; font-weight: 700; fill: #fff; font-variant-numeric: tabular-nums; }
.rgn-lbl { font-size: 11px; fill: var(--ink); paint-order: stroke; stroke: var(--mp-land); stroke-width: 3px; stroke-linejoin: round; }
.rgn-lbl-home { font-size: 12.5px; font-weight: 700; }
.rgn-home circle { fill: none; stroke: var(--band-cta-bg, var(--accent)); stroke-width: 2; }
.rgn-home-dot { fill: var(--band-cta-bg, var(--accent)); stroke: none; }
.rgn-leader line { stroke: var(--ink-soft); stroke-width: 1; stroke-dasharray: 3 3; }
.rgn-bar-line { stroke: var(--ink-soft); stroke-width: 1.25; }
.rgn-north-head { fill: var(--ink-soft); }
.rgn-furn-lbl { font-size: 10px; fill: var(--ink-soft); }
.rgn-legend { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: .25rem 1rem; }
.rgn-meta, .rgn-attrib { font-size: var(--step--1, .9rem); color: var(--band-muted, var(--ink-soft)); }
.rgn-cards { margin-top: var(--s3, 1rem); }

/* A flagged placeholder is VISIBLY a placeholder (CLAUDE.md: placeholders are legal only when
   visually flagged). build/qa-dist.py fails the deploy while one is still in dist. */
.placeholder-flag { outline:2px dashed var(--warn); outline-offset:4px; background:var(--gold-soft); color:var(--gold-ink); padding:.4rem .6rem; border-radius:4px; font-size:var(--step--1); }
/* The honest one-liner on a tour page whose listing departs from more than one city. */
.tour-caveat { border-left:3px solid var(--brand); background:var(--paper-2); padding:.7rem 1rem; margin:var(--s4) 0; }

/* ---- Infographics (lane D3, build/gen-infographics.mjs). Canonical copy lives in
   src/public/assets/css/infographics.css; duplicated here so the sitewide stylesheet already
   linked on every page carries the rule with no compiler/head-partial change, matching this
   repo's own live-blocks.css/styles.css duplication convention. ---- */
.infographic { margin: 1.75rem 0; }
.infographic-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.infographic-scroll img { display: block; width: 680px; max-width: none; height: auto; }
.infographic figcaption { font-size: 0.85rem; color: var(--ink-soft, #4B5850); margin-top: 0.5rem; }

/* decision-names: tour-official (rule 36) */
.tour-official{margin:.35rem 0 0;font-size:var(--step-0,1rem);line-height:1.45;color:var(--ink-soft,var(--slate,#6b6b6b));font-weight:400}
