/* .content-page (base.css) provides the site-shell-width column every content page uses;
   .region-header keeps its own narrower 65ch cap for the intro text specifically, nested inside
   the wider .content-page container for grids/galleries. */

/* Shared placeholder box for attraction cards whose KTO record has no licensed image
   (`imageLicense` null) — never render an unlicensed image; show this instead. A plain #F7F9F8
   fill holding the slot's shape (DESIGN.md § Empty & fallback states), no wireframe border. */
.media-placeholder {
  background: var(--color-surface);
  border-radius: var(--radius-sm);
}

.data-provenance {
  margin-top: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* Photo-licence links (e.g. "CC BY 3.0 ↗") are outbound — orange with the ↗, per the palette. */
.data-provenance a {
  color: var(--color-accent);
  text-decoration: underline;
}

/* On the region page the galleries sit directly above their KTO source line — give it more air
   than the default so the credit reads as its own foot-of-block note (design reference 5b). */
.region-page .data-provenance {
  margin-top: 28px;
}

/* A second provenance line (study-café fallback note under the population line) is the same
   footnote block: 8px on phone, where each note wraps and needs to stay its own item, none from
   768px up (the line-height already spaces the two lines). */
.region-page .data-provenance + .data-provenance {
  margin-top: 8px;
}

@media (min-width: 768px) {
  .region-page .data-provenance + .data-provenance {
    margin-top: 0;
  }
}

/* Breadcrumb row under the nav (DESIGN.md § Recurring parts): 13px muted, hairline underneath. */
.region-breadcrumb {
  margin-bottom: 28px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--color-border-soft);
  font-size: 13px;
  color: var(--color-text-muted);
}

.region-breadcrumb a {
  color: var(--color-text-muted);
  text-decoration: none;
}

/* Grey family, not green: this link starts muted (not the usual green), so it darkens the same
   way the Clear button does (Muted → Ink soft) instead of jumping to a different hue on hover. */
.region-breadcrumb a:hover {
  color: var(--color-text-soft);
}

.region-breadcrumb__here {
  color: var(--color-text);
}

/* Plain muted line — no framed box (the dashed border read as "broken" / placeholder). */
.empty-state {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  line-height: 1.6;
}

/* The only links inside an empty state are the "browse the KTO site ↗" outbound fallbacks —
   orange with the ↗, per the DESIGN.md palette. */
.empty-state a {
  color: var(--color-accent);
  text-decoration: underline;
}

.region-header {
  margin-bottom: var(--space-6);
}

/* Shared .section-nav strip (section-nav.css, section-nav.js) — same sticky sub-nav as
   visa-info/settling-in, and the same 26px/36px gap around it visa-info gets for free from its
   own flex-column `gap`. .content-page is a plain block, not flex, so both edges are stated here
   explicitly instead — scoped with :has() to when a strip actually follows, so
   decline-counties.njk (shares .region-header, has no strip) keeps the plain --space-6 gap.
   Needs the .region-page ancestor in the selector, not just :has() alone — .region-page
   .region-header further down (the split-layout rule) sets its own margin-bottom at equal
   (class+class) specificity, and being later in the file would otherwise win the tie. */
.region-page .region-header:has(+ .section-nav) {
  margin-bottom: 26px;
}

.region-page > .section-nav {
  margin-bottom: 26px;
}

@media (min-width: 1024px) {
  .region-page .region-header:has(+ .section-nav) {
    margin-bottom: 36px;
  }

  .region-page > .section-nav {
    margin-bottom: 36px;
  }
}

.region-header h1 {
  max-width: 65ch;
}

.region-header__tags {
  max-width: 65ch;
}

.region-header__ko {
  font-family: var(--font-family-ko);
  font-weight: 400;
  color: var(--color-text-muted);
  font-size: var(--font-size-lg);
}

.region-header__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-2) 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.region-header__intro {
  margin-top: var(--space-3);
}

/* Season line (design reference 5b): orange dot → bold season name → its window, as wrapping
   plain-text items. ul.* selector — base.css's `ul[class] { margin: 0 }` reset ties with a bare
   class and would otherwise zero the margin-top. */
ul.region-seasons {
  display: flex;
  flex-wrap: wrap;
  gap: 7px 24px;
  max-width: none;
  margin-top: 18px;
  padding: 0;
  list-style: none;
  font-size: 15px;
  line-height: 1.6;
}

.region-seasons li {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.region-seasons__dot {
  flex: 0 0 5px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-accent-rule);
  transform: translateY(-2px);
}

.region-seasons strong {
  font-weight: 600;
}

.region-seasons li > span:last-child {
  color: var(--color-text-soft);
}

.region-seasons strong {
  color: var(--color-text);
}

/* ── Region-detail headline block (design reference 5b/5d) ────────────────────────────────────
   Scoped to .region-page (region.njk's wrapper) so /visa-info/ and /settling-in/ — which reuse
   the plain .region-header — keep their current styling this round. Layout: orange 56×3 rule →
   H1 + Korean name → vibe-tag pills → intro paragraphs → (Gangwon-do only) season line. */
.region-page .region-header__rule {
  display: block;
  width: 56px;
  height: 3px;
  border-radius: 2px;
  background: var(--color-accent-rule);
  margin-bottom: 24px;
}

.region-page .region-header h1 {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  max-width: none;
  font-size: clamp(2rem, 1.6rem + 1.8vw, 2.75rem);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.1;
}

.region-page .region-header__ko {
  font-size: clamp(1rem, 0.9rem + 0.4vw, 1.125rem);
}

.region-page .region-header__tags--vibe {
  max-width: none;
  gap: 7px;
  margin: 14px 0 0;
}

.region-page .region-header__tags--vibe li {
  padding: 7px 15px;
  border: 1px solid var(--color-primary-tint-border);
  background: var(--color-vibe-tag-bg);
  color: var(--color-primary-dark);
  border-radius: 22px;
  font-size: clamp(0.875rem, 0.84rem + 0.15vw, 0.9375rem);
  font-weight: 500;
  line-height: 1.2;
}

.region-page .region-header__intro {
  max-width: 66ch;
  margin-top: 14px;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-text-soft);
}

.region-page .region-header__intro:first-of-type {
  margin-top: 18px;
  font-size: var(--font-size-base);
}

/* ── Headline block: two columns on desktop (design reference 5b) ─────────────────────────────
   Left = rule → H1 → vibe tags → intro → season line. Right = (Gangwon only) furnished-rent
   recap card, then the capital-area note plate. One column below 900px, aside after the intro.
   Every region page uses the split so the note plate fills the right column at a consistent
   width; the county page (07d) reuses this block too. */
.region-page .region-header {
  display: grid;
  gap: 24px;
  margin-bottom: var(--space-8);
}

.region-page .region-header__aside {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* From 900px there's room for the aside (rent recap / note plate) beside the intro instead of
   stacked beneath it — below that it stays single-column. */
@media (min-width: 900px) {
  .region-page .region-header--split {
    grid-template-columns: 1.35fr 1fr;
    gap: 40px;
    align-items: start;
  }
}

/* Furnished short-term rent recap (Gangwon-do only — the one region with a market scan). */
.rent-summary {
  padding: 20px 22px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
}

.rent-summary__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.rent-summary__label {
  font-size: 13px;
  line-height: 1.45;
  color: var(--color-text-muted);
}

.rent-summary__figure {
  font-size: 24px;
  font-weight: 600;
  white-space: nowrap;
}

.rent-summary__note > div + div {
  margin-top: 4px;
}

.rent-summary__note {
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
  font-size: 13px;
  line-height: 1.6;
  color: var(--color-text-muted);
}

/* Note plate (DESIGN.md § Recurring parts): a line of text + a trailing "Visa info →" link.
   Green tint = "easier" (non-capital, lower income floor), orange tint = "stricter" (capital
   area). Capital-area regions also link "population-decline areas" inline. Copy is inline
   microcopy — no _data home yet (task-04 pattern). */
.note-plate {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 16px;
  border-radius: 10px;
}

.note-plate--easier {
  background: var(--color-primary-tint);
  border: 1px solid var(--color-primary-tint-border);
}

.note-plate--stricter {
  background: var(--color-accent-tint);
  border: 1px solid var(--color-accent-rule);
}

.note-plate__text {
  font-size: 13px;
  line-height: 1.45;
  color: var(--color-text-soft);
}

/* Inline "population-decline areas" link — in-site, so green (DESIGN.md palette). */
.note-plate__text a {
  color: var(--color-primary);
  font-weight: 500;
  text-decoration: underline;
}

/* Both note-plate links point to in-site pages with a → arrow, so both are green
   (DESIGN.md palette: green = in-site) — only the plate's tint differs by "easier"/"stricter".
   Hover colour comes from base.css's global a:hover; only the underline is added here. */
.note-plate__link {
  flex-shrink: 0;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  color: var(--color-primary);
  text-decoration: none;
}

.note-plate__link:hover,
.note-plate__link:focus-visible {
  text-decoration: underline;
}

/* Phone: the notice text wraps, so a trailing action beside it collides with the inline link.
   Stack — notice first, action on its own line beneath it, left-aligned. */
@media (max-width: 767.98px) {
  .note-plate {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
}

/* ── "Around the region" cover gallery (DESIGN.md § region page order; design reference 5b/5d) ──
   A heading + sub, a horizontal scroll-snap strip of photos (one full slide plus a peek of the
   next), a "1 / N" counter and prev/next arrows, then the KTO provenance line below. The strip
   scrolls/swipes with zero JS (same pattern as .attraction-list); region-hero-gallery.js layers
   the counter, arrows and autoplay loop on top. Region-page-exclusive markup — safe to own these
   selectors outright (visa-info.css reuses .region-header/.region-section, not .region-hero). */
/* Top margin matches .section-nav' own margin-bottom above (26px/36px) — block-flow margin
   collapsing takes the larger of two adjoining margins, so both sides need to actually agree on
   the target value rather than leaving this at the page's general --space-6 rhythm. */
.region-gallery {
  margin: 26px 0 var(--space-8);
}

@media (min-width: 1024px) {
  .region-gallery {
    margin-top: 36px;
  }
}

.region-gallery__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 10px 24px;
  margin-bottom: 14px;
}

.region-gallery__head .region-section__head {
  margin-bottom: 4px;
}

.region-gallery__sub {
  margin: 0;
  max-width: 60ch;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* Arrows + counter are a desktop convenience only — the phone gallery is swipe-only (design 5d),
   which also keeps the 34px arrows off the ≥44px-tap-target requirement. */
.region-gallery__controls {
  display: none;
}

.region-gallery__counter {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.region-hero {
  position: relative;
}

.region-hero__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.region-hero-gallery__track {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.region-hero-gallery__track::-webkit-scrollbar {
  display: none;
}

.region-hero-gallery__slide {
  position: relative;
  flex: 0 0 min(600px, 82%);
  height: clamp(210px, 52vw, 400px);
  margin: 0;
  border-radius: 12px;
  overflow: hidden;
  scroll-snap-align: start;
}

.region-hero-gallery__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-text-soft);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.region-hero-gallery__nav:hover,
.region-hero-gallery__nav:focus-visible {
  background: var(--color-surface);
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* Per-slide caption: full-width gradient overlay along the bottom edge (design 5b). Title line
   is the KTO photo title; the sub line carries the city plus the Korean name as a plain
   cross-reference aid (CLAUDE.md), not a 1:1 translation. */
.region-hero__caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 0;
  padding: 32px 20px 16px;
  color: var(--color-on-dark);
  background: linear-gradient(rgba(22, 32, 28, 0), rgba(22, 32, 28, 0.9));
}

.region-hero__caption-title {
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  font-weight: 600;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.region-hero__caption-sub {
  font-size: var(--font-size-sm);
  color: rgba(255, 255, 255, 0.78);
  /* cityEn · titleKo mixes Latin and Korean — same keep-all fix as the title above. */
  word-break: keep-all;
  overflow-wrap: break-word;
}

.region-hero__credit {
  margin: 10px 0 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

@media (min-width: 768px) {
  .region-gallery__controls {
    display: flex;
    align-items: center;
    /* 8px, matching .event-pager's gap (event-timeline.css) — same stepper control, same rhythm. */
    gap: 8px;
  }
}

.region-section {
  margin-bottom: var(--space-8);
  scroll-margin-top: var(--space-4);
}

/* Task 06: flat-scroll region page — 32px between sections (DESIGN.md § region page order),
   scoped so the wider .region-section default still holds on visa-info / settling-in. */
.region-page .region-section {
  margin-bottom: 32px;
}

/* The page ends on a one-line photo credit, not a full block — trim the trailing gap before the
   footer so it doesn't read as an empty section. */
.region-page .region-section:last-child {
  margin-bottom: var(--space-4);
}

/* base.css zeroes all heading margins, so every block title on this page sat flush against its
   content until this rule — restore the gap only within region-page contexts rather than
   globally, since other pages rely on the zeroed default. Section heading + orange tick
   (DESIGN.md "Section tick"), same recurring part as visa-info/settling-in's own section heads —
   the wrapper carries the gap that used to sit directly on the (now nested) h2. */
.region-section > h3 {
  margin-bottom: var(--space-3);
}

/* Base row layout (tick + h2) everywhere this wrapper is used — the gallery head (further up)
   and decline-counties' single section both nest it in markup that isn't .region-section/
   .region-band__col, so this stays unscoped; only the margin-bottom below varies by context. */
.region-section__head {
  display: flex;
  align-items: center;
  gap: 9px;
}

.region-section__tick {
  width: 3px;
  height: 15px;
  flex: 0 0 auto;
  background: var(--color-accent-rule);
}

.region-section > .region-section__head,
.region-band__col > .region-section__head {
  margin-bottom: var(--space-3);
}

/* Section headings on the flat region page are the DESIGN.md § Type "Section H2" size — the
   design reference sets every region-page section heading at 20px / 600 / -0.015em. Scoped to
   .region-page broadly (not just .region-section) so it also reaches the gallery and band-col
   heads, which sit in sibling markup rather than a .region-section itself. */
.region-page .region-section__head > h2 {
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.015em;
}

/* One-line intro under a section H2 (design reference 5b). Tightens the H2 gap when present —
   `:not([hidden])` so a JS-hidden subtitle (e.g. events.js's quotaExceeded state)
   falls back to the normal H2 margin instead of leaving the tight gap with nothing to fill it. */
.region-page .region-section > .region-section__head:has(+ .region-section__sub:not([hidden])),
.region-band__col > .region-section__head:has(+ .region-section__sub:not([hidden])) {
  margin-bottom: 4px;
}

.region-section__sub {
  margin: 0 0 18px;
  max-width: 62ch;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ── Guides strip (Gangwon-do only; design reference 5b) ──────────────────────────────────────
   Same inline-label row as settling-in's Reviews/Guides panels (settling-in.css
   .settling-reviews/.settling-inline-label): the orange tick + "Guides:" label sit on the same
   row as the link(s) whenever there's room, dropping to its own line only below 600px. */
.region-guides {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px 28px;
  padding: 15px 18px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
}

/* Not flex, same reason as .settling-inline-label (settling-in.css): a flex container's
   exported baseline is its first flex item's baseline, and the decorative tick (no text) would
   export its own bottom edge instead of "Guides:"'s actual text baseline, misaligning the whole
   row. Tick as inline-block + plain inline text reports the text's own baseline instead. */
.region-guides__head {
  white-space: nowrap;
}

.region-guides__items {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px 28px;
}

/* Below 600px (same breakpoint as settling-in's inline labels): force the label onto its own
   line so the links wrap cleanly underneath instead of competing for space beside it. */
@media (max-width: 599px) {
  .region-guides__head {
    flex-basis: 100%;
  }
}

/* Phone: tighten the panel and the gap between the two links so both fit on one line. */
@media (max-width: 767.98px) {
  .region-guides {
    padding: 14px;
  }

  .region-guides__items {
    gap: 10px 16px;
  }

  .region-guides__link {
    font-size: 13px;
  }
}

.region-guides__tick {
  display: inline-block;
  width: 3px;
  height: 15px;
  border-radius: 2px;
  margin-right: 9px;
  vertical-align: -2px;
  background: var(--color-accent-rule);
}

.region-guides__label {
  font-size: 13px;
  color: var(--color-text-muted);
}

/* min-width: 0 overrides the flex-item default (min-width: auto, i.e. "never shrink below my
   content's natural width") — without it, a long link/meta line (e.g. the decline-counties
   Source citation) can't wrap and just overflows the panel on narrow phones instead. */
.region-guides__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.region-guides__link {
  font-size: 14px;
  font-weight: 500;
  color: var(--color-accent);
  text-decoration: underline;
}

.region-guides__meta {
  font-size: 12px;
  color: var(--color-text-muted);
}

/* ── Costs + festivals band (DESIGN.md § region page order) ───────────────────────────────────
   One primary-tinted band that does the section-divider job: costs left, festivals right on
   desktop, stacked on phone. The columns sit flush with the page column (same left/right edge as
   the gallery and every other section); the tint + hairlines bleed 16px past that on each side
   via ::before, so it still reads as a full-width colour break without a viewport-wide full-bleed
   (which would add a scrollbar) and without indenting the content (design reference 5b). */
.region-band {
  position: relative;
  margin-block: 32px;
  padding-block: var(--space-6);
}

.region-band::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  margin-inline: calc(-1 * var(--space-4));
  background: var(--color-primary-tint);
  border-block: 1px solid var(--color-primary-tint-border-soft);
}

.region-band__inner {
  display: grid;
  gap: var(--space-6);
}

/* Costs + festivals sit side by side from 900px; below that they stack, and the cost block is
   capped to its desktop measure so it doesn't stretch to an unreadable line length. */
@media (min-width: 900px) {
  .region-band__inner {
    grid-template-columns: 1fr 1fr;
    gap: 40px;
    align-items: start;
  }
}

@media (max-width: 899.98px) {
  .region-band__col--costs {
    max-width: 32rem;
  }

  /* Stacked: the band's bottom padding already sits below the source line, so give it a bit more
     air above than below rather than an equal gap. */
  .region-page .region-band__col--events .data-provenance {
    margin-top: 44px;
  }
}

/* Region cost table (design reference 5b, Gangwon-do): white card, one figure per row on a light rule. */
.cost-table {
  margin: 0 0 14px;
  padding: 2px 18px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 10px;
}

.cost-table > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid var(--color-border-soft);
}

.cost-table > div:last-child {
  border-bottom: 0;
}

.cost-table dt {
  grid-row: span 1;
  font-size: 14px;
  color: var(--color-text-soft);
}

/* Label spanning a city's stacked size tiers. */
.cost-table dt.cost-table__label--span-2 {
  grid-row: span 2;
}

.cost-table dt.cost-table__label--span-3 {
  grid-row: span 3;
}

.cost-table dd {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
}

/* Gyeonggi-do's per-city breakdown: city, size and price each get their own column instead of
   the shared label/value pair. Columns are defined on the <dl> itself (not per-row) and each row
   is display:contents so every dt/dd is a direct grid item sharing one set of column tracks —
   sizing each row's own grid independently (the first version of this) let the "auto" price
   column's width vary row to row (e.g. "none" vs "₩1.8–2M"), which pushed the size column's
   start position sideways per row and produced a staircase instead of a lined-up column. */
/* align-items: stretch (not baseline) — dt is 14px, the size dd is 14px/400 and the price dd is
   15px/500, so baseline alignment let each cell's padding box end at a slightly different height
   per column, and the shared row divider came out visibly stepped at the column boundaries.
   Stretching every cell to the full row height makes every border-bottom land on the same line
   regardless of its own font size. */
.cost-table--3col {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) auto;
  align-items: stretch;
}

.cost-table--3col > div {
  display: contents;
}

/* No column-gap: cells sit flush against each other so each row's border-bottom is one
   continuous edge-to-edge line instead of breaking at the column gaps. The 12px gap that used to
   come from column-gap is recreated as padding-right on the two non-last columns instead. */
.cost-table--3col dt,
.cost-table--3col dd {
  padding: 11px 0;
  border-bottom: 1px solid var(--color-border-soft);
}

.cost-table--3col dt,
.cost-table--3col dd.cost-table__size {
  padding-right: 12px;
}

.cost-table--3col > div:last-child dt,
.cost-table--3col > div:last-child dd {
  border-bottom: 0;
}

/* Small column-label row above the city rows (design reference 7b): same grid columns as the
   data rows, just smaller and muted so it reads as a caption, not another data row. Equal
   top/bottom padding balances the gap to the card's top border against the gap to the first
   city row. The dd.cost-table__size selector is repeated to out-specificity the later
   `.cost-table dd.cost-table__size` rule below — without it, the "Size" label alone would fall
   back to that rule's 14px/soft-color style while "City"/"Per month" stayed small and muted. */
.cost-table--3col .cost-table__head dt,
.cost-table--3col .cost-table__head dd,
.cost-table--3col .cost-table__head dd.cost-table__size {
  padding-top: 8px;
  padding-bottom: 8px;
  font-size: 12px;
  font-weight: 400;
  color: var(--color-text-muted);
}

/* The two tiers read as one row: no divider between them and a tighter gap than between
   cities. */
.cost-table--3col dd.cost-table__cell--stacked-first {
  padding-bottom: 3px;
  border-bottom: 0;
}

.cost-table--3col dd.cost-table__cell--stacked-last {
  padding-top: 3px;
}

/* The row right above "Upfront deposit" gives up its own bottom divider so only the deposit
   row's (stronger) top divider draws there — otherwise the two 1px lines sit flush against each
   other and read as one thick/doubled line. */
.cost-table--3col .cost-table__row--before-deposit dt,
.cost-table--3col .cost-table__row--before-deposit dd {
  border-bottom: 0;
}

/* Upfront deposit is a different kind of row from the city prices above it — a visibly heavier
   rule, not just the same hairline in a darker shade. */
.cost-table--3col .cost-table__row--deposit dt,
.cost-table--3col .cost-table__row--deposit dd {
  border-top: 2px solid var(--color-border);
  border-bottom: 0;
}

.cost-table dd.cost-table__size {
  font-size: 14px;
  font-weight: 400;
  color: var(--color-text-soft);
}

.cost-caption {
  margin: 0 0 12px;
  font-size: var(--font-size-sm);
  line-height: 1.5;
  color: var(--color-text-muted);
}

.cost-note {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--color-text-soft);
}

.cost-note + .cost-note {
  margin-top: 10px;
}

.cost-link {
  margin: 14px 0 0;
  font-size: 14px;
  font-weight: 500;
}

.cost-link a {
  color: var(--color-primary);
  text-decoration: none;
}

.cost-link a:hover {
  text-decoration: underline;
}

/* ── Gyeonggi-do population-decline areas (population-decline-areas.njk) ─────────────────
   Redesign style: reuses the wide .region-page shell + two-column .region-header--split headline
   (rule → H1 → Korean name → intro; aside holds the threshold card instead of the rent recap).
   Below: a source note, a "by tier" section with two chip-labelled scroll strips of dark photo
   cards, and a placeholder plate for the future distance-from-Seoul map. */
.county-page__ko {
  margin: 6px 0 0;
  font-family: var(--font-family-ko);
  font-size: 17px;
  color: var(--color-text-muted);
}

/* Tinted threshold-summary card (design reference 6c). Sits in the headline aside; rows and the
   lead line are divided by the soft primary hairline, no inner card. */
.threshold-card {
  padding: 18px 20px;
  background: var(--color-primary-tint);
  border: 1px solid var(--color-primary-tint-border-soft);
  border-radius: 12px;
}

.threshold-card__table {
  margin: 0;
}

.threshold-card__table > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px solid var(--color-primary-tint-border-soft);
}

.threshold-card__table > div:last-child {
  border-bottom: 0;
}

.threshold-card__table dt {
  font-size: 13px;
  color: var(--color-text-soft);
}

.threshold-card__table dd {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  text-align: right;
  white-space: nowrap;
}

.threshold-card__note {
  margin: 12px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-text-muted);
}

.threshold-card__links {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 12px 0 0;
}

.threshold-card__links a {
  font-size: 14px;
  font-weight: 500;
  color: var(--color-primary);
  text-decoration: none;
}

.threshold-card__links a:hover {
  text-decoration: underline;
}

/* Source note — panel with an orange tick, "Source:" and the link sitting on the same row
   whenever there's room (design ref 6c; same inline-label pattern as .region-guides and
   settling-in's Reviews/Guides rows — settling-in.css .settling-reviews). */
.source-note {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 24px;
  padding: 15px 18px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
}

/* Not flex, same reason as .region-guides__head/.settling-inline-label — keeps "Source:"'s own
   text baseline instead of a nested flex container's exported baseline. */
.source-note__head {
  font-size: 13px;
  color: var(--color-text-muted);
  white-space: nowrap;
}

.source-note__tick {
  display: inline-block;
  width: 3px;
  height: 15px;
  border-radius: 2px;
  margin-right: 9px;
  vertical-align: -2px;
  background: var(--color-accent-rule);
}

/* Below 600px (same breakpoint as settling-in's inline labels): force the label onto its own
   line so the link wraps cleanly underneath instead of competing for space beside it. */
@media (max-width: 599px) {
  .source-note__head {
    flex-basis: 100%;
  }
}

/* Body reuses .region-guides__item/__link/__meta (link + source/date caption stack) — same
   citation-link pattern as the Gangwon-do Guides strip and settling-in's Reviews/Guides links. */

/* "The seven, by tier" — one chip-labelled row + a horizontal scroll-snap strip per tier
   (same no-JS pattern as .attraction-list / .region-hero-gallery__track). */
.tier-group {
  margin-top: 22px;
}

.tier-group:first-of-type {
  margin-top: 0;
}

.tier-label {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  font-size: 14px;
  color: var(--color-text-soft);
}

.tier-chip {
  flex-shrink: 0;
  padding: 4px 11px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 500;
}

.tier-chip--designated {
  background: var(--color-primary-tint);
  border: 1px solid var(--color-primary-tint-border-soft);
  color: var(--color-primary);
}

.tier-chip--watch {
  background: var(--color-accent-tint);
  border: 1px solid var(--color-accent-rule);
  color: var(--color-accent-chip);
}

.tier-grid {
  display: flex;
  gap: 16px;
  margin: 0;
  padding: 0 0 4px;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.tier-grid::-webkit-scrollbar {
  display: none;
}

.tier-card {
  flex: 0 0 264px;
  scroll-snap-align: start;
  border: 1px solid var(--color-border);
  border-radius: 12px;
  overflow: hidden;
}

.tier-card__figure {
  position: relative;
  margin: 0;
  height: 150px;
  background: var(--color-surface);
}

.tier-card__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tier-card__spot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 40px 14px 12px;
  background: linear-gradient(
    rgba(22, 32, 28, 0),
    rgba(22, 32, 28, 0.4) 45%,
    rgba(22, 32, 28, 0.9)
  );
  color: var(--color-on-dark);
  text-shadow: 0 1px 3px rgba(22, 32, 28, 0.55);
}

.tier-card__spot-en {
  display: block;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.35;
}

.tier-card__spot-ko {
  display: block;
  font-family: var(--font-family-ko);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.72);
}

.tier-card__body {
  padding: 14px 16px;
}

.tier-card__name {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.tier-card__ko {
  font-family: var(--font-family-ko);
  font-weight: 400;
  font-size: 13px;
  color: var(--color-text-muted);
}

.tier-card__metro {
  margin: 2px 0 0;
  font-size: 13px;
  color: var(--color-text-muted);
}

@media (min-width: 768px) {
  .tier-card {
    flex-basis: 288px;
  }
}

/* "Places to see nearby" filter row — two independent single-select pill groups, Area (city,
   plus "Elsewhere" for attractions not tied to one) and Type (category). Selection is handled
   by attraction-filters.js; it only toggles pill state for now, it does not filter
   .attraction-list yet. */
.attraction-filters {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  margin-bottom: var(--space-4);
}

.attraction-filters__group {
  display: flex;
  gap: 7px;
  align-items: center;
  flex-wrap: wrap;
}

.attraction-filters__label {
  font-size: 13px;
  color: var(--color-text-muted);
  margin-right: 2px;
}

.attraction-filters__pills {
  display: flex;
  gap: 7px;
  align-items: center;
  flex-wrap: wrap;
}

.filter-pill {
  position: relative; /* anchors the ::after tap-target hit-slop added for phone below */
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  /* Body text's line-height (1.65) inherits into buttons in most browsers — reset it, or the
     pill's box grows well past what the 7px 13px padding alone implies. Matches the vibe-tag
     pill's line-height (region-header__tags--vibe li). */
  line-height: 1.2;
  padding: 7px 13px;
  border-radius: 20px;
  cursor: pointer;
  background: var(--color-bg);
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
}

.filter-pill.is-selected {
  background: var(--color-primary);
  color: var(--color-on-dark);
  border-color: var(--color-primary);
}

@media (hover: hover) {
  .filter-pill:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
  }

  .filter-pill.is-selected:hover {
    color: var(--color-on-dark);
  }
}

/* Phone: two stacked rows (one per group) instead of one wrapping row; pills scroll rather than
   wrap, label pinned to a fixed width so "Area" and "Type" line up. */
@media (max-width: 899.98px) {
  .attraction-filters {
    flex-direction: column;
    /* Also keeps clear of the invisible 44px tap-target ::after below (each pill's own row
       overflows ~6px above/below its visible 30px height) so the Area and Type rows' hit
       areas don't overlap. */
    gap: 9px;
  }

  .attraction-filters__group {
    /* .attraction-filters is a column flex container below 900px, so this group is itself a
       flex item — align-items' default "stretch" doesn't reliably cap a wrapping flex item's
       cross size to the line's cross size in every engine, so state the width explicitly
       instead of relying on it. Without a definite width here, the group (and the page) grows
       to its content's full min-content size (all pills laid out flat) instead of leaving the
       overflow inside the pills track below. */
    width: 100%;
    min-width: 0;
    flex-wrap: nowrap;
  }

  .attraction-filters__label {
    flex: 0 0 38px;
    margin-right: 0;
  }

  .attraction-filters__pills {
    /* Without this the track's flex-basis defaults to its unwrapped content width (every pill
       laid out flat), which pushes .attraction-filters__group — and the page — wider than the
       viewport instead of scrolling internally. */
    min-width: 0;
    /* Matches the pills' own ::after tap-target height below so it fits with zero vertical
       overflow. Without this the track is only as tall as the ~30px visible pill, the ::after
       overhangs top and bottom, and browsers silently promote this element's overflow-y from
       "visible" to "auto" (they refuse to leave one axis visible when the other, overflow-x, is
       not) — surfacing an unwanted vertical scrollbar on what's meant to be a one-line row. */
    min-height: 44px;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .attraction-filters__pills::-webkit-scrollbar {
    display: none;
  }

  .filter-pill {
    white-space: nowrap;
  }

  /* Reach the 44px tap-target minimum (DESIGN.md § Accessibility) via an invisible hit-slop
     instead of padding, so the pill looks identical to desktop (13px / 7px 13px / 20px radius,
     ~30px tall) on phone too. */
  .filter-pill::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    height: 44px;
  }
}

/* Attractions + dishes: horizontal scroll-snap strips (no carousel library, no JS). The
   scrollbar track is hidden (design reference 5b/5d) — the peek of the next card is the
   scroll affordance. */
.attraction-list,
.dish-list {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-bottom: 2px;
}

.attraction-list::-webkit-scrollbar,
.dish-list::-webkit-scrollbar {
  display: none;
}

.attraction-card,
.dish-card {
  flex: 0 0 240px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
}

/* attraction-filters.js toggles the hidden attribute to filter cards — needed because an
   author stylesheet's `display: flex` above always beats the browser's own `[hidden]` default,
   regardless of source order. */
.attraction-card[hidden] {
  display: none;
}

.attraction-card__media,
.dish-card__media {
  aspect-ratio: 3 / 2;
  width: 100%;
  object-fit: cover;
  border-radius: 10px;
  margin-bottom: 9px;
}

/* Wraps the media so the category plate (below) can sit over the photo's top-left corner —
   same pattern as .dish-card__figure. */
.attraction-card__figure {
  position: relative;
  margin-bottom: 9px;
}

.attraction-card__figure .attraction-card__media {
  margin-bottom: 0;
}

/* Category plate — the same value the Type filter above uses, so a filtered result confirms
   itself. Neutral white/no border, unlike the dish plates: it's a filter value, not a semantic
   tag. */
.attraction-card__category {
  position: absolute;
  left: 10px;
  top: 10px;
  font-size: 12px;
  font-weight: 400;
  /* Same inherited-line-height fix as .filter-pill above. */
  line-height: 1.2;
  padding: 3px 9px;
  border-radius: 20px;
  background: var(--color-bg);
  color: var(--color-text);
}

/* Phone: slightly narrower card so more of the next one peeks past the viewport edge;
   aspect-ratio 3/2 on the media derives the ~140px image height. */
@media (max-width: 899.98px) {
  .attraction-card {
    flex: 0 0 210px;
  }
}

/* attractions.js renders the attraction title as an <h4> — bring it down to the design's
   card-title size (15px / 500), not base.css's page-scale h4. Titles mix an English name with a
   Korean name in .attraction-card__ko/.dish-card__ko (inherits word-break/overflow-wrap from
   here): keep-all stops a Korean word splitting mid-character (e.g. "미술관" hanging a lone "관"
   on the next line). (text-wrap: pretty was tried here too, for the English name's own
   hyphen-free wrapping, e.g. "Seogwipo-si" — but on these two-line titles it moved a whole
   trailing word to line two to "balance" the lines even when it fit on line one, e.g.
   "Gongjicheon Recreation" / "Area 공지천유원지" with visible slack left after "Recreation" — so
   it's not used.) */
.attraction-card h4,
.dish-card__name {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.3;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.attraction-card__address,
.dish-card__note {
  margin: 2px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-text-muted);
  word-break: keep-all;
  overflow-wrap: break-word;
}

.attraction-card__address {
  margin-top: 5px;
}

/* Same glyph as the festival pin (event-timeline.css PIN_ICON) — fill: currentColor inherits
   this muted colour automatically, never the accent green. Sits inline before the address text
   on purpose (not flex): plain inline flow only puts the pin on line one and returns any wrapped
   second line flush to the card's own left edge, which a flex/hang-indent layout would not. The
   festival pin never needed `display: inline-block` here because .event-place is a flex
   container; base.css's global `svg { display: block }` reset otherwise makes an inline SVG
   stack as its own line instead of sitting in the text. */
.attraction-card__pin {
  display: inline-block;
  width: 12px;
  height: 12px;
  vertical-align: -1px;
  margin-right: 4px;
}

.attraction-card__ko,
.dish-card__ko {
  font-family: var(--font-family-ko);
  font-weight: 400;
  color: var(--color-text-muted);
  font-size: 12px;
}

/* Phone: open up the text block so it doesn't crowd the card edges. */
@media (max-width: 767.98px) {
  .attraction-card,
  .dish-card {
    padding-bottom: 14px;
  }

  .attraction-card__ko,
  .dish-card__ko {
    display: block;
    margin-top: 6px;
  }

  .attraction-card__address,
  .dish-card__note {
    margin-top: 8px;
  }
}

.dish-card__figure {
  position: relative;
  margin-bottom: 9px;
}

.dish-card__figure .dish-card__media {
  margin-bottom: 0;
}

/* Dish plate — one component, three colour variants (DESIGN.md § Dish plate). Heat (spicy) and
   kind (spicy ingredient / drink / dessert) are separate axes; heat renders first when both are
   present. Backgrounds are fully opaque so a plate reads the same on a photo as off it. */
.dish-plate {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.005em;
  border-radius: 20px;
  padding: 3px 10px;
  white-space: nowrap;
  border: 1px solid transparent;
}

.dish-plate--spicy {
  background: var(--color-accent-tint);
  border-color: var(--color-accent-rule);
  color: var(--color-accent-ink);
}

.dish-plate--spicy-ingredient {
  background: var(--color-surface);
  border-color: var(--color-accent-rule);
  color: var(--color-accent-ink);
}

.dish-plate--drink,
.dish-plate--dessert {
  background: var(--color-surface);
  border-color: var(--color-border);
  color: var(--color-text-soft);
}

.dish-card__plates {
  position: absolute;
  top: 9px;
  left: 9px;
  right: 9px;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

/* City overlay — English only, same bottom-scrim treatment as the attraction cards. */
.dish-card__city {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 64px;
  margin: 0;
  padding: 0 11px 9px;
  display: flex;
  align-items: flex-end;
  border-radius: 0 0 10px 10px;
  background: linear-gradient(rgba(22, 32, 28, 0), rgba(22, 32, 28, 0.72));
  color: var(--color-on-dark);
  font-size: 13px;
  font-weight: 500;
  pointer-events: none;
}

.dish-card__restaurant {
  display: block;
  margin-top: auto;
  padding-top: 10px;
  font-size: 13px;
  color: var(--color-accent);
  text-decoration: underline;
}

/* Legend line for any plate whose meaning isn't obvious on its own (DESIGN.md § Dish plate) —
   only "spicy ingredient" needs one; "spicy", "drink" and "dessert" are self-explanatory. */
.dish-legend {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 16px 0 0;
  font-size: 13px;
  color: var(--color-text-muted);
}

/* Light grey divider between the attractions strip and the dishes strip (design reference 5b). */
.region-section--food {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-6);
}
