/**
 * WanderIndo — front page "portal" build.
 *
 * Hand-authored, self-contained CSS for the homepage only (enqueued when
 * is_front_page() in inc/theme-setup.php). Deliberately outside the Tailwind
 * pipeline: every class here is bespoke to this page, so there is nothing for
 * the Tailwind content scanner to purge and no dependency on a local build
 * step. Everything is scoped under .wip (WanderIndo Portal) so it can never
 * collide with the hull/copper classes the rest of the theme still uses.
 *
 * Palette: near-black ground, warm bone ink, and the two accents re-pointed
 * to Merah Putih — a saturated flag red and a clean white — instead of the
 * original amber/teal pull from the hero photograph. Both stay confined to
 * type, a dot, or a hairline rule — never a filled area — per the design
 * spec; --wip-red is tuned a shade brighter than the official flag red
 * (#FF3B30 vs. #CE1126-ish) so it still clears ~5.5:1 contrast on the near-
 * black ground at small uppercase sizes, which a fully saturated flag red
 * does not.
 */

.wip {
  --wip-ground: #0a0c0e;
  --wip-ground-2: #101317;
  --wip-ink: #ede7dc;
  --wip-ink-2: #9ea5a8;
  --wip-muted: #6c7378;
  --wip-red: #ff3b30;
  --wip-white: #f5f5f0;
  --wip-hairline: rgba(237, 231, 220, 0.13);

  background: var(--wip-ground);
  color: var(--wip-ink);
  font-family: "Sora", -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 15px;
  line-height: 1.6;
}

.wip * {
  box-sizing: border-box;
}

.wip a {
  color: inherit;
  text-decoration: none;
}

.wip .wip-wrap {
  width: 100%;
  max-width: 78rem;
  margin: 0 auto;
  padding: 0 1.25rem;
}

@media (min-width: 640px) {
  .wip .wip-wrap {
    padding: 0 2rem;
  }
}

.wip .wip-eyebrow {
  font-family: "Sora", sans-serif;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-red);
}

/* html .wip h2, not .wip h2: the rest of the theme's compiled Tailwind CSS
   carries a bare `h1,h2,h3,h4,h5,h6{font-family:Cormorant Garamond,serif}`
   from its own base layer (src/css/tailwind.css). That selector's
   specificity is only (0,0,1); `.wip h2` at (0,1,1) already outranks it on
   paper, but a heading occasionally still rendered in the old serif — some
   asset-loading order this project's build produces evidently ties or beats
   it in practice. Adding the `html` ancestor brings this to (0,1,2), which
   wins outright rather than relying on a specificity margin that clearly
   wasn't reliable. */
html .wip h1,
html .wip h2,
html .wip h3,
html .wip .wip-display {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--wip-ink);
  margin: 0;
}

/* ------------------------------------------------------------------ nav */

.wip-nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: 58px;
  display: flex;
  align-items: center;
  background: rgba(10, 12, 14, 0.72);
  border-bottom: 1px solid var(--wip-hairline);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}

.wip-nav__row {
  width: 100%;
  max-width: 78rem;
  margin: 0 auto;
  padding: 0 1.25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

@media (min-width: 640px) {
  .wip-nav__row {
    padding: 0 2rem;
  }
}

.wip-nav__mark {
  display: inline-flex;
  align-items: center;
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.02em;
  color: var(--wip-ink);
  white-space: nowrap;
}

.wip-nav__mark span {
  color: var(--wip-red);
}

/* Logo variant. jhg_render_wip_mark() (inc/global-brand.php) prints an <img>
   here instead of the wordmark once a logo is set in Appearance → Wording →
   Site wide. Height-capped rather than width-capped so wordmark-shaped and
   square marks both land on the same optical weight as the text they replace;
   max-width is the guard against a very wide banner file crowding the links. */
.wip-nav__mark img {
  display: block;
  height: 28px;
  width: auto;
  max-width: 170px;
  object-fit: contain;
}

@media (max-width: 480px) {
  .wip-nav__mark img {
    height: 24px;
    max-width: 128px;
  }
}

.wip-nav__links {
  display: none;
  align-items: center;
  gap: 1.4rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* 1100px, not the 900px this started at, and a tighter gap: the bar was sized
   for the four hardcoded labels it used to hold. It now prints the Header
   Menu — seven top-level labels plus their carets, ~920px of nowrap text
   beside the mark and the CTA pill — which wrapped the row at 900px. Below
   this width the whole menu is the panel behind .wip-nav__toggle instead. */
@media (min-width: 1100px) {
  .wip-nav__links {
    display: flex;
  }
}

.wip-nav__links a {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-ink-2);
  transition: color 0.2s ease-out;
}

.wip-nav__links a:hover,
.wip-nav__links a:focus-visible {
  color: var(--wip-red);
}

/* a.wip-pill, not .wip-pill: `.wip a { color: inherit }` above is a class
   plus a type selector, specificity (0,1,1). A bare `.wip-pill` is only
   (0,1,0) and loses to it outright regardless of source order, so its
   colour silently fell back to whatever the link inherited. Every button
   rule below qualifies with `a` for the same reason — see the .wip-btn fix
   further down for the state that actually broke. */
a.wip-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 38px;
  padding: 0 1.15rem;
  border-radius: 999px;
  border: 1px solid var(--wip-red);
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-ink);
  transition: background-color 0.2s ease-out, color 0.2s ease-out;
  white-space: nowrap;
}

a.wip-pill:hover,
a.wip-pill:focus-visible {
  background: var(--wip-red);
  color: var(--wip-ground);
}

/* ----------------------------------------------- nav: menu + mega panel */

/* The bar prints the WordPress "Header Menu" menu (jhg_render_wip_nav), so a
   page reaches the header by being in that menu rather than by another edit
   in here. A parent opens a mega panel — full bar width, section name on the
   left, its pages in columns on the right. Below 1100px the whole menu drops
   down as one panel with every mega inline and open. */

.wip-nav__end {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* Full bar height, so hovering a label and moving down to its panel never
   crosses dead space — the classic dropdown-closes-mid-travel bug, solved by
   the geometry instead of by an invisible bridge element. */
.wip-nav {
  align-items: stretch;
}

.wip-nav__links {
  align-self: stretch;
  align-items: stretch;
}

/* Static on purpose: the mega panel spans the whole bar, so it must resolve
   against .wip-nav (position: fixed), not against the label it hangs from. */
.wip-nav__item {
  position: static;
  display: flex;
  align-items: center;
}

.wip-nav__links a {
  display: inline-flex;
  align-items: center;
}

.wip-nav__links a.is-current {
  color: var(--wip-red);
}

.wip-nav__caret {
  width: 11px;
  height: 11px;
  margin-left: 0.3rem;
  flex: none;
  opacity: 0.7;
  transition: transform 0.2s ease-out;
}

.wip-nav__item--parent:hover > a .wip-nav__caret,
.wip-nav__item--parent:focus-within > a .wip-nav__caret {
  transform: rotate(180deg);
}

.wip-mega {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 5;
  background: rgba(10, 12, 14, 0.97);
  border-top: 1px solid var(--wip-hairline);
  border-bottom: 1px solid var(--wip-hairline);
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.5);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.18s ease-out, transform 0.18s ease-out, visibility 0.18s;
}

.wip-nav__item--parent:hover > .wip-mega,
.wip-nav__item--parent:focus-within > .wip-mega {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* Same max-width and padding as .wip-nav__row, so the panel's lead column
   starts on the same left edge as the wordmark above it. */
.wip-mega__inner {
  width: 100%;
  max-width: 78rem;
  margin: 0 auto;
  padding: 1.75rem 2rem 2rem;
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: 2.5rem;
  align-items: start;
}

.wip-mega__eyebrow {
  margin: 0 0 0.5rem;
  font-family: "Syne", sans-serif;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--wip-ink);
}

.wip-mega__blurb {
  margin: 0 0 0.75rem;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--wip-ink-2);
}

.wip-mega__hub {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-red);
}

.wip-mega__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 0.15rem 0.75rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Qualified past `.wip-nav__links a` above: panel entries are page titles,
   which are sentences — the bar's uppercase 10.5px tracking is for one-word
   labels and turns these into three cramped lines. */
.wip-nav__links .wip-mega__grid a {
  display: block;
  padding: 0.6rem 0.7rem;
  border-radius: 10px;
  border: 1px solid transparent;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0;
  text-transform: none;
  white-space: normal;
  transition: background-color 0.18s ease-out, border-color 0.18s ease-out,
    color 0.18s ease-out;
}

.wip-nav__links .wip-mega__grid a:hover,
.wip-nav__links .wip-mega__grid a:focus-visible {
  background: rgba(255, 255, 255, 0.05);
  border-color: var(--wip-hairline);
  color: var(--wip-ink);
}

.wip-nav__toggle {
  display: none;
  height: 38px;
  width: 38px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--wip-hairline);
  border-radius: 999px;
  background: none;
  color: var(--wip-ink);
  cursor: pointer;
  transition: border-color 0.2s ease-out, color 0.2s ease-out;
}

.wip-nav__toggle:hover,
.wip-nav__toggle:focus-visible {
  border-color: var(--wip-red);
  color: var(--wip-red);
}

.wip-nav__toggle svg {
  width: 20px;
  height: 20px;
}

.wip-nav__toggle-close,
.wip-nav.is-open .wip-nav__toggle-open {
  display: none;
}

.wip-nav.is-open .wip-nav__toggle-close {
  display: block;
}

@media (max-width: 1099px) {
  .wip-nav__toggle {
    display: inline-flex;
  }

  /* Panel, not a drawer: the bar is already fixed to the top, so dropping the
     list out of it costs no overlay, no scroll lock and no focus trap. */
  .wip-nav.is-open .wip-nav__links {
    display: flex;
    position: fixed;
    top: 58px;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    max-height: calc(100vh - 58px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.5rem 1.25rem 1.5rem;
    background: rgba(10, 12, 14, 0.97);
    border-bottom: 1px solid var(--wip-hairline);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
  }

  /* The bar's own items are laid out as a row of full-height flex cells;
     stacked in the panel they are plain blocks again. */
  .wip-nav.is-open .wip-nav__links > li {
    display: block;
    border-top: 1px solid var(--wip-hairline);
  }

  .wip-nav.is-open .wip-nav__links > li:first-child {
    border-top: 0;
  }

  .wip-nav.is-open .wip-nav__links > li > a {
    padding: 0.85rem 0;
  }

  /* Inline and already open. The panel's own chrome — full-bleed backdrop,
     lead column, columns — is all desktop framing, so it comes off and what
     is left is an indented list under its parent. */
  .wip-nav.is-open .wip-mega {
    position: static;
    border: 0;
    background: none;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }

  .wip-nav.is-open .wip-mega__inner {
    display: block;
    max-width: none;
    padding: 0 0 0.7rem 0.85rem;
    border-left: 1px solid var(--wip-hairline);
    margin-left: 0.1rem;
  }

  /* The section is already named by the parent link directly above it. */
  .wip-nav.is-open .wip-mega__lead {
    display: none;
  }

  .wip-nav.is-open .wip-mega__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  .wip-nav__links .wip-mega__grid a {
    padding: 0.55rem 0.5rem;
  }

  .wip-nav__caret {
    display: none;
  }
}

@media (max-width: 480px) {
  .wip-nav__row {
    gap: 0.75rem;
  }

  a.wip-pill {
    padding: 0 0.9rem;
  }
}

/* ---------------------------------------------------------------- hero */

.wip-hero {
  position: relative;
  height: 250vh;
}

.wip-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  isolation: isolate;
}

.wip-stage__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Grayscale first: the duotone below is what's supposed to add colour back
     in (red/white only), per the "confined to type, a dot, or a hairline
     rule — never a filled area" spec. Without this, whatever the source
     photo actually contains — right now the dev placeholder's orange
     "PLACEHOLDER" stroke, later a real photo's own palette — shows through
     the 28%-opacity overlay mostly unfiltered instead of reading as Merah
     Putih. This holds regardless of what image ends up here. */
  filter: grayscale(1) contrast(1.05) brightness(0.95);
  transform: scale(1.15);
  transition: none;
  z-index: 1;
}

.wip-stage__duotone {
  position: absolute;
  inset: 0;
  z-index: 2;
  mix-blend-mode: overlay;
  opacity: 0.5;
  background:
    radial-gradient(circle at 20% 20%, var(--wip-red), transparent 55%),
    radial-gradient(circle at 80% 80%, var(--wip-white), transparent 55%);
}

.wip-stage__veil {
  position: absolute;
  inset: 0;
  z-index: 3;
  background: radial-gradient(ellipse at center, transparent 40%, rgba(10, 12, 14, 0.75) 100%);
}

.wip-panel {
  position: absolute;
  inset: 0 auto 0 0;
  width: 51%;
  z-index: 5;
  background: var(--wip-ground);
  display: none;
}

.wip-panel--right {
  inset: 0 0 0 auto;
  left: auto;
}

/* Merah Putih lightning, across the seam where the two panels meet.
   Motion-only: with html.wip-motion absent (reduced motion, or the panels
   never rendering — see above) both the sheet flash and the canvas stay
   invisible, since there is no closed portal for a strike to precede. --wip-p
   is the same scroll-position custom property front-portal.js already writes
   onto .wip-hero every frame; it inherits straight down to these descendants
   with no extra JS.

   The flash is no longer a one-shot @keyframes: every bolt the canvas draws
   pulses it through .is-lit / .is-fading (see front-portal.js), so the sheet
   lightning stays tied to the strike that caused it rather than to a fixed
   1s-after-load timeline. */
.wip-stage__flash {
  position: absolute;
  inset: 0;
  z-index: 6;
  background: radial-gradient(circle at center, rgba(245, 245, 240, 0.85), transparent 55%);
  opacity: 0;
  pointer-events: none;
}

html.wip-motion .wip-stage__flash.is-lit {
  /* Damped by --wip-p on the same curve as the bolts below, so a strike that
     lands mid-scroll can't wash out an already-open portal. */
  opacity: clamp(0, calc(0.45 * (1 - (var(--wip-p, 0) * 1.5))), 0.45);
  transition: opacity 0.05s ease-out;
}

html.wip-motion .wip-stage__flash.is-fading {
  opacity: 0;
  transition: opacity 0.4s ease-out;
}

/* Canvas the fractal bolts are drawn on: stage-sized, backed by a
   device-pixel-ratio transform set in JS, never hit-tested (clicks fall
   through to .wip-stage, which is what listens for them). */
.wip-lightning {
  position: absolute;
  inset: 0;
  z-index: 7;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
}

html.wip-motion .wip-lightning {
  /* Fades out as the panels slide open (p -> 1), so the strike always reads
     as something that happened before the photograph, never over it. */
  opacity: clamp(0, calc(1 - (var(--wip-p, 0) * 1.5)), 1);
}

.wip-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 6;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  opacity: 0.7;
  box-shadow: 0 0 12px 2px currentColor;
}

.wip-dot--red {
  color: var(--wip-red);
  background: var(--wip-red);
  transform: translate(-140%, -50%);
}

.wip-dot--white {
  color: var(--wip-white);
  background: var(--wip-white);
  transform: translate(40%, -50%);
}

.wip-wordmark {
  position: relative;
  z-index: 10;
  display: flex;
  /* center, not baseline. This box is height: 100% of a 100vh stage, and
     align-items: baseline puts the flex line at cross-START — so the wordmark
     sat pinned to the very top of the hero, which under the 58px fixed nav
     left it clipped on small screens and the hero looking empty. The two
     spans are the same size and both inline-block, so they line up
     identically either way; all this moves is the line itself, down to the
     middle of the stage where the lockup belongs. */
  align-items: center;
  justify-content: center;
  gap: 0.35em;
  height: 100%;
  white-space: nowrap;
  font-family: "Syne", sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
  /* Mobile/tablet-safe size — unchanged. The bleed treatment below only
     kicks in at 900px, the same breakpoint the nav already uses to switch
     into its "desktop chrome"; below it the corner labels sit close enough
     to the wordmark's baseline that a bigger size collides with them. */
  font-size: clamp(2.75rem, 11vw, 8.5rem);
  color: var(--wip-ink);
  pointer-events: none;
}

@media (min-width: 900px) {
  .wip-wordmark {
    /* Sized to bleed past both edges of .wip-stage (overflow: hidden,
       above) rather than to fit inside it. The old clamp topped out at
       8.5rem, well short of the viewport at typical desktop widths —
       mathematically the flex row was still centred inside the full-width
       box either way, but with "WANDER" and "INDO." differing in length
       and colour weight, a lockup that comfortably fits reads as if it is
       leaning, not centred. Cropped equally at both edges is a much harder
       read to mistake — same technique as the reference. justify-content:
       center still centres the (now-overflowing) flex items within the
       full-width box, so the crop stays symmetric at every viewport width
       this applies to. */
    font-size: clamp(8.5rem, 16vw, 14rem);
  }
}

.wip-wordmark__start,
.wip-wordmark__end {
  display: inline-block;
}

.wip-wordmark__end {
  color: var(--wip-red);
}

.wip-corner {
  position: absolute;
  z-index: 10;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-ink-2);
}

.wip-corner--tl {
  top: 5.5rem;
  left: 1.25rem;
}

.wip-corner--tr {
  top: 5.5rem;
  right: 1.25rem;
  color: var(--wip-red);
}

.wip-corner--bl {
  bottom: 1.75rem;
  left: 1.25rem;
  max-width: 60vw;
}

.wip-corner--br {
  bottom: 1.75rem;
  right: 1.25rem;
}

@media (min-width: 640px) {
  .wip-corner--tl,
  .wip-corner--tr {
    top: 4.5rem;
  }
  .wip-corner--tl,
  .wip-corner--bl {
    left: 2rem;
  }
  .wip-corner--tr,
  .wip-corner--br {
    right: 2rem;
  }
}

/* Scroll cue — centred at the foot of the stage.
   Type plus a hairline, never a filled pill or circle: the hero's palette is
   confined to type, a dot or a rule, and a solid button would be the one
   filled area on the whole screen.
   Parked well above .wip-corner--bl rather than level with it — that corner
   is allowed 60vw and wraps to two lines under 640px, which on a phone runs
   straight through the centre where this sits. */
.wip-scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 5.25rem;
  z-index: 10;
  transform: translateX(-50%);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  padding: 0.25rem 0.5rem;
  text-decoration: none;
  color: var(--wip-ink-2);
  /* Damped on the same curve as the bolts and the veil above, so the cue is
     gone by the time the portal is two thirds open and never sits over the
     photograph it was inviting you towards. */
  opacity: clamp(0, calc(1 - (var(--wip-p, 0) * 1.5)), 1);
  transition: color 0.2s ease-out;
}

/* Faded is not gone: without this the cue stays clickable — and reachable by
   tab — as an invisible target over the open hero. JS sets it from the same
   --wip-p it writes, since opacity alone cannot take an element out of play. */
.wip-scroll-cue.is-gone {
  pointer-events: none;
  visibility: hidden;
}

.wip-scroll-cue__label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

.wip-scroll-cue__line {
  position: relative;
  display: block;
  width: 1px;
  height: 40px;
  overflow: hidden;
  background: var(--wip-hairline);
}

.wip-scroll-cue:hover,
.wip-scroll-cue:focus-visible {
  color: var(--wip-red);
}

.wip-scroll-cue:focus-visible {
  outline: 1px solid var(--wip-red);
  outline-offset: 6px;
}

/* The travelling spark. Motion-gated like everything else scroll-linked here:
   under reduced motion the rule is simply a static hairline. */
html.wip-motion .wip-scroll-cue__line::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 14px;
  background: var(--wip-red);
  animation: wip-scroll-cue-travel 1.9s ease-in-out infinite;
}

@keyframes wip-scroll-cue-travel {
  0% {
    transform: translateY(-14px);
    opacity: 0;
  }
  30% {
    opacity: 1;
  }
  70% {
    opacity: 1;
  }
  100% {
    transform: translateY(40px);
    opacity: 0;
  }
}

@media (min-width: 640px) {
  .wip-scroll-cue {
    bottom: 4rem;
  }
}

/* Landing point for the cue: clears the fixed 58px bar so the fold's top edge
   is not tucked under it on arrival. */
.wip-fold {
  scroll-margin-top: 58px;
}

/* Motion-enhanced hero state, gated behind html.wip-motion (see JS: only
   added once prefers-reduced-motion is confirmed off). Without it every
   element above renders at its settled, fully-open resting state, so the
   photograph is always visible and nothing needs JavaScript to be legible. */
html.wip-motion .wip-panel {
  display: block;
  transform: translateX(calc(var(--wip-p, 0) * -115%));
  transition: none;
}

html.wip-motion .wip-panel--right {
  transform: translateX(calc(var(--wip-p, 0) * 115%));
}

html.wip-motion .wip-stage__img {
  transform: scale(calc(1.15 - (var(--wip-p, 0) * 0.15)));
}

html.wip-motion .wip-stage__duotone {
  opacity: calc(var(--wip-p, 0) * 0.32);
}

html.wip-motion .wip-dot--red {
  transform: translate(calc(-50% - (var(--wip-p, 0) * 34vw)), calc(-50% - (var(--wip-p, 0) * 26vh)));
  opacity: calc(0.35 + (var(--wip-p, 0) * 0.65));
}

html.wip-motion .wip-dot--white {
  transform: translate(calc(-50% + (var(--wip-p, 0) * 34vw)), calc(-50% + (var(--wip-p, 0) * 26vh)));
  opacity: calc(0.35 + (var(--wip-p, 0) * 0.65));
}

html.wip-motion .wip-wordmark {
  transform: scale(calc(1 + (var(--wip-p, 0) * 0.5)));
  letter-spacing: calc(-0.02em - (var(--wip-p, 0) * 0.06em));
}

html.wip-motion .wip-wordmark__start {
  transform: translateX(calc(var(--wip-p, 0) * -55%));
}

html.wip-motion .wip-wordmark__end {
  transform: translateX(calc(var(--wip-p, 0) * 55%));
}

/* ----------------------------------------------------------- statement */

.wip-fold {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  padding: 6rem 0;
  overflow: hidden;
  background: var(--wip-ground);
}

.wip-fold__inner {
  position: relative;
  z-index: 2;
}

.wip-fold__label {
  margin-bottom: 1.25rem;
}

.wip-fold__statement {
  max-width: 22ch;
  font-size: clamp(24px, 3.6vw, 52px);
  line-height: 1.18;
  letter-spacing: -0.02em;
}

.wip-fold__statement em {
  font-style: normal;
  color: var(--wip-red);
}

.wip-fold__index {
  position: absolute;
  top: 50%;
  right: 1.25rem;
  transform: translateY(-50%);
  z-index: 1;
  font-family: "Syne", sans-serif;
  font-weight: 800;
  font-size: clamp(7rem, 22vw, 17rem);
  line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1px var(--wip-hairline);
  pointer-events: none;
  user-select: none;
}

.wip-fold__orb {
  position: absolute;
  top: 12%;
  right: -8vw;
  z-index: 1;
  width: min(34vw, 22rem);
  height: min(34vw, 22rem);
  border-radius: 50%;
  overflow: hidden;
  opacity: 0.4;
  border: 1px solid var(--wip-hairline);
  will-change: transform;
}

.wip-fold__orb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Same reasoning as .wip-stage__img: neutralise whatever the source photo
     actually contains so the orb reads as part of the near-black/ink/red
     palette rather than whatever colour the placeholder or photo happens
     to carry. */
  filter: grayscale(1);
}

html.wip-motion .wip-fold__orb {
  transform: translateY(calc(var(--wip-fold-p, 0) * -6rem)) rotate(calc(var(--wip-fold-p, 0) * 16deg));
}

/* -------------------------------------------------------------- journal */

/* The full-length editorial guide. Sits between the statement fold and the
   condensed catalogue deck: same palette and type system as the rest of the
   page. A bento mosaic gives the scannable version of the facts up top (quick
   answer, read time, one card per route, byline); a sticky/rail table of
   contents plus a plain reading column carry the full prose below it, kept
   legible rather than over-designed since that is what a long-form article
   still needs. */
.wip-journal {
  padding: 6rem 0;
  background: var(--wip-ground);
  border-top: 1px solid var(--wip-hairline);
}

/* Featured-image hero. When a page/post has a thumbnail, inc/wip-hero-image.php
   adds .wip-has-hero to <body> and sets --wip-hero-img, so the opening journal
   section shows that photo behind its own copy instead of the flat ground.
   Driven from the body rather than a modifier class on the section itself so
   the ~40 per-slug templates that each carry their own copy of this markup
   need no edit — one filter covers all of them at once.

   Two stacked layers, both behind the content (isolation: isolate keeps the
   negative z-index inside this section): ::before is the photo, ::after is the
   scrim that buys back contrast. The scrim is deliberately heaviest on the
   left and at the bottom — that is where the title, Quick Answer callout and
   facts row sit, and the bottom fade is what lets the section dissolve into
   the flat ground of whatever follows it. */
body.wip-has-hero .wip-journal {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-top: 8.5rem;
  border-top: 0;
}

body.wip-has-hero .wip-journal::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image: var(--wip-hero-img);
  background-size: cover;
  background-position: center 32%;
  background-repeat: no-repeat;
}

body.wip-has-hero .wip-journal::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(
      to right,
      rgb(10 12 14 / 0.97) 0%,
      rgb(10 12 14 / 0.9) 32%,
      rgb(10 12 14 / 0.62) 66%,
      rgb(10 12 14 / 0.46) 100%
    ),
    linear-gradient(
      to bottom,
      rgb(10 12 14 / 0.72) 0%,
      rgb(10 12 14 / 0.32) 38%,
      rgb(10 12 14 / 0.82) 82%,
      var(--wip-ground) 100%
    );
}

/* Narrow screens put the copy over the middle of the photo rather than to one
   side of it, so the left-to-right falloff stops doing any work — swap it for
   a flat wash that keeps the same total contrast under the text. */
@media (max-width: 780px) {
  body.wip-has-hero .wip-journal {
    padding-top: 7rem;
  }

  body.wip-has-hero .wip-journal::after {
    background:
      linear-gradient(
        to bottom,
        rgb(10 12 14 / 0.8) 0%,
        rgb(10 12 14 / 0.62) 40%,
        rgb(10 12 14 / 0.88) 80%,
        var(--wip-ground) 100%
      );
  }
}

.wip-journal__meta {
  max-width: 60ch;
  margin-top: 0.5rem;
  font-size: 12.5px;
  color: var(--wip-muted);
}

.wip-journal__head .wip-journal__meta:first-child {
  margin-top: 0;
}

.wip-journal__title {
  margin-top: 0.6rem;
  font-size: clamp(28px, 3.6vw, 44px);
  max-width: 20ch;
}

/* Standalone article pages (template-parts/{slug}.php, not the homepage)
   open with this instead of the bento mosaic: a plain way back up to
   WanderIndo before the page's own title. */
.wip-journal__back {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-ink-2);
}

.wip-journal__back:hover,
.wip-journal__back:focus-visible {
  color: var(--wip-red);
}

/* Bento mosaic — the "at a glance" read of the same facts the full article
   states in prose: quick answer, read time, island count, one link-card per
   route, and the byline. Mobile-first two-column grid; widens to four
   columns with a tall hero cell once there is room. grid-auto-flow: dense
   plus per-cell spans (not hand-placed coordinates) so the packing stays
   correct regardless of how many route cards $routes holds. */
.wip-bento {
  margin-top: 2.25rem;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: auto;
  grid-auto-flow: dense;
  gap: 0.85rem;
}

.wip-bento__cell {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 7.5rem;
  padding: 1.35rem 1.5rem;
  border: 1px solid var(--wip-hairline);
  border-radius: 0.85rem;
  background: var(--wip-ground-2);
  overflow: hidden;
}

.wip-bento__label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-red);
}

.wip-bento__cell--answer {
  grid-column: span 2;
  border-left: 3px solid var(--wip-red);
  background:
    radial-gradient(circle at 100% 0%, rgba(255, 59, 48, 0.12), transparent 60%),
    var(--wip-ground-2);
}

.wip-bento__lead {
  margin-top: 0.6rem;
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--wip-ink);
}

.wip-bento__cell--meta {
  grid-column: span 1;
  align-items: center;
  text-align: center;
  gap: 0.35rem;
}

.wip-bento__num {
  font-family: "Syne", sans-serif;
  font-weight: 800;
  font-size: clamp(1.9rem, 4vw, 2.4rem);
  line-height: 1;
  color: var(--wip-ink);
}

.wip-bento__unit {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-muted);
}

.wip-bento__cell--route {
  grid-column: span 2;
  transition: border-color 0.2s ease-out, transform 0.2s ease-out, background-color 0.2s ease-out;
}

.wip-bento__cell--route:hover,
.wip-bento__cell--route:focus-visible {
  border-color: var(--wip-red);
  background: var(--wip-ground);
  transform: translateY(-2px);
}

.wip-bento__route-code {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-red);
}

.wip-bento__route-name {
  margin-top: 0.5rem;
  font-family: "Syne", sans-serif;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-size: 1.1rem;
  color: var(--wip-ink);
}

.wip-bento__route-fact {
  margin-top: 0.5rem;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--wip-ink-2);
}

.wip-bento__cell--editor {
  grid-column: span 2;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  background: var(--wip-ground);
}

.wip-bento__editor-name {
  margin-top: 0.35rem;
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--wip-ink);
}

.wip-bento__editor-date {
  font-size: 11.5px;
  color: var(--wip-muted);
}

@media (min-width: 640px) {
  .wip-bento__cell--route {
    grid-column: span 1;
  }
}

@media (min-width: 900px) {
  .wip-bento {
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: 8.5rem;
    gap: 1rem;
  }
  .wip-bento__cell--answer {
    grid-column: span 2;
    grid-row: span 2;
  }
  .wip-bento__cell--meta {
    grid-row: span 1;
  }
  .wip-bento__cell--route {
    grid-column: span 2;
    grid-row: span 1;
  }
  .wip-bento__cell--editor {
    grid-column: span 4;
    grid-row: span 1;
  }
}

/* Contents rail + reading column. Sticky sidebar on desktop, collapses to a
   horizontal chip rail pinned under the fixed nav on mobile — either way it
   is a plain anchor list, so navigation works with front-portal.js absent. */
.wip-journal__layout {
  margin-top: 3rem;
}

@media (min-width: 1024px) {
  .wip-journal__layout {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 4.5rem;
    align-items: start;
    margin-top: 3.5rem;
  }
}

.wip-journal__toc {
  position: sticky;
  top: 58px;
  z-index: 40;
  margin: 0 -1.25rem 2.75rem;
  padding: 0.85rem 1.25rem;
  background: rgba(10, 12, 14, 0.92);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--wip-hairline);
}

@media (min-width: 640px) {
  .wip-journal__toc {
    margin-left: -2rem;
    margin-right: -2rem;
    padding-left: 2rem;
    padding-right: 2rem;
  }
}

.wip-journal__toc-label,
.wip-journal__toc-cta {
  display: none;
}

.wip-journal__toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  scrollbar-width: none;
}

.wip-journal__toc-list::-webkit-scrollbar {
  display: none;
}

.wip-journal__toc-list a {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--wip-hairline);
  font-size: 12px;
  font-weight: 600;
  color: var(--wip-ink-2);
  white-space: nowrap;
  transition: border-color 0.2s ease-out, color 0.2s ease-out, background-color 0.2s ease-out;
}

.wip-journal__toc-list a:hover,
.wip-journal__toc-list a:focus-visible {
  color: var(--wip-ink);
  border-color: var(--wip-ink-2);
}

.wip-journal__toc-list a.is-active {
  background: var(--wip-red);
  border-color: var(--wip-red);
  color: var(--wip-ground);
}

.wip-journal__toc-num {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 11px;
  color: var(--wip-red);
}

.wip-journal__toc-list a.is-active .wip-journal__toc-num {
  color: inherit;
  opacity: 0.75;
}

@media (min-width: 1024px) {
  .wip-journal__toc {
    position: sticky;
    top: calc(58px + 3rem);
    z-index: 1;
    margin: 0;
    padding: 0;
    background: none;
    border-bottom: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    align-self: start;
  }

  .wip-journal__toc-label,
  .wip-journal__toc-cta {
    display: block;
  }

  .wip-journal__toc-list {
    flex-direction: column;
    overflow: visible;
    gap: 0.15rem;
  }

  .wip-journal__toc-list a {
    padding: 0.5rem 0;
    border: none;
    border-radius: 0;
    background: none;
  }

  .wip-journal__toc-list a:hover,
  .wip-journal__toc-list a:focus-visible,
  .wip-journal__toc-list a.is-active {
    background: none;
    color: var(--wip-ink);
  }

  .wip-journal__toc-list a.is-active .wip-journal__toc-num {
    color: var(--wip-red);
    opacity: 1;
  }

  .wip-journal__toc-cta {
    margin-top: 2rem;
    display: inline-block;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--wip-red);
    border-top: 1px solid var(--wip-hairline);
    padding-top: 1.25rem;
  }

  .wip-journal__toc-cta:hover,
  .wip-journal__toc-cta:focus-visible {
    color: var(--wip-white);
  }
}

.wip-journal__body {
  margin-top: 0;
  max-width: 68ch;
}

.wip-journal__body p {
  margin: 0 0 1.25rem;
  font-size: 14.5px;
  line-height: 1.8;
  color: var(--wip-ink-2);
}

.wip-journal__body p:last-child {
  margin-bottom: 0;
}

/* Plain headings from the_content() — a migrated page's real post_content,
   not the hand-built numbered .wip-journal__section-head used on the
   homepage's own hard-coded sections. Same type system, no numbered badge. */
.wip-journal__body h2 {
  margin: 3rem 0 1rem;
  font-size: clamp(22px, 2.6vw, 30px);
}

.wip-journal__body h2:first-child {
  margin-top: 0;
}

.wip-journal__body h3 {
  margin: 2.5rem 0 0.9rem;
  font-size: clamp(18px, 2.1vw, 23px);
}

.wip-journal__body ul,
.wip-journal__body ol {
  margin: 0 0 1.25rem;
  padding-left: 1.25rem;
  color: var(--wip-ink-2);
  font-size: 14.5px;
  line-height: 1.8;
}

.wip-journal__body li {
  margin-bottom: 0.4rem;
}

/* The AEO/quick-answer summary block some articles open with — WordPress
   content already tags it `class="x-aeo"`, so this styles it as a callout
   with zero PHP-side detection needed, matching .wip-callout elsewhere. */
.wip-journal__body .x-aeo {
  margin: 0 0 2rem;
  padding: 1.5rem 1.75rem;
  border: 1px solid var(--wip-hairline);
  border-left: 3px solid var(--wip-red);
  border-radius: 0.5rem;
  background: var(--wip-ground-2);
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--wip-ink);
}

.wip-journal__body p.wip-journal__lede {
  margin-bottom: 1.5rem;
  font-size: 15.5px;
  line-height: 1.8;
}

.wip-journal__body p.wip-journal__lede::first-letter {
  float: left;
  font-family: "Syne", sans-serif;
  font-weight: 800;
  font-size: 3.4em;
  line-height: 0.85;
  padding: 0.05em 0.08em 0 0;
  color: var(--wip-red);
}

.wip-journal__pull {
  margin: 0 0 2.75rem;
  padding: 0 0 0 1.5rem;
  border-left: 3px solid var(--wip-red);
}

.wip-journal__body .wip-journal__pull p {
  margin: 0;
  font-family: "Syne", sans-serif;
  font-weight: 600;
  font-size: clamp(17px, 2vw, 22px);
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--wip-ink);
}

.wip-journal__section {
  margin-top: 3.5rem;
  scroll-margin-top: 130px;
}

@media (min-width: 1024px) {
  .wip-journal__section {
    scroll-margin-top: 90px;
  }
}

.wip-journal__section-head {
  display: flex;
  align-items: baseline;
  gap: 1rem;
}

.wip-journal__num {
  flex: none;
  font-family: "Syne", sans-serif;
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--wip-red);
}

.wip-journal__section-head h3 {
  margin: 0;
  font-size: clamp(20px, 2.2vw, 26px);
}

.wip-journal__body p.wip-journal__stat {
  margin: 1rem 0 1.5rem;
  display: inline-flex;
  align-items: center;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--wip-hairline);
  border-radius: 999px;
  background: var(--wip-ground-2);
}

.wip-journal__stat-label {
  flex: none;
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-red);
}

.wip-journal__stat-text {
  margin-left: 0.6rem;
  padding-left: 0.6rem;
  border-left: 1px solid var(--wip-hairline);
  font-size: 12.5px;
  color: var(--wip-ink-2);
}

.wip-journal__body a {
  color: var(--wip-red);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.wip-journal__body a:hover,
.wip-journal__body a:focus-visible {
  color: var(--wip-white);
}

/* ---------------------------------------------------- article page kit */

/* Three components a migrated article page (template-parts/{slug}.php)
   reaches for instead of piping the_content() straight into .wip-journal__body
   as one long scroll — a quick-facts strip, an FAQ accordion, and a card
   grid for topic breakdowns. The point is the same content read as a page,
   not a blog post: distinct components, not one long column of paragraphs. */

.wip-facts {
  margin-top: 2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2.5rem;
}

.wip-facts__item {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.wip-facts__num {
  font-family: "Syne", sans-serif;
  font-weight: 800;
  font-size: clamp(20px, 2.4vw, 28px);
  letter-spacing: -0.01em;
  color: var(--wip-ink);
}

.wip-facts__label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-red);
}

.wip-section {
  padding: 5rem 0;
}

.wip-section + .wip-section {
  border-top: 1px solid var(--wip-hairline);
}

.wip-section--alt {
  background: var(--wip-ground-2);
}

.wip-section__head {
  max-width: 60ch;
  margin-bottom: 2.5rem;
}

.wip-section__title {
  margin-top: 0.6rem;
  font-size: clamp(24px, 3vw, 34px);
}

/* FAQ accordion — native <details>/<summary>, no JS required to open a row:
   the point is progressive enhancement stays true even for interaction, not
   just for the scroll-linked hero. Full .wip-wrap width, matching the
   roster rows elsewhere: a single capped-width column here left the rest of
   a wide layout looking half-empty. Only the answer copy (.wip-faq-item__body)
   stays capped, since that is prose and needs a readable line length. */
.wip-faq {
  width: 100%;
}

/* ------------------------------------------------------------- faq tabs */

/* The FAQ page carries 98 questions. Flat, that is a wall you have to scroll
   to discover that packing and safety are even covered; grouped into topic
   tabs, the whole scope is legible in one glance at the tab row.

   Panels are hidden with the `hidden` attribute rather than removed, so all
   98 answers stay in the page source for crawlers and for the browser's own
   find-in-page. Note that find-in-page will not reach inside a hidden panel —
   that is the accepted cost of tabs, and the reason the tab labels have to
   name their contents plainly. */
.wip-faq-tabs__list {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 2.25rem;
  /* Sideways scroll instead of four stacked rows on a phone. The mask is the
     affordance that there is more past the right edge — a scrollbar is hidden
     on touch and would not say so. */
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  mask-image: linear-gradient(to right, #000 88%, transparent 100%);
}

.wip-faq-tabs__list::-webkit-scrollbar {
  display: none;
}

@media (min-width: 760px) {
  .wip-faq-tabs__list {
    flex-wrap: wrap;
    overflow-x: visible;
    mask-image: none;
  }
}

.wip-faq-tab {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.95rem;
  border: 1px solid var(--wip-hairline);
  border-radius: 999px;
  background: var(--wip-ground-2);
  font-family: inherit;
  font-size: 12.5px;
  line-height: 1.2;
  color: var(--wip-ink-2);
  white-space: nowrap;
  cursor: pointer;
  transition:
    color 0.18s ease-out,
    border-color 0.18s ease-out,
    background-color 0.18s ease-out;
}

.wip-faq-tab:hover {
  color: var(--wip-ink);
  border-color: rgb(237 231 220 / 0.3);
}

.wip-faq-tab:focus-visible {
  outline: 2px solid var(--wip-white);
  outline-offset: 3px;
}

/* Red is used sparingly in this design — eyebrows, the wordmark full stop,
   the accordion's own +/− — so the active tab borrows it as an outline and a
   tint rather than a solid fill, which at one-of-eight would shout. */
.wip-faq-tab.is-active {
  color: var(--wip-ink);
  border-color: var(--wip-red);
  background: rgb(255 59 48 / 0.1);
}

.wip-faq-tab__count {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--wip-ink-2);
  font-variant-numeric: tabular-nums;
}

.wip-faq-tab.is-active .wip-faq-tab__count {
  color: var(--wip-red);
}

.wip-faq-item {
  border-top: 1px solid var(--wip-hairline);
}

.wip-faq-item:last-child {
  border-bottom: 1px solid var(--wip-hairline);
}

.wip-faq-item > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.35rem 0;
  font-family: "Syne", sans-serif;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-size: clamp(15px, 1.8vw, 18px);
  color: var(--wip-ink);
}

.wip-faq-item > summary::-webkit-details-marker {
  display: none;
}

.wip-faq-item__icon {
  flex: none;
  position: relative;
  width: 18px;
  height: 18px;
}

.wip-faq-item__icon::before,
.wip-faq-item__icon::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  background: var(--wip-red);
  transform: translate(-50%, -50%);
  transition: transform 0.2s ease-out;
}

.wip-faq-item__icon::before {
  width: 14px;
  height: 2px;
}

.wip-faq-item__icon::after {
  width: 2px;
  height: 14px;
}

.wip-faq-item[open] .wip-faq-item__icon::after {
  transform: translate(-50%, -50%) rotate(90deg);
  opacity: 0;
}

.wip-faq-item__body {
  padding: 0 0 1.75rem;
}

.wip-faq-item__body p {
  margin: 0 0 1.1rem;
  font-size: 14px;
  line-height: 1.8;
  color: var(--wip-ink-2);
}

.wip-faq-item__body p:last-child {
  margin-bottom: 0;
}

.wip-faq-item__body a {
  color: var(--wip-red);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Region / topic card grid. */
.wip-region-grid {
  display: grid;
  gap: 1.5rem;
}

@media (min-width: 860px) {
  .wip-region-grid {
    grid-template-columns: repeat(3, 1fr);
    align-items: start;
  }
}

.wip-region-card {
  padding: 1.75rem;
  border: 1px solid var(--wip-hairline);
  border-radius: 0.75rem;
  background: var(--wip-ground);
}

.wip-section--alt .wip-region-card {
  background: var(--wip-ground-2);
}

.wip-region-card__code {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-red);
}

.wip-region-card__title {
  margin-top: 0.75rem;
  font-size: 1.2rem;
}

.wip-region-card__body {
  margin-top: 1rem;
}

.wip-region-card__body p {
  margin: 0 0 1rem;
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--wip-ink-2);
}

.wip-region-card__body p:last-child {
  margin-bottom: 0;
}

/* Lists inside imported prose.
   Tailwind's preflight ships `ol,ul{list-style:none;margin:0;padding:0}`, so
   without this a <ul> in a region card or an FAQ answer renders as unindented,
   unmarked lines that read as ordinary sentences that happen to break early.
   The red dot is borrowed from .wip-prose so the two prose contexts agree
   rather than each inventing a bullet. */
.wip-region-card__body ul,
.wip-region-card__body ol,
.wip-faq-item__body ul,
.wip-faq-item__body ol {
  margin: 0 0 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.45em;
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--wip-ink-2);
}

.wip-region-card__body ul,
.wip-faq-item__body ul {
  list-style: none;
  padding-left: 0;
}

.wip-region-card__body ul > li,
.wip-faq-item__body ul > li {
  position: relative;
  padding-left: 1.35em;
}

.wip-region-card__body ul > li::before,
.wip-faq-item__body ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--wip-red);
}

.wip-region-card__body ol,
.wip-faq-item__body ol {
  list-style: decimal;
  padding-left: 1.3em;
}

.wip-region-card__body ol > li::marker,
.wip-faq-item__body ol > li::marker {
  color: var(--wip-red);
  font-weight: 700;
}

.wip-region-card__body ul:last-child,
.wip-region-card__body ol:last-child,
.wip-faq-item__body ul:last-child,
.wip-faq-item__body ol:last-child {
  margin-bottom: 0;
}

/* A topic's own <h3> sub-heading, folded into the same card rather than a
   new component — jhg_parse_wip_article() in inc/page-templates.php. */
.wip-region-card__body p.wip-region-card__sub {
  margin: 1.25rem 0 0.5rem;
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--wip-ink);
}

.wip-region-card__body p.wip-region-card__sub:first-child {
  margin-top: 0;
}

/* Bulleted fact lists inside a region card or FAQ answer — plain rows, not
   pills, since these sit in a narrower column than the day blocks do. */
.wip-region-card__body .wip-line-facts,
.wip-faq-item__body .wip-line-facts {
  margin: 0 0 1rem;
  padding-left: 1.1rem;
  list-style: disc;
}

.wip-region-card__body .wip-line-facts li,
.wip-faq-item__body .wip-line-facts li {
  margin-bottom: 0.4rem;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--wip-ink-2);
}

.wip-region-card__body .wip-line-facts li strong,
.wip-faq-item__body .wip-line-facts li strong {
  color: var(--wip-ink);
}

/* -------------------------------------------------- day-by-day itinerary */

/* Highlight chips under the header's Quick Answer callout. */
.wip-chips {
  margin-top: 1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.wip-chip {
  padding: 0.4rem 0.85rem;
  border: 1px solid var(--wip-hairline);
  border-radius: 999px;
  font-size: 12px;
  color: var(--wip-ink-2);
  background: var(--wip-ground-2);
}

.wip-day-list {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.wip-day {
  padding: 2rem;
  border: 1px solid var(--wip-hairline);
  border-radius: 0.9rem;
  background: var(--wip-ground-2);
}

.wip-section--alt .wip-day {
  background: var(--wip-ground);
}

.wip-day__badge {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-red);
}

.wip-day__title {
  margin-top: 0.6rem;
  font-size: clamp(19px, 2.2vw, 24px);
}

.wip-day__intro {
  margin-top: 0.9rem;
}

.wip-day__intro p {
  margin: 0 0 0.9rem;
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--wip-ink-2);
}

.wip-day__intro p:last-child {
  margin-bottom: 0;
}

.wip-day__timeline {
  margin-top: 1.5rem;
  border-top: 1px solid var(--wip-hairline);
}

.wip-day__block {
  padding: 1.25rem 0;
  border-bottom: 1px solid var(--wip-hairline);
}

.wip-day__block-time {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--wip-ink);
}

.wip-day__block p {
  margin: 0.6rem 0 0;
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--wip-ink-2);
}

.wip-day__facts {
  margin-top: 0.75rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Reuses the same pill shape as .wip-journal__stat, sized down slightly for
   a dense day-block grid rather than one lede callout. */
.wip-day__fact {
  display: inline-flex;
  align-items: center;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--wip-hairline);
  border-radius: 999px;
  background: var(--wip-ground);
  font-size: 11.5px;
  color: var(--wip-ink-2);
}

.wip-section--alt .wip-day__fact {
  background: var(--wip-ground-2);
}

.wip-day__fact strong {
  margin-right: 0.5rem;
  padding-right: 0.5rem;
  border-right: 1px solid var(--wip-hairline);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 9.5px;
  letter-spacing: 0.1em;
  color: var(--wip-red);
}

/* Budget breakdown / sample-routes fact lists — plain rows rather than
   pills, for a longer flatter list. */
.wip-fact-list {
  margin: 1.5rem 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.wip-fact-list__group {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--wip-ink);
  margin-top: 0.75rem;
}

.wip-fact-list__group:first-child {
  margin-top: 0;
}

.wip-fact-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--wip-hairline);
  font-size: 13.5px;
  color: var(--wip-ink-2);
}

.wip-fact-row__label {
  flex: none;
  color: var(--wip-ink);
}

.wip-fact-row__value {
  text-align: right;
}

.wip-total-banner {
  margin-top: 1.5rem;
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.75rem;
  padding: 1.1rem 1.5rem;
  border: 1px solid var(--wip-red);
  border-radius: 0.6rem;
}

.wip-total-banner__label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-red);
}

.wip-total-banner__value {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--wip-ink);
}

/* ------------------------------------------------------------ releases */

.wip-releases {
  padding: 6rem 0;
  background: var(--wip-ground-2);
  border-top: 1px solid var(--wip-hairline);
  border-bottom: 1px solid var(--wip-hairline);
}

.wip-releases__grid {
  display: grid;
  gap: 3.5rem;
  align-items: center;
}

@media (min-width: 960px) {
  .wip-releases__grid {
    grid-template-columns: 1fr 1fr;
    gap: 4rem;
  }
}

.wip-releases__heading {
  font-size: clamp(28px, 3.2vw, 44px);
  margin-top: 1rem;
}

.wip-releases__lede {
  margin-top: 1.25rem;
  max-width: 46ch;
  color: var(--wip-ink-2);
  font-size: 15px;
  line-height: 1.7;
}

.wip-releases__actions {
  margin-top: 2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.wip-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  height: 46px;
  padding: 0 1.5rem;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  transition: background-color 0.2s ease-out, color 0.2s ease-out, border-color 0.2s ease-out;
}

/* a.wip-btn--*, not .wip-btn--*: same specificity trap as a.wip-pill above.
   `.wip-btn--solid { color: var(--wip-ground) }` alone is (0,1,0), which
   loses outright to `.wip a { color: inherit }` at (0,1,1) — so the button
   silently rendered with inherited ink-coloured text instead of the
   near-black it was supposed to have. Barely visible on the red resting
   state; on :hover, once the background also switches to --wip-ink, it was
   ink text on an ink background — invisible. Qualifying with the `a` type
   selector brings these to (0,1,1) too, so the later rule in the cascade
   wins as intended, and the hover state repeats its own colour explicitly
   rather than depend on that. */
a.wip-btn--solid {
  background: var(--wip-red);
  color: var(--wip-ground);
}

a.wip-btn--solid:hover,
a.wip-btn--solid:focus-visible {
  background: var(--wip-ink);
  color: var(--wip-ground);
}

a.wip-btn--outline {
  border: 1px solid var(--wip-hairline);
  color: var(--wip-ink);
}

a.wip-btn--outline:hover,
a.wip-btn--outline:focus-visible {
  border-color: var(--wip-white);
  color: var(--wip-white);
}

/* Deck */

.wip-deck {
  position: relative;
  width: 100%;
  max-width: 24rem;
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  touch-action: pan-y;
}

.wip-deck:focus-visible {
  outline: 2px solid var(--wip-white);
  outline-offset: 6px;
  border-radius: 1rem;
}

.wip-card {
  position: absolute;
  inset: 0;
  border-radius: 1rem;
  border: 1px solid var(--wip-hairline);
  background: var(--wip-ground);
  box-shadow: 0 24px 48px -20px rgba(0, 0, 0, 0.6);
  padding: 1.75rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  cursor: grab;
  user-select: none;
  will-change: transform;
}

.wip-card:active {
  cursor: grabbing;
}

/* Static stack order, matching the offsets front-portal.js applies via
   layout(). This is the resting state before that script runs (or if it
   never does) — five cards fanned into a legible deck rather than piled on
   one point, so the "physical stack" reads correctly with zero JS. */
.wip-card:nth-child(1) {
  z-index: 5;
  transform: none;
}
.wip-card:nth-child(2) {
  z-index: 4;
  transform: translate(8px, -10px) rotate(1.5deg) scale(0.965);
}
.wip-card:nth-child(3) {
  z-index: 3;
  transform: translate(16px, -20px) rotate(-3deg) scale(0.93);
}
.wip-card:nth-child(4) {
  z-index: 2;
  transform: translate(24px, -30px) rotate(4.5deg) scale(0.895);
}
.wip-card:nth-child(5) {
  z-index: 1;
  opacity: 0;
  transform: translate(32px, -40px) rotate(-6deg) scale(0.86);
}

.wip-card__code {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-red);
}

.wip-card__kicker {
  margin-top: 0.9rem;
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 1.5rem;
  letter-spacing: -0.02em;
  color: var(--wip-ink);
}

.wip-card__fact {
  margin-top: 0.75rem;
  font-size: 12.5px;
  color: var(--wip-ink-2);
}

/* Route photo. Fills the space the card used to leave empty between the fact
   line and the blurb — flex: 1 with min-height: 0 so it absorbs whatever is
   left over at any card size rather than forcing the deck taller (the deck is
   a fixed 1:1 box, so a media block that could grow would push the blurb out
   of the card entirely).

   pointer-events: none is not decoration: .wip-card is a drag handle, and
   letting the photo take the pointer would swallow the throw gesture on the
   two thirds of the card it covers. draggable="false" in the markup stops the
   browser's native image drag for the same reason. */
.wip-card__media {
  flex: 1 1 auto;
  min-height: 0;
  margin: 1.1rem 0 0;
  overflow: hidden;
  border-radius: 0.7rem;
  border: 1px solid var(--wip-hairline);
  background: rgb(255 255 255 / 0.03);
  pointer-events: none;
}

.wip-card__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-user-drag: none;
  user-select: none;
}

.wip-card__blurb {
  margin-top: auto;
  padding-top: 1rem;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--wip-ink-2);
  border-top: 1px solid var(--wip-hairline);
}

/* The blurb sits directly under the photo once there is one, so its own top
   rule would read as a second border a few pixels from the frame's. */
.wip-card__media + .wip-card__blurb {
  margin-top: 0;
  padding-top: 0.9rem;
  border-top: 0;
}

.wip-deck__hint {
  margin-top: 1.5rem;
  text-align: center;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-muted);
}

.wip-deck__dots {
  margin-top: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.wip-deck__dot {
  /* Button reset — these are real controls, but must still read as 6px dots. */
  appearance: none;
  -webkit-appearance: none;
  padding: 0;
  border: 0;
  flex: 0 0 auto;
  position: relative;
  cursor: pointer;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--wip-hairline);
  transition: background-color 0.2s ease-out, transform 0.2s ease-out;
}

/* Invisible tap target centred on each dot. Kept to exactly the 14px dot
   pitch (6px dot + 8px gap) so neighbouring targets never overlap and a tap
   always lands on the dot it looks like it landed on, while still clearing a
   comfortable height on touch. */
.wip-deck__dot::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 24px;
  transform: translate(-50%, -50%);
}

/* .is-active scales the button by 1.3, which would scale its hit area with it
   and let the active dot steal ~2px from each neighbour. Cancel the scale on
   the target so every dot keeps exactly its own 14px column in every state. */
.wip-deck__dot.is-active::after {
  transform: translate(-50%, -50%) scale(calc(1 / 1.3));
}

.wip-deck__dot:hover {
  background: var(--wip-muted);
}

.wip-deck__dot:focus-visible {
  outline: 2px solid var(--wip-red);
  outline-offset: 3px;
}

.wip-deck__dot.is-active {
  background: var(--wip-red);
  transform: scale(1.3);
}

/* -------------------------------------------------------------- roster */

.wip-roster {
  padding: 5.5rem 0;
  background: var(--wip-ground);
}

.wip-roster__head {
  margin-bottom: 2.5rem;
}

.wip-roster__title {
  margin-top: 0.75rem;
  font-size: clamp(26px, 3vw, 38px);
}

.wip-roster__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.35rem 0;
  border-top: 1px solid var(--wip-hairline);
}

.wip-roster__row:last-child {
  border-bottom: 1px solid var(--wip-hairline);
}

.wip-roster__main {
  display: flex;
  align-items: baseline;
  gap: 1.1rem;
  min-width: 0;
}

.wip-roster__label {
  flex: none;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-white);
}

.wip-roster__name {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-size: clamp(1.05rem, 2vw, 1.4rem);
  color: var(--wip-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wip-roster__count {
  flex: none;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--wip-ink-2);
}

/* --------------------------------------------------------------- dates */

.wip-dates {
  padding: 5.5rem 0;
  background: var(--wip-ground-2);
  border-top: 1px solid var(--wip-hairline);
}

.wip-dates__head {
  margin-bottom: 2rem;
}

.wip-dates__title {
  margin-top: 0.75rem;
  font-size: clamp(26px, 3vw, 38px);
  max-width: 22ch;
}

.wip-dates__lede {
  margin-top: 1rem;
  max-width: 60ch;
  color: var(--wip-ink-2);
  font-size: 14.5px;
  line-height: 1.7;
}

.wip-dates__group {
  margin-top: 3rem;
}

.wip-dates__group-title {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-red);
  margin-bottom: 1rem;
}

.wip-table {
  width: 100%;
  border-collapse: collapse;
}

.wip-table thead th {
  text-align: left;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--wip-ink-2);
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--wip-hairline);
}

.wip-table tbody td {
  padding: 1rem 0;
  border-bottom: 1px solid var(--wip-hairline);
  font-size: 14px;
  vertical-align: top;
}

.wip-table tbody td:first-child {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--wip-ink);
  white-space: nowrap;
  padding-right: 1.5rem;
}

.wip-table tbody td:nth-child(2) {
  color: var(--wip-red);
  white-space: nowrap;
  padding-right: 1.5rem;
}

.wip-table tbody td:last-child {
  color: var(--wip-ink-2);
}

@media (max-width: 640px) {
  .wip-table thead {
    display: none;
  }
  .wip-table,
  .wip-table tbody,
  .wip-table tr {
    display: block;
    width: 100%;
  }
  .wip-table tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 1rem;
    padding: 1rem 0;
    border-bottom: 1px solid var(--wip-hairline);
  }
  .wip-table tbody td {
    border-bottom: none;
    padding: 0.15rem 0;
  }
  .wip-table tbody td:last-child {
    grid-column: 1 / -1;
    margin-top: 0.35rem;
  }
}

/* -------------------------------------------------------------- close */

.wip-close {
  position: relative;
  padding: 6rem 0 0;
  background: var(--wip-ground);
  overflow: hidden;
}

.wip-close__top {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
  padding-bottom: 3.5rem;
}

@media (min-width: 768px) {
  .wip-close__top {
    flex-direction: row;
    align-items: flex-end;
    /* Not justify-content: space-between — that pins the actions to the far
       right edge of whatever .wip-wrap resolves to, which reads as a huge,
       unexplained gap next to the heading on a very wide viewport. Capping
       the text column's own width (below) and using a fixed gap instead
       keeps the two groups a constant, readable distance apart regardless
       of how wide the row actually is; any leftover room falls to the right
       of the buttons, not between the two groups. */
    justify-content: flex-start;
    gap: 3rem;
  }

  .wip-close__top > div:first-child {
    max-width: 46rem;
  }
}

.wip-close__heading {
  font-size: clamp(28px, 4vw, 48px);
  max-width: 18ch;
}

.wip-close__body {
  margin-top: 1rem;
  max-width: 52ch;
  font-size: 14px;
  line-height: 1.75;
  color: var(--wip-ink-2);
}

/* .wip-close__body is also used as a <div> wrapper around parsed HTML
   (multiple <p>) rather than a single <p> — reset so it reads the same
   either way. */
.wip-close__body p {
  margin: 0 0 1em;
}

.wip-close__body p:last-child {
  margin-bottom: 0;
}

.wip-close__body a {
  color: var(--wip-red);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.wip-close__body a:hover,
.wip-close__body a:focus-visible {
  color: var(--wip-white);
}

.wip-close__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  flex: none;
}

.wip-close__strip {
  padding: 1.75rem 0;
  border-top: 1px solid var(--wip-hairline);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

@media (min-width: 768px) {
  .wip-close__strip {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.wip-close__copy {
  font-size: 11.5px;
  color: var(--wip-muted);
}

.wip-close__press {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-muted);
}

.wip-close__press span {
  color: var(--wip-ink-2);
  margin: 0 0.4em;
}

.wip-close__mark {
  transform: translateY(22%);
  font-family: "Syne", sans-serif;
  font-weight: 800;
  letter-spacing: -0.03em;
  font-size: clamp(4rem, 15vw, 13rem);
  line-height: 1;
  white-space: nowrap;
  /* Solid ink, not a near-invisible ground-tone outline: cropped by the
     page edge is the effect, not "hard to read". */
  color: var(--wip-ink);
  text-align: center;
}

/* ------------------------------------------------------------------ blog */

.wip-blog-grid {
  display: grid;
  gap: 1.75rem;
}

@media (min-width: 640px) {
  .wip-blog-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .wip-blog-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.wip-blog-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--wip-hairline);
  border-radius: 0.9rem;
  overflow: hidden;
  background: var(--wip-ground);
}

.wip-blog-card__media {
  display: block;
  aspect-ratio: 16 / 10;
  background: var(--wip-ground-2);
}

.wip-blog-card__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.wip-blog-card__media-fallback {
  display: flex;
  height: 100%;
  align-items: center;
  justify-content: center;
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.02em;
  color: var(--wip-muted);
}

.wip-blog-card__media-fallback span {
  color: var(--wip-red);
}

.wip-blog-card__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 1.5rem;
}

.wip-blog-card__meta {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-muted);
}

.wip-blog-card__meta span {
  color: var(--wip-hairline);
  margin: 0 0.35em;
}

.wip-blog-card__title {
  margin-top: 0.75rem;
  font-size: 1.15rem;
}

.wip-blog-card__title a {
  color: var(--wip-ink);
}

.wip-blog-card__title a:hover,
.wip-blog-card__title a:focus-visible {
  color: var(--wip-red);
}

.wip-blog-card__excerpt {
  margin-top: 0.75rem;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--wip-ink-2);
}

.wip-blog-card__link {
  margin-top: auto;
  padding-top: 1.25rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-red);
}

.wip-blog-card__link:hover,
.wip-blog-card__link:focus-visible {
  color: var(--wip-white);
}

.wip-pagination {
  margin-top: 3rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
}

.wip-pagination__status {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-muted);
}

.wip-blog-empty {
  max-width: 46ch;
  margin: 0 auto;
  padding: 3rem 0;
  text-align: center;
}

.wip-blog-empty__heading {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 1.35rem;
  letter-spacing: -0.02em;
  color: var(--wip-ink);
}

.wip-blog-empty__body {
  margin-top: 0.75rem;
  font-size: 14px;
  line-height: 1.7;
  color: var(--wip-ink-2);
}

/* --------------------------------------------------- floating WA button */

/* Hex literals, not var(--wip-red)/var(--wip-ground): this prints from
   wp_footer (hooks/wa-button/initialize.php), after the page's own closing
   </div class="wip">, so it is not a descendant of .wip and the custom
   properties declared there don't reach it. */
.wip-wa-float {
  position: fixed;
  right: 1.25rem;
  bottom: 1.5rem;
  z-index: 50;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 999px;
  background: #ff3b30;
  color: #0a0c0e;
  box-shadow: 0 12px 28px -10px rgba(0, 0, 0, 0.7);
  transition: transform 0.2s ease-out, background-color 0.2s ease-out;
}

.wip-wa-float:hover,
.wip-wa-float:focus-visible {
  background: #f5f5f0;
  transform: translateY(-3px);
}

.wip-wa-float i {
  font-size: 28px;
}

@media (prefers-reduced-motion: reduce) {
  .wip-wa-float {
    transition: background-color 0.2s ease-out;
  }
  .wip-wa-float:hover,
  .wip-wa-float:focus-visible {
    transform: none;
  }
}

/* Back to top. Printed from wp_footer by hooks/back-to-top/initialize.php, so
   like .wip-wa-float above it sits outside .wip and cannot read var(--wip-*) —
   hence the hard-coded hex here too.

   Parked directly on top of the WhatsApp float: bottom clears that button's
   56px plus a 12px gap, and the right edge is nudged the 4px that makes this
   48px button share a centre line with the 56px one below it. Deliberately
   quieter than the WhatsApp float — outlined near-black rather than solid red
   — so the primary action stays the loudest thing in the corner. */
.wip-to-top {
  position: fixed;
  right: calc(1.25rem + 4px);
  bottom: calc(1.5rem + 56px + 0.75rem);
  z-index: 50;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid rgba(245, 245, 240, 0.18);
  border-radius: 999px;
  background: rgba(18, 20, 23, 0.92);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #f5f5f0;
  cursor: pointer;
  box-shadow: 0 12px 28px -10px rgba(0, 0, 0, 0.7);
  /* Hidden until scrolled. visibility (not just opacity) so the button is
     genuinely untabbable while it is invisible; its transition is delayed by
     the length of the fade on the way out, and instant on the way in. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.2s ease-out, transform 0.2s ease-out,
    background-color 0.2s ease-out, border-color 0.2s ease-out,
    visibility 0s linear 0.2s;
}

.wip-to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.2s ease-out, transform 0.2s ease-out,
    background-color 0.2s ease-out, border-color 0.2s ease-out,
    visibility 0s linear 0s;
}

.wip-to-top:hover,
.wip-to-top:focus-visible {
  background: #ff3b30;
  border-color: #ff3b30;
  color: #0a0c0e;
}

.wip-to-top:focus-visible {
  outline: 2px solid #f5f5f0;
  outline-offset: 3px;
}

.wip-to-top i {
  font-size: 22px;
  line-height: 1;
}

@media (prefers-reduced-motion: reduce) {
  .wip-to-top,
  .wip-to-top.is-visible {
    transform: none;
    transition: opacity 0.2s ease-out, background-color 0.2s ease-out,
      border-color 0.2s ease-out, visibility 0s linear 0.2s;
  }
  .wip-to-top.is-visible {
    transition: opacity 0.2s ease-out, background-color 0.2s ease-out,
      border-color 0.2s ease-out, visibility 0s linear 0s;
  }
}

/* ------------------------------------------------------- single post */

/* single.php: a real WordPress post body (the_content()) can contain
   anything the editor put there — headings, lists, quotes, images, tables —
   unlike the 39 migrated pages, which only ever render their own extracted
   prose/facts through jhg_render_lines_html(). .wip-prose is the generic
   rich-text treatment for that: same Syne/Sora + red/ink/white tokens as
   the rest of .wip, just scoped wide enough to cover arbitrary post HTML. */

.wip-prose__cover {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 0.9rem;
  margin-bottom: 3rem;
}

.wip-prose {
  max-width: 72ch;
  margin: 0 auto;
  font-family: "Sora", sans-serif;
  font-size: 16.5px;
  line-height: 1.75;
  color: var(--wip-ink-2);
}

.wip-prose > *:first-child {
  margin-top: 0;
}

.wip-prose p {
  margin: 0 0 1.4em;
}

.wip-prose h2,
.wip-prose h3,
.wip-prose h4 {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  color: var(--wip-ink);
  letter-spacing: -0.01em;
  margin: 2.4em 0 0.9em;
}

.wip-prose h2 {
  font-size: clamp(22px, 2.6vw, 28px);
}

.wip-prose h3 {
  font-size: clamp(19px, 2.1vw, 22px);
}

.wip-prose h4 {
  font-size: 17px;
}

.wip-prose a {
  color: var(--wip-red);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-color: rgba(255, 59, 48, 0.4);
}

.wip-prose a:hover,
.wip-prose a:focus-visible {
  text-decoration-color: var(--wip-red);
}

.wip-prose strong {
  color: var(--wip-ink);
  font-weight: 600;
}

.wip-prose ul,
.wip-prose ol {
  margin: 0 0 1.4em;
  padding-left: 1.4em;
  display: flex;
  flex-direction: column;
  gap: 0.5em;
}

.wip-prose ul {
  list-style: none;
  padding-left: 0;
}

.wip-prose ul > li {
  position: relative;
  padding-left: 1.4em;
}

.wip-prose ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--wip-red);
}

.wip-prose ol {
  list-style: decimal;
  padding-left: 1.3em;
}

.wip-prose ol > li::marker {
  color: var(--wip-red);
  font-weight: 700;
}

.wip-prose blockquote {
  margin: 2em 0;
  padding: 0.2em 0 0.2em 1.4em;
  border-left: 2px solid var(--wip-red);
  font-family: "Syne", sans-serif;
  font-size: 19px;
  font-weight: 600;
  color: var(--wip-ink);
}

.wip-prose blockquote p:last-child {
  margin-bottom: 0;
}

.wip-prose figure {
  margin: 2.4em 0;
}

.wip-prose img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 0.75rem;
}

.wip-prose figcaption {
  margin-top: 0.75em;
  font-size: 12.5px;
  color: var(--wip-muted);
  text-align: center;
}

.wip-prose hr {
  margin: 3em 0;
  border: none;
  border-top: 1px solid var(--wip-hairline);
}

.wip-prose table {
  width: 100%;
  margin: 0 0 1.6em;
  border-collapse: collapse;
  font-size: 14.5px;
}

.wip-prose th,
.wip-prose td {
  padding: 0.7em 1em;
  border: 1px solid var(--wip-hairline);
  text-align: left;
}

.wip-prose th {
  font-family: "Syne", sans-serif;
  color: var(--wip-ink);
  background: var(--wip-ground-2);
}

.wip-prose code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.9em;
  padding: 0.15em 0.4em;
  border-radius: 0.35em;
  background: var(--wip-ground-2);
  color: var(--wip-white);
}

.wip-prose pre {
  margin: 0 0 1.6em;
  padding: 1.2em 1.4em;
  border-radius: 0.75rem;
  background: var(--wip-ground-2);
  border: 1px solid var(--wip-hairline);
  overflow-x: auto;
}

.wip-prose pre code {
  padding: 0;
  background: none;
}

.wip-post-tags {
  max-width: 72ch;
  margin: 3rem auto 0;
  padding-top: 2rem;
  border-top: 1px solid var(--wip-hairline);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
}

.wip-post-tags__label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-red);
}

.wip-post-tags .wip-chips {
  margin-top: 0;
}

.wip-post-nav {
  max-width: 72ch;
  margin: 2rem auto 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--wip-hairline);
  border: 1px solid var(--wip-hairline);
  border-radius: 0.9rem;
  overflow: hidden;
}

@media (min-width: 640px) {
  .wip-post-nav {
    grid-template-columns: 1fr 1fr;
  }
}

.wip-post-nav__item {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.4rem 1.6rem;
  background: var(--wip-ground-2);
  transition: background-color 0.2s ease-out;
}

.wip-post-nav__item--next {
  text-align: right;
  align-items: flex-end;
}

.wip-post-nav__item:hover,
.wip-post-nav__item:focus-visible {
  background: var(--wip-ground);
}

.wip-post-nav__label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wip-red);
}

.wip-post-nav__title {
  font-family: "Syne", sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--wip-ink);
  line-height: 1.4;
}

/* -------------------------------------------------------------- misc */

/* Entry reveals reuse the site-wide .reveal/.is-visible convention already
   shipped in tailwind.css and driven by assets/js/reveal.js: gated behind
   .js on <html>, fired once, never reversed, and neutralised entirely under
   prefers-reduced-motion. No need to redefine any of that here. */

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