/* =========================================================================
   MyPixtory — design system
   Concept: a darkroom light table. Photos glow like prints/slides held up
   to light in a dim room; folders read as negative strips with stamped
   frame data. Dates use a mono "digital date-stamp" face, on purpose --
   EXIF timestamps are the whole point of this product.
   ========================================================================= */

@import url('https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@700;900&family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap');

:root {
  /* ---- palette (named, drawn from the darkroom/photo-lab world) ---- */
  --darkroom: #1c1815;      /* base canvas -- unlit room, warm charcoal, not pure black */
  --safelight: #c1432e;     /* primary accent -- muted photographic safelight red */
  --safelight-bright: #e05a3f;
  --litho-cream: #ede6d6;   /* print paper -- lives on cards/mats, never the whole page */
  --fixer-green: #6b7a5e;   /* secondary accent -- desaturated darkroom chemical green */
  --contact-grey: #4a4540;  /* borders, negative-strip stock */
  --contact-grey-light: #6b645c;
  --stamp-amber: #e8a33d;   /* date-stamp digits only */
  --flash-green: #22c55e;   /* person hotspots -- bright, high-visibility green, easy to spot against any photo (previously a muted blue that was too easy to miss) */
  --flash-blue: #2d8cff;    /* audio hotspots -- vivid electric blue, clearly distinct from the green person markers */
  --text-on-dark: #ede8de;
  --text-muted: #a89f92;

  --font-display: 'Big Shoulders Display', sans-serif;
  --font-body: 'IBM Plex Sans', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;

  --radius-card: 3px;
  --radius-pill: 999px;

  --shadow-glow: 0 0 0 1px rgba(237, 230, 214, 0.06), 0 12px 28px -8px rgba(0, 0, 0, 0.6);
  --shadow-glow-hover: 0 0 0 1px rgba(237, 230, 214, 0.12), 0 18px 40px -8px rgba(0, 0, 0, 0.7);

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
}

* {
  box-sizing: border-box;
}

/* Global [hidden] rule. Author styles like .btn { display: inline-block } or
   .contact-sheet { display: grid } otherwise override the browser's built-in
   [hidden] { display: none }, so JS doing el.hidden = true silently did
   nothing on those elements. !important is deliberate: it makes the hidden
   attribute win over any component's display rule, everywhere. */
[hidden] {
  display: none !important;
}

html {
  color-scheme: dark;
}

body {
  margin: 0;
  background: var(--darkroom);
  background-image:
    radial-gradient(ellipse 80% 50% at 50% -10%, rgba(193, 67, 46, 0.08), transparent 60%),
    radial-gradient(ellipse 60% 40% at 90% 100%, rgba(107, 122, 94, 0.06), transparent 60%);
  color: var(--text-on-dark);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  min-height: 100vh;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 0.95;
  margin: 0;
}

h1 { font-size: clamp(2.25rem, 5vw, 3.5rem); }
h2 { font-size: clamp(1.5rem, 3vw, 2rem); }
h3 { font-size: 1.125rem; letter-spacing: 0.04em; }

p { margin: 0 0 var(--space-4); color: var(--text-muted); }

a { color: var(--stamp-amber); }

.mono {
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
}

.date-stamp {
  font-family: var(--font-mono);
  color: var(--stamp-amber);
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
}

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

.page {
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--space-8) var(--space-6) var(--space-16);
  padding-top: 7px;
}

.page-narrow {
  max-width: 440px;
  margin: 0 auto;
  padding: var(--space-16) var(--space-6);
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-8);
  padding-bottom: var(--space-4);
  border-bottom: 1px dashed var(--contact-grey);
}

.topbar .wordmark {
  font-family: 'Brush Script MT', cursive;
  font-size: 48pt;
  color: var(--text-on-dark);
}

.topbar .wordmark span {
  color: var(--safelight-bright);
}

/* perforated divider -- evokes a strip of film leader */
.perf-divider {
  display: flex;
  gap: 6px;
  align-items: center;
  margin: var(--space-6) 0;
  opacity: 0.5;
}
.perf-divider::before,
.perf-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: repeating-linear-gradient(
    to right,
    var(--contact-grey-light) 0,
    var(--contact-grey-light) 3px,
    transparent 3px,
    transparent 9px
  );
}

/* ---- buttons & inputs ---- */

.btn {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  padding: 0.7rem 1.4rem;
  cursor: pointer;
  text-decoration: none; /* .btn is applied to <button>s and, e.g. the "Find
                             People" link on albums.html, plain <a>s -- this
                             keeps both looking identical rather than the
                             link getting a stray default underline */
  display: inline-block;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}
.btn:focus-visible {
  outline: 2px solid var(--stamp-amber);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
}

.btn-primary {
  background: var(--safelight);
  color: var(--litho-cream);
}
.btn-primary:hover { background: var(--safelight-bright); }
.btn-primary:active { transform: scale(0.98); }

.btn-ghost {
  background: transparent;
  border-color: var(--contact-grey-light);
  color: var(--text-on-dark);
}
.btn-ghost:hover { border-color: var(--text-on-dark); }

.btn-danger {
  background: transparent;
  border-color: var(--safelight);
  color: var(--safelight-bright);
}
.btn-danger:hover { background: var(--safelight); color: var(--litho-cream); }

.field {
  margin-bottom: var(--space-4);
}
.field label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: var(--space-2);
}
.field input,
.field textarea {
  width: 100%;
  background: rgba(237, 230, 214, 0.04);
  border: 1px solid var(--contact-grey);
  border-radius: var(--radius-card);
  color: var(--text-on-dark);
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.65rem 0.8rem;
}
.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--stamp-amber);
  background: rgba(237, 230, 214, 0.07);
}

.error-text {
  color: var(--safelight-bright);
  font-size: 0.875rem;
  margin-top: var(--space-2);
  min-height: 1.2em;
}

/* ---- auth card ---- */

.auth-card {
  background: rgba(237, 230, 214, 0.03);
  border: 1px solid var(--contact-grey);
  border-radius: var(--radius-card);
  padding: var(--space-8);
}

.auth-toggle {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-6);
  font-size: 0.875rem;
  color: var(--text-muted);
}
.auth-toggle button {
  background: none;
  border: none;
  color: var(--stamp-amber);
  cursor: pointer;
  font: inherit;
  padding: 0;
  text-decoration: underline;
}

/* =========================================================================
   Light table -- the album/folder grid (signature element)
   ========================================================================= */

.light-table {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--space-6);
}

.slide-mount {
  position: relative;
  min-width: 0;
  background: var(--litho-cream);
  border-radius: var(--radius-card);
  padding: var(--space-3) var(--space-3) 0;
  box-shadow: var(--shadow-glow);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  color: #2a2620;
  text-decoration: none;
}
.slide-mount:hover,
.slide-mount:focus-visible {
  box-shadow: var(--shadow-glow-hover);
  transform: translateY(-2px);
}
.slide-mount:focus-visible {
  outline: 2px solid var(--stamp-amber);
  outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .slide-mount { transition: none; }
}

.slide-mount .photo-stack {
  position: relative;
  width: 100%;
  padding-top: 75%; /* 4:3 box via padding-percentage trick -- see .frame-img
                        for why this replaces aspect-ratio inside column flex */
  flex-shrink: 0;
  border-radius: 2px;
  overflow: visible;
  margin-bottom: var(--space-3);
}
.photo-stack .stack-layer {
  position: absolute;
  inset: 0;
  background: #d8cfba;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 2px;
}
.photo-stack .stack-layer.behind-2 { transform: rotate(-4deg) translate(-3px, 2px); z-index: 1; }
.photo-stack .stack-layer.behind-1 { transform: rotate(3deg) translate(2px, -1px); z-index: 2; }
.photo-stack .stack-top {
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: 2px;
  overflow: hidden;
  background: #cfc6b0;
}
.photo-stack .stack-top img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.photo-stack .empty-sleeve {
  position: absolute;
  inset: 0;
  z-index: 3;
  border: 1.5px dashed #a89a78;
  border-radius: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: #8c7f60;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.slide-mount .folder-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.1rem;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.05;
  margin-bottom: 2px;
}

/* stamped frame-data strip along the bottom, like a negative's edge print */
.frame-strip {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid rgba(42, 38, 32, 0.15);
  margin-top: var(--space-2);
  padding: var(--space-2) 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: #6b6152;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* blank sleeve -- the "create new folder" card, styled as an unlabeled slide mount */
.slide-mount.new-folder {
  background: transparent;
  border: 1.5px dashed var(--contact-grey-light);
  box-shadow: none;
  align-items: center;
  justify-content: center;
  min-height: 100%;
  color: var(--text-muted);
}
.slide-mount.new-folder:hover {
  border-color: var(--stamp-amber);
  color: var(--stamp-amber);
  transform: translateY(-2px);
}
.new-folder-inner {
  text-align: center;
  padding: var(--space-8) var(--space-4);
}
.new-folder-inner .plus {
  font-family: var(--font-display);
  font-size: 2.5rem;
  line-height: 1;
  display: block;
  margin-bottom: var(--space-2);
}
.new-folder-inner span.label {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* inline creation form, appears in place of the blank sleeve */
.new-folder-form {
  background: var(--litho-cream);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-glow);
  padding: var(--space-4);
  color: #2a2620;
}
.new-folder-form .field label { color: #6b6152; }
.new-folder-form .field input,
.new-folder-form .field textarea {
  background: rgba(42, 38, 32, 0.04);
  border-color: rgba(42, 38, 32, 0.2);
  color: #2a2620;
}
.new-folder-form .form-actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-4);
}
.new-folder-form .btn { flex: 1; font-size: 0.8125rem; padding: 0.55rem 0.8rem; }
.new-folder-form .btn-ghost {
  color: #2a2620;
  border-color: rgba(42, 38, 32, 0.3);
}
.new-folder-form .btn-ghost:hover { border-color: #2a2620; }

.empty-state {
  text-align: center;
  padding: var(--space-16) var(--space-4);
  border: 1px dashed var(--contact-grey);
  border-radius: var(--radius-card);
  color: var(--text-muted);
}
.empty-state h3 { color: var(--text-on-dark); margin-bottom: var(--space-2); }

.loading-strip {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.toast {
  position: fixed;
  bottom: var(--space-6);
  left: 50%;
  transform: translateX(-50%);
  background: var(--contact-grey);
  color: var(--text-on-dark);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-glow);
  z-index: 100;
}
.toast.error { background: var(--safelight); }

@media (max-width: 560px) {
  .page { padding: var(--space-6) var(--space-4) var(--space-12); }
  .light-table { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--space-4); }
}

/* =========================================================================
   Folder view -- contact sheet grid, upload zone, lightbox
   ========================================================================= */

.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--text-muted);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: var(--space-4);
}
.back-link:hover { color: var(--stamp-amber); }

.folder-header {
  margin-bottom: var(--space-6);
}
.folder-header .folder-desc {
  margin-top: var(--space-2);
  max-width: 60ch;
}
.folder-header .folder-meta {
  margin-top: var(--space-2);
}

.upload-zone {
  border: 1.5px dashed var(--contact-grey-light);
  border-radius: var(--radius-card);
  padding: var(--space-8) var(--space-4);
  text-align: center;
  color: var(--text-muted);
  margin-bottom: var(--space-8);
  transition: border-color 0.15s ease, background 0.15s ease;
  cursor: pointer;
}
.upload-zone:hover,
.upload-zone.dragover {
  border-color: var(--stamp-amber);
  background: rgba(232, 163, 61, 0.04);
  color: var(--text-on-dark);
}
.upload-zone input[type='file'] { display: none; }
.upload-zone .upload-label {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
@media (prefers-reduced-motion: reduce) {
  .upload-zone { transition: none; }
}

.contact-sheet {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-4);
}

.frame {
  position: relative;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  background: var(--litho-cream);
  border-radius: 2px;
  padding: var(--space-2) var(--space-2) 0;
  box-shadow: var(--shadow-glow);
  cursor: pointer;
  border: none;
  font: inherit;
  text-align: left;
  color: #2a2620;
  display: flex;
  flex-direction: column;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.frame:hover, .frame:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--shadow-glow-hover);
}
.frame:focus-visible { outline: 2px solid var(--stamp-amber); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .frame { transition: none; } }

.frame .frame-img {
  position: relative;
  width: 100%;
  min-width: 0;
  padding-top: 100%; /* 1:1 box via padding-percentage trick -- never depends on
                         flex/aspect-ratio main-size resolution, always correct */
  flex-shrink: 0;
  overflow: hidden;
  border-radius: 1px;
  background: #cfc6b0;
}
.frame .frame-img img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.frame .frame-number {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  color: #6b6152;
  padding: 4px 0 6px;
  display: flex;
  justify-content: space-between;
}
.frame .frame-number .gps-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fixer-green);
  align-self: center;
}

.frame .hotspot-count {
  color: #6b6152;
  font-size: 0.6875rem;
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

.frame .frame-delete {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 5;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: rgba(28, 24, 21, 0.75);
  color: var(--litho-cream);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
}
.frame:hover .frame-delete,
.frame:focus-within .frame-delete { display: flex; }
.frame .frame-delete:hover { background: var(--safelight); }

.gps-prompt {
  background: rgba(107, 122, 94, 0.12);
  border: 1px solid var(--fixer-green);
  border-radius: var(--radius-card);
  padding: var(--space-4);
  margin-bottom: var(--space-6);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}
.gps-prompt p { margin: 0; color: var(--text-on-dark); }
.gps-prompt .form-actions { display: flex; gap: var(--space-2); }

/* =========================================================================
   Find People -- cross-album name search and the unidentified review queue
   ========================================================================= */

.people-toolbar {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-6);
}
.people-search-field {
  flex: 1 1 240px;
  margin-bottom: 0;
}
.people-toolbar .btn {
  flex: 0 0 auto;
}

/* Reuses .frame/.frame-img from the contact sheet for the card shell, so
   these read as the same visual language as the folder grid -- just with
   a name/status label where the delete button and frame number normally
   sit, since these cards span multiple folders and aren't deletable from
   here. */
.frame .result-names {
  padding: 0 0 var(--space-2);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--flash-green);
}

/* =========================================================================
   Photo view -- hotspot placement canvas
   ========================================================================= */

.photo-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-4);
}

/* Scoped to photo.html only -- turns .page into a column: toolbar, then the
   photo (centered in whatever space remains), then the filmstrip. Everything
   is in normal flow, so in a short window the page simply scrolls instead of
   the filmstrip or caption overlapping the photo and toolbar. */
.page-photo {
  max-width: 1500px; /* wider than the default 1100px so the photo can grow to fill the window height */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  padding-bottom: 0;
}

/* On the photo page only, the topbar (logo, Sign out and the dashed line
   under them), the "Back to album" link and the toolbar (Hotspots On/Off on
   the left, the hint text and full-size link on the right) are all held to
   the SAME column as every other page's header: .page is max-width 1100px
   with var(--space-6) side padding, so its content column is 1100px minus
   twice that. Keeping the two in step means the wordmark, Sign out, the
   dashed line and the controls never shift when you move between pages.
   Only the photo row itself is wider (see .page-photo's own max-width). */
.page-photo .topbar,
.page-photo .back-link,
.page-photo .photo-toolbar {
  width: 100%;
  max-width: calc(1100px - 2 * var(--space-6));
  margin-left: auto;
  margin-right: auto;
}
.page-photo .back-link { display: flex; }

.photo-center {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Room above the photo for the date/place caption, which hangs off the
     top of .photo-stage (bottom: 100%) -- without this it rides up over
     the toolbar. */
  padding-top: 3rem;
}

.toggle-pill {
  display: inline-flex;
  border: 1px solid var(--contact-grey-light);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
.toggle-pill button {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.5rem 1rem;
  cursor: pointer;
}
.toggle-pill button.active {
  background: var(--safelight);
  color: var(--litho-cream);
}

.photo-row {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: var(--space-4);
}

.photo-stage {
  position: relative;
  background: #0c0a08;
  box-shadow: var(--shadow-glow);
  line-height: 0;
  max-width: 100%;
}
.photo-stage img {
  display: block;
  max-width: 100%;
  /* Fills the viewport height left after everything else on the page: the
     topbar, back link and toolbar above (~350px), the caption's 3rem, and
     the filmstrip below (~150px) -- hence the 540px. Raise it if the photo
     ever pushes the filmstrip below the fold; lower it for a bigger photo.
     The 220px floor keeps the photo usable in a short window, where the
     page scrolls instead of overlapping. */
  max-height: max(220px, calc(100vh - 540px));
  width: auto;
  height: auto;
  border-radius: var(--radius-card);
  user-select: none;
  cursor: crosshair;
}

/* Auto-generated date/place caption -- date from the photo's own EXIF
   DateTimeOriginal, place from reverseGeocodeService.js (lazy, on-view,
   never a batch call -- see getPhotoLocationInfo in photoController.js).
   Deliberately NOT a hotspot: nothing to click or edit, so it shouldn't
   look like one. Positioned above the image (bottom: 100% on this
   position:relative-anchored parent) rather than overlaid on it, so it
   stays out of the carousel arrows' height calculation (they stretch to
   match .photo-stage's own height) and reads as page chrome, not part of
   the photo -- always visible, independent of the Hotspots On/Off toggle. */
.photo-location-label {
  position: absolute;
  bottom: 100%;
  left: 0;
  margin-bottom: var(--space-6);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--stamp-amber);
  white-space: nowrap;
  pointer-events: none;
}
.photo-location-label .link-btn { pointer-events: auto; }
.photo-location-label a.link-btn { display: inline-block; } /* match the (Edit) <button>'s box so the two sit on one baseline */

.location-edit-form {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  pointer-events: auto;
}
.location-edit-form input {
  background: rgba(237, 230, 214, 0.06);
  border: 1px solid var(--contact-grey);
  border-radius: var(--radius-card);
  color: var(--text-on-dark);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  padding: 0.3rem 0.5rem;
  width: 120px;
}
.location-edit-form input:focus {
  outline: none;
  border-color: var(--stamp-amber);
}
.location-edit-form .btn { font-size: 0.6875rem; padding: 0.3rem 0.6rem; }
.location-edit-form .error-text { flex-basis: 100%; margin: 0; }

.hotspot-marker {
  position: absolute;
  width: 17px;
  height: 17px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--safelight);
  border: 1px solid var(--litho-cream);
  box-shadow: 0 0 0 2px rgba(193, 67, 46, 0.28), 0 1px 4px rgba(0, 0, 0, 0.5);
  cursor: pointer;
  z-index: 5;
  padding: 0;
  transition: transform 0.12s ease;
}
.hotspot-marker:hover,
.hotspot-marker:focus-visible {
  transform: translate(-50%, -50%) scale(1.15);
}
.hotspot-marker.audio { background: var(--flash-blue); }
.hotspot-marker.video { background: var(--stamp-amber); }
.hotspot-marker.person { background: var(--flash-green); }
@media (prefers-reduced-motion: reduce) { .hotspot-marker { transition: none; } }

.hotspot-marker-pending {
  position: absolute;
  width: 17px;
  height: 17px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 1px dashed var(--stamp-amber);
  z-index: 6;
  pointer-events: none;
}

.hotspot-preview {
  position: absolute;
  z-index: 15;
  max-width: 240px;
  background: var(--contact-grey);
  color: var(--text-on-dark);
  border-radius: 10px;
  box-shadow: 0 10px 24px -6px rgba(0, 0, 0, 0.6);
  padding: 0.6rem 0.8rem;
  font-size: 0.8125rem;
  line-height: 1.4;
  pointer-events: none;
  overflow-wrap: break-word;
}

.hotspot-popover {
  position: absolute;
  z-index: 20;
  width: 280px;
  max-width: calc(100vw - 2 * var(--space-6));
  background: var(--litho-cream);
  color: #2a2620;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-glow-hover);
  padding: var(--space-4);
}
.hotspot-popover .field label { color: #6b6152; }
.hotspot-popover .field input,
.hotspot-popover .field textarea,
.hotspot-popover .field select {
  background: rgba(42, 38, 32, 0.04);
  border-color: rgba(42, 38, 32, 0.2);
  color: #2a2620;
}
.hotspot-popover .type-tabs {
  display: flex;
  gap: var(--space-1);
  margin-bottom: var(--space-3);
}
.hotspot-popover .type-tabs button {
  flex: 1;
  background: rgba(42, 38, 32, 0.05);
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  padding: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  cursor: pointer;
  color: #6b6152;
}
.hotspot-popover .type-tabs button.active {
  background: var(--safelight);
  color: var(--litho-cream);
}
.hotspot-popover .popover-actions {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.hotspot-popover .popover-actions .right { display: flex; gap: var(--space-2); }
.hotspot-popover .btn { font-size: 0.8125rem; padding: 0.5rem 0.9rem; }
.hotspot-popover .btn-ghost {
  color: var(--safelight-bright);
  border-color: var(--safelight);
}
.hotspot-popover .btn-ghost:hover {
  background: var(--safelight);
  color: var(--litho-cream);
}
.hotspot-popover .popover-close {
  position: absolute;
  top: 6px;
  right: 8px;
  background: none;
  border: none;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  color: #8c7f60;
}
.hotspot-popover .content-view {
  font-size: 0.9375rem;
  line-height: 1.4;
  margin-bottom: var(--space-3);
  white-space: pre-wrap;
}
.hotspot-popover .content-note {
  font-size: 0.8125rem;
  color: #6b6152;
  font-style: italic;
  margin-top: calc(-1 * var(--space-2));
  margin-bottom: var(--space-3);
  white-space: pre-wrap;
}
.hotspot-popover .meta-line {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: #8c7f60;
  margin-bottom: var(--space-3);
}

.recorder {
  border: 1px dashed rgba(42, 38, 32, 0.25);
  border-radius: var(--radius-card);
  padding: var(--space-3);
  text-align: center;
  margin-bottom: var(--space-3);
}
.recorder .rec-status {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: #6b6152;
  margin-bottom: var(--space-2);
}
.recorder .rec-status.recording { color: var(--safelight); }
.recorder audio { width: 100%; margin-top: var(--space-2); }
.recorder .rec-buttons { display: flex; gap: var(--space-2); justify-content: center; }
.rec-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--safelight);
  margin-right: 6px;
  animation: rec-pulse 1s ease-in-out infinite;
}
@keyframes rec-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
@media (prefers-reduced-motion: reduce) { .rec-dot { animation: none; } }

.link-btn {
  background: none;
  border: none;
  padding: 0;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--stamp-amber);
  text-decoration: underline;
  cursor: pointer;
}
.link-btn:hover { color: var(--safelight-bright); }

/* Full-size overlay -- padding (not calc/inset math) enforces the 50px
   clearance from every viewport edge: the overlay's own box is the full
   viewport (inset:0), and with box-sizing:border-box (our global default)
   the padding eats into that box rather than growing past it, so the
   flex content area used to center/size the image is automatically
   exactly (100vw - 100px) x (100vh - 100px). */
.fullsize-overlay {
  position: fixed;
  inset: 0;
  z-index: 500;
  background: rgba(12, 10, 8, 0.85);
  backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 50px;
  cursor: zoom-out;
}
.fullsize-overlay img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  display: block;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-glow-hover);
}

/* =========================================================================
   Cold Storage reminder -- albums.html only, directly under "Find People".
   Deliberately amber-tinted (not the litho-cream card language used
   elsewhere) since this is a time-sensitive notice, not a photo surface --
   same reasoning as the mono amber date-stamps used for EXIF dates.
   ========================================================================= */

.cold-storage-section {
  background: rgba(232, 163, 61, 0.08);
  border: 1px solid var(--stamp-amber);
  border-radius: var(--radius-card);
  padding: var(--space-4) var(--space-6);
  margin-top: var(--space-4);
  overflow: hidden;
  animation: cold-storage-slide-down 0.35s ease;
}
@keyframes cold-storage-slide-down {
  from { opacity: 0; transform: translateY(-12px); }
  to { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .cold-storage-section { animation: none; }
}

.cold-storage-section h3 {
  color: var(--stamp-amber);
  font-size: 1rem;
  margin-bottom: var(--space-3);
}

.cold-storage-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px dashed rgba(232, 163, 61, 0.25);
  font-size: 0.875rem;
  flex-wrap: wrap;
}
.cold-storage-row:last-of-type { border-bottom: none; }
.cold-storage-row .cs-name { color: var(--text-on-dark); }
.cold-storage-row .cs-expires {
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  margin-left: var(--space-2);
}
.cold-storage-row .cs-actions { display: flex; gap: var(--space-3); flex-shrink: 0; }
.cold-storage-row .cs-actions button {
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: pointer;
  color: var(--stamp-amber);
  text-decoration: underline;
}
.cold-storage-row .cs-actions button.cs-delete { color: var(--safelight-bright); }
.cold-storage-row .cs-actions button:hover { opacity: 0.8; }
.cold-storage-row .cs-actions button:disabled { opacity: 0.5; cursor: default; text-decoration: none; }

.cold-storage-more {
  padding-top: var(--space-2);
  margin: 0;
  font-size: 0.8125rem;
  color: var(--text-muted);
}
.cold-storage-more a { cursor: pointer; }

.cold-storage-close { margin-top: var(--space-3); }

/* Reverse of cold-storage-slide-down, for the exif-check-panel's closing
   state below -- kept next to its counterpart even though it's used by a
   different section further down. */
@keyframes cold-storage-slide-up {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(-12px); }
}

/* albums.html's collapsible "Read an Image's Info" panel -- full-width,
   slides down above the Cold Storage reminder on open, slides up and is
   removed on close (see albums.js for the animationend-driven removal,
   with a reduced-motion fallback that skips waiting on the event
   entirely). Reuses .upload-zone / .exif-results / .exif-table as-is --
   this is just the outer wrapper controlling the slide. */
.exif-check-panel {
  margin-top: var(--space-4);
  animation: cold-storage-slide-down 0.3s ease;
}
.exif-check-panel.closing {
  animation: cold-storage-slide-up 0.25s ease forwards;
}
@media (prefers-reduced-motion: reduce) {
  .exif-check-panel,
  .exif-check-panel.closing { animation: none; }
}

/* =========================================================================
   Modal -- confirm dialogs (album delete, and later cold storage's own
   "delete permanently" confirm). Reuses the litho-cream card treatment
   from .hotspot-popover/.new-folder-form, just centered over a full-
   viewport backdrop rather than positioned relative to a page element.
   ========================================================================= */

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(12, 10, 8, 0.75);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}

.modal-card {
  width: 100%;
  max-width: 440px;
  background: var(--litho-cream);
  color: #2a2620;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-glow-hover);
  padding: var(--space-6);
}
.modal-card h3 { color: #2a2620; margin-bottom: var(--space-4); }
.modal-card p { color: #4a4136; margin-bottom: var(--space-4); }
.modal-card .modal-warning { color: var(--safelight); font-weight: 600; }

.modal-checkbox {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
  font-size: 0.875rem;
  color: #4a4136;
  cursor: pointer;
}
.modal-checkbox input[type='checkbox'] {
  margin-top: 3px;
  accent-color: var(--safelight);
}
.modal-checkbox.locked { color: #8c7f60; cursor: default; }

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  flex-wrap: wrap;
}
.modal-actions .btn { font-size: 0.875rem; }
.modal-actions .btn-danger {
  background: var(--safelight);
  color: var(--litho-cream);
  border-color: var(--safelight);
}
.modal-actions .btn-danger:hover { background: var(--safelight-bright); }
.modal-actions .btn-ghost {
  color: #2a2620;
  border-color: rgba(42, 38, 32, 0.3);
}
.modal-actions .btn-ghost:hover { border-color: #2a2620; }

/* =========================================================================
   Landing page -- three-card chooser (sign in / create account / check a
   photo's info, the last needing no account). Each card expands in place
   on click to reveal its form/tool; the other two stay collapsed. Kept
   separate from .page-narrow (used only by the old single-form layout)
   since this needs more horizontal room for three cards side by side.
   ========================================================================= */

.page-landing {
  max-width: 640px;
  margin: 0 auto;
  padding: var(--space-16) var(--space-6);
}

.landing-welcome {
  text-align: center;
  margin-bottom: var(--space-8);
  color: var(--text-on-dark);
  font-size: 1.0625rem;
}

.landing-cards {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.landing-card {
  background: rgba(237, 230, 214, 0.03);
  border: 1px solid var(--contact-grey);
  border-radius: var(--radius-card);
  overflow: hidden;
  transition: border-color 0.15s ease;
}
.landing-card.expanded { border-color: var(--stamp-amber); }
@media (prefers-reduced-motion: reduce) {
  .landing-card { transition: none; }
}

.landing-card-header {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: var(--space-6);
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.landing-card-header h2 { font-size: 1.25rem; margin-bottom: var(--space-1); }
.landing-card-header p { margin: 0; }
.landing-card-header:hover h2 { color: var(--stamp-amber); }

/* "Click here" cue inside the Read an Image's Info card's header. A styled
   span rather than an <a>: the whole header is already a <button>, and a link
   nested inside a button is invalid HTML. Clicks on it bubble to the button. */
.click-here {
  color: var(--stamp-amber);
  text-decoration: underline;
}
.landing-card-header:hover .click-here { color: var(--safelight-bright); }

.landing-card-body {
  padding: 0 var(--space-6) var(--space-6);
  /* Eases open when un-hidden (the animation restarts each time display
     changes from none), reusing the Cold Storage reminder's slide-down. */
  animation: cold-storage-slide-down 0.3s ease;
}
@media (prefers-reduced-motion: reduce) {
  .landing-card-body { animation: none; }
}

.exif-results {
  margin-top: var(--space-8);
  animation: cold-storage-slide-down 0.3s ease; /* reused -- same gentle entrance, no need for a second keyframe */
}
@media (prefers-reduced-motion: reduce) {
  .exif-results { animation: none; }
}
.exif-results h3 { font-size: 1.0625rem; text-transform: none; letter-spacing: normal; margin-bottom: var(--space-4); color: var(--text-on-dark); }
.exif-results #exif-close-btn { display: block; margin-bottom: var(--space-6); }
.exif-preview {
  max-width: 320px;
  width: 100%;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-glow);
  margin-bottom: var(--space-4);
  display: block;
}
.exif-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
.exif-table tr { border-bottom: 1px dashed var(--contact-grey); }
.exif-table tr:last-child { border-bottom: none; }
.exif-table td { padding: var(--space-2) var(--space-3); vertical-align: top; }
.exif-table td:first-child {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  white-space: nowrap;
  width: 1%;
}
.exif-table td:last-child { color: var(--text-on-dark); white-space: pre-wrap; word-break: break-word; }

/* =========================================================================
   Carousel -- prev/next arrows and filmstrip
   ========================================================================= */

.carousel-arrow {
  flex: 0 0 auto;
  width: 64px;
  border: none;
  background: transparent;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.carousel-arrow .tri {
  width: 0;
  height: 0;
  border-top: 25px solid transparent;
  border-bottom: 25px solid transparent;
  transition: border-color 0.15s ease; 
}
.carousel-arrow.left .tri { border-right: 43px solid var(--contact-grey-light); }
.carousel-arrow.right .tri { border-left: 43px solid var(--contact-grey-light); }
.carousel-arrow.left:hover .tri { border-right-color: var(--safelight-bright); }
.carousel-arrow.right:hover .tri { border-left-color: var(--safelight-bright); }
.carousel-arrow:active .tri { transform: scale(0.9); }
@media (prefers-reduced-motion: reduce) { .carousel-arrow .tri { transition: none; } }

@media (max-width: 700px) {
  .carousel-arrow { width: 36px; }
  .carousel-arrow .tri { border-top-width: 16px; border-bottom-width: 16px; }
  .carousel-arrow.left .tri { border-right-width: 28px; }
  .carousel-arrow.right .tri { border-left-width: 28px; }
}

.filmstrip {
  position: relative; /* offsetParent for the scroll-to-active math in photo.js */
  width: fit-content;
  max-width: 100%;
  margin: var(--space-4) auto var(--space-8);
  flex: 0 0 auto;
  display: flex;
  justify-content: safe center;
  gap: var(--space-2);
  overflow-x: auto;
  padding: var(--space-2) var(--space-3);
  scroll-behavior: smooth;
  background: rgba(12, 10, 8, 0.75);
  border-radius: var(--radius-card);
  backdrop-filter: blur(6px);
  box-shadow: var(--shadow-glow);
}
.filmstrip::-webkit-scrollbar { height: 6px; }
.filmstrip::-webkit-scrollbar-thumb { background: var(--contact-grey-light); border-radius: var(--radius-pill); }

.filmstrip-thumb {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  border-radius: 3px;
  overflow: hidden;
  border: 2px solid transparent;
  padding: 0;
  cursor: pointer;
  background: var(--litho-cream);
  opacity: 0.6;
  transition: opacity 0.12s ease, border-color 0.12s ease;
}
.filmstrip-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.filmstrip-thumb:hover { opacity: 0.85; }
.filmstrip-thumb.active {
  opacity: 1;
  border-color: var(--safelight);
}
@media (prefers-reduced-motion: reduce) { .filmstrip-thumb { transition: none; } }

/* Recorder fixes (audio tab of the hotspot popover):
   - .photo-stage sets line-height: 0 and the popover inherits it, which
     collapses wrapped text onto itself -- restore a normal line-height here.
   - (The Stop button's [hidden] problem is now handled by the global
     [hidden] rule near the top of this file.) */
.recorder { line-height: 1.4; }
.recorder .rec-buttons { align-items: center; }
.recorder .rec-buttons .btn { white-space: nowrap; }
.recorder .rec-buttons [hidden] { display: none; }

/* "Read an Image's Info" -- full hotspot content listed under the EXIF table.
   Left border color matches the hotspot marker colors on photo.html. */
.exif-results .exif-hotspots-heading { margin-top: var(--space-8); }
.exif-hotspots {
  list-style: none;
  margin: 0;
  padding: 0;
}
.exif-hotspot {
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-3);
  border: 1px solid var(--contact-grey);
  border-left: 4px solid var(--contact-grey-light);
  border-radius: var(--radius-card);
  background: rgba(237, 230, 214, 0.03);
}
.exif-hotspot.text { border-left-color: var(--safelight); }
.exif-hotspot.audio { border-left-color: var(--flash-blue); }
.exif-hotspot.person { border-left-color: var(--flash-green); }
.exif-hotspot.video { border-left-color: var(--stamp-amber); }
.exif-hotspot-meta {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin-bottom: var(--space-2);
}
.exif-hotspot-body {
  color: var(--text-on-dark);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.exif-hotspot-note {
  margin-top: var(--space-2);
  color: var(--text-muted);
  font-style: italic;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.exif-hotspot audio { width: 100%; }