/* ─── PHOTOS DOMAIN ──────────────────────────────────────────── */
.photos-page {
  position: relative;
  min-height: 100vh;
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 1.5rem;
  padding-top: var(--nav-h);
}

/* Atmospheric background — the photo itself must stay clearly visible
   ("like looking at it without glasses"): light blur only, mild dimming.
   Legibility comes from the text-shadow on header text below, not from
   flattening the photo under a heavy overlay.
   --photos-bg-image is a custom property (not a hardcoded background-image)
   specifically so a future feature can rotate it through real library
   photos with one line of JS: root.style.setProperty('--photos-bg-image',
   `url(${item.url})`) — no other change needed. */
:root {
  --photos-bg-image: url('/assets/backgrounds/photos.jpg');
}

.photos-bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  background-image: var(--photos-bg-image);
  background-size: cover;
  background-position: center;
  filter: blur(0.5px) brightness(0.74) saturate(1.05);
  transform: scale(1.02);
}

.photos-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(6,9,18,0.1), rgba(6,9,18,0.22));
}

[data-theme="light"] .photos-bg { filter: blur(0.5px) brightness(1) saturate(1); }
[data-theme="light"] .photos-bg::after { background: linear-gradient(180deg, rgba(30,26,20,0.12), rgba(30,26,20,0.22)); }

/* ─── LEFT: Upload / Sync tiles ──────────────────────────────── */
.photos-side {
  padding: 1.5rem 0 1.5rem 5%;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.photos-tile {
  position: relative;
  width: 56%;
  margin: 0 auto;
  aspect-ratio: 1 / 1;
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  color: #fff;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  box-shadow: var(--shadow-md);
  border: 1.5px solid transparent;
  transition: transform var(--transition), box-shadow var(--transition);
}

.photos-tile:hover {
  transform: scale(1.03);
  box-shadow: var(--shadow-lg);
}

.photos-tile-icon {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(255,255,255,0.16);
  display: flex;
  align-items: center;
  justify-content: center;
}

.photos-tile-upload {
  background: linear-gradient(155deg, #3b7dd8, #2c5fa8);
  border-color: rgba(255,255,255,0.25);
}

.photos-tile-sync {
  background: linear-gradient(155deg, #1fa88a, #17836c);
  border-color: rgba(255,255,255,0.25);
}

.photos-tile-badge {
  position: absolute;
  top: 10px; right: 10px;
  min-width: 8px; height: 8px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 2px rgba(255,255,255,0.3);
}

/* ─── MAIN: Library grid ─────────────────────────────────────── */
.photos-main {
  padding: 1.5rem 5% 2.5rem 0;
  min-width: 0;
}

.photos-header {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-bottom: 1.4rem;
}

/* Text-shadow (not a heavier overlay) is what keeps this legible over a
   now much-more-visible photo background — a soft dark halo in dark mode,
   a soft light halo in light mode, tuned to whatever sits behind it. */
.photos-header-icon {
  color: var(--text-secondary);
  opacity: 0.85;
  margin-bottom: 0.15rem;
  filter: drop-shadow(0 1px 6px rgba(0,0,0,0.4));
}

.photos-header h1 {
  font-size: 1.7rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  text-shadow: 0 1px 3px rgba(0,0,0,0.45), 0 2px 16px rgba(0,0,0,0.3);
}

.photos-count {
  font-size: 0.82rem;
  color: var(--text-secondary);
  text-shadow: 0 1px 3px rgba(0,0,0,0.45), 0 2px 12px rgba(0,0,0,0.25);
}

[data-theme="light"] .photos-header-icon { filter: drop-shadow(0 1px 6px rgba(255,255,255,0.55)); }
[data-theme="light"] .photos-header h1,
[data-theme="light"] .photos-count { text-shadow: 0 1px 3px rgba(255,255,255,0.6), 0 2px 14px rgba(255,255,255,0.4); }

.photos-state {
  padding: 3rem 1rem;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 0.85rem;
  grid-column: 1 / -1;
}

.photos-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.85rem;
}

.photo-thumb {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-subtle);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: transform var(--transition), box-shadow var(--transition);
}

.photo-thumb:hover {
  transform: scale(1.04);
  box-shadow: var(--shadow-md);
  z-index: 2;
}

.photo-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ─── PHOTO VIEWER ───────────────────────────────────────────── */
.pv-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(8,8,10,0.94);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

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

.pv-stage {
  position: relative;
  flex: 1;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4.5rem 5rem;
  min-height: 0;
  /* F11 — without this, the browser's own native scroll/pinch-zoom
     competes with the custom Pointer Events zoom/pan handling in
     photos.js for any touch starting here. Scoped to the viewer stage
     only — never the page's viewport meta tag, which would disable
     zoom accessibility site-wide. */
  touch-action: none;
}

.pv-stage img {
  /* `width/height: 100%` + object-fit, not max-width/max-height: an
     image sized only by max-width/max-height has no definite box of its
     own — its rendered size is derived from intrinsic size clamped by a
     percentage, and on iOS Safari that derived box does not reliably get
     recomputed when an ancestor (.pv-stage, sized via flex:1 inside the
     fixed-position .pv-overlay) changes size after an orientation
     rotation, so the image visually stays at its pre-rotation portrait
     size. Giving the image a definite 100%/100% box removes that
     intrinsic-size dependency entirely — the box is always exactly
     .pv-stage's current content box, trivially correct on every reflow —
     and object-fit: contain still does the aspect-ratio-preserving
     scale/letterbox within that box exactly as before. */
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 6px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
  touch-action: none; /* F11 — see .pv-stage's own touch-action for why */
  /* Zoom/pan (photos.js) transforms only this element — transform-origin
     keeps scaling centered, will-change hints the browser this repaints
     often during wheel zoom. Never affects layout/box size, so it can't
     change the stage/overlay's own dimensions. */
  transform-origin: center center;
  will-change: transform;
  user-select: none;
  -webkit-user-drag: none;
}

/* Large, forgiving tap/click zones for Previous/Next — the visible round
   buttons stay for affordance, but real thumbs/mice rarely land precisely
   on a 40px circle. This is what actually makes repeated navigation
   reliable, especially on phones. */
.pv-zone {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 38%;
  z-index: 1;
  cursor: pointer;
  touch-action: manipulation;
}
.pv-zone-prev { left: 0; }
.pv-zone-next { right: 0; }

/* Small, unobtrusive indicator while the full-resolution image is still
   loading behind the instant thumbnail preview. */
.pv-loading {
  position: absolute;
  top: 50%; left: 50%;
  width: 28px; height: 28px;
  margin: -14px 0 0 -14px;
  border-radius: 50%;
  border: 2.5px solid rgba(255,255,255,0.25);
  border-top-color: rgba(255,255,255,0.85);
  z-index: 2;
  opacity: 0;
  pointer-events: none;
  transition: opacity 150ms ease;
  animation: pv-spin 0.8s linear infinite;
}
.pv-loading.visible { opacity: 1; }

@keyframes pv-spin { to { transform: rotate(360deg); } }

.pv-btn {
  position: relative;
  z-index: 3;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: rgba(255,255,255,0.1);
  border: 1px solid rgba(255,255,255,0.14);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  touch-action: manipulation;
  transition: background var(--transition);
}

.pv-btn:hover { background: rgba(255,255,255,0.2); }

.pv-close  { position: absolute; top: 1.25rem; right: 1.25rem; }
.pv-prev   { position: absolute; left: 1.25rem; top: 50%; transform: translateY(-50%); }
.pv-next   { position: absolute; right: 1.25rem; top: 50%; transform: translateY(-50%); }

.pv-bottom {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-bottom: 1.5rem;
}

.pv-counter {
  color: rgba(255,255,255,0.6);
  font-size: 0.78rem;
  min-width: 60px;
  text-align: center;
}

.pv-delete:hover { background: rgba(220,38,38,0.6); }

@media (max-width: 700px) {
  .pv-stage { padding: 4rem 1rem; }
  .pv-prev  { left: 0.5rem; }
  .pv-next  { right: 0.5rem; }
  .pv-btn   { width: 34px; height: 34px; }
}

/* Landscape phones: max-width:700px above doesn't catch these (a rotated
   phone is often >700px wide), but the short height is the real
   constraint here -- the desktop 4.5rem top/bottom padding eats ~144px
   off an ~390px-tall screen, badly undersizing the photo. Width stays
   plentiful in landscape, so only the vertical padding needs shrinking. */
@media (max-height: 500px) and (orientation: landscape) {
  .pv-stage { padding: 1rem 4rem; }
}

/* ─── SYNC PANEL ─────────────────────────────────────────────── */
.sync-overlay {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: rgba(0,0,0,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Keeps the panel clear of the iPhone notch/Dynamic Island and home
     indicator; harmless everywhere else since it's just padding around
     an already-centered box. */
  padding: max(1rem, env(safe-area-inset-top)) 1rem max(1rem, env(safe-area-inset-bottom));
  /* Second, independent line of defense (see the mobile override below
     and .sync-panel's own max-height/overflow) -- if the panel still
     ends up taller than the visible area for any reason, the overlay
     itself can scroll to reach it, rather than the content being
     unreachable. */
  overflow-y: auto;
}

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

@media (max-width: 900px) {
  .sync-overlay {
    /* A real iPhone still clipped the panel's top under centering, even
       with the height cap below -- confirmed by real-device testing,
       not assumed away. iOS Safari's dynamic toolbar means the "available
       height" used to center a box isn't reliably the actual visible
       height at the moment it's computed; centering then splits whatever
       error there is between the top AND bottom, so the top can end up
       pushed above y=0 with nothing to scroll to reach it. Anchoring to
       the top instead removes the dependency on that calculation being
       exactly right: the panel's top edge is pinned at a small, fixed,
       always-visible offset no matter what the real toolbar is doing,
       and only the bottom -- which the height cap + scroll below already
       handle -- can ever extend past the fold. Desktop is unaffected,
       centered exactly as before, since this only applies here. */
    align-items: flex-start;
  }
}

.sync-panel {
  width: min(360px, 90vw);
  /* iOS Safari's layout viewport (100vh) stays large even while the
     address-bar toolbar is covering part of the screen, so a centered,
     unconstrained-height panel can render with its top edge above the
     actually-visible area, with nothing to scroll to reach it. Capping
     the height and scrolling internally fixes that; svh (small viewport
     height) is the unit made for exactly this, with a vh fallback for
     anything that doesn't support it -- the second declaration simply
     wins in browsers that understand it. On desktop this cap is well
     above the panel's natural height, so it never engages and nothing
     here changes desktop's existing centered look. */
  max-height: min(85vh, calc(100vh - 2rem));
  max-height: min(85svh, calc(100svh - 2rem));
  overflow-y: auto;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.sync-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--text-primary);
  /* Stays reachable even if the panel's own content scrolls internally
     (see .sync-panel's max-height/overflow above) -- the close button
     must never scroll out of reach. */
  position: sticky;
  top: 0;
  background: var(--bg-card);
  z-index: 1;
}

/* #syncClose reuses .pv-btn's shape/sizing, but .pv-btn's own colors (a
   pale, translucent white icon on translucent white) were tuned for the
   near-black .pv-overlay -- on this light .sync-panel card that leaves the
   close button essentially invisible (confirmed by rendering it: no visible
   glyph, just blank white-on-white), not merely low-contrast. Overriding
   color/background/border here for this specific instance restores real
   visibility without touching .pv-btn's actual usage in the photo viewer. */
.sync-panel-head .pv-btn {
  background: var(--bg-subtle);
  border-color: var(--border);
  color: var(--text-secondary);
}
.sync-panel-head .pv-btn:hover {
  background: var(--border);
  color: var(--text-primary);
}

.sync-row { display: flex; flex-direction: column; gap: 0.4rem; }
.sync-row[hidden] { display: none; }

.sync-mode-toggle {
  display: flex;
  background: var(--bg-subtle);
  border-radius: var(--radius);
  padding: 3px;
  gap: 3px;
}

.sync-mode-btn {
  flex: 1;
  padding: 0.5rem;
  border-radius: calc(var(--radius) - 3px);
  font-size: 0.8rem;
  font-weight: 600;
  font-family: inherit;
  color: var(--text-secondary);
  cursor: pointer;
}

.sync-mode-btn.active {
  background: var(--bg-card);
  color: var(--accent);
  box-shadow: var(--shadow-sm);
}

.sync-label {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  font-weight: 500;
}

.sync-select {
  padding: 0.5rem 0.6rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 0.82rem;
}

.sync-trigger {
  padding: 0.65rem;
  border-radius: var(--radius);
  background: var(--accent);
  color: #fff;
  font-weight: 600;
  font-size: 0.85rem;
  font-family: inherit;
}

.sync-trigger:hover { opacity: 0.9; }
.sync-trigger:disabled { opacity: 0.5; cursor: default; }

.conflict-cancel {
  padding: 0.6rem;
  border-radius: var(--radius);
  background: none;
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-weight: 600;
  font-size: 0.85rem;
  font-family: inherit;
  cursor: pointer;
}
.conflict-cancel:hover { color: var(--text-primary); border-color: var(--border-strong); }

.sync-status {
  font-size: 0.74rem;
  color: var(--text-tertiary);
  line-height: 1.5;
}

/* Honest current-capability notice (Automatic mode) -- deliberately a
   distinct boxed treatment, not plain body text, so it reads as a
   status fact rather than incidental copy. */
.sync-notice {
  font-size: 0.76rem;
  color: var(--text-tertiary);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 0.7rem;
  line-height: 1.5;
}

/* Plain-language per-run result breakdown (Manual mode). */
.sync-result {
  border-top: 1px solid var(--border);
  padding-top: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.sync-result[hidden] { display: none; }

.sync-result-line {
  font-size: 0.82rem;
  color: var(--text-secondary);
}
.sync-result-added  { color: var(--accent); font-weight: 600; }
.sync-result-failed { color: #d64545; }
.sync-result-empty  { color: var(--text-tertiary); }

.sync-summary {
  border-top: 1px solid var(--border);
  padding-top: 0.75rem;
  font-size: 0.78rem;
  color: var(--text-secondary);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.3rem 0.75rem;
}

.sync-progress-bar {
  width: 100%;
  height: 5px;
  border-radius: 3px;
  background: var(--bg-subtle);
  overflow: hidden;
}

.sync-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.2s ease;
}

/* ─── RESPONSIVE ─────────────────────────────────────────────── */
@media (max-width: 900px) {
  .photos-page {
    grid-template-columns: 1fr;
  }
  .photos-side {
    flex-direction: row;
    padding: 1rem 5% 0;
  }
  .photos-tile {
    width: auto;
    margin: 0;
    flex: 1;
    aspect-ratio: auto;
    flex-direction: row;
    padding: 0.75rem 1rem;
    font-size: 0.72rem;
    gap: 0.6rem;
  }
  .photos-tile-icon { width: 28px; height: 28px; }
  .photos-main { padding: 1rem 5% 2rem; }

  /* The shared navbar hides its center nav below 900px (layout.css) —
     here it holds the Photos/Movies/Music/Books domains, not the
     Assistant/Runtime/Devices items it hides for elsewhere, so it needs
     to stay visible. Logo + domain nav + runtime/theme/avatar cluster
     don't fit on one mobile line, so the nav wraps onto its own line
     within the same navbar (still one component, not a second bar). */
  .navbar { flex-wrap: wrap; height: auto; padding: 0.55rem 4%; row-gap: 0.4rem; }
  .navbar-nav {
    display: flex;
    position: static;
    left: auto;
    transform: none;
    order: 3;
    flex-basis: 100%;
    width: 100%;
    justify-content: center;
    gap: 0.3rem;
  }
  .navbar-nav .nav-item { padding: 0.3rem 0.55rem; font-size: 0.72rem; }
  .photos-page { padding-top: 5.5rem; }
}

@media (max-width: 480px) {
  .photos-grid { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 0.5rem; }
  .photos-side { flex-direction: column; }
}

/* ─── FOOTER (same principle as Home) ────────────────────────── */
.principles-strip {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 1.75rem;
  padding: 1.5rem 5%;
  margin-top: 1rem;
  border-top: 1px solid var(--border);
}

.principle-item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--text-tertiary);
  white-space: nowrap;
}

.principle-item svg { flex-shrink: 0; opacity: 0.7; }

@media (max-width: 700px) {
  .principle-item { font-size: 0.66rem; }
}
