/* Neutral, low-chroma palette with a single accent - colour is reserved for
   the one action that matters on a screen, everything else is greyscale so
   the photos stay the loudest thing in the UI. */
:root {
  --bg: #fbfbfd;
  --surface: #ffffff;
  --surface-2: #f5f5f7;
  --border: rgba(0, 0, 0, 0.09);
  --text: #1d1d1f;
  --text-dim: #6e6e73;
  --accent: #0071e3;
  --accent-dark: #0077ed;
  --accent-soft: #f0f6ff;
  --danger: #d70015;
  --danger-dark: #b3000f;
  --radius: 14px;
  --radius-sm: 10px;
  --radius-pill: 980px;
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.12);
  color-scheme: light;
}

/* Follows the OS preference automatically unless the user picks a theme
   explicitly via the toggle (which stamps data-theme on <html>). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #000000;
    --surface: #1c1c1e;
    --surface-2: #2c2c2e;
    --border: rgba(255, 255, 255, 0.12);
    --text: #f5f5f7;
    --text-dim: #98989d;
    --accent: #0a84ff;
    --accent-dark: #409cff;
    --accent-soft: #1c2c40;
    --danger: #ff453a;
    --danger-dark: #ff6961;
    --shadow-sm: none;
    --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.6);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #000000;
  --surface: #1c1c1e;
  --surface-2: #2c2c2e;
  --border: rgba(255, 255, 255, 0.12);
  --text: #f5f5f7;
  --text-dim: #98989d;
  --accent: #0a84ff;
  --accent-dark: #409cff;
  --accent-soft: #1c2c40;
  --danger: #ff453a;
  --danger-dark: #ff6961;
  --shadow-sm: none;
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.6);
  color-scheme: dark;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", "Segoe UI", Roboto, system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Large type gets tightened tracking and a lighter weight, the way Apple
   sets headlines - bold-and-wide reads as heavy next to a photo grid. */
h1 {
  font-size: 2rem;
  font-weight: 600;
  letter-spacing: -0.021em;
  line-height: 1.1;
  margin: 0 0 8px;
}
h2 { font-size: 1.25rem; font-weight: 600; letter-spacing: -0.014em; }
h3 { font-size: 1rem; font-weight: 600; letter-spacing: -0.01em; }

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

/* The menu runs down the left rather than across the top. The old bar had six
   destinations plus a dropdown, language, theme, name and sign-out fighting for
   one line; vertically there is room for all of it, plus a count beside each
   entry and the storage bar at the foot.

   The offset for the page content comes from `.sidebar ~ main` below: the
   sidebar is rendered immediately before each page's <main>, so no view needed
   restructuring, and a page without a sidebar (login, a public share link)
   simply doesn't match. */
:root {
  --sidebar-w: 208px;
  --sidebar-w-collapsed: 62px;
  --mobile-bar-h: 52px;
}
:root.sidebar-collapsed {
  --sidebar-w: var(--sidebar-w-collapsed);
}

.sidebar {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--sidebar-w);
  z-index: 40;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--border);
  padding: 10px 8px 8px;
  overflow-y: auto;
  overflow-x: hidden;
  transition: width 0.18s ease;
}
/* Suppressed for the first two frames after load so a folded bar doesn't
   animate open while the page is still settling. */
:root.sidebar-no-transition .sidebar { transition: none; }

/* width: auto matters as much as the margin - .page sets width: 100%, which
   with a left margin adds up to wider than the window and gives the whole page
   a horizontal scrollbar. */
.sidebar ~ main { margin-left: var(--sidebar-w); width: auto; }

.sidebar-head {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 2px 8px;
  min-height: 44px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-decoration: none;
  color: var(--text);
  min-width: 0;
  flex: 1;
}
.brand-logo-icon { height: 34px; width: auto; display: block; flex: 0 0 auto; }
.brand-logo-wordmark { height: 22px; width: auto; display: block; }
.brand-logo-wordmark-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-logo-wordmark-light { display: none; }
  :root:not([data-theme="light"]) .brand-logo-wordmark-dark { display: block; }
}
:root[data-theme="dark"] .brand-logo-wordmark-light { display: none; }
:root[data-theme="dark"] .brand-logo-wordmark-dark { display: block; }

.sidebar-collapse {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0;
}
.sidebar-collapse:hover { background: var(--surface-2); color: var(--text); }

.sidebar-nav { display: flex; flex-direction: column; gap: 1px; }
.sidebar-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 9px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--text);
  font-size: 0.875rem;
  white-space: nowrap;
}
.sidebar-item:hover { background: var(--surface-2); text-decoration: none; }
/* The page you are on, in the one accent this design allows itself. */
.sidebar-item-active { background: var(--accent-soft); color: var(--accent); font-weight: 500; }
.sidebar-item-active:hover { background: var(--accent-soft); color: var(--accent); }
.sidebar-icon {
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
}
.sidebar-icon svg { width: 18px; height: 18px; display: block; }
.sidebar-item-active .sidebar-icon { color: var(--accent); }
.sidebar-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sidebar-count {
  flex: 0 0 auto;
  font-size: 0.6875rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.sidebar-item-active .sidebar-count { color: var(--accent); }
/* Accounts still waiting to be let in - a job, not a total. */
.sidebar-count-alert {
  background: var(--accent);
  color: #fff;
  border-radius: var(--radius-pill);
  padding: 1px 7px;
}
.sidebar-group-label {
  font-size: 0.6875rem;
  color: var(--text-dim);
  padding: 14px 11px 4px;
  border-top: 1px solid var(--border);
  margin: 10px 2px 2px;
  white-space: nowrap;
}

.sidebar-foot { margin-top: auto; padding-top: 12px; }
.sidebar-quota {
  display: block;
  text-decoration: none;
  padding: 6px 9px 9px;
  border-radius: var(--radius-sm);
}
.sidebar-quota:hover { background: var(--surface-2); text-decoration: none; }
.sidebar-quota-text { display: block; font-size: 0.6875rem; color: var(--text-dim); margin-bottom: 5px; white-space: nowrap; }
.sidebar-quota-track {
  display: block;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  overflow: hidden;
}
.sidebar-quota-bar { display: block; height: 100%; background: var(--accent); border-radius: var(--radius-pill); }

.sidebar-account { border-top: 1px solid var(--border); padding-top: 6px; }
.sidebar-account > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 9px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  list-style: none;
  font-size: 0.875rem;
}
.sidebar-account > summary::-webkit-details-marker { display: none; }
.sidebar-account > summary:hover { background: var(--surface-2); }
.sidebar-avatar {
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-dim);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
}
.sidebar-account-caret { flex: 0 0 auto; font-size: 0.75rem; color: var(--text-dim); }
.sidebar-account[open] .sidebar-account-caret { transform: rotate(180deg); }
.sidebar-account-menu {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  padding: 4px 0 2px;
}
.sidebar-account-menu a,
.sidebar-account-menu .link-button {
  display: block;
  /* A block-level <button> still shrinks to its text, so "Abmelden" would be a
     narrow hit area in a full-width row. */
  width: 100%;
  padding: 8px 9px;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  color: var(--text);
  text-decoration: none;
  text-align: left;
  white-space: nowrap;
}
.sidebar-account-menu a:hover,
.sidebar-account-menu .link-button:hover { background: var(--surface-2); text-decoration: none; }
.sidebar-account-menu .inline-form { display: block; }
/* Scoped through the menu so it outranks .theme-toggle-btn's grey pill, which
   is right on the login hero but reads as an odd lone button in a list of
   plain rows. */
.sidebar-account-menu .theme-toggle-btn {
  justify-content: flex-start;
  padding: 0 9px;
  height: 34px;
  background: transparent;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
}
.sidebar-account-menu .theme-toggle-btn:hover { background: var(--surface-2); }

/* Folded to icons: labels, counts, the storage bar and the account menu all go,
   leaving a column of symbols. Their title attributes carry the names. */
:root.sidebar-collapsed .sidebar { padding-left: 6px; padding-right: 6px; }
:root.sidebar-collapsed .sidebar-label,
:root.sidebar-collapsed .sidebar-count,
:root.sidebar-collapsed .sidebar-quota,
:root.sidebar-collapsed .sidebar-account-caret,
:root.sidebar-collapsed .brand-logo-wordmark,
:root.sidebar-collapsed .sidebar-group-label { display: none; }
:root.sidebar-collapsed .sidebar-item,
:root.sidebar-collapsed .sidebar-account > summary { justify-content: center; padding-left: 0; padding-right: 0; }
:root.sidebar-collapsed .sidebar-head { flex-direction: column; gap: 6px; }
:root.sidebar-collapsed .sidebar-account-menu { display: none; }
/* The separator the group label carried has to come from somewhere once the
   label itself is hidden. */
:root.sidebar-collapsed .sidebar-group-label + .sidebar-item { border-top: 1px solid var(--border); margin-top: 8px; padding-top: 12px; }

/* Only exists on phones, where the sidebar is a drawer and something has to
   hold the button that opens it. */
.mobile-bar { display: none; }

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  flex: 0 0 auto;
}
.nav-toggle span {
  display: block;
  height: 2px;
  width: 22px;
  background: var(--text);
  border-radius: 2px;
}

.sidebar-backdrop {
  position: fixed;
  inset: 0;
  z-index: 35;
  background: rgba(0, 0, 0, 0.4);
}
.sidebar-backdrop[hidden] { display: none; }

@media (max-width: 900px) {
  /* Off-canvas: the bar slides in over the page instead of taking width from
     it, which on a phone there is none of to give. */
  .sidebar {
    width: 264px;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: var(--shadow-lg);
  }
  .sidebar.sidebar-open { transform: none; }
  .sidebar ~ main { margin-left: 0; }
  /* Folding is a desktop affordance; a drawer is already out of the way. */
  .sidebar-collapse { display: none; }
  :root.sidebar-collapsed .sidebar-label,
  :root.sidebar-collapsed .sidebar-count,
  :root.sidebar-collapsed .sidebar-quota,
  :root.sidebar-collapsed .sidebar-account-caret,
  :root.sidebar-collapsed .brand-logo-wordmark,
  :root.sidebar-collapsed .sidebar-group-label { display: revert; }
  :root.sidebar-collapsed .sidebar-item,
  :root.sidebar-collapsed .sidebar-account > summary { justify-content: flex-start; padding-left: 9px; padding-right: 9px; }
  :root.sidebar-collapsed .sidebar-head { flex-direction: row; }
  :root.sidebar-collapsed .sidebar-account-menu { display: flex; }
  :root.sidebar-collapsed .sidebar-group-label + .sidebar-item { border-top: 0; margin-top: 0; padding-top: 8px; }

  .mobile-bar {
    display: flex;
    align-items: center;
    gap: 4px;
    position: sticky;
    top: 0;
    z-index: 30;
    min-height: var(--mobile-bar-h);
    padding: 3px 10px;
    background: color-mix(in srgb, var(--surface) 82%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    border-bottom: 1px solid var(--border);
  }
  @supports not (background: color-mix(in srgb, red 50%, transparent)) {
    .mobile-bar { background: var(--surface); }
  }
  .nav-toggle { display: flex; }
  .mobile-bar .brand-logo-icon { height: 30px; }
  .mobile-bar .brand-logo-wordmark { height: 19px; }
  /* With the drawer open its own logo sits right where the bar's logo is, and
     two wordmarks side by side read as a rendering fault. visibility rather
     than display so nothing in the bar shifts. */
  body.sidebar-drawer-open .mobile-bar .brand { visibility: hidden; }
  /* Larger touch targets in the drawer than the mouse version needs: 13px of
     padding around an 18px line comes to the 44px a fingertip wants. */
  .sidebar-item,
  .sidebar-account > summary { padding-top: 13px; padding-bottom: 13px; }
  .sidebar-account-menu a,
  .sidebar-account-menu .link-button { padding-top: 13px; padding-bottom: 13px; }
  body.sidebar-drawer-open { overflow: hidden; }
}

.theme-toggle-btn {
  background: var(--surface-2);
  border: none;
  color: var(--text);
  border-radius: var(--radius-pill);
  height: 32px;
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 14px;
  white-space: nowrap;
  transition: background 0.2s ease;
}
.theme-toggle-btn:hover { background: color-mix(in srgb, var(--surface-2) 85%, var(--text)); }

.lang-switch { display: inline-flex; gap: 2px; font-size: 0.8125rem; }
.lang-switch a {
  padding: 5px 9px;
  border-radius: 7px;
  color: var(--text-dim);
  text-decoration: none;
  font-weight: 400;
}
.lang-switch a:hover { background: var(--surface-2); text-decoration: none; }

.hero-utils .lang-switch a { color: #1c2430; }

.auth-lang-switch { display: flex; justify-content: center; margin-top: 16px; }

.hero-utils {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 5;
  display: flex;
  gap: 8px;
}
.hero-utils .theme-toggle-btn {
  background: rgba(255, 255, 255, 0.85);
  border: none;
  color: #1c2430;
}
.hero-utils .theme-toggle-btn:hover { background: #fff; }

.page {
  width: 100%;
  padding: 32px 24px 64px;
}

@media (max-width: 640px) {
  .page { padding: 20px 18px 56px; }
  /* A 2rem headline wraps to three lines on a phone; scaling it down keeps
     the title to one or two lines without shrinking body text. */
  h1 { font-size: 1.5rem; }
}

.auth-page {
  max-width: 420px;
  margin: 60px auto;
  padding: 0 20px;
}
.auth-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 36px;
}
.auth-card h1 { margin-top: 0; font-size: 1.5rem; letter-spacing: -0.016em; }
.auth-footer { text-align: center; color: var(--text-dim); font-size: 0.875rem; }

.hero-split {
  position: relative;
  display: flex;
  min-height: 100vh;
  background-image: url('/img/background.svg');
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}
.hero-left {
  flex: 1 1 50%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 40px;
}
.hero-logo-wrap {
  background: transparent;
  padding: 0;
  border-radius: 0;
  box-shadow: none;
  max-width: 90%;
}
/* The logo file itself has an opaque white background baked into the
   artwork; multiply-blending it against the photo makes that white square
   disappear so the logo appears to sit transparently on the background. */
.hero-logo { display: block; width: min(60vw, 380px); height: auto; mix-blend-mode: multiply; }
.hero-right {
  flex: 1 1 50%;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 24px;
}
.hero-right .auth-card { width: 100%; max-width: 420px; box-shadow: 0 16px 50px rgba(10, 14, 30, 0.3); }

@media (max-width: 900px) {
  .hero-split { flex-direction: column; background-attachment: scroll; }
  .hero-left { flex: 0 0 auto; min-height: 220px; padding: 24px; justify-content: center; }
  .hero-logo { width: min(55vw, 220px); }
  .hero-right { flex: 1 1 auto; padding: 32px 16px 56px; justify-content: center; }
}

.stack-form { display: flex; flex-direction: column; gap: 16px; }
.stack-form label { display: flex; flex-direction: column; gap: 7px; font-size: 0.8125rem; color: var(--text-dim); }
.stack-form input {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 1rem;
  background: var(--surface);
  color: var(--text);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.stack-form input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.password-field { position: relative; display: flex; }
.password-field input { flex: 1; width: 100%; padding-right: 40px; }
.password-toggle-btn {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  background: none;
  border: none;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 6px 8px;
  color: var(--text-dim);
  border-radius: 6px;
}
.password-toggle-btn:hover { background: var(--bg); }

/* Pill-shaped, flat, no borders on the filled variants - the shape carries
   the affordance instead of a stroke. */
.btn {
  display: inline-block;
  border: none;
  border-radius: var(--radius-pill);
  padding: 9px 20px;
  font-size: 0.875rem;
  font-weight: 400;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  transition: background 0.2s ease, opacity 0.2s ease;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dark); }
.btn-secondary { background: var(--surface-2); color: var(--text); }
.btn-secondary:hover { background: color-mix(in srgb, var(--surface-2) 85%, var(--text)); }
.btn-danger { background: transparent; color: var(--danger); }
.btn-danger:hover { background: color-mix(in srgb, var(--danger) 10%, transparent); }
/* Disabled buttons drop their colour entirely rather than fading it - a
   washed-out blue or pink reads as a rendering glitch, a grey chip reads as
   "not available yet". */
.btn:disabled,
.btn:disabled:hover {
  background: var(--surface-2);
  color: var(--text-dim);
  opacity: 0.65;
  cursor: not-allowed;
}
.btn-icon-only {
  width: 36px;
  height: 36px;
  padding: 0;
  font-size: 1.25rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn-small { padding: 6px 14px; font-size: 0.8125rem; }

.inline-form { display: inline-block; }
.link-button {
  background: none;
  border: none;
  color: var(--text-dim);
  font-weight: 500;
  cursor: pointer;
  padding: 0;
  font-size: 0.95rem;
}
.link-button:hover { color: var(--accent); }

.alert { padding: 12px 16px; border-radius: var(--radius-sm); font-size: 0.875rem; margin-bottom: 16px; }
.alert-error { background: color-mix(in srgb, var(--danger) 10%, transparent); color: var(--danger); }
.alert-success { background: color-mix(in srgb, #34c759 12%, transparent); color: #248a3d; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .alert-success { color: #30d158; }
}
:root[data-theme="dark"] .alert-success { color: #30d158; }

.hint { color: var(--text-dim); font-size: 0.875rem; }

.upload-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  margin-bottom: 24px;
}
.upload-box h2 { margin-top: 0; font-size: 1.0625rem; }
.upload-form { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.upload-form input[type="file"] { flex: 1; min-width: 220px; }

.dropzone {
  flex: 1;
  min-width: 220px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  transition: border-color 0.15s, background 0.15s;
}
.dropzone.dropzone-active {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.dropzone input[type="file"] { width: 100%; }
.dropzone-hint { margin: 0; }

.guest-upload-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
}
.guest-upload-logo,
.guest-upload-wordmark { height: 44px; width: auto; display: block; }
.guest-upload-wordmark-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .guest-upload-wordmark-light { display: none; }
  :root:not([data-theme="light"]) .guest-upload-wordmark-dark { display: block; }
}
:root[data-theme="dark"] .guest-upload-wordmark-light { display: none; }
:root[data-theme="dark"] .guest-upload-wordmark-dark { display: block; }

.upload-request-box { margin-top: 8px; }
.upload-request-link-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin: 10px 0;
}
.upload-request-link-row input {
  flex: 1;
  min-width: 240px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.85rem;
  background: var(--bg);
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.mobile-upload-btn {
  flex: 1;
  min-width: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 15px 18px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-weight: 400;
  font-size: 0.9375rem;
  color: var(--text);
  cursor: pointer;
}
.mobile-upload-btn:hover { background: color-mix(in srgb, var(--surface-2) 85%, var(--text)); }
.file-input-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.upload-progress {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}
.upload-progress[hidden] { display: none; }
.upload-progress-track {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  background: var(--bg);
  border: 1px solid var(--border);
  overflow: hidden;
}
.upload-progress-bar {
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.15s ease;
}
.upload-progress-label {
  font-size: 0.85rem;
  color: var(--text-dim);
  font-weight: 600;
  min-width: 3.5em;
  text-align: right;
}

.upload-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 18, 0.6);
  z-index: 1100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.upload-modal-overlay[hidden] { display: none; }
.upload-modal-panel {
  background: var(--surface);
  border-radius: 18px;
  padding: 32px;
  max-width: 520px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  position: relative;
  box-shadow: var(--shadow-lg);
}
.upload-modal-panel h2 { margin-top: 0; font-size: 1.0625rem; }
.upload-modal-panel .upload-form { flex-direction: column; align-items: stretch; }
.upload-modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  background: none;
  border: none;
  font-size: 1.2rem;
  cursor: pointer;
  color: var(--text-dim);
}

.gallery-toolbar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 18px;
}

.sort-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 24px;
}
.sort-bar a {
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  border: none;
  background: var(--surface-2);
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.8125rem;
  font-weight: 400;
  transition: background 0.2s ease, color 0.2s ease;
}
.sort-bar a:hover { color: var(--text); text-decoration: none; }
.sort-bar a.sort-active { background: var(--text); color: var(--surface); }
.toolbar-actions,
.toolbar-secondary {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.photo-grid {
  position: relative;
  /* Height is set inline by justified-layout.js once it has measured every
     item; until then this keeps the grid from collapsing to 0 height. */
  min-height: 160px;
}
.photo-card {
  position: absolute;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin: 0;
  transition: box-shadow 0.4s ease, left 0.2s ease, top 0.2s ease, width 0.2s ease, height 0.2s ease;
}
.photo-card-highlight {
  box-shadow: 0 0 0 3px var(--accent);
}
.photo-media {
  position: relative;
  display: block;
  cursor: pointer;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #111;
}
.photo-media:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  z-index: 1;
}
.photo-card img,
.photo-card video {
  position: absolute;
  top: 50%;
  left: 50%;
  object-fit: cover;
  display: block;
}
.media-type-badge {
  position: absolute;
  bottom: 8px;
  right: 8px;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 0.75rem;
  padding: 2px 8px;
  border-radius: 999px;
  z-index: 2;
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: 4px;
}
.photo-select {
  position: absolute;
  top: 8px;
  left: 8px;
  background: rgba(255, 255, 255, 0.85);
  border-radius: 6px;
  padding: 4px;
  z-index: 2;
}
.photo-select input { width: 18px; height: 18px; }
.photo-meta-extra:not([hidden]) {
  padding: 8px 12px;
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
  color: #f0f2f7;
  z-index: 2;
}

/* Introduces each person's group when the grid is sorted by who added the
   photos. Absolutely positioned like the cards, since the justified layout
   places every child itself. */
.user-band {
  position: absolute;
  left: 0;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.user-band span {
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}
/* The first group needs no line above it - there is nothing to separate from. */
.photo-grid > .user-band:first-child {
  border-top: 0;
  padding-top: 0;
}

.admin-section { margin-bottom: 32px; }
.user-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.user-table th, .user-table td {
  text-align: left;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
}
.user-table th { background: var(--surface-2); color: var(--text-dim); font-weight: 500; }
.user-table tr:last-child td { border-bottom: none; }
.user-table .actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* One row per person: access box, name, delete switch. Fixed side columns
   with the name taking the slack keeps the switches in a straight line
   however long the names are. */
.member-list {
  display: flex;
  flex-direction: column;
  margin-bottom: 12px;
  max-height: 340px;
  overflow-y: auto;
}
.member-row {
  display: grid;
  grid-template-columns: 34px 1fr 112px;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  border-radius: 8px;
  min-height: 40px;
}
.member-row:not(.member-head):hover { background: var(--surface-2); }
.member-head {
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-dim);
  min-height: 0;
  padding-top: 0;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--text-dim);
  border-radius: 0;
  margin-bottom: 2px;
}
.member-row.member-head .member-name {
  font-size: 0.75rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  cursor: default;
}
.member-row .member-access { display: flex; justify-content: center; }
.member-row .member-access input { width: 18px; height: 18px; margin: 0; }
.member-row .member-delete { display: flex; justify-content: center; }
.member-head .member-delete,
.member-head .member-access { justify-content: center; text-align: center; }
/* Name and address share the middle column and collapse to one line each on
   narrow screens rather than wrapping mid-word. */
/* Needs .member-row in front: the plain class alone loses to
   `.stack-form label`, which stacks its children and dims them - right for
   the name/description fields above, wrong for a table row. */
.member-row .member-name {
  display: flex;
  flex-direction: row;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
  margin: 0;
  cursor: pointer;
  font-size: 0.9375rem;
  color: var(--text);
}
.member-row .member-name-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.member-row .member-name .hint { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Admins may always delete, so their row states that instead of offering a
   switch that could not be turned off. */
.member-always { font-size: 0.8125rem; color: var(--text-dim); }

@media (max-width: 560px) {
  .member-row { grid-template-columns: 30px 1fr 64px; }
  .member-row .member-name { flex-direction: column; align-items: flex-start; gap: 0; }
  .member-head { font-size: 0.7rem; }
}

/* iOS-style switch built on a real checkbox, so it keeps keyboard focus and
   form semantics without any JavaScript. */
.switch { display: inline-flex; gap: 0; cursor: pointer; }
.switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.switch-track {
  width: 44px;
  height: 26px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  border: 1px solid var(--border);
  display: block;
  position: relative;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.switch-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 0.18s ease;
}
.switch input:checked + .switch-track {
  background: var(--accent);
  border-color: var(--accent);
}
.switch input:checked + .switch-track .switch-knob { transform: translateX(18px); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch input:disabled + .switch-track { opacity: 0.4; }
.switch:has(input:disabled) { cursor: not-allowed; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.cover-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* Wider than the standard modal so a row holds several thumbnails. */
.cover-picker-panel { max-width: 720px; }
.cover-picker-panel .cover-picker { margin-top: 16px; margin-bottom: 0; }

.cover-current {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-bottom: 18px;
}
.cover-preview {
  width: 140px;
  height: 100px;
  object-fit: cover;
  border-radius: 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.cover-preview-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  color: var(--text-dim);
}
.cover-subheading { font-size: 0.95rem; margin: 18px 0 8px; }
.settings-preview {
  width: 100%;
  height: 140px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background-color: var(--bg);
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 8px;
}
.settings-reset-form { margin-top: 14px; }
.cover-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 8px;
}
.cover-picker-item { margin: 0; }
.cover-picker-thumb {
  padding: 0;
  border: 2px solid transparent;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  background: none;
  display: block;
  width: 90px;
  height: 68px;
}
.cover-picker-thumb:hover { border-color: var(--accent); }
.cover-picker-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.album-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 24px;
  margin-bottom: 24px;
}
/* Borderless: the cover image itself defines the card's edge, and a very
   soft lift on hover replaces the old accent-coloured outline. */
.album-card {
  background: transparent;
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: var(--text);
  display: flex;
  flex-direction: column;
  transition: transform 0.25s ease;
}
.album-card:hover { text-decoration: none; transform: translateY(-2px); }
.album-cover {
  width: 100%;
  aspect-ratio: 4 / 3;
  height: auto;
  object-fit: cover;
  display: block;
  background: var(--surface-2);
  border-radius: var(--radius);
}
.album-cover-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.25rem;
  color: var(--text-dim);
}
.album-card-body {
  padding: 12px 2px 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.album-card h3 { margin: 0; font-size: 0.9375rem; font-weight: 500; }
.album-card .hint { margin: 0; font-size: 0.8125rem; }

.slideshow-overlay {
  position: fixed;
  inset: 0;
  /* Fully opaque: a photo viewer should be immersive, and letting the page
     ghost through behind the image muddies the colours you're judging. */
  background: #000;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.slideshow-overlay[hidden] { display: none; }
.slideshow-stage {
  flex: 1;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
}
.slideshow-media {
  max-width: 92vw;
  max-height: 80vh;
  object-fit: contain;
  background: #000;
  border-radius: 2px;
}
.slideshow-caption {
  color: rgba(255, 255, 255, 0.65);
  font-size: 0.8125rem;
  padding: 6px 12px 0;
  text-align: center;
  max-width: 80vw;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.slideshow-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 1.4rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.slideshow-btn:hover { background: rgba(255, 255, 255, 0.24); }
.slideshow-prev { left: 16px; }
.slideshow-next { right: 16px; }

.slideshow-topbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 8px 12px;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.6), transparent);
}
.slideshow-topbar-spacer { flex: 1 1 auto; }
.slideshow-icon-btn {
  background: none;
  border: none;
  color: #fff;
  font-size: 1.2rem;
  cursor: pointer;
  line-height: 1;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  flex: 0 0 auto;
}
.slideshow-icon-btn:hover { background: rgba(255, 255, 255, 0.15); }
.slideshow-icon-btn[hidden] { display: none; }
.slideshow-icon-btn.is-favorited { color: #ff375f; }
.slideshow-counter {
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.8125rem;
  min-width: 46px;
  text-align: center;
  white-space: nowrap;
}
.slideshow-more-wrap { position: relative; flex: 0 0 auto; }
/* Frosted dark menu, mirroring the iOS/macOS context menu look. */
.slideshow-menu {
  position: absolute;
  top: 46px;
  right: 0;
  background: rgba(42, 42, 44, 0.86);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  color: #f5f5f7;
  border-radius: 13px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  min-width: 240px;
  padding: 5px;
  display: flex;
  flex-direction: column;
  z-index: 10;
}
.slideshow-menu[hidden] { display: none; }
.slideshow-menu-item {
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  font-size: 0.9375rem;
  text-align: left;
  padding: 9px 13px;
  border-radius: 8px;
  cursor: pointer;
  text-decoration: none;
  display: block;
  width: 100%;
}
.slideshow-menu-item:hover { background: rgba(255, 255, 255, 0.1); text-decoration: none; }
.slideshow-menu-item[hidden] { display: none; }
.slideshow-menu-danger { color: #ff453a; }
.slideshow-menu-divider {
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
  margin: 5px 0;
}
.slideshow-menu-divider[hidden] { display: none; }

.album-picker-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 18, 0.6);
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.album-picker-overlay[hidden] { display: none; }
.album-picker-panel {
  background: var(--surface);
  border-radius: 18px;
  padding: 32px;
  max-width: 420px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
  position: relative;
  box-shadow: var(--shadow-lg);
}
.album-picker-panel h2 { margin: 0 30px 18px 0; font-size: 1.0625rem; }
.album-picker-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.album-picker-item {
  width: 100%;
  text-align: left;
  padding: 11px 13px;
  border-radius: var(--radius-sm);
  border: none;
  background: none;
  color: var(--text);
  cursor: pointer;
  font: inherit;
  font-size: 0.9375rem;
}
.album-picker-item:hover { background: var(--surface-2); }

.metadata-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8125rem;
  color: var(--text-dim);
  margin-left: 12px;
  cursor: pointer;
  vertical-align: middle;
}
.metadata-toggle input { width: 16px; height: 16px; }

/* Only fades in on hover/focus so a wall of thumbnails stays clean; still
   permanently visible on touch devices, which have no hover state. */
.info-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  /* Fixed dark icon color (not var(--text)): this button overlays arbitrary
     photo thumbnails, not the page background, so it must stay legible
     against its own light circle regardless of the site's light/dark theme. */
  color: #1d1d1f;
  font-size: 0.8125rem;
  cursor: pointer;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.photo-card:hover .info-btn,
.info-btn:focus-visible { opacity: 1; }
@media (hover: none) {
  .info-btn { opacity: 1; }
}
.info-btn:hover { background: #fff; }

.photo-meta-extra {
  font-size: 0.78rem;
  color: var(--text-dim);
  line-height: 1.35;
}

/* Docked to the right edge rather than centered, so the photo behind it stays
   visible while its metadata is open (matches how desktop photo apps do it). */
.metadata-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 18, 0.4);
  z-index: 1100;
  display: flex;
  align-items: stretch;
  justify-content: flex-end;
}
.metadata-overlay[hidden] { display: none; }
.metadata-panel {
  background: var(--surface);
  padding: 28px;
  width: 380px;
  max-width: 100%;
  overflow-y: auto;
  position: relative;
  box-shadow: -8px 0 40px rgba(0, 0, 0, 0.3);
}
@media (max-width: 640px) {
  /* On phones a 380px side panel would cover almost the whole screen anyway,
     so it becomes a bottom sheet instead. */
  .metadata-overlay { align-items: flex-end; justify-content: stretch; }
  .metadata-panel {
    width: 100%;
    max-height: 85vh;
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.3);
  }
}
.metadata-description-label { display: block; margin-bottom: 12px; }
.metadata-description {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
  resize: vertical;
}
.metadata-description-status { margin: -6px 0 12px; font-size: 0.8rem; }
.metadata-close {
  position: absolute;
  top: 14px;
  right: 14px;
  background: none;
  border: none;
  font-size: 1.2rem;
  cursor: pointer;
  color: var(--text-dim);
}
.metadata-title { margin: 0 30px 16px 0; font-size: 1.1rem; word-break: break-word; }
.metadata-list {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 16px;
  margin: 0 0 16px;
}
.metadata-list dt { color: var(--text-dim); font-size: 0.85rem; }
.metadata-list dd { margin: 0; font-size: 0.9rem; word-break: break-word; }
.metadata-map-wrap { border-radius: 10px; overflow: hidden; border: 1px solid var(--border); }
.metadata-map { width: 100%; height: 220px; border: none; display: block; }

.photo-map {
  width: 100%;
  height: 70vh;
  min-height: 360px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  overflow: hidden;
}

.map-pin-icon {
  background: transparent;
  border: none;
  position: relative;
}
.map-pin-icon svg { display: block; filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.35)); }
.map-pin-count {
  position: absolute;
  top: 2px;
  left: 50%;
  transform: translateX(-50%);
  background: #fff;
  color: #7a1c14;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.7rem;
  line-height: 1;
}

.map-popup { max-width: 240px; }
.map-popup-location {
  font-size: 0.8rem;
  color: var(--text-dim);
  margin-bottom: 8px;
  font-weight: 600;
}
.map-popup-photos {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  max-height: 260px;
  overflow-y: auto;
}
.map-popup-photo {
  width: 100px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.map-popup-photo img {
  width: 100px;
  height: 80px;
  object-fit: cover;
  border-radius: 6px;
  display: block;
  background: var(--bg);
}
.map-popup-photo-name {
  font-size: 0.72rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.map-popup-album-link { font-size: 0.72rem; }

/* ---- Admin: Server-Auslastung ---------------------------------------- */

.stat-grid {
  display: grid;
  /* 220px keeps all three cards on one row at normal desktop widths instead
     of dropping the disk card onto a lonely second line. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px;
  margin-bottom: 24px;
}
.stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px 24px;
}
.stat-card h2 {
  margin: 0 0 10px;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-dim);
}
/* Tabular figures so the number does not jiggle sideways on every refresh. */
.stat-value {
  margin: 0 0 14px;
  font-size: 2.25rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.meter {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  overflow: hidden;
  margin-bottom: 16px;
}
.meter-fill { display: block; height: 100%; border-radius: var(--radius-pill); }
/* Colour only when it means something: a calm bar until the machine is
   genuinely under pressure. */
.meter-ok { background: var(--accent); }
.meter-warn { background: #ff9f0a; }
.meter-critical { background: var(--danger); }

.stat-detail { margin: 0; font-size: 0.8125rem; }
.stat-detail > div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 3px 0;
}
.stat-detail dt { color: var(--text-dim); }
.stat-detail dd { margin: 0; font-variant-numeric: tabular-nums; text-align: right; }

.count-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}
.count-tile {
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 18px 16px;
  text-align: center;
}
.count-num {
  display: block;
  font-size: 1.75rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.count-label {
  display: block;
  margin-top: 2px;
  font-size: 0.8125rem;
  color: var(--text-dim);
}

/* Label/value pairs rather than a real table of records - the left column is
   a heading, so it stays quiet and the value carries the weight. */
.stat-table th {
  width: 40%;
  font-weight: 400;
  color: var(--text-dim);
  text-align: left;
}
.stat-table td { font-variant-numeric: tabular-nums; }
.stat-warn { color: #b25000; }
:root[data-theme="dark"] .stat-warn { color: #ff9f0a; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .stat-warn { color: #ff9f0a; }
}
@media (max-width: 560px) {
  .stat-table th, .stat-table td { display: block; width: auto; }
  .stat-table th { padding-bottom: 0; }
  .stat-table td { padding-top: 2px; }
}

/* ---- Versionslog ------------------------------------------------------ */

.release { border-top: 1px solid var(--border); }
.release:first-of-type { border-top: 0; }
.release > summary {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 14px 2px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.release > summary::-webkit-details-marker { display: none; }
/* Own marker so it can sit before the date and turn on open. */
.release > summary::before {
  content: '›';
  display: inline-block;
  width: 12px;
  color: var(--text-dim);
  transition: transform 0.15s ease;
}
.release[open] > summary::before { transform: rotate(90deg); }
.release-date { font-weight: 600; letter-spacing: -0.01em; }
.release-count { font-size: 0.8125rem; color: var(--text-dim); }

.release-list {
  list-style: none;
  margin: 0 0 18px;
  padding: 0 0 0 22px;
}
.release-list li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 0;
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* Fixed width so the sentences line up in a column however long the label. */
.tag {
  flex-shrink: 0;
  width: 78px;
  text-align: center;
  padding: 2px 0;
  border-radius: var(--radius-pill);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.tag-new { background: var(--accent-soft); color: var(--accent); }
.tag-improved { background: var(--surface-2); color: var(--text-dim); }
.tag-fixed { background: rgba(255, 159, 10, 0.15); color: #b25000; }
:root[data-theme="dark"] .tag-fixed { color: #ff9f0a; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tag-fixed { color: #ff9f0a; }
}

@media (max-width: 560px) {
  .release-list { padding-left: 0; }
  .release-list li { flex-direction: column; gap: 3px; }
  .tag { width: auto; padding: 2px 9px; align-self: flex-start; }
}

/* ---- Sitzungs-Warnung ------------------------------------------------- */

.session-timeout-panel { max-width: 420px; text-align: center; }
.session-timeout-panel h2 { margin: 0 0 10px; font-size: 1.25rem; letter-spacing: -0.02em; }
.session-timeout-panel p { margin: 0 0 6px; color: var(--text-dim); font-size: 0.9375rem; line-height: 1.55; }
/* Tabular figures so the seconds tick down without the text shifting. */
.session-countdown {
  margin: 18px 0 22px !important;
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text) !important;
  font-variant-numeric: tabular-nums;
}
.session-timeout-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

.alert-info {
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid transparent;
}

/* ---- Speicherplatz ----------------------------------------------------- */

.quota-summary { max-width: 460px; }
.quota-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 10px;
  font-size: 0.9375rem;
}
.quota-line strong { font-variant-numeric: tabular-nums; }
.quota-summary .meter { margin-bottom: 10px; }
.quota-summary .hint { margin: 0; }
/* The storage column carries two numbers and a percentage - keep it from
   wrapping mid-figure in the middle of the table. */
.user-table td .hint { white-space: nowrap; }

/* ---- Papierkorb -------------------------------------------------------- */

.trash-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.trash-list { display: flex; flex-direction: column; gap: 12px; }
/* Thumbnail, facts, actions - a row per entry, so a long trash reads as a
   list rather than a wall of tiles. */
.trash-item {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  gap: 16px;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 16px;
}
.trash-thumb {
  width: 96px;
  height: 72px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  display: block;
}
.trash-info { min-width: 0; }
.trash-info p { margin: 0 0 2px; }
.trash-name {
  font-weight: 600;
  font-size: 0.9375rem;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.trash-soon { font-size: 0.8125rem; color: var(--danger); font-weight: 500; }

.trash-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.trash-restore-form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }
.trash-select, .trash-new-name {
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 0.875rem;
}
/* Wide enough for a real album name in "Zurück nach „…“" without truncating,
   which is the whole point of showing where it came from. */
.trash-select { max-width: 300px; }
.trash-new-name { max-width: 220px; }
.trash-new-name[hidden] { display: none; }

@media (max-width: 720px) {
  .trash-item { grid-template-columns: 72px 1fr; }
  .trash-thumb { width: 72px; height: 56px; }
  /* Actions drop to their own full-width row rather than squeezing. */
  .trash-actions { grid-column: 1 / -1; }
  .trash-restore-form { width: 100%; }
  .trash-select, .trash-new-name { flex: 1 1 140px; max-width: none; }
}


/* ---- Suche ------------------------------------------------------------- */

.search-form { margin-bottom: 24px; }
.search-main { display: flex; gap: 10px; margin-bottom: 12px; }
.search-input {
  flex: 1;
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font-size: 1rem;
}
.search-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.search-details > summary {
  cursor: pointer;
  font-size: 0.875rem;
  color: var(--text-dim);
  padding: 6px 2px;
  list-style: none;
  user-select: none;
}
.search-details > summary::-webkit-details-marker { display: none; }
.search-details > summary::before { content: '› '; display: inline-block; transition: transform 0.15s ease; }
.search-details[open] > summary::before { transform: rotate(90deg); }
.search-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin: 12px 0;
}
.search-grid label { display: flex; flex-direction: column; gap: 5px; font-size: 0.8125rem; color: var(--text-dim); }
.search-grid select,
.search-grid input {
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 0.9375rem;
}
.search-checkbox { display: flex; align-items: center; gap: 8px; font-size: 0.875rem; margin-bottom: 12px; }
.search-actions { margin: 0; }

/* ---- Zeitleiste -------------------------------------------------------- */

/* Photo bands on the left, the timeline pinned on the right. The right column
   is a fixed width rather than `auto` because the live scale is taken out of the
   flow (see .year-rail-live) and would otherwise collapse the column it is
   supposed to sit in. */
.timeline-layout { display: grid; grid-template-columns: minmax(0, 1fr) 58px; gap: 20px; align-items: start; }
.timeline-day { margin-bottom: 28px; }
.timeline-date {
  margin: 0 0 10px;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}
/* Without JavaScript this is a plain list of year links; the script below turns
   it into a scale. Both states share the class, so the fallback needs no markup
   of its own. */
.year-rail {
  position: sticky;
  top: 70px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-left: 8px;
  border-left: 1px solid var(--border);
  max-height: calc(100vh - 100px);
  overflow-y: auto;
}
.year-rail-item {
  font-size: 0.75rem;
  color: var(--text-dim);
  text-decoration: none;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  font-variant-numeric: tabular-nums;
}
.year-rail-item:hover { color: var(--text); background: var(--surface-2); }

/* The live scale: labels are positioned absolutely at the height their own
   photos occupy, so the gap between two years shows how much lies between
   them. */
.year-rail-live {
  display: block;
  /* Fixed, not sticky. A sticky rail sits in the flow until the page scrolls
     past it and then snaps up to its offset - which, at the moment somebody
     starts dragging near the top, moves the whole scale about 90px under their
     finger. Fixed means the scale is in the same place at every scroll
     position, which is the least a scale can be asked. */
  position: fixed;
  top: 88px;
  bottom: 28px;
  right: 24px;
  height: auto;
  max-height: none;
  overflow: visible;
  width: 58px;
  padding-left: 10px;
  /* No text selection while dragging the scale, and no browser scroll-panning
     stealing the gesture on a touchscreen. */
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
  cursor: ns-resize;
}
.rail-label {
  position: absolute;
  left: 10px;
  transform: translateY(-50%);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding: 1px 4px;
  border-radius: 5px;
}
.rail-label-year { font-size: 0.75rem; color: var(--text-dim); }
.rail-label-month { font-size: 0.625rem; color: var(--text-dim); opacity: 0.6; }
.rail-label:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
/* The year you are actually reading, so the scale says where you are as well as
   where you could go. */
.year-rail-active { color: var(--accent); }
.rail-label-year.year-rail-active { font-weight: 500; }

/* Position marker: a short accent tick against the rail's own hairline. */
.rail-marker {
  position: absolute;
  left: 0;
  width: 3px;
  height: 22px;
  margin-top: -11px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  pointer-events: none;
}
/* The date under the pointer while hovering or dragging. */
.rail-bubble {
  position: absolute;
  right: calc(100% + 4px);
  transform: translateY(-50%);
  white-space: nowrap;
  font-size: 0.75rem;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--text);
  color: var(--bg);
  pointer-events: none;
  box-shadow: var(--shadow-sm);
  z-index: 5;
}
.rail-bubble[hidden] { display: none; }
.year-rail-scrubbing { cursor: grabbing; }
/* Widen the grab area while dragging so a slipping finger keeps hold of it. */
.year-rail-scrubbing .rail-marker { height: 28px; margin-top: -14px; }

@media (max-width: 700px) {
  /* On a phone the scale keeps its place but loses the month names and most of
     its width - a thin strip to drag, with the year beside your thumb. The
     bubble is what tells you where you are. */
  /* Wider than the 30px strip it looks like it needs: a four-digit year sets
     about 37px wide including its padding, and a clipped "202" is worse than a
     slightly fatter rail. Anchored to the right edge rather than the left, so
     the label can never run off the screen however wide the digits set. */
  .year-rail-live { width: 42px; padding-left: 4px; right: 2px; top: 74px; bottom: 16px; }
  .rail-label { left: auto; right: 2px; padding: 1px 2px; }
  .rail-label-year { font-size: 0.6875rem; }
  .timeline-layout { grid-template-columns: minmax(0, 1fr) 42px; gap: 6px; }
  /* A fallback rail without JavaScript has no fixed height to work with, so it
     lies down above the photos instead. */
  .year-rail:not(.year-rail-live) {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    border-left: 0;
    padding-left: 0;
    max-height: none;
    margin-bottom: 16px;
  }
  .timeline-layout:not(:has(.year-rail-live)) { grid-template-columns: 1fr; }
}

/* Marks an archived photo wherever it is still shown. */
.archived-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: 2;
}

/* ---- Freigabe-Links: Verwaltung im Album ------------------------------- */

.share-list { list-style: none; margin: 0 0 18px; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.share-list-item {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  background: var(--surface);
}
.share-list-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 8px; }
.share-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.share-tag {
  font-size: 0.6875rem;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text-dim);
  white-space: nowrap;
}
.share-list-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-top: 8px; }
.share-list-foot .hint { margin: 0; }
.share-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
}
/* Two rules have to be overridden here: .switch sets gap: 0, which is right for
   a bare toggle but not for one with text beside it, and .stack-form label
   stacks its children in a column, which would put the toggle above the text
   instead of in front of it. */
.stack-form label.share-switch {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  font-size: 0.9375rem;
  color: var(--text);
}

/* ---- Freigabe-Links: die öffentliche Seite ----------------------------- */

.share-header { border-bottom: 1px solid var(--border); background: var(--surface); }
.share-header-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 8px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.share-brand { display: flex; align-items: center; gap: 8px; }
.share-logo { height: 34px; width: auto; }
.share-wordmark { height: 22px; width: auto; }
.share-header-actions { display: flex; align-items: center; gap: 12px; }
.share-lang { font-size: 0.8125rem; color: var(--text-dim); text-decoration: none; }
.share-lang:hover { color: var(--text); }
.share-main { padding-top: 24px; padding-bottom: 40px; }
.share-footer-note { margin-top: 32px; font-size: 0.75rem; color: var(--text-dim); text-align: center; }
/* No select checkbox and no info button on a public page, so the card is just
   the picture. */
.share-card .photo-media { cursor: zoom-in; }

/* Same light/dark wordmark swap as the nav and the guest upload page, honouring
   both the OS setting and an explicit data-theme choice. */
.share-wordmark-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .share-wordmark-light { display: none; }
  :root:not([data-theme="light"]) .share-wordmark-dark { display: block; }
}
:root[data-theme="dark"] .share-wordmark-light { display: none; }
:root[data-theme="dark"] .share-wordmark-dark { display: block; }

.share-viewer {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: #0b0b0d;
  display: flex;
  align-items: center;
  justify-content: center;
}
.share-viewer[hidden] { display: none; }
body.share-viewer-open { overflow: hidden; }
.share-viewer-stage {
  flex: 1;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 56px 12px 84px;
  min-width: 0;
}
.share-viewer-media { max-width: 100%; max-height: 100%; object-fit: contain; }
/* A quarter-turned photo is boxed by the *other* axis after rotating. */
.share-viewer-media-rotated { max-width: calc(100vh - 140px); max-height: calc(100vw - 24px); }
.share-viewer-close,
.share-viewer-nav {
  position: absolute;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.share-viewer-close { top: 14px; right: 14px; width: 40px; height: 40px; font-size: 1rem; }
.share-viewer-nav { top: 50%; transform: translateY(-50%); width: 46px; height: 46px; font-size: 1.75rem; line-height: 1; }
.share-viewer-prev { left: 14px; }
.share-viewer-next { right: 14px; }
.share-viewer-close:hover,
.share-viewer-nav:hover { background: rgba(255, 255, 255, 0.2); }
.share-viewer-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 14px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.8125rem;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
}
.share-viewer-caption { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 640px) {
  /* Arrows would sit on top of the photo on a narrow screen; swiping covers it. */
  .share-viewer-nav { display: none; }
  .share-viewer-stage { padding: 52px 6px 76px; }
}

/* ---- Aufräumen: Duplikate und große Dateien ---------------------------- */

.dup-list { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.dup-group { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; }
.dup-group-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 10px; }
.dup-group-head .hint { margin: 0; }
.dup-group-head form { margin-left: auto; }
.dup-copies { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.dup-copy {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
  border-top: 1px solid var(--border);
}
.dup-copies > .dup-copy:first-child { border-top: 0; }
.dup-thumb { flex: 0 0 auto; line-height: 0; }
.dup-thumb img { width: 64px; height: 64px; object-fit: cover; border-radius: var(--radius-sm); }
/* min-width: 0 so a long filename ellipsises instead of pushing the button off. */
.dup-copy-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.dup-copy-info .hint { margin: 0; }
.dup-copy-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.9375rem; }
.dup-size { font-variant-numeric: tabular-nums; font-size: 0.875rem; color: var(--text-dim); white-space: nowrap; }

@media (max-width: 600px) {
  .dup-copy { flex-wrap: wrap; }
  .dup-copy-info { flex-basis: 100%; order: 3; }
  .dup-group-head form { margin-left: 0; flex-basis: 100%; }
}
