/* ---------- Lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  background: #000;
  z-index: 100;
  touch-action: none;
}

.lightbox[hidden] {
  display: none;
}

.lightbox-viewport {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.lightbox-viewport img {
  max-width: 100%;
  max-height: 100%;
  touch-action: none;
  user-select: none;
  -webkit-user-drag: none;
  will-change: transform;
}

.lightbox-viewport video {
  max-width: 100%;
  max-height: 100%;
  /* Overrides .lightbox's touch-action:none - a touch starting in the
     native controls' bottom strip is left alone by the gesture handlers
     (see VIDEO_CONTROLS_ZONE in script.js) so scrubbing/play-pause still
     reach the browser's own controls; a touch elsewhere on the video is
     captured for horizontal swipe-to-navigate, same as photos (#48). */
  touch-action: auto;
}

.lightbox-viewport img[hidden],
.lightbox-viewport video[hidden] {
  display: none;
}

.lightbox-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: #fff;
  font-size: 1.9rem;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
}

.lightbox-favorite {
  position: absolute;
  top: 14px;
  left: 14px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
}

.lightbox-note-toggle {
  position: absolute;
  top: 68px;
  left: 14px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: #fff;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
  border-radius: 50%;
}

/* Same invert-on-active convention as .filter-type button.active/
   .filter-favorites.active, adapted for the lightbox's dark background:
   filled white circle instead of filled black, so it still reads as
   "on" against black instead of disappearing into it. */
.lightbox-note-toggle.has-content {
  background: #fff;
  color: #000;
}

/* Issue #154 - same left-column stack as .lightbox-favorite/.lightbox-
   note-toggle above it, next 54px increment down. */
.lightbox-download {
  position: absolute;
  top: 122px;
  left: 14px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: #fff;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
  border-radius: 50%;
  /* Same root cause .lightbox-reaction-toggle already documents: a native
     <button> carries the browser's own default padding (Chrome: ~1px 6px,
     asymmetric) unless explicitly zeroed, which shrinks/off-centers
     whatever content box a percentage-sized child (the SVG below) measures
     against - confirmed via getBoundingClientRect (2026-08-29): the icon
     came out 32x42, not the expected ~44x44 square. */
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Issue #173 - .lightbox-download/.lightbox-delete's icon is now an
   inline SVG (was a Unicode glyph/color emoji sized via font-size, which
   does nothing for an SVG) - same fill-the-button-box sizing as
   .reaction-toggle-icon below, so `color: #fff` on the button alone
   controls it via stroke=currentColor. Padding lives here, not on the
   button (see .lightbox-download's own comment on why). */
.lightbox-icon-svg {
  width: 100%;
  height: 100%;
  padding: 12px;
  box-sizing: border-box;
}

/* Issue #154 - same bottom-center placement family as .lightbox-counter,
   sitting just above it. pointer-events:none: same reasoning as
   .lightbox-note-overlay - never intercepts a swipe/pinch touch. */
.lightbox-date {
  position: absolute;
  bottom: 44px;
  left: 50%;
  transform: translateX(-50%);
  color: #fff;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  opacity: 0.65;
  pointer-events: none;
  z-index: 1;
}

.lightbox-date[hidden] {
  display: none;
}

/* Issue #158 - same left-column stack as .lightbox-favorite/.lightbox-
   note-toggle/.lightbox-download, next 54px increment down. Hidden by
   default - shown only for uploaded photos (site/js/lightbox.js). */
.lightbox-delete {
  position: absolute;
  top: 176px;
  left: 14px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: #fff;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
  border-radius: 50%;
  /* See .lightbox-download's own comment - same fix, same root cause. */
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox-delete[hidden] {
  display: none;
}

/* Issue #185: native <video controls> chrome (fullscreen/PiP/edit icons
   top-left, volume top-right on iOS Safari) lands in the same corners as
   this left-column stack and .lightbox-reaction-toggle - the app can't
   reposition or restyle browser-native controls, so hide its own overlay
   for videos instead (lightbox.js's showPhoto toggles this class). */
.lightbox-video-active .lightbox-favorite,
.lightbox-video-active .lightbox-note-toggle,
.lightbox-video-active .lightbox-download,
.lightbox-video-active .lightbox-delete,
.lightbox-video-active .lightbox-reaction-toggle {
  display: none;
}

/* Issue #158 - centered confirm dialog, same plain/technical panel look as
   .lightbox-note-save/.lightbox-note-cancel (not the warm .note-glass
   treatment - this is UI chrome, not personal content). Sits above
   everything else in the lightbox (z-index 3 vs. 2 for the toolbar
   buttons) since it's a modal blocking further action until answered. */
.lightbox-delete-confirm {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  width: min(280px, calc(100% - 48px));
  padding: 20px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.85);
  color: #fff;
  text-align: center;
}

.lightbox-delete-confirm[hidden] {
  display: none;
}

.lightbox-delete-confirm p {
  margin: 0 0 16px;
  font-size: 0.9rem;
  line-height: 1.4;
}

.lightbox-delete-status {
  margin: -8px 0 16px;
  font-size: 0.78rem;
  opacity: 0.75;
}

.lightbox-delete-status[hidden] {
  display: none;
}

.lightbox-delete-confirm-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
}

.lightbox-delete-confirm-actions button {
  flex: 1;
  padding: 10px 0;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 4px;
  background: transparent;
  color: #fff;
  font-size: 0.85rem;
  cursor: pointer;
}

.lightbox-delete-confirm-actions .lightbox-delete-confirm-yes {
  background: #fff;
  color: #000;
}

/* Issue #124 - mirrors .lightbox-note-toggle's position exactly, just on
   the right column below .lightbox-close instead of the left one below
   .lightbox-favorite. Hidden outside reel mode (see js/reel.js). */
.lightbox-reel-pause {
  position: absolute;
  top: 68px;
  right: 14px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: #fff;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
  border-radius: 50%;
}

.lightbox-note-panel {
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 96px;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.lightbox-note-panel .lightbox-note-text {
  flex: 1;
}

/* Explicit save/close action (bug report 2026-08-25: blur-to-save alone
   wasn't discoverable). Plain/technical styling is deliberate here, not an
   oversight - Malte confirmed the editor itself is fine looking like UI
   chrome; only the read-only caption (.note-glass) needed the warmer
   treatment. */
.lightbox-note-save,
.lightbox-note-cancel {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
}

/* Discard action (feature request 2026-08-25) - deliberately plain/
   technical like .lightbox-note-save, not the warm .note-glass treatment;
   Malte confirmed the editor chrome itself is fine looking like UI, only
   the read-only caption needed the warmer style. Slightly larger glyph
   (×) than Save's checkmark for visual parity - they're different glyphs
   at the same font-size otherwise reading unevenly sized. */
.lightbox-note-cancel {
  font-size: 1.6rem;
}

.lightbox-note-panel[hidden] {
  display: none;
}

/* Shared read-only-caption look (issue #75, unified 2026-08-25 after the
   lightbox and timeline-card captions were reported as looking
   inconsistent - different box, different alignment). Every visual rule
   common to both lives here; only position/size (which differ - the
   lightbox and a card are very different containers) stays on
   .lightbox-note-overlay / .card-note-overlay below. Keep this the ONLY
   place that defines the "glass caption" look, or the two will drift
   apart again. */
.note-glass {
  /* Multi-line ellipsis, not a scroll cutoff - bug report 2026-08-25: a
     note past the box's cap used to end mid-line with no indication more
     text existed. -webkit-line-clamp (all target browsers support it
     despite the prefix - Chrome/Android WebView/Safari/Firefox 68+) counts
     VISUAL lines including wraps, so it also clamps one long paragraph,
     not just explicit newlines. The actual line count is per-context (the
     lightbox has far more room than a card) - see .lightbox-note-overlay
     / .card-note-overlay below. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
  padding: 12px 18px;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-radius: 12px;
  color: #fff;
  text-align: center;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-style: italic;
  font-size: 1.15rem;
  line-height: 1.55;
  white-space: pre-wrap;
  pointer-events: none;
}

/* bottom-anchored directly above the reaction trigger (bottom:54px,
   height 40px -> top edge at 94px), like a WhatsApp caption sitting above
   its reactions, instead of the old top-of-screen placement unrelated to
   the reaction UI. `left`/`width` are overwritten inline by script.js's
   updateLightboxNoteOverlayPosition() to match the actual rendered photo
   bounds (letterboxing means the img/video often isn't full-viewport
   width) - no `right` here so that inline `width` isn't fighting it; these
   are just the pre-JS/no-photo-yet fallback. */
.lightbox-note-overlay {
  position: absolute;
  left: 14px;
  width: calc(100% - 28px);
  bottom: 104px;
  z-index: 2;
  -webkit-line-clamp: 8;
}

.lightbox-note-overlay[hidden] {
  display: none;
}

.lightbox-note-text {
  width: 100%;
  min-height: 4.5em;
  resize: none;
  font-family: "Inter", sans-serif;
  /* 16px, not smaller - same iOS Safari auto-zoom trap as .filter-select
     (issue #61): a focusable control under 16px triggers a zoom that
     doesn't reliably release on blur. */
  font-size: 16px;
  padding: 8px 10px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
}

.lightbox-note-text::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.lightbox-reaction-toggle {
  position: absolute;
  left: 50%;
  bottom: 54px;
  transform: translateX(-50%);
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  /* Root cause of the "still not centered" report (measured via
     getComputedStyle, 2026-08-25): removing the old `padding: 8px` here
     didn't leave the content box at the full 40x40 - a native <button>
     carries the browser's own default padding (Chrome: ~1px 6px,
     asymmetric) whenever nothing overrides it, and nothing here did. That
     phantom asymmetric padding, not glyph metrics, was shrinking and
     off-centering the content box. Explicit 0 - not omission - is the
     actual fix. */
  padding: 0;
  cursor: pointer;
  z-index: 2;
  font-size: 22px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* padding lives here, not on the button - a 40x40 button with 8px padding
   left only a 24x24 content box, and centering a 22px emoji glyph inside a
   24px box made any sub-pixel/glyph-bearing difference read as visibly
   off-center (bug report 2026-08-25, image 2). The SVG icon still wants
   the same 8px inset it always had; box-sizing:border-box keeps its own
   box at the full 40x40 so it stays concentric with the button/badge. */
.reaction-toggle-icon {
  width: 100%;
  height: 100%;
  padding: 8px;
  box-sizing: border-box;
}

/* The SVG icon fills its box edge-to-edge so the button's own flex-
   centering is enough, but a color-emoji glyph sits inside its own text
   line box with baseline/leading quirks that flex-centering the *button*
   doesn't reach - center the glyph within its own span too. Deliberately
   NO padding here (unlike the old button padding) - matching
   .reaction-quick, which never had padding and was never reported as
   off-center. */
.reaction-toggle-emoji {
  /* position:absolute + inset:0, not width/height (100% or flex-grow) -
     measured via getComputedStyle (2026-08-25): a flex item nested inside
     a <button> that is itself display:flex would not grow/stretch to fill
     it (both a percentage width and flex-grow:1 resolved to the glyph's
     own ~23px content width instead of the button's 40px) - a Chromium
     quirk with flex layout inside a button's own formatting context.
     .lightbox-reaction-toggle is already `position: absolute`, which also
     makes it the containing block for this, so inset:0 reliably fills it
     exactly regardless of the flex algorithm. */
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

/* Same [hidden]-vs-author-display gotcha as .lightbox-note-panel[hidden]
   etc. - this rule's own `display: flex` outranks the UA `[hidden]
   { display: none }` at equal specificity. */
.reaction-toggle-emoji[hidden] {
  display: none;
}

/* Same invert-on-active convention as .lightbox-note-toggle.has-content -
   kept even though the trigger now usually shows the chosen emoji itself
   (the active state still matters for the no-reaction outline icon case,
   e.g. right after clearing one). */
.lightbox-reaction-toggle.active {
  background: #fff;
}

/* WhatsApp-style horizontal reaction strip, opened by a tap on the trigger
   above (not a long-press on the photo - see index.html's comment on
   #lightbox-reaction-picker for why). Positioned above both the trigger
   and (usually) the note caption now that the caption is also bottom-
   anchored just above the trigger - a long caption can still be covered
   while the picker is open, same tolerance already accepted for the emoji
   grid bottom sheet covering the caption while it's open. */
.lightbox-reaction-picker {
  position: absolute;
  left: 50%;
  bottom: 150px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  background: rgba(0, 0, 0, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  z-index: 3;
}

/* Same as .lightbox-note-panel[hidden]: the base rule's own `display: flex`
   is an author-origin declaration, so it wins the cascade over the UA
   stylesheet's `[hidden] { display: none }` even at equal specificity -
   without this override the picker stays laid out (and clickable/
   occluding) while `hidden` is set. */
.lightbox-reaction-picker[hidden] {
  display: none;
}

.reaction-quick,
.reaction-more {
  width: 38px;
  height: 38px;
  border: none;
  border-radius: 50%;
  background: transparent;
  /* Same latent bug as .lightbox-reaction-toggle (see its comment) - never
     had an explicit override, so the browser's own default <button>
     padding was silently shrinking/off-centering these too. */
  padding: 0;
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
}

.reaction-quick.active {
  background: rgba(255, 255, 255, 0.25);
}

.reaction-more {
  font-size: 20px;
  font-weight: 500;
}

/* Full emoji grid - a bottom sheet over the lightbox, opened by the "+"
   above (issue #74). Sibling of #lightbox-viewport/#lightbox-reaction-
   picker, same gesture-isolation reasoning. */
.lightbox-emoji-grid {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 4;
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  background: rgba(0, 0, 0, 0.92);
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 14px 14px 0 0;
}

/* Same reasoning as .lightbox-reaction-picker[hidden] above. */
.lightbox-emoji-grid[hidden] {
  display: none;
}

.emoji-grid-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  flex-shrink: 0;
}

.emoji-grid-search {
  flex: 1;
  /* 16px floor (issue #61): a smaller font on a focusable control triggers
     an iOS-style zoom that doesn't reliably release on blur - same
     reasoning as .lightbox-note-text. */
  font-size: 16px;
  padding: 8px 12px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
}

.emoji-grid-search::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.emoji-grid-close {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  font-size: 20px;
  cursor: pointer;
}

.emoji-grid-body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 4px 12px 16px;
}

.emoji-category-label {
  margin: 12px 0 6px;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.emoji-category-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
  gap: 2px;
}

.emoji-btn {
  width: 38px;
  height: 38px;
  border: none;
  border-radius: 8px;
  background: transparent;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.emoji-btn:active {
  background: rgba(255, 255, 255, 0.15);
}

.emoji-grid-empty {
  padding: 24px 8px;
  text-align: center;
  color: rgba(255, 255, 255, 0.5);
  font-size: 0.85rem;
}

.lightbox-counter {
  position: absolute;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  color: #fff;
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  opacity: 0.65;
}

.closing {
  min-height: 70dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 48px 32px;
  background: var(--white);
}

.closing-text {
  font-family: "Cormorant Garamond", serif;
  font-size: clamp(1.5rem, 6vw, 2.1rem);
  color: var(--black);
  line-height: 1.6;
  white-space: pre-line;
  direction: ltr; /* verbatim, never translated - see AI-HANDOFF.md */
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 1s ease, transform 1s ease;
}

.closing-text.visible {
  opacity: 1;
  transform: translateY(0);
}

