:root {
  --bg: #0a0e0a;
  --bg-panel: #0e130e;
  --border: #25382a;
  --border-bright: #3a5540;
  --text: #dff5df;
  --text-dim: #7fa085;
  --accent: #7cffb2;
  --accent-2: #57cf8e;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Space Mono', monospace;
  font-size: 16px;
  line-height: 1.6;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  color: #c8ffe0;
  text-decoration: underline;
}

::selection {
  background: var(--accent);
  color: #06110a;
}

.pixel {
  font-family: 'Press Start 2P', monospace;
}

@keyframes blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

.cursor {
  display: inline-block;
  width: 10px;
  height: 16px;
  background: var(--accent);
  margin-left: 6px;
  animation: blink 1.1s steps(1) infinite;
  vertical-align: -2px;
}

/* ---- layout chrome ---- */

.scanline-overlay {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 50;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0) 0px, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, 0.10) 3px);
  opacity: 0.5;
}

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 48px;
  height: 76px;
  border-bottom: 2px solid var(--border);
  background: var(--bg);
}

.logo-link {
  display: flex;
  align-items: center;
  gap: 14px;
  text-decoration: none;
}

.logo-text {
  font-size: 14px;
  letter-spacing: 2px;
  color: var(--text);
}

.main-nav {
  display: flex;
  gap: 36px;
}

.main-nav a {
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--text);
}

.nav-toggle {
  display: none;
}

@media (max-width: 768px) {
  .site-header {
    position: relative;
    padding: 0 20px;
  }

  .nav-toggle {
    display: block;
    background: transparent;
    border: 2px solid var(--border-bright);
    color: var(--text);
    font-size: 18px;
    line-height: 1;
    padding: 6px 12px;
    cursor: pointer;
  }

  .nav-toggle:hover {
    border-color: var(--accent);
    color: var(--accent);
  }

  /* Absolutely positioned so it drops over the page rather than pushing
     content down — .site-header's own position:relative (set above) is
     its containing block. Hidden by default; nav.js only ever toggles
     the .is-open class, so this still works (menu just stays closed) if
     nav.js fails to load at all. */
  .main-nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    background: var(--bg);
    border-bottom: 2px solid var(--border-bright);
    z-index: 60;
  }

  .main-nav.is-open {
    display: flex;
  }

  .main-nav a {
    padding: 18px 20px;
    border-top: 1px solid var(--border);
  }
}

.page-body {
  max-width: 1360px;
  margin: 0 auto;
  padding: 40px 48px 64px;
  min-height: 50vh;
}

.page-layout {
  display: grid;
  grid-template-columns: 1fr 280px;
  align-items: start;
  gap: 48px;
}

.page-main {
  min-width: 0;
}

@media (max-width: 900px) {
  .page-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 768px) {
  .page-body {
    padding: 24px 16px 40px;
  }
}

/* ---- sidebar ---- */

.sidebar {
  display: flex;
  flex-direction: column;
  gap: 36px;
}

.sidebar-section__title {
  margin: 0 0 14px;
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--text);
}

.sidebar-empty {
  margin: 0;
  font-size: 12px;
  color: var(--text-dim);
}

.archive-year {
  margin-bottom: 12px;
}

.archive-year__label {
  display: block;
  font-size: 12px;
  color: var(--text);
  margin-bottom: 4px;
}

.archive-year__label--family {
  color: var(--accent);
}

.archive-family {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 2px solid var(--border);
}

.archive-months {
  margin: 0;
  padding: 0;
  list-style: none;
}

.archive-months li {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 3px 0 3px 10px;
  font-size: 12px;
}

.archive-months a,
.archive-entry--timeless a {
  color: var(--text-dim);
}

.archive-months a:hover,
.archive-entry--timeless a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.archive-entry--timeless {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 12px;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.archive-count {
  color: var(--text-dim);
  opacity: 0.7;
  font-variant-numeric: tabular-nums;
}

.tag-cloud {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tag-cloud__item {
  color: var(--text-dim);
}

.tag-cloud__item:hover {
  color: var(--accent);
}

.tag-cloud__item--sm { font-size: 11px; }
.tag-cloud__item--md { font-size: 13px; }
.tag-cloud__item--lg { font-size: 16px; }
.tag-cloud__item--xl { font-size: 19px; color: var(--text); }

.location-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.location-list li {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 0;
  font-size: 12px;
}

.location-list a {
  color: var(--text-dim);
}

.location-list a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.site-footer {
  border-top: 2px solid var(--border);
  padding: 24px 48px;
  text-align: center;
}

.footer-text {
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--text-dim);
}

/* ---- photo grid ---- */

.photo-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
}

/* Single-column feed on touch — same (hover:none)/(pointer:coarse)
   capability query as the rest of the mobile-specific CSS (see the
   viewer's own touch media query further down for why this is a
   capability check, not a width one: a landscape phone is routinely
   wider than any reasonable "mobile" breakpoint, but it's exactly as
   touch-only as portrait). A 4-across grid on a phone-width screen
   leaves each card too small to read the photo at, and the caption
   (title/tags/date) already renders full-width under each card
   regardless of column count — nothing else about .photo-card-wrap
   changes here, just how many fit per row. */
@media (hover: none) and (pointer: coarse) {
  .photo-grid {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}

.photo-card {
  display: block;
  text-decoration: none;
  color: inherit;
}

.photo-card__frame {
  aspect-ratio: 4/3;
  border: 2px solid var(--border-bright);
  position: relative;
  overflow: hidden;
  background-size: cover;
  background-position: center;
}

.photo-card__title {
  margin-top: 8px;
  font-size: 15px;
  color: var(--text);
}

.photo-card__meta {
  font-size: 12px;
  color: var(--text-dim);
}

.photo-card__meta--family {
  color: var(--accent);
}

.photo-card-wrap {
  display: block;
}

.photo-card__description {
  margin-top: 4px;
  font-size: 12px;
  font-style: italic;
  color: var(--text-dim);
}

.photo-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.photo-card__tags a {
  font-size: 11px;
  color: var(--text-dim);
  text-decoration: none;
}

.photo-card__tags a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.back-button {
  display: inline-block;
  margin-bottom: 24px;
  padding: 10px 18px;
  background: transparent;
  border: 2px solid var(--border-bright);
  color: var(--text-dim);
  font-size: 10px;
  letter-spacing: 1px;
  cursor: pointer;
}

.back-button:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.photo-card__album {
  font-style: italic;
}

.photo-card__album a {
  color: inherit;
}

.photo-card__album a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.load-more {
  display: block;
  margin: 32px auto 0;
  padding: 14px 32px;
  background: transparent;
  border: 2px solid var(--border-bright);
  color: var(--text);
  font-size: 11px;
  letter-spacing: 1px;
  cursor: pointer;
}

.load-more:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.load-more[hidden] {
  display: none;
}

.load-more:disabled {
  opacity: 0.5;
  cursor: default;
}

.section-heading {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 24px;
}

.section-heading h1, .section-heading h2 {
  margin: 0;
  font-size: 18px;
  color: var(--text);
  letter-spacing: 1px;
}

.section-heading--large h1 {
  font-size: 30px;
}

.year-heading {
  gap: 16px;
}

.year-nav-link {
  font-family: 'Press Start 2P', monospace;
  font-size: 13px;
  color: var(--text-dim);
  letter-spacing: 1px;
  white-space: nowrap;
}

.year-nav-link:hover {
  color: var(--accent);
  text-decoration: none;
}

@media (max-width: 768px) {
  .year-heading {
    flex-wrap: wrap;
    row-gap: 10px;
  }

  .year-nav-link {
    font-size: 11px;
  }
}

/* ---- home page year-jump row ---- */

.year-nav-bar {
  margin-bottom: 36px;
}

.year-nav-bar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.year-nav-bar__row--family {
  margin-top: 10px;
}

.year-nav-bar__label {
  font-size: 12px;
  color: var(--accent);
  margin-right: 2px;
}

.year-chip {
  display: inline-block;
  border: 1px solid var(--border-bright);
  padding: 6px 14px;
  font-size: 13px;
  color: var(--text-dim);
  text-decoration: none;
}

.year-chip:hover {
  color: var(--accent);
  border-color: var(--accent);
  text-decoration: none;
}

.section-divider {
  height: 2px;
  margin: 48px 0;
  border: none;
  background: var(--accent);
}

/* ---- photo stack (year.html.twig month grid, family.html.twig year grid) ---- */

.photo-stack-link {
  display: block;
  text-decoration: none;
  color: inherit;
}

/* Month/year stacks (year.html.twig, family.html.twig) share .photo-grid's
   column count with plain photo listings normally — this only overrides
   it for the ".photo-grid--stacks" variant those two templates add, so
   the actual photo-listing .photo-grid (its own touch override right
   above notwithstanding) is untouched by this specific rule. A stack's
   own 3-layer fan-out (.photo-stack__layer, 68% width each, offset
   16%/32%) needs real width to read as three photos rather than a
   smudge, so this drops straight to 1 column on touch rather than 2.
   Same (hover:none)/(pointer:coarse) capability query as .photo-grid's
   own touch rule above, not a width breakpoint — see that rule's
   comment for why. */
@media (hover: none) and (pointer: coarse) {
  .photo-grid--stacks {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}

.photo-stack {
  position: relative;
  width: 100%;
  aspect-ratio: 4/3;
}

.photo-stack__layer {
  position: absolute;
  width: 68%;
  aspect-ratio: 4/3;
  background-size: cover;
  background-position: center;
  border: 2px solid var(--border-bright);
  background-color: var(--bg-panel);
}

.photo-stack__layer--back {
  top: 0;
  left: 0;
  z-index: 1;
}

.photo-stack__layer--middle {
  top: 16%;
  left: 16%;
  z-index: 2;
}

.photo-stack__layer--front {
  top: 32%;
  left: 32%;
  z-index: 3;
  border-color: var(--accent);
}

.photo-stack__caption {
  margin-top: 12px;
  font-size: 15px;
  color: var(--text);
}

.photo-stack-link:hover .photo-stack__caption {
  color: var(--accent);
}

.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 20px;
  font-size: 9px;
  letter-spacing: 1px;
  color: var(--text-dim);
}

.breadcrumbs a {
  color: var(--text-dim);
  text-decoration: none;
}

.breadcrumbs a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.breadcrumbs__sep {
  opacity: 0.5;
}

.breadcrumbs-bottom {
  margin-top: 32px;
  padding-top: 20px;
  border-top: 2px solid var(--border);
}

.breadcrumbs-bottom .breadcrumbs {
  margin-bottom: 0;
}

/* ---- login form (Login plugin's own login.html.twig / login-form.html.twig —
   generic form-plugin field markup, unstyled by default) ---- */

#grav-login {
  max-width: 420px;
  margin: 5rem auto;
  /* The Login plugin's own login.css sets a plain #grav-login selector too
     (background: #fcfcfc; border: 4px solid #eee) and loads AFTER this
     stylesheet in <head> — same specificity, later source wins, so without
     !important that light panel silently comes back regardless of what's
     declared here. */
  background: var(--bg-panel) !important;
  border: 4px solid var(--border) !important;
  border-radius: 4px;
  padding: 1rem 2rem 2rem;
}

#grav-login h1 {
  font-family: 'Press Start 2P', monospace;
  font-size: 16px;
  color: var(--text);
  letter-spacing: 1px;
  margin: 0 0 28px;
}

#grav-login .form-field {
  margin-bottom: 20px;
}

#grav-login .form-label label {
  display: block;
  margin-bottom: 8px;
  font-family: 'Press Start 2P', monospace;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--text-dim);
}

#grav-login input[type="text"],
#grav-login input[type="email"],
#grav-login input[type="password"] {
  width: 100%;
  background: var(--bg-panel);
  border: 2px solid var(--border-bright);
  border-radius: 0;
  color: var(--text);
  font-family: 'Space Mono', monospace;
  font-size: 14px;
  padding: 10px 12px;
}

#grav-login input[type="text"]:focus,
#grav-login input[type="email"]:focus,
#grav-login input[type="password"]:focus {
  outline: none;
  border-color: var(--accent);
}

#grav-login input[type="text"]::placeholder,
#grav-login input[type="email"]::placeholder,
#grav-login input[type="password"]::placeholder {
  color: var(--text-dim);
}

#grav-login .form-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 8px;
}

#grav-login .rememberme .form-input-wrapper {
  display: flex;
  align-items: center;
  gap: 8px;
}

#grav-login .rememberme label {
  font-size: 13px;
  color: var(--text-dim);
}

#grav-login button.button,
#grav-login a.button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  border: 2px solid var(--border-bright);
  background: transparent;
  color: var(--text);
  font-family: 'Press Start 2P', monospace;
  font-size: 10px;
  letter-spacing: 1px;
  text-decoration: none;
  cursor: pointer;
}

#grav-login a.button.secondary {
  color: var(--accent) !important;
}

#grav-login a.button.secondary:hover {
  border-color: var(--accent);
  background: rgba(124, 255, 178, 0.1);
  text-decoration: none;
}

#grav-login button.button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #06110a;
}

#grav-login button.button.primary:hover {
  background: var(--accent-2);
  border-color: var(--accent-2);
}

/* Touch-only tweaks — checked against a real ~44px tap-target minimum:
   the text/email/password inputs already measured exactly 44px tall as
   written (padding+border alone), so nothing to change there, but the
   button measured only ~37.6px (Press Start 2P plus the UA stylesheet's
   own line-height for <button> falls short of the input's own height at
   this padding) — min-height fixes that without changing its padding/
   look on desktop, where the shortfall doesn't matter with a mouse.
   margin-top is also reduced here: on a short mobile viewport with the
   on-screen keyboard open, the desktop 5rem top margin pushes the Login
   button uncomfortably close to (or under) the keyboard — see
   login-scroll.js for the other half of this (scrolling the focused
   field into view). */
@media (hover: none) and (pointer: coarse) {
  #grav-login {
    margin: 2rem auto;
  }

  #grav-login input[type="text"],
  #grav-login input[type="email"],
  #grav-login input[type="password"] {
    min-height: 44px;
  }

  #grav-login button.button,
  #grav-login a.button {
    min-height: 44px;
  }
}

/* ---- photo viewer (lightbox) ---- */

body.viewer-open {
  overflow: hidden;
}

.photo-viewer {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  background: rgba(6, 10, 7, 0.96);
}

.photo-viewer[hidden] {
  display: none;
}

.photo-viewer__main {
  position: relative;
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
}

.photo-viewer__frame {
  position: relative;
  max-width: 100%;
  max-height: calc(100vh - 80px);
}

.photo-viewer__image {
  display: block;
  max-width: 100%;
  max-height: calc(100vh - 80px);
  object-fit: contain;
}

.photo-viewer__corner {
  position: absolute;
  width: 22px;
  height: 22px;
  border: 3px solid var(--accent);
  pointer-events: none;
}

.photo-viewer__corner--tl { top: -10px; left: -10px; border-right: none; border-bottom: none; }
.photo-viewer__corner--tr { top: -10px; right: -10px; border-left: none; border-bottom: none; }
.photo-viewer__corner--bl { bottom: -10px; left: -10px; border-right: none; border-top: none; }
.photo-viewer__corner--br { bottom: -10px; right: -10px; border-left: none; border-top: none; }

.photo-viewer__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-panel);
  border: 2px solid var(--border-bright);
  color: var(--text);
  font-size: 18px;
  cursor: pointer;
}

.photo-viewer__nav:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.photo-viewer__nav[hidden] {
  display: none;
}

.photo-viewer__nav--prev { left: 12px; }
.photo-viewer__nav--next { right: 12px; }

.photo-viewer__sidebar {
  width: 340px;
  flex-shrink: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 20px;
  background: var(--bg-panel);
  border-left: 2px solid var(--border);
}

.photo-viewer__sheet-handle {
  display: none;
}

.photo-viewer__sidebar-header {
  display: flex;
  align-items: center;
  gap: 8px;
}

.photo-viewer__lamp {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--border-bright);
}

.photo-viewer__lamp--accent {
  background: var(--accent);
}

.photo-viewer__sidebar-title {
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--text);
}

.photo-viewer__close {
  width: 30px;
  height: 30px;
  margin-left: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 2px solid var(--border-bright);
  color: var(--text);
  cursor: pointer;
}

.photo-viewer__close:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.photo-viewer__controls {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 20px;
}

.photo-viewer__play {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 2px solid var(--border-bright);
  color: var(--text);
  cursor: pointer;
}

.photo-viewer__play:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.photo-viewer__play[hidden] {
  display: none;
}

.photo-viewer__interval {
  font: inherit;
  font-size: 12px;
  padding: 8px 10px;
  background: var(--bg);
  border: 2px solid var(--border-bright);
  color: var(--text);
}

.photo-viewer__interval[hidden] {
  display: none;
}

.photo-viewer__divider {
  height: 2px;
  margin: 20px 0;
  background: var(--border);
}

.photo-viewer__caption {
  overflow-y: auto;
  min-height: 0;
}

.photo-viewer__title {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
}

.photo-viewer__description {
  margin-top: 8px;
  font-size: 13px;
  font-style: italic;
  color: var(--text-dim);
}

.photo-viewer__geo {
  display: block;
  margin-top: 14px;
  padding: 0;
  background: none;
  border: none;
  font-family: 'Space Mono', monospace;
  font-size: 12px;
  color: var(--text-dim);
  text-align: left;
  cursor: pointer;
}

.photo-viewer__geo:hover {
  color: var(--accent);
}

/* ---- mobile viewer: bottom-sheet sidebar (touch devices) ----
   (hover:none) and (pointer:coarse) — a *capability* query, not a width
   one: a phone in landscape is routinely wider than any reasonable
   "mobile" breakpoint (900/768px, both used elsewhere in this file for
   the site's own layout/nav), but it's exactly as touch-only, no-mouse
   as it is in portrait. A width-based query here previously meant
   landscape phones fell back to the desktop fixed-sidebar layout, which
   doesn't fit the screen's short height at all and had no scroll to
   compensate. viewer.js's own isTouch flag uses this identical condition
   — see its top-of-file doc comment. */

@media (hover: none) and (pointer: coarse) {
  /* Full-bleed photo — the sidebar no longer shares the row with it
     (position:fixed below takes it out of the .photo-viewer flex flow
     entirely), so .photo-viewer__main's flex:1 already fills the whole
     viewer; this just drops the desktop padding so the image itself can
     reach every edge, safe-area insets aside (notches/home-indicator). */
  .photo-viewer__main {
    padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  }

  /* var(--real-vw)/var(--real-vh), with 100dvw/100dvh only as the
     fallback — plain vw/vh were the original bug here (measured against
     the browser's largest-possible viewport, stale for a beat right
     after a real rotation; object-fit:contain then scales the image to
     fit a box computed from that stale value, reading as an anomalous
     zoom/crop). Switching to dvw/dvh alone did NOT fix this on a real
     Android Chrome device — confirmed that dvh itself is still stale
     there right after rotation, even though the identical CSS is correct
     immediately in Firefox on the same device (a documented Chrome/
     Android gap in how promptly dynamic viewport units recompute on
     orientationchange). --real-vw/--real-vh are plain px values viewer.js
     computes from window.innerWidth/innerHeight — which don't have this
     lag — and keeps current via resize/orientationchange/
     screen.orientation "change" (see that file's own comment). The
     ", 100dvw"/", 100dvh" fallback only ever matters for the brief window
     before that first runs, or if JS fails to load at all. */
  .photo-viewer__frame,
  .photo-viewer__image {
    max-width: var(--real-vw, 100dvw);
    max-height: var(--real-vh, 100dvh);
  }

  /* Bigger hit target for thumbs on a real phone screen, not just a
     bigger icon — the button's own box is the tap target. Visually
     de-emphasized (no box, low-ish opacity) since the primary way to
     move between photos here is the horizontal swipe on the photo
     itself (viewer.js) — these stay as a discoverable, always-available
     fallback rather than the main affordance a desktop mouse user still
     needs. 0.35 opacity (the original value here) turned out to blend
     into some photos' own busy/light-colored detail enough that the
     arrows weren't reliably noticeable in peripheral vision — bumped to
     0.52 (and the box itself a touch bigger, 60px) without going back to
     a solid background/border, which would compete with the photo as a
     second visual focus instead of reading as a light on-image control. */
  .photo-viewer__nav {
    width: 60px;
    height: 60px;
    font-size: 24px;
    background: none;
    border: none;
    opacity: 0.52;
  }

  .photo-viewer__nav:active {
    opacity: 0.8;
  }

  .photo-viewer__nav--prev { left: max(12px, env(safe-area-inset-left)); }
  .photo-viewer__nav--next { right: max(12px, env(safe-area-inset-right)); }

  /* Both are desktop-only affordances that don't apply here: closing the
     viewer on touch happens exclusively through the hardware Back button
     (viewer.js's History API integration) — see that file's doc comment
     on isTouch/viewerDepth — so advertising "ESC or click outside" would
     just be wrong, and a ✕ that quietly closes the whole viewer instead
     of "just this info panel" is a surprising trap on a touchscreen. */
  .photo-viewer__hint,
  .photo-viewer__close {
    display: none;
  }

  /* The sidebar becomes a swipe-up bottom sheet. Collapsed by default —
     translateY(calc(100% - 64px)) — showing only its own top ~64px
     (.photo-viewer__sheet-handle, always its first child) as a handle
     strip sitting over the bottom of the photo. Height is content-sized
     (capped by max-height) rather than a fixed vh, and max-height itself
     is 100dvh (not 78vh) precisely BECAUSE this query now also covers
     short landscape screens: translateY(%) resolves against the
     element's own rendered box either way, so a short/tall cap changes
     nothing about the collapse math, but overflow-y:auto plus a cap that
     can't be exceeded means content is always reachable by scrolling
     even when there's barely any vertical room at all, rather than
     silently clipped off with no way to reach it. z-index sits between
     the viewer (200) and the location modal (300) — LOCATION still opens
     on top of an expanded sheet, never underneath it. */
  .photo-viewer__sidebar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    width: auto;
    height: auto;
    max-height: 100dvh;
    flex-shrink: initial;
    padding: 0 20px calc(20px + env(safe-area-inset-bottom));
    background: rgba(6, 10, 7, 0.92);
    border-left: none;
    border-top: 2px solid var(--border-bright);
    z-index: 250;
    overflow-y: auto;
    transform: translateY(calc(100% - 64px));
    transition: transform 0.25s ease;
  }

  .photo-viewer__sidebar.is-expanded {
    transform: translateY(0);
  }

  .photo-viewer__sheet-handle {
    display: flex;
    position: sticky;
    top: 0;
    height: 64px;
    background: inherit;
  }

  .photo-viewer__sheet-grip {
    position: absolute;
    left: 50%;
    top: 14px;
    transform: translateX(-50%);
    width: 36px;
    height: 4px;
    background: var(--border-bright);
  }

  .photo-viewer__sheet-toggle {
    position: absolute;
    left: 0;
    bottom: 14px;
    background: transparent;
    border: none;
    color: var(--text-dim);
    font-size: 10px;
    letter-spacing: 1px;
    padding: 4px 0;
    cursor: pointer;
  }

  .photo-viewer__sheet-toggle:hover {
    color: var(--accent);
  }
}

/* Landscape refinement of the same touch bottom sheet above — still
   bottom-anchored, still opened/closed by the exact same vertical swipe
   (viewer.js makes no distinction at all between orientations, see its
   isTouch flag), just narrower: a landscape phone is short but wide, and
   a sheet spanning that entire width would be an oddly long, shallow
   strip. Capping its width and centering it (left:0/right:0 from the
   base rule above, plus this max-width and auto margins) instead lets it
   sit as a narrower panel over the bottom-center of the photo, with the
   exact same collapse/expand/scroll behavior as portrait. */
@media (hover: none) and (pointer: coarse) and (orientation: landscape) {
  .photo-viewer__sidebar {
    max-width: 45%;
    margin: 0 auto;
  }
}

.photo-viewer__location-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(6, 10, 7, 0.85);
  padding: 20px;
}

.photo-viewer__location-modal[hidden] {
  display: none;
}

.photo-viewer__location-panel {
  width: min(640px, 100%);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-panel);
  border: 2px solid var(--border-bright);
}

.photo-viewer__location-panel .photo-viewer__sidebar-header {
  padding: 14px 16px;
  border-bottom: 2px solid var(--border);
}

.photo-viewer__location-body {
  padding: 16px;
  overflow-y: auto;
}

.photo-viewer__location-body iframe {
  display: block;
  width: 100%;
  height: 360px;
  border: 2px solid var(--border-bright);
}

.photo-viewer__location-link {
  display: inline-block;
  margin-top: 10px;
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--text-dim);
}

.photo-viewer__location-link:hover {
  color: var(--accent);
}

.photo-viewer__location-caption {
  margin-top: 10px;
  font-size: 12px;
  color: var(--text-dim);
  font-style: italic;
}

.photo-viewer__location-loading {
  text-align: center;
  padding: 20px 0;
  font-size: 13px;
  color: var(--text-dim);
}

.photo-viewer__location-unknown {
  text-align: center;
  padding: 20px 0;
}

.photo-viewer__location-unknown p {
  margin: 0 0 16px;
  font-size: 13px;
  color: var(--text-dim);
}

.photo-viewer__location-find {
  display: inline-block;
  padding: 12px 20px;
  background: transparent;
  border: 2px solid var(--border-bright);
  color: var(--text);
  font-family: 'Space Mono', monospace;
  font-size: 13px;
  text-decoration: none;
}

.photo-viewer__location-find:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.photo-viewer__date {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-dim);
}

.photo-viewer__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
  padding: 0;
  list-style: none;
}

.photo-viewer__tags a {
  display: inline-block;
  border: 1px solid var(--border-bright);
  padding: 3px 9px;
  font-size: 11px;
  color: var(--text-dim);
  text-decoration: none;
}

.photo-viewer__tags a:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.photo-viewer__exif {
  margin-top: 16px;
  font-size: 11px;
  color: var(--text-dim);
}

.photo-viewer__original-link {
  display: inline-block;
  margin-top: 16px;
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--text-dim);
}

.photo-viewer__original-link:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* ---- viewer admin controls (site.photo_admin only) ---- */

.photo-viewer__admin-actions {
  display: flex;
  gap: 16px;
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.photo-viewer__admin-actions[hidden] {
  display: none;
}

.photo-viewer__admin-link {
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--text-dim);
  cursor: pointer;
}

.photo-viewer__admin-link:hover {
  color: var(--accent);
  text-decoration: underline;
}

.photo-viewer__admin-link--danger:hover {
  color: #ff6b6b;
}

.photo-viewer__edit-form {
  display: flex;
  flex-direction: column;
}

.photo-viewer__edit-form[hidden] {
  display: none;
}

.photo-viewer__edit-label {
  margin-top: 12px;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--text-dim);
}

.photo-viewer__edit-input {
  margin-top: 6px;
  width: 100%;
  background: var(--bg);
  border: 2px solid var(--border-bright);
  color: var(--text);
  font-family: 'Space Mono', monospace;
  font-size: 13px;
  padding: 7px 9px;
}

.photo-viewer__geo-field {
  position: relative;
}

.photo-viewer__geo-suggest {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  z-index: 20;
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
  background: var(--bg-panel);
  border: 2px solid var(--border-bright);
  max-height: 200px;
  overflow-y: auto;
  font-family: 'Space Mono', monospace;
  font-size: 12px;
}

.photo-viewer__geo-suggest[hidden] {
  display: none;
}

.photo-viewer__geo-suggest li {
  padding: 6px 9px;
  cursor: pointer;
  color: var(--text-dim);
}

.photo-viewer__geo-suggest li:hover,
.photo-viewer__geo-suggest li.is-active {
  background: var(--border);
  color: var(--accent);
}

.photo-viewer__edit-input:focus {
  outline: none;
  border-color: var(--accent);
}

.photo-viewer__edit-textarea {
  resize: vertical;
}

.photo-viewer__edit-checkbox {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 12px;
  color: var(--text-dim);
}

.photo-viewer__edit-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}

.photo-viewer__edit-tags li {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--border-bright);
  padding: 3px 8px;
  font-size: 11px;
  color: var(--text-dim);
}

.photo-viewer__edit-tag-remove {
  cursor: pointer;
}

.photo-viewer__edit-tag-remove:hover {
  color: var(--accent);
}

.photo-viewer__edit-actions {
  display: flex;
  gap: 10px;
  margin-top: 18px;
}

.photo-viewer__edit-save,
.photo-viewer__edit-cancel {
  padding: 8px 18px;
  background: transparent;
  border: 2px solid var(--border-bright);
  color: var(--text);
  font-size: 11px;
  letter-spacing: 1px;
  cursor: pointer;
}

.photo-viewer__edit-save:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.photo-viewer__edit-cancel:hover {
  color: var(--text-dim);
  border-color: var(--text-dim);
}

.photo-viewer__edit-save:disabled {
  opacity: 0.5;
  cursor: default;
}

.photo-viewer__edit-error {
  margin-top: 10px;
  font-size: 11px;
  color: #ff6b6b;
}

.photo-viewer__hint {
  margin-top: auto;
  padding-top: 20px;
  font-size: 9px;
  letter-spacing: 1px;
  color: var(--text-dim);
  opacity: 0.6;
}
