/* Shared tokens and the full-screen image viewer.
   Both map.html and item.html load this. Page-specific layout stays in the page. */

:root{
  --ground:#1C1C1C; --deep:#0C0C0C;
  --ink:#F9F9F9;                 /* 16.2:1 on --ground */
  --muted:#A8A49F;               /*  6.9:1 */
  --faint:#8A8784;               /*  4.8:1, the faintest text permitted here */
  --accent:#B8A88F;              /*  7.3:1 */
  --rule:rgba(249,249,249,.14);
  --display:'Cinzel',Georgia,serif;
  --text:'Spectral',Georgia,serif;
  /* Tracking. Small uppercase labels are the workhorse of this interface, and
     they had drifted to eleven different values across the five pages, which
     reads as several slightly different design systems sharing a screen. Four
     tokens, every one of them a value already in use. */
  --ls-display:.02em;   /* headings that want a little air, nothing more */
  --ls-tight:.1em;      /* dense labels: chips, counts inside a control */
  --ls-label:.14em;     /* the default for small uppercase */
  --ls-wide:.2em;       /* section heads and navigation */

  /* The smallest type in the interface. Nothing goes below this: 9px labels
     were being set on a dark ground, which is where legibility gives out. */
  --label-min:.625rem;  /* 10px */
  --safe-b:env(safe-area-inset-bottom,0px);
  --safe-t:env(safe-area-inset-top,0px);
}

/* ------------------------------------------------------------- viewer */
.viewer{
  position:fixed;inset:0;z-index:40;background:rgba(6,6,6,.97);
  display:none;opacity:0;transition:opacity .2s ease;
  backdrop-filter:blur(6px);
}
.viewer.open{display:block;opacity:1}
body.viewer-open{overflow:hidden}

.viewer-map{
  position:absolute;inset:0;opacity:0;transition:opacity .5s ease;
  filter:brightness(.22) saturate(.65);pointer-events:none;
}
.viewer.hasMap .viewer-map{opacity:1}
.viewer.hasMap::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse at center, transparent 30%, rgba(6,6,6,.72) 100%);
}
.viewer-stage{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  overflow:hidden;touch-action:none;cursor:zoom-in;
}
.viewer.zoomed .viewer-stage{cursor:grab}
.viewer.zoomed .viewer-stage:active{cursor:grabbing}
.viewer-stage img{
  max-width:100vw;max-height:100dvh;
  /* No transition on transform: it would fight the pinch gesture. */
  transform-origin:center center;user-select:none;-webkit-user-drag:none;
  display:block;
}
@supports not (max-height:100dvh){ .viewer-stage img{max-height:100vh} }

.viewer-close{
  position:absolute;top:calc(var(--safe-t) + .75rem);right:.75rem;z-index:2;
  width:2.75rem;height:2.75rem;                 /* 44px, the minimum tap target */
  background:rgba(12,12,12,.8);border:1px solid var(--rule);
  color:var(--ink);cursor:pointer;font-size:1rem;font-family:var(--text);
}
.viewer-close:hover{background:rgba(28,28,28,.95)}
.viewer-close:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* slideshow controls, hidden unless the viewer was opened with a series */
.viewer-nav,.viewer-bar{display:none}
.viewer.hasSeries .viewer-nav{display:grid}
.viewer.hasSeries .viewer-bar{display:flex}

.viewer-nav{
  position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  width:2.75rem;height:4.5rem;place-items:center;
  background:rgba(12,12,12,.55);border:1px solid var(--rule);
  color:var(--ink);cursor:pointer;font-size:1.5rem;line-height:1;font-family:var(--text);
}
.viewer-nav:hover{background:rgba(28,28,28,.9)}
.viewer-nav.prev{left:.5rem}
.viewer-nav.next{right:.5rem}

.viewer-bar{
  position:absolute;left:50%;transform:translateX(-50%);
  bottom:calc(var(--safe-b) + .75rem);z-index:3;
  align-items:center;gap:.85rem;max-width:calc(100vw - 1.5rem);
  background:rgba(12,12,12,.82);border:1px solid var(--rule);
  padding:.4rem .5rem .4rem .4rem;
}
.viewer-play{
  width:2.25rem;height:2.25rem;flex:0 0 auto;
  background:none;border:1px solid var(--rule);color:var(--ink);
  cursor:pointer;font-size:.75rem;line-height:1;font-family:var(--text);
}
.viewer-play:hover{background:rgba(249,249,249,.1)}
.viewer-count{
  flex:0 0 auto;font-family:var(--text);font-size:.6875rem;letter-spacing:var(--ls-label);
  color:var(--faint);white-space:nowrap;
}
.viewer-caption{
  font-family:var(--text);font-size:.75rem;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:.35rem;
}
/* While playing, the side arrows recede so the photographs carry the screen. */
.viewer.playing .viewer-nav{opacity:0;transition:opacity .4s}
.viewer.playing:hover .viewer-nav{opacity:1}

@media (max-width:600px){
  .viewer-nav{width:2.5rem;height:3.5rem;font-size:1.25rem}
  .viewer-caption{display:none}
}

.viewer-hint{
  position:absolute;left:50%;transform:translateX(-50%);
  bottom:calc(var(--safe-b) + 1rem);z-index:2;
  font-family:var(--text);font-size:.6875rem;letter-spacing:var(--ls-label);
  text-transform:uppercase;color:var(--faint);
  background:rgba(12,12,12,.7);padding:.5rem .85rem;pointer-events:none;
  transition:opacity .3s;
}
.viewer.zoomed .viewer-hint{opacity:0}
/* the series bar occupies the same spot, so the hint stands down */
.viewer.hasSeries .viewer-hint{display:none}

/* ------------------------------------------------------------- shared bits */
.u-hidden{display:none!important}

::selection{background:var(--accent);color:var(--deep)}

:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* Scrollbars, so a dark panel does not sprout a light gutter */
*{scrollbar-width:thin;scrollbar-color:rgba(249,249,249,.2) transparent}
*::-webkit-scrollbar{width:8px;height:8px}
*::-webkit-scrollbar-thumb{background:rgba(249,249,249,.2)}
*::-webkit-scrollbar-track{background:transparent}

/* ---------------------------------------------------------- multiselect
   Filter dropdowns. One control per facet, holding several selections. */
.ms{position:relative;display:inline-block}
.ms-btn{
  display:inline-flex;align-items:center;gap:.5rem;
  min-height:2.75rem;padding:.5rem .7rem;
  background:none;border:1px solid var(--rule);color:var(--muted);
  font-family:var(--text);font-size:.6875rem;letter-spacing:var(--ls-label);
  text-transform:uppercase;cursor:pointer;
}
.ms-btn:hover{color:var(--ink);border-color:var(--faint)}
.ms-btn.on{color:var(--ink);border-color:var(--accent)}
.ms-count{
  display:inline-grid;place-items:center;min-width:1.25rem;height:1.25rem;
  padding:0 .25rem;background:var(--accent);color:var(--deep);
  font-size:.625rem;letter-spacing:0;
}
.ms-chev{font-size:var(--label-min);opacity:.7;transition:transform .2s}
.ms.open .ms-chev{transform:rotate(180deg)}

.ms-panel{
  position:absolute;top:calc(100% + .35rem);left:0;z-index:50;
  min-width:14rem;max-width:min(22rem, 92vw);
  max-height:min(60vh, 22rem);overflow-y:auto;overscroll-behavior:contain;
  background:rgba(12,12,12,.98);border:1px solid var(--rule);
  backdrop-filter:blur(12px);box-shadow:0 10px 32px rgba(0,0,0,.6);
  padding:.35rem;
}
/* Near the right edge the panel would otherwise run off screen. */
.ms:last-child:not(:first-child) .ms-panel{left:auto;right:0}
/* Right-aligning keeps the LAST of several filters from overflowing the page
   edge. A lone filter is both first and last, so that rule threw its panel off
   the left of the screen instead. The Locations page has exactly one filter,
   which is why the fault only appeared there. */

.ms-row{
  display:flex;align-items:center;gap:.6rem;
  padding:.5rem .55rem;min-height:2.75rem;cursor:pointer;
  font-size:.8125rem;color:var(--muted);line-height:1.3;
}
.ms-row:hover{background:rgba(249,249,249,.06);color:var(--ink)}
.ms-row input{
  appearance:none;-webkit-appearance:none;flex:0 0 auto;
  width:1rem;height:1rem;margin:0;border:1px solid var(--faint);
  background:transparent;cursor:pointer;display:grid;place-items:center;
}
.ms-row input:checked{background:var(--accent);border-color:var(--accent)}
.ms-row input:checked::after{content:'✓';color:var(--deep);font-size:.7rem;line-height:1}
.ms-row input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ms-text{flex:1 1 auto;min-width:0}
.ms-n{flex:0 0 auto;font-size:.625rem;color:var(--faint);letter-spacing:var(--ls-tight)}

.ms-clear{
  display:block;width:100%;margin:.35rem 0 0;padding:.55rem;
  background:none;border:0;border-top:1px solid var(--rule);
  color:var(--faint);font-family:var(--text);font-size:.625rem;
  letter-spacing:var(--ls-label);text-transform:uppercase;cursor:pointer;
}
.ms-clear:hover{color:var(--ink)}

.facets{display:flex;flex-wrap:wrap;gap:.5rem;margin:1rem 0 0}

/* ---------------------------------------------------------------- motion ---
   One easing curve and three durations, so everything that moves in this
   archive moves the same way. Before this each page invented its own.        */
:root{
  --ease:cubic-bezier(.22,.61,.36,1);
  --t-fast:.18s;
  --t-mid:.3s;
  --t-slow:.5s;
}

/* Anything that responds to a pointer settles rather than snapping. Kept to
   colour and border so no layout is animated: transitioning geometry on a
   masonry grid causes reflow on every hover. .card is handled separately
   below, with no transform, for exactly that reason. */
a, button, .chip, .ms-btn, .sort, .clear, .back, .share, .views a, .place{
  transition:color var(--t-fast) var(--ease),
             background-color var(--t-fast) var(--ease),
             border-color var(--t-fast) var(--ease),
             opacity var(--t-fast) var(--ease),
             box-shadow var(--t-mid) var(--ease),
             transform var(--t-mid) var(--ease);
}

/* .card lives inside a column-count masonry on both the Gallery and a place
   page. Promoting one to its own layer makes the browser re-fragment the
   column flow, and the thumbnail blinks as the pointer crosses it. So a
   masonry card gets no transform at all: its hover is border and shadow,
   which cannot refragment anything.
   .place is in a real CSS grid, where a lift is safe. */
.place:hover{ transform:translateY(-2px) }
.card:hover, .place:hover{ box-shadow:0 12px 28px -18px rgba(0,0,0,.95) }
.card:hover{ border-color:rgba(249,249,249,.32) }
/* No entrance animation and no opacity change on hover. Both were here and
   they fought: an animation with fill-mode `both` holds the property it
   animates, which outranks the hover rule, and the pair made every thumbnail
   blink as the pointer crossed it. The lift below is enough, and it is a
   composited property that cannot reflow a column layout.
   Scale lives on the image, so the card's own edge stays still. */
.place{ overflow:hidden }
.place img{ transition:transform var(--t-slow) var(--ease) }
.place:hover img{ transform:scale(1.03) }
/* Deliberately nothing on .card img. Any transform inside a multi-column
   container reintroduces the blink. */

/* Everything above is decoration. Someone who has asked their system to stop
   animating gets none of it. */
@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{
    animation-duration:.001ms !important; animation-iteration-count:1 !important;
    transition-duration:.001ms !important; scroll-behavior:auto !important;
  }
  .place:hover{ transform:none }
  .place:hover img{ transform:none }
}

/* Masonry cards: colour only, no geometry, no layer promotion. */
.card{ transition:border-color var(--t-fast) var(--ease), box-shadow var(--t-mid) var(--ease) }

/* Available to a screen reader, never on screen. Not display:none, which would
   hide it from assistive technology too, and not a negative text-indent, which
   breaks in right-to-left. The clip-path rectangle is the pattern that keeps
   the text in the accessibility tree while taking it out of the layout. */
.u-sr-only{
  position:absolute !important;width:1px;height:1px;
  margin:-1px;padding:0;overflow:hidden;white-space:nowrap;
  clip:rect(0 0 0 0);clip-path:inset(50%);border:0;
}
