/* The next screen — everything that is not the hero starts below the fold */
.page-next {
  min-height: calc(100vh - 64px);
  min-height: calc(100svh - 64px);
  padding: 48px 24px 72px;
  scroll-margin-top: 64px;
}

/* ===================================================================
   Image placeholder — the .ph block (endurance still carries a local copy
   pending the drift sweep): a quiet
   dashed frame on the elevated ground holding the slot until the real
   photo lands. Aspect via ::before — 62% base, .wide 48%, .square 100%.
   =================================================================== */
.ph {
  position: relative;
  display: block;
  width: 100%;
  max-width: var(--read-w, 430px);   /* section image/diagram — the shared reading measure */
  border: 1px dashed rgba(241, 241, 241, 0.28);
  border-radius: var(--r);
  background:
    linear-gradient(135deg, rgba(241, 241, 241,0.03) 0%, transparent 48%),
    var(--g-elev);
  overflow: hidden;
  min-height: 200px;
}
.ph::before {
  content: "";
  display: block;
  padding-top: 62%;
}
.ph.wide::before { padding-top: 48%; }
.ph.square::before { padding-top: 100%; }

/* ===================================================================
   The poster duo — rs-duo ("the classic grid"): ONE full screen, two equal
   columns on
   the house frame + rail — copy one side, media the other (.ph slot,
   rs-globe, img, canvas). Successive duos alternate sides with
   .rs-duo--flip (media leads, copy rides right). Mobile stacks to one
   column, COPY FIRST regardless of flip — the words lead, the image
   follows. The copy column carries the 20px stack rhythm and the body
   measure; pages dress faces (serif titles etc.), never layout.
   Markup:
     <section class="rs-duo [rs-duo--flip]">
       <div class="rs-duo-copy"> eyebrow · h2 · body lines </div>
       <div class="rs-duo-media"> .ph | .rs-globe | <img> </div>
     </section>
   =================================================================== */
.rs-duo {
  min-height: calc(100vh - 64px);
  min-height: calc(100svh - 64px);
  width: 100%;
  max-width: var(--frame);
  margin: 0 auto;
  padding: 24px clamp(24px, 5vw, 48px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  align-content: center;
  column-gap: clamp(24px, 5vw, 64px);
  row-gap: 20px;
  scroll-margin-top: 64px;
}
.rs-duo-copy {
  display: grid;
  gap: 20px;
  align-content: center;
}
.rs-duo-copy p {
  margin: 0;
  font-size: var(--t-body);
  line-height: 1.7;
  color: var(--ink-2);
}
.rs-duo-media { min-width: 0; }
/* The flip — the alternating grid's other stride. */
.rs-duo--flip .rs-duo-copy { order: 2; }
.rs-duo--flip .rs-duo-media { order: 1; }
/* The top rail — copy and media share a top edge instead of centring:
   the readout's first line meets the globe's crown. */
.rs-duo--top { align-items: start; }
@media (max-width: 900px) {
  .rs-duo { grid-template-columns: 1fr; }
  .rs-duo--flip .rs-duo-copy { order: 1; }
  .rs-duo--flip .rs-duo-media { order: 2; }
}
/* Location brick — the undisclosed-locations globe section (.rs-duo--flip--top).
   The title types out (mountClimb); the 3D snow-star + outline globe auto-mount
   via the section kit (star-3d.js, globe.js). Self-contained so the brick drops
   into any page with no local style block. */
.rs-duo h2.globe-title {
  margin: 0;
  font-family: "Fira Code", ui-monospace, monospace;
  font-size: var(--t-head);
  font-weight: 500;
  letter-spacing: var(--track-label);
  line-height: 1.6;
  text-transform: lowercase;
  color: var(--ink);
}
.globe-title-line { display: block; }
.loc-star-3d { width: 36px; height: 36px; pointer-events: none; }
.senses-globe { justify-self: center; width: min(100%, 76vh); aspect-ratio: 1; }
@media (min-width: 901px) { .rs-duo--top .senses-globe { margin-top: clamp(48px, 8vh, 96px); } }
.senses-globe canvas {
  outline: none;
  /* Vignette masks the map canvas only, so the pins and wires above stay crisp. */
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 66%, transparent 100%);
          mask-image: radial-gradient(circle at 50% 50%, #000 66%, transparent 100%);
}

/* Static location brick — the native app (WKWebView) cannot hold a live map
   WebGL context, so the same section renders a static Costa Rica globe SVG
   (tools/attic/render-globe.mjs). Shared so home and the retreat page drop
   the same brick. The coastline is an outline on a transparent canvas so the
   particle field shows through; a ground fill or a vignette to --g reads as a
   black square (William, 2026-08-25). A live MapLibre globe (.rs-globe) still
   clips and fades into the card. */
.loc-lockup { display: flex; align-items: center; gap: clamp(14px, 2.2vw, 24px); }
.loc-lockup .loc-mark { width: 48px; height: 48px; flex: 0 0 auto; }
.loc-lockup .globe-title { margin: 0; font-size: clamp(13px, 4.1vw, 16px); }
.loc-lockup .globe-title-line { white-space: nowrap; }
.globe-card {
  position: relative;
  width: 100%;
  /* Section images/diagrams span the --read-w reading measure, so a map/diagram
     lines up with the justified body column (NOT the narrower --card-w trading
     card). The one section-media width, app-wide. */
  max-width: var(--read-w, 430px);
  aspect-ratio: 1;
  margin-inline: auto;
  overflow: visible;
  border: 1px solid transparent;   /* invisible stroke — no visible line */
  background: transparent;
}
.globe-card img { display: block; width: 100%; height: 100%; object-fit: contain; }
.globe-card::after { content: none; }
/* Coastline globe (loc-globe.js). The still PNG is the fallback. The pin
   is the Costa Rica name and flag. */
.globe-card:has(.loc-globe-stage) { display: grid; place-items: center; }
.loc-globe-stage {
  position: relative;
  width: 86%;
  height: 86%;
}
.globe-card.is-live .loc-globe-stage,
.globe-card.is-live canvas.loc-globe {
  cursor: grab;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}
.globe-card.is-live.is-dragging .loc-globe-stage,
.globe-card.is-live.is-dragging canvas.loc-globe { cursor: grabbing; }
.globe-card canvas.loc-globe {
  display: block;
  width: 100%;
  height: 100%;
}
.globe-card.is-live img { display: none; }
.globe-card .loc-pin-label {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(4px, calc(-50% - 7px));
  z-index: 3;
  background: var(--g);
  color: var(--ink);
  font-family: var(--font-code, "Fira Code", ui-monospace, monospace);
  font-size: var(--t-caption);
  letter-spacing: var(--track-head);
  line-height: 1.2;
  padding: 2px 5px;
  white-space: nowrap;
  pointer-events: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--hibiscus);
}
.globe-card.is-live .loc-pin-label {
  left: 0;
  top: 0;
  will-change: transform;
}
.globe-card .loc-pin-flag {
  height: 0.72em;
  height: 1cap;
  width: auto;
  flex: 0 0 auto;
  display: block;
}
.globe-card:has(.rs-globe) {
  overflow: hidden;
  background: var(--g);
}
.globe-card:has(.rs-globe)::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, transparent 52%, var(--g) 100%);
  pointer-events: none;
}

/* ===================================================================
   Weather CTA buttons — a reusable component
   ONE construction carrying a weather MARK, in two styles: the primary
   (--solid) wears the stroke in that glyph's OWN weather colours at rest
   and presses into the inverse (ink fill, ground text) — its third state;
   the ghost is a hairline that lights the same colours on hover. One
   colour → a solid stroke; more than one → a gradient across them (SCENT
   stars carry all six, so they paint the full spectrum — the home
   "experiences" button). The stroke is read straight off the mark
   (data-wx-mark) via :has(), so a button is just the mark you drop in —
   no extra colour class to keep in sync.

   Markup (use anywhere):
     <div class="btn-row">
       <a class="btn btn--ghost" href="…">
         <img class="btn__mark" data-wx-mark="brand" src="…" alt="" aria-hidden="true">
         <span class="btn__words"><span class="btn__lead">Join rainyseason.cr</span></span>
       </a>
       … a second button …
       <button class="btn btn--curl" type="button">…curl…</button>  (optional copy bar)
     </div>
   Weather → token: Sun --sun · Thunder --thunder · Snow --snow · Hard rain
   --hard-rain · Rain --rain · Cloud --lit. Wire the curl clipboard per page. */

/* The row — the private line gate-step geometry, every screen size: ONE column
   of full-width rows capped at the private line button width (--btn-w-full),
   --btn-gap apart. Buttons centre their label + mark as one group; the curl
   bar keeps its own left-code / right-icon layout. */
.btn-row {
  display: grid;
  grid-template-columns: 1fr;
  align-items: stretch;
  gap: var(--btn-gap, 12px);
  width: min(100%, var(--btn-w-full, 420px));
}
/* Width comes from the button's own full-row law (button.css). */
.btn-row .btn:not(.btn--curl) { justify-content: center; }
.btn-row .btn:not(.btn--curl) .btn__words { flex: 0 1 auto; }
/* A .btn--full-row spans every column of the row — the shell utility
   (William, 2026-08-05; lifted from the home page). */
.btn-row > .btn--full-row { grid-column: 1 / -1; }
/* The copy bar matches the button's FULL width (William, 2026-07-30) and now
   rides BELOW the buttons (2026-08-06): the buttons sit on top, the curl on
   the floor as the last row, everywhere. The curl is secondary matter, so it
   takes the baseline while the primary action leads. */
.btn-row .btn--curl { grid-column: 1 / -1; order: 1; }

/* The cluster goes full-width on phones — it's a centred grid item that
   otherwise shrink-wraps to its widest child (a 92vw 3D mark, say). */
@media (max-width: 760px) {
  .page-hero-center { width: 100%; }
}

/* .btn and every variant live in packages/shell/button.css — one canonical
   source, shared verbatim with the private line (tools/sync-shared.sh). */

/* Narrow screens — labels wrap rather than overflow. */
@media (max-width: 720px) {
  .btn .btn__lead { white-space: normal; }
}

/* ---- Globe pins — brand lockups riding the outline globe ----
   Square-edge pills carrying the menu-bar lockup grammar (mark + wordmark,
   filled by the declarative data-wx-mark + data-brand-name system). globe.js
   lifts each .rs-globe-pin into a MapLibre marker at its data-lng/lat: the
   MARKER owns geographic placement, while the inner .pin-body is the visible
   pill AND the drag handle — so a community can be flung and spring home
   without fighting MapLibre's transform (pin-wires.js). Each community
   carries a stroke in its own weather colour, and a 1pt wire runs from its
   nearest corner to the heart of Guanacaste. Hidden until mounted. */
.rs-globe-pin {
  display: none;
  align-items: center;
  pointer-events: none; /* the marker is inert — only .pin-body grabs */
  white-space: nowrap;
}
.rs-globe-pin.is-mounted { display: inline-flex; }
.pin-body {
  --pin-a: 5%; /* stroke opacity — barely there, so the LOCKUP is all you read */
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 9px;
  background: var(--g); /* ground fill lays the lockup over the coastline ink */
  border: 1px solid var(--line-strong); /* overridden per community below */
  border-radius: 0; /* square edges — never the pill radius */
  white-space: nowrap;
  pointer-events: auto; /* the grab handle */
  cursor: grab;
  touch-action: pan-y; /* let the page scroll on touch */
  will-change: transform;
}
.pin-body.is-dragging { cursor: grabbing; }
/* Per-community stroke — EXACTLY the glyph's colours (pin-wires.js echoes the
   same set in the wire), each mixed down to --pin-a so the lockup carries the
   eye and the border stays a quiet accent. Single-weather glyphs are solid;
   multi-weather glyphs get a gradient of their colours. Square pills, so
   border-image sits flush. Greater = Sun. Coffee = Cloud + Rain. triathlon =
   Sun · Hard Rain · Thunder. SCENT carries all six. */
.rs-globe-pin:has([data-wx-mark="greater"]) .pin-body {
  border-color: color-mix(in srgb, var(--sun) var(--pin-a), transparent);
}
.rs-globe-pin:has([data-wx-mark="coffee"]) .pin-body {
  border-image: linear-gradient(90deg,
    color-mix(in srgb, var(--lit) var(--pin-a), transparent),
    color-mix(in srgb, var(--rain) var(--pin-a), transparent)) 1;
}
.rs-globe-pin:has([data-wx-mark="triathlon"]) .pin-body {
  border-image: linear-gradient(90deg,
    color-mix(in srgb, var(--hard-rain) var(--pin-a), transparent),
    color-mix(in srgb, var(--sun) var(--pin-a), transparent),
    color-mix(in srgb, var(--thunder) var(--pin-a), transparent)) 1;
}
.rs-globe-pin:has([data-wx-mark="scent"]) .pin-body {
  border-image: linear-gradient(90deg,
    color-mix(in srgb, var(--sun) var(--pin-a), transparent),
    color-mix(in srgb, var(--snow) var(--pin-a), transparent),
    color-mix(in srgb, var(--thunder) var(--pin-a), transparent),
    color-mix(in srgb, var(--hard-rain) var(--pin-a), transparent),
    color-mix(in srgb, var(--rain) var(--pin-a), transparent),
    color-mix(in srgb, var(--lit) var(--pin-a), transparent)) 1;
}
/* rainyseason.cr — the master mark (Cloud · Thunder · Hard Rain). */
.rs-globe-pin:has([data-wx-mark="brand"]) .pin-body {
  border-image: linear-gradient(90deg,
    color-mix(in srgb, var(--lit) var(--pin-a), transparent),
    color-mix(in srgb, var(--thunder) var(--pin-a), transparent),
    color-mix(in srgb, var(--hard-rain) var(--pin-a), transparent)) 1;
}
/* Light mode — the label frames drop the faint weather tint for a crisp VANTA
   BLACK stroke, riding the light-mode ink law (every stroke goes full black,
   hierarchy from size + weight). Wins over the per-community rules above by
   specificity; border-image reset so the solid colour shows. */
html.is-light .rs-globe-pin .pin-body {
  border-image: none;
  border-color: #000;
}
.rs-globe-pin .pin-mark { display: block; width: 18px; height: 18px; flex: 0 0 auto; }
.rs-globe-pin .brand-name { font-size: var(--t-caption); line-height: 1; color: var(--ink-2); }

/* The heart of Guanacaste — the geographic centre the communities point to.
   A sharp four-point spark-star (not a round dot), lifted by globe.js like any
   other pin so it rides the same coordinate space. Its concave points read as
   a spark/twinkle; a soft glow lifts it off the coastline. */
.rs-globe-heart { pointer-events: none; }
.rs-globe-heart .heart-dot {
  width: 13px; height: 13px;
  background: var(--ink);
  /* four-point sparkle — long thin points, pinched waist between them */
  clip-path: polygon(50% 0%, 57% 43%, 100% 50%, 57% 57%, 50% 100%, 43% 57%, 0% 50%, 43% 43%);
  filter: drop-shadow(0 0 3px color-mix(in srgb, var(--ink) 55%, transparent));
}

/* The wires — 1pt lines from each community's nearest corner to the heart,
   drawn into this overlay by pin-wires.js, coloured per community. */
.pin-wires { position: absolute; inset: 0; z-index: 1; overflow: visible; pointer-events: none; }

/* Snap-home — a flung pin springs back on the curl bar's EXACT speed profile:
   turbo out of the corner, a steady cruise, then a hard brake. The --sx/--sy
   the script parks on the pin are the release offset; the keyframes scale that
   vector home and the per-segment easings mirror @keyframes btnBeam
   one-for-one (accelerate · linear cruise · decelerate). */
@keyframes pinSnap {
  0%   { transform: translate(var(--sx, 0), var(--sy, 0)); animation-timing-function: cubic-bezier(0.5, 0, 1, 0.55); }
  22%  { transform: translate(calc(var(--sx, 0) * 0.928), calc(var(--sy, 0) * 0.928)); animation-timing-function: linear; }
  78%  { transform: translate(calc(var(--sx, 0) * 0.072), calc(var(--sy, 0) * 0.072)); animation-timing-function: cubic-bezier(0, 0.45, 0.5, 1); }
  100% { transform: translate(0, 0); }
}
/* MapLibre's own stylesheet hides overflow on the map box, which crops pills
   near the container edge. The globes are borderless ink on the bare ground,
   so letting them overflow is invisible — and the FULL lockups always render. */
.rs-globe.maplibregl-map { overflow: visible; }

/* --- Site footer (bottom chrome; single source) ---
   The studio's directory beneath the page — ONE source: home mounts it, the
   components page shows it live. A full-bleed ground (no boxes), columns of
   links. Column titles speak the house uppercase; the link rows stay
   sentence case one notch under at weight 400 — the quiet "h4" the
   directory asks for. */
.site-footer {
  position: relative;
  z-index: 1;
  width: 100%;
  background: var(--g);
  /* Horizontal pad on the shared 22px rail, so the
     directory's first column lands with the menu glyph, the offer cards and the
     knowledge teaser above it — not in a narrower centred block. */
  padding: clamp(48px, 8vh, 88px) var(--rail) clamp(16px, 3vh, 24px);
}
.site-footer-inner {
  width: 100%;
  max-width: none; /* fill the frame so the first column sits on the rail */
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: clamp(32px, 5vw, 56px) clamp(24px, 4vw, 40px);
}
.foot-col {
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-align: left; /* every column, first row included, stays flush-left */
}
