/* Khumbu trail viewer — no build step, no framework. */

:root{
  --shell:#111111;
  --accent:#F6A102;          /* Nepal, from krismcd.com/smile */
  --ease:cubic-bezier(.4,0,0,1);
  --pad:48px;
  --line:rgba(255,255,255,.5);
  --dot:rgba(255,255,255,.4);
  --shadow:0 1px 3px rgba(0,0,0,.6);
  --stack:"General Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;
  background:var(--shell);
  color:#fff;
  font-family:var(--stack);
  overflow:hidden;
  -webkit-font-smoothing:antialiased;
}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ---------- photo stage ---------- */

.stage{position:fixed;inset:0;background:var(--shell)}

.layer{
  position:absolute;inset:0;
  opacity:0;
  transition:opacity .6s var(--ease);
  /* No placeholder image here any more. It was painted at background-size:contain
     while the photo is object-fit:contain, and a 20px LQIP cannot hold the exact
     aspect — a 3:2 frame rounds to 20x13 (1.538), so the blurred copy rendered
     ~35px wider than the photo and showed as strips down both edges. It has had
     no job since the layer started waiting on img.decode() before revealing. */
  /* Opaque, including the letterbox bands beside a contain-fitted photograph.
     Without this the layer is see-through there, and holding the outgoing layer
     underneath during a fade shows the previous photograph in those bands. */
  background-color:var(--shell);
}
.layer.is-active{opacity:1}
.layer img{
  position:absolute;inset:0;
  width:100%;height:100%;
  display:block;
}
/* One class only: nothing is cropped and everything sits right — see fitClass(). */
.layer img.fit-right  {object-fit:contain;object-position:right center}

/* ---------- region name ---------- */

/* The country alone, pinned top left. It is the nav trigger. */
/* The whole corner block is what's pinned; .region is a static child of it, so
   the mobile meta line can sit under the country name without a second anchor. */
.topleft{
  position:fixed;top:40px;left:var(--pad);z-index:60;   /* above the nav overlay, so it also closes it */
}
.topmeta{display:none}                                  /* desktop keeps these in the rail */

.region{
  display:flex;align-items:center;gap:10px;
  background:none;border:0;padding:0;cursor:pointer;text-align:left;
  color:var(--accent);
  font:700 32px/1.15 var(--stack);      /* General Sans Bold */
  /* the only thing standing between amber text and a bright sky */
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
}

/* The region within Nepal — sits with the photo's own text, above its title. */
.region-sub{
  margin:0 0 6px;
  font:400 17px/1.3 var(--stack);
  color:#fff;
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
}
/* Position within the whole region, not within the stop — so it keeps moving
   even when three photographs share a point. */
.step-line{
  margin:6px 0 0;
  font:400 14px/1.3 var(--stack);
  color:#fff;
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
}
.region .caret{transition:transform .3s var(--ease)}
.region[aria-expanded="true"] .caret{transform:rotate(180deg)}

/* ---------- trail map ---------- */

/* Desktop left rail: trail map, then the details directly beneath it.
   On mobile the rail dissolves (display:contents) and the two go their own ways. */
/* Centred on the MAP's height, not the rail's. Centring the whole rail meant a
   two-line title grew the block and shoved everything up half a line; anchoring
   to the map keeps the text block's top fixed, so a wrapping title pushes the
   date and stepper down instead of moving itself. --map-h is set by app.js. */
.rail{
  position:fixed;left:var(--pad);top:50%;z-index:20;
  /* Centred on the MAP's height, so a wrapping title pushes the date and stepper
     down rather than moving the block. The -34px is the gap below going 18 -> 52:
     the rail rises by the same amount it grew, so the text block stays where it
     was and only the map moves up. Keep the two in step if the gap changes. */
  transform:translateY(calc(var(--map-h, 420px) / -2 - 34px));
  display:flex;flex-direction:column;align-items:flex-start;gap:52px;
}

.map{
  overflow:visible;
  transition:width .5s var(--ease),height .5s var(--ease);
  /* No container anywhere, so this is the whole legibility budget: a tight shadow
     for edge definition plus a wider soft one to lift the marks off pale skies
     and snowfields. Applied to the svg, so line, points, labels and the count
     all inherit it. */
  filter:drop-shadow(0 0 1px rgba(0,0,0,1))
         drop-shadow(0 0 2px rgba(0,0,0,1))
         drop-shadow(0 1px 3px rgba(0,0,0,.95))
         drop-shadow(0 2px 12px rgba(0,0,0,.75));
}
.map .route{fill:none;stroke:var(--line);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
/* ground covered on the current leg, drawn over the pale base line */
.map .route-fill{
  fill:none;stroke:var(--accent);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
  transition:stroke-dasharray .45s var(--ease), stroke-dashoffset .45s var(--ease);
}
.map .outline{fill:none;stroke:var(--line);stroke-width:1.5;stroke-linejoin:round}
.map .stop{cursor:pointer}
/* :not(.halo) throughout — the ring is a circle too, and must keep fill:none */
.map .stop circle:not(.halo){fill:#fff;transition:fill .3s var(--ease),r .3s var(--ease)}
.map .stop:hover circle:not(.halo),
.map .stop:focus-visible circle:not(.halo){fill:var(--accent)}
.map .stop:focus-visible{outline:none}
.map .stop.is-active circle:not(.halo){fill:var(--accent)}
/* progress arc — length set per photo in app.js, grown into place on change */
.map .halo{
  fill:none;stroke:var(--accent);stroke-width:2;stroke-linecap:butt;
  transition:stroke-dashoffset .45s var(--ease);
}
.map .label{
  fill:var(--accent);font:600 14px/1 var(--stack);
}
.map .landmark{fill:none;stroke:rgba(255,255,255,.55);stroke-width:1.5;stroke-linejoin:round}
.map .landmark-label{fill:rgba(255,255,255,.55);font:400 12px/1 var(--stack)}
.map .count{fill:#fff;fill-opacity:1;font:400 11px/1 var(--stack)}
/* Trek day, not trail position. The route doubles back, so stop order can never
   run in sequence — days always can. Live per visit: Lukla reads Day 1 going up
   and Day 16 coming down. */
.map .stop-name{fill:#fff;fill-opacity:.75;font:400 11px/1 var(--stack)}
.map .stop-day{fill:#fff;fill-opacity:1;font:400 11px/1 var(--stack)}
.map .group{transition:opacity .25s var(--ease)}
.map.is-morphing .group{opacity:0}

/* ---------- button (portfolio .btn-secondary) ---------- */

.btn-secondary{
  position:fixed;bottom:var(--pad);right:var(--pad);z-index:30;
  display:flex;align-items:center;
  padding:24px;
  border:0;border-radius:48px;
  background:transparent;
  color:#fff;
  font:600 16px/22px var(--stack);
  letter-spacing:.4px;
  text-transform:uppercase;
  cursor:pointer;
  transition:.15s var(--ease);
}
.btn-secondary::after{
  content:"";
  position:absolute;inset:0;
  border:2px solid #fff;
  border-radius:48px;
  box-shadow:0 4px 12px 2px rgba(7,7,8,.45);
  transition:.3s var(--ease);
}
.btn-secondary:hover::after,
.btn-secondary:focus-visible::after{
  transform:scale(1.15);
  box-shadow:0 10px 12px 2px rgba(7,7,8,.3);
}
.btn-secondary:focus-visible{outline:none}
.btn-secondary[hidden]{display:none}

/* Same ring, smaller: a corner control, not a primary action. */
.nav-close{
  /* fixed, not absolute: the grid scrolls and the way out must not scroll with it */
  position:fixed;top:34px;right:var(--pad);z-index:55;
  bottom:auto;left:auto;
  padding:12px 22px;
  font-size:13px;
  border-radius:32px;
}
.nav-close::after{border-radius:32px;border-width:1.5px}

/* ---------- details ---------- */

/* Desktop: no card. The map has no container, so neither does this — same
   drop-shadow treatment, sitting straight on the photograph. */
.details{max-width:380px}
.details[hidden]{display:none}
.details h2{
  margin:0 0 8px;font:600 26px/1.25 var(--stack);color:#fff;
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
}
.details-meta{
  margin:0;font:400 16px/1.4 var(--stack);color:var(--accent);
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
}
.details-desc{
  margin:14px 0 0;font:400 17px/1.55 var(--stack);color:rgba(255,255,255,.88);
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
}
.details-desc:empty{display:none}          /* descriptions are blank for now — no gap */
.details-grab{display:none}
.details-map-slot{display:none}
.details .icon-close{display:none}         /* nothing to close: it is always there */
#details-btn{display:none}                 /* desktop has no Details button */

.icon-close{
  position:absolute;top:26px;right:24px;
  background:none;border:0;padding:4px;cursor:pointer;
  color:rgba(255,255,255,.6);line-height:0;
}
.icon-close:hover{color:#fff}

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

.nav{
  position:fixed;inset:0;z-index:50;
  background:none;
  /* 46px, not 40: .region is pinned at top:40px but its capitals start 6px lower,
     past the half-leading and the gap between ascender and cap height. Measured off
     the rendered glyphs rather than computed, so it is a constant — revisit it if
     the title's size or line-height changes. */
  padding:46px var(--pad) var(--pad);
  overflow:auto;
}
.nav[hidden]{display:none}
.nav:focus{outline:none}          /* it is focused to hold focus, not to be seen */
/* An animation, not a transition: the overlay goes from display:none to shown, and
   there is no from-state to transition out of. Only set when the overlay opens
   itself at the end of a set — see openNav().
   Applied to the layers rather than to .nav, deliberately: opacity on .nav would
   make it the backdrop root, and a backdrop-filter inside a backdrop root has
   nothing behind it to filter — the blur would quietly stop working. */
.nav.fade-in .nav-scrim,
.nav.fade-in .nav-grid,
.nav.fade-in .nav-close{animation:navIn .45s var(--ease) both}
@keyframes navIn{from{opacity:0}to{opacity:1}}
/* The scrim: fixed, so it is outside .nav's scrolling content and the compositor
   is not asked to re-filter it on every scrolled frame. pointer-events:none is
   load-bearing — being fixed it sits outside the scroll flow, so a wheel over it
   resolves to the viewport, which does not scroll, and the grid refused to move
   anywhere the cards did not cover it.
   The colour is deliberately short of opaque so the blur has something to work on:
   at .95 the photograph was already gone and the filter did nothing. Saturation is
   pulled back so the blurred photo reads as ground rather than as content. */
.nav-scrim{
  position:fixed;inset:0;
  pointer-events:none;
  background:rgba(17,17,17,.78);
  -webkit-backdrop-filter:blur(28px) saturate(.85);
          backdrop-filter:blur(28px) saturate(.85);
}

/* Sets within the current country, left-aligned under the country name. Fixed, so
   they stay with the title while the grid scrolls past — same treatment as Close. */
.nav-sets{
  position:fixed;top:96px;left:var(--pad);z-index:55;
  list-style:none;margin:0;padding:0;
  display:flex;flex-direction:column;gap:12px;
}
.nav-set{
  display:inline-flex;align-items:baseline;gap:8px;
  color:#fff;text-decoration:none;
  font:600 17px/1.3 var(--stack);
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
}
.nav-set-arrow{transition:transform .2s var(--ease)}
.nav-set:hover,.nav-set:focus-visible{text-decoration:none}
.nav-set:hover .nav-set-arrow,
.nav-set:focus-visible .nav-set-arrow{transform:translateX(4px)}
.nav-set:focus-visible{outline:none}

/* Photo grid, after the one on krismcd.com/smile: 3-up, each card darkened so the
   name reads over any photograph, the name in that place's own colour. */
.nav-grid{
  position:relative;z-index:1;      /* above .nav-scrim */
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:22px;
  max-width:1000px;margin:0 auto;
}
.nav-card{
  position:relative;display:block;
  aspect-ratio:3/2;
  overflow:hidden;
  background-size:cover;background-position:center;   /* lqip, until the jpeg decodes */
  text-decoration:none;
  transform:translateZ(0);                            /* keeps the scale inside the box */
}
.nav-card img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block;
  transition:transform .4s var(--ease);
}
/* The scrim is the card's own, not a filter on the photo — the title sits above it
   and stays at full strength while the photograph behind it lifts on hover. */
.nav-card::after{
  content:"";position:absolute;inset:0;
  background:rgba(0,0,0,.55);
  transition:background .25s var(--ease);
}
.nav-card-title{
  position:absolute;inset:0;z-index:2;
  display:flex;align-items:center;justify-content:center;
  padding:0 14px;text-align:center;
  font:700 26px/1.2 var(--stack);
  color:var(--c);
  text-shadow:0 1px 3px rgba(0,0,0,.8), 0 0 14px rgba(0,0,0,.5);
}
/* Awaiting a cover: the place's own colour, well below the title's strength. */
.nav-card.no-cover{background:color-mix(in srgb, var(--c) 14%, #1a1a1a)}
.nav-card.no-cover::after{background:rgba(0,0,0,.15)}
.nav-card.no-cover:hover::after,
.nav-card.no-cover:focus-visible::after{background:rgba(0,0,0,0)}

.nav-card:hover img,
.nav-card:focus-visible img{transform:scale(1.06)}
.nav-card:hover::after,
.nav-card:focus-visible::after{background:rgba(0,0,0,.38)}
.nav-card:focus-visible{outline:2px solid var(--c);outline-offset:3px}
/* You are here: the place's own colour washed over the photograph, under the title,
   instead of an underline. Two notes on the formula —
   the colour is lifted 12% toward white before the wash, because at full strength
   Vienna's red only reached 3.96:1 against the dark title; 12% puts the worst case
   at 4.73 and leaves every colour still recognisably itself. And the title flips to
   the shell dark, since a card washed in the place's colour cannot also carry the
   title in it. Placed after the hover rules deliberately: same specificity, so
   source order is what makes this win. */
.nav-card.is-current::after{
  background:var(--c);                                      /* fallback */
  background:color-mix(in srgb, color-mix(in srgb, var(--c) 88%, #fff) 88%, transparent);
}
.nav-card.is-current:hover::after,
.nav-card.is-current:focus-visible::after{
  background:var(--c);
  background:color-mix(in srgb, color-mix(in srgb, var(--c) 88%, #fff) 88%, transparent);
}
.nav-card.is-current .nav-card-title,
.nav-card.is-current:hover .nav-card-title,
.nav-card.is-current:focus-visible .nav-card-title{
  color:#111;
  text-shadow:none;
  text-decoration:none;
}


/* ---------- no-JS ---------- */

.fallback{list-style:none;margin:0;padding:24px;max-width:900px}
.fallback li{margin:0 0 40px}
.fallback img{width:100%;height:auto;display:block;margin-bottom:10px}
.fallback h2{margin:0 0 4px;font:600 18px/1.3 var(--stack)}
.fallback p{margin:0;font:400 13px/1.5 var(--stack);color:rgba(255,255,255,.6)}

/* ---------- mobile ---------- */

@media (max-width:767px){
  :root{--pad:24px}
  /* hard into the corner, clear of a notch */
  .topleft{top:calc(16px + env(safe-area-inset-top, 0px));left:18px}
  .region{font-size:22px}

  /* region name, then position within it — the sheet is shut most of the time */
  .topmeta{
    display:flex;align-items:baseline;gap:10px;
    margin:2px 0 0;
    font:400 13px/1.3 var(--stack);color:#fff;
    text-shadow:0 1px 3px rgba(0,0,0,.75), 0 0 12px rgba(0,0,0,.4);
  }
  .topmeta-step{font-size:12px;color:rgba(255,255,255,.7)}
  /* said once, in the corner */
  .region-sub,#step-slot{display:none}
  /* ...and not at all while the place grid is open: which photograph you were on is
     not the question being asked there. Keyed off the button's own aria-expanded,
     so opening the overlay is the only thing that has to stay in sync. */
  .region[aria-expanded="true"] + .topmeta{display:none}

  /* the rail dissolves; map and details position themselves again */
  .rail{display:contents}

  /* no persistent map on mobile — it lives in the overlay */
  .map{display:none}

  #details-btn{
    display:flex;
    left:50%;right:auto;transform:translateX(-50%);
    bottom:40px;
    padding:13px 22px;                 /* 48px tall, down from 70 */
    font-size:13px;letter-spacing:.3px;
    border-radius:32px;
  }
  .btn-secondary::after{border-radius:32px;border-width:1.5px}
  #details-btn:hover::after,
  #details-btn:focus-visible::after{transform:scale(1.15)}

  .details{
    position:fixed;z-index:40;
    left:0;right:0;bottom:0;width:auto;max-width:none;
    padding:12px 24px 34px;
    border:1px solid rgba(255,255,255,.14);
    border-radius:18px 18px 0 0;
    background:rgba(0,0,0,.8);
    -webkit-backdrop-filter:blur(12px);
            backdrop-filter:blur(12px);
  }
  .details h2,.details-meta,.details-desc{text-shadow:none}
  .details .icon-close{display:block}
  .details-grab{
    display:block;width:44px;height:4px;border-radius:2px;
    background:rgba(255,255,255,.3);margin:0 0 16px;
  }
  .details h2{font-size:20px}
  .details-desc{font-size:13px}
  .icon-close{top:18px;right:20px}

  /* the overlay carries the map, below the text */
  /* cap the map so the sheet never eats the whole screen — the photograph
     behind it is still the point */
  .details-map-slot{display:block;margin-top:16px}
  .details-map-slot .map{
    display:block;position:static;
    width:100%;height:38vh;
    filter:drop-shadow(0 1px 3px rgba(0,0,0,.6));
  }

  .nav{padding:96px var(--pad) var(--pad)}
  .nav-sets{
    position:static;margin:0 0 22px;gap:10px;
  }
  .nav-set{font-size:16px}
  .nav-grid{grid-template-columns:repeat(2,1fr);gap:10px}
  .nav-card-title{font-size:16px}
  .nav-close{
    top:calc(14px + env(safe-area-inset-top, 0px));
    right:var(--pad);bottom:auto;left:auto;transform:none;
    padding:10px 18px;font-size:12px;
  }
}

/* ---------- motion ---------- */

@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .nav-scrim{background:rgba(17,17,17,.95)}     /* no blur available — go back to opaque */
}

@media (prefers-reduced-transparency:reduce){
  .nav-scrim{background:rgba(17,17,17,.97);-webkit-backdrop-filter:none;backdrop-filter:none}
}

@media (prefers-reduced-motion:reduce){
  *,*::after{transition-duration:.01ms !important}
  /* Cancel it outright rather than shortening it. A near-zero duration left the
     overlay sitting at the keyframe's opacity:0 — invisible but present, which is
     worse than no animation at all. */
  .nav.fade-in .nav-scrim,
  .nav.fade-in .nav-grid,
  .nav.fade-in .nav-close{animation:none}
  .layer{transition:none}
}
