:root {
  --radius: 10px; /* corner radius of all UI elements: buttons, text fields, menus, dialogs, panels… */
  --share-radius: 20px; /* the share sheet's own corners */
  --tile-radius: 14px; /* image tiles on boards only */
  /* Frosted glass of the image viewer's panel and detail action buttons */
  --glass-bg: color-mix(in srgb, var(--bg) 62%, transparent);
  --glass-bg-active: color-mix(in srgb, var(--bg) 80%, transparent);
  --glass-blur: blur(28px) saturate(1.3);
  --star: #ffdd00; /* a starred image's star; more vivid on wide-colour (P3) screens, below */
  --nav-edge: #fff; /* the line along the board's top edge while the board list is open (phones) */
  --sharing: #00ff44; /* the dot on the Sharing button; more vivid on wide-colour (P3) screens, below */
  --bg: #000;
  --btn-bg: rgb(255 255 255 / 0.12); /* standard buttons: a little lighter than whatever they sit on */
  --btn-bg-hover: rgb(255 255 255 / 0.14);
  --btn-bg-pressed: rgb(255 255 255 / 0.2); /* while a finger (or the mouse button) is down on it */
  --surface: #1e1d1b;
  --surface-2: #282724;
  --text: #ecebe8;
  --muted: #9b978f;
  --line: #2f2d2a;
  --accent: #198BC7;
  --accent-text: #ffffff;
  --danger: #ff6b6b;
  --success: #69db7c;
  --placeholder: #24231f;
  --shadow: 0 8px 50px rgb(0 0 0 / 0.75);
  --nav-label: #5b5b5a; /* section headings in the sidebar ("Boards", "Shared with you") */
  --comment-time: rgba(255,255,255,0.6); /* when a comment was written ("5 minutes ago") */
  --nav-text: #aaaaaa; /* boards in the sidebar */
  --nav-text-hover: #dddddd;
  --nav-text-current: #ffffff; /* the board on screen */
  /* The board on screen: a glow and a drop shadow on its name (each: x y blur colour) */
  --nav-current-glow: 0 4px 12px rgb(255 255 255 / 0.3);
  --nav-current-shadow: 0 6px 1px rgb(0 0 0 / 0.8);
  /* Where they start when switching boards (and end when leaving): fully transparent, the glow 2px lower
     and the shadow without its y offset */
  --nav-current-glow-from: 0 -2px 12px rgb(255 255 255 / 0);
  --nav-current-shadow-from: 0 0 1px rgb(0 0 0 / 0);
  color-scheme: dark;
}

/* Wide-colour (Display P3) screens: a more saturated yellow than sRGB can show */
@media (color-gamut: p3) {
  @supports (color: color(display-p3 1 1 0)) {
    :root { --star: color(display-p3 1 0.86 0); --sharing: color(display-p3 0 1 0.2); }
  }
}

/* Pixel font for the board list's group headings (Silkscreen, SIL Open Font License: fonts/silkscreen-OFL.txt).
   Drawn on a grid of 8px at 8px: sharp at multiples of 8px. */
@font-face {
  font-family: 'Silkscreen';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/silkscreen.woff2) format('woff2');
}

/* Comments switched off (COMMENTS in config.js): everything about them hidden, including the sharing
   table's Comment column (its third) */
.no-comments .comments-only { display: none !important; }
.no-comments .invite-table tr > :nth-child(3):not(:last-child) { display: none; }

* { box-sizing: border-box; }
/* Every checkbox looks the same (share sheet, edit mode, …) */
input[type="checkbox"] { width: 18px; height: 18px; margin: 0; accent-color: var(--accent); cursor: pointer; }
input[type="checkbox"]:disabled { cursor: default; opacity: 0.3; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 Inter, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* While the viewer is open, the page behind it doesn't scroll. Only with a mouse or trackpad (the wheel):
   on touch screens the viewer blocks scrolling touches itself, and overflow: hidden on body would make
   Mobile Safari clip the page to the area between its bars (nothing behind the address bar). */
@media (hover: hover) { body.locked { overflow: hidden; } }
/* The page's box reaches 48px past the screen on both sides (padding puts the content back where it was),
   so while an image is open and the page shrinks and blurs behind it, its edges stay off screen: browsers
   cut the blur off at an element's edges, which showed as hard left and right edges. */
.app { margin-inline: -48px; padding-inline: 48px; }
/* The extra width is cut off at the screen's sides by a wrapper around the page (on <html> it would apply
   to the browser window, which Mobile Safari still lets you pan sideways) */
.page-clip { overflow-x: clip; }
/* The page can't be zoomed (pinch or double-tap): zooming is the image viewer's own */
html { touch-action: pan-x pan-y; }

h1, h2 { margin: 0; letter-spacing: -0.01em; }
a { color: inherit; }
code, kbd {
  font: 0.85em ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface-2);
  border-radius: 5px;
  padding: 1px 5px;
}
.muted { color: var(--muted); }

/* ---------- buttons ---------- */
/* Buttons' text can't be selected (a long press on a phone presses the button, nothing else) */
button, .btn, .icon-btn, .menu-btn, .menu-item, .user-btn, .detail-btn, .nav-item, .landing-connect {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* Buttons: each look is defined with its pressed state next to it (.pressed: set while a finger or the
   mouse button is down on it, see wirePressed in app.js), and its hover state only for a mouse or
   trackpad (@media (hover: hover): touch screens would keep it after a tap). */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 38px;
  padding: 0 16px;
  border: 1px solid transparent; /* no visible border: the background sets it apart from the ground */
  border-radius: var(--radius);
  background: var(--btn-bg);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.btn.pressed { background: var(--btn-bg-pressed); transform: scale(0.97); }
@media (hover: hover) { .btn:hover { background: var(--btn-bg-hover); } }
.btn:disabled { opacity: 0.5; cursor: default; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.btn-primary.pressed { background: var(--accent); filter: brightness(0.88); }
@media (hover: hover) { .btn-primary:hover { background: var(--accent); filter: brightness(1.08); } }
.btn-ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn-ghost.pressed { background: var(--btn-bg); color: var(--text); }
@media (hover: hover) { .btn-ghost:hover { color: var(--text); } }
.btn-small { height: 30px; padding: 0 12px; font-size: 13px; }
.btn-lg { height: 48px; padding: 0 24px; font-size: 16px; }

.icon-btn {
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--muted);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.icon-btn.pressed { background: var(--surface-2); color: var(--text); }
@media (hover: hover) { .icon-btn:hover { background: var(--surface-2); color: var(--text); } }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- logo ---------- */
.logo {
  display: block;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  box-shadow: 0 0 0 1px var(--line);
}
.logo-lg { width: 96px; height: 96px; border-radius: 22px; }

/* ---------- splash ---------- */
.splash {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px 16px;
}
.splash-card {
  max-width: 420px;
  text-align: center;
  display: grid;
  justify-items: center;
  gap: 16px;
}
.splash-card h1 { font-size: 32px; }
.splash-card p { margin: 0 0 8px; color: var(--muted); }

/* ---------- landing page (signed out): the app without its sidebar ---------- */
/* What Trove is and Connect, above the public board (an ordinary board view) */
.landing-intro, .landing-follow { display: none; }
.app.landing .landing-intro { display: grid; }
.app.landing .landing-follow { display: block; }
.app.landing .body { grid-template-columns: minmax(0, 1fr); }
.app.landing .site-nav, .app.landing .mobile-bar { display: none !important; }
.app.landing main { width: 100%; max-width: 1240px; margin: 0 auto; padding: 56px 40px 80px; }
.app.landing.no-board main > :not(.landing-intro) { display: none !important; }
.landing-intro { justify-items: start; padding: 0 clamp(0px, 6vw, 80px); }
.landing-brand { margin: 0 0 52px; font-size: clamp(56px, 8vw, 76px); font-weight: 700; line-height: 1; letter-spacing: -0.02em; }
.landing-intro h1 { margin: 0 0 30px; font-size: clamp(28px, 4vw, 42px); line-height: 1.2; letter-spacing: -0.02em; }
.landing-lead { max-width: 680px; margin: 0; color: var(--nav-text); font-size: clamp(19px, 2.2vw, 24px); line-height: 1.4; }
.landing-start { margin: 52px 0 22px; }
.landing-intro .note { margin: 0 0 28px; padding: 10px 14px; border-radius: var(--radius); background: var(--surface-2); color: var(--text); font-size: 14px; }
.landing-connect { gap: 12px; height: 52px; padding: 0 24px; border: 0; border-radius: 10px; background: #4a86f7; color: #fff; font-size: 17px; font-weight: 600; }
.landing-connect.pressed { background: #4a86f7; filter: brightness(0.88); }
@media (hover: hover) { .landing-connect:hover { background: #4a86f7; filter: brightness(1.08); } }
.landing-connect svg { flex: none; }
.landing-privacy { margin-top: 26px; color: var(--muted); font-size: 15px; text-decoration: none; }
@media (hover: hover) { .landing-privacy:hover { color: var(--text); text-decoration: underline; } }
/* The board's title row, further down and indented like the text above */
.app.landing .toolbar { margin: 140px 0 36px; padding: 0 clamp(0px, 6vw, 80px); align-items: flex-start; }
.landing-follow { margin: 0; color: var(--nav-text); font-size: 16px; line-height: 1.5; overflow-wrap: anywhere; }
.landing-follow a { color: var(--nav-text); }
@media (hover: hover) { .landing-follow a:hover { color: var(--text); } }
@media (max-width: 600px) {
  .app.landing main { padding: 32px 16px 48px; }
  .landing-brand { margin-bottom: 36px; }
  .landing-start { margin-top: 36px; }
  .app.landing .toolbar { margin-top: 80px; }
}

/* ---------- app shell: sidebar with logo, boards and account; content on the right ---------- */
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 26px; text-decoration: none; }
/* The name, as the logo type: drawn at half its pixel size (sharp on high-resolution screens), twice that
   on the landing page */
.brand-name { display: block; width: auto; height: 44px; }
.landing-brand .brand-name { height: 88px; image-rendering: pixelated; }

.user { position: relative; }
.avatar-btn { display: grid; place-items: center; flex: none; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%; overflow: hidden; background: var(--surface-2); }
.avatar-btn img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-btn { color: #fff; font-weight: 600; font-size: 14px; }
.user-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font: inherit;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}
.user-btn.pressed { background: var(--surface-2); }
@media (hover: hover) { .user-btn:hover { background: var(--surface-2); } }
.user-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Grid/flex items default to their content's width; let the account row shrink so long names get "…" */
.nav-foot > *, .user, .user-btn { min-width: 0; }
.menu {
  position: absolute;
  left: 0;
  bottom: calc(100% + 6px);
  min-width: 240px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.menu-head { display: grid; padding: 8px 10px 10px; border-bottom: 1px solid var(--line); margin-bottom: 4px; font-size: 14px; }
.menu-head span { color: var(--muted); font-size: 13px; overflow: hidden; text-overflow: ellipsis; }
.menu-item {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.menu-item.pressed { background: var(--surface-2); }
@media (hover: hover) { .menu-item:hover { background: var(--surface-2); } }

.banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 10px 16px;
  background: color-mix(in srgb, var(--accent) 14%, var(--bg));
  font-size: 14px;
}

.body { --head-height: 46px; display: grid; grid-template-columns: 220px minmax(0, 1fr); }

.site-nav {
  position: sticky;
  top: 0;
  align-self: start;
  display: flex;
  flex-direction: column;
  height: 100vh;
  padding: 20px 12px 14px;
  border-right: 1px solid var(--line);
}
/* As tall as the board's title row, which starts at the same height, so the two line up */
/* (Stacked above the list's top padding, which reaches up into it, so it stays clickable.) */
.site-nav .brand { position: relative; z-index: 1; height: var(--head-height); margin-bottom: 13px; padding: 0 12px; }
/* The list scrolls, which clips it at its edges. The padding (undone by the negative margin, so nothing
   moves) leaves room for the current board's glow around the names. */
.nav-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 18px 20px 12px; margin: -18px -20px -12px; }
.nav-foot { display: grid; gap: 8px; padding-top: 12px; border-top: 1px solid var(--line); }
.nav-group { display: grid; gap: 2px; }
.nav-label {
  margin: 36px 12px 6px 30px; /* lined up with the names */
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nav-label);
}
.nav-item {
  position: relative;
  display: block;
  padding: 1px 12px 1px 30px; /* room on the left for the gem of the board on screen (all names, so none moves) */
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--nav-text);
  font: inherit;
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.nav-item { transition: color 0.15s; }
.nav-item.pressed { opacity: 0.6; }
@media (hover: hover) { .nav-item:hover { color: var(--nav-text-hover); } }
.nav-item[aria-current="page"] { color: var(--nav-text-current); }
/* The board on screen: a gem to the left of its name (larger on phones, see there) */
.nav-item[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 7px;
  top: 50%;
  width: 18px;
  height: 18px;
  margin-top: -9px;
  background: url(board-list-gem.png) center / contain no-repeat;
}
/* The shadow and glow are a filter on the name: a filter is drawn after the name's clipping (needed for
   the "…"), so it isn't cut off at the edges. Each applies to the result of the one before, so the glow
   also lights the shadow (as with text-shadow's order: shadow on top, glow below). */
.nav-item[aria-current="page"] .nav-name {
  filter: drop-shadow(var(--nav-current-shadow)) drop-shadow(var(--nav-current-glow));
}
/* Fading in on the board you switch to, and out on the one you left (classes set in renderNav) */
.nav-item.glow-in .nav-name { animation: nav-glow-in 0.2s ease; }
.nav-item.glow-out .nav-name { animation: nav-glow-out 0.2s ease; }
/* The shadow and glow fade in while sliding into place (the shadow down from behind the name, the glow
   up by 2px), and fade out sliding back when leaving */
@keyframes nav-glow-in {
  from { filter: drop-shadow(var(--nav-current-shadow-from)) drop-shadow(var(--nav-current-glow-from)); }
}
@keyframes nav-glow-out {
  from { filter: drop-shadow(var(--nav-current-shadow)) drop-shadow(var(--nav-current-glow)); }
  to { filter: drop-shadow(var(--nav-current-shadow-from)) drop-shadow(var(--nav-current-glow-from)); }
}
.nav-empty { margin: 0; padding: 1px 12px 1px 30px; color: var(--nav-label); font-size: 13px; line-height: 1.4; }
/* "My Boards", "Shared With Me": yellow, in the pixel font, with the text's smoothing off where the browser
   allows it (macOS only) */
#nav-boards-label, #nav-shared-label {
  color: #fbd916;
  font-family: 'Silkscreen', monospace;
  font-size: 16px; /* a multiple of the font's 8px grid */
  font-weight: 400;
  letter-spacing: 0;
  -webkit-font-smoothing: none;
  -moz-osx-font-smoothing: unset;
  font-smooth: never;
  text-rendering: optimizeSpeed;
}
.nav-new { margin-top: 2px; width: 100%; color: var(--nav-label); } /* spacing as between boards; colour as the section labels */
.nav-new.nav-new-first, .nav-new.nav-new-first:hover { color: var(--accent); } /* no boards of my own yet */

main { padding: 20px 24px 80px; min-width: 0; }
.toolbar { display: flex; align-items: center; gap: 12px; min-height: var(--head-height); margin-bottom: 20px; }
.toolbar h1 { font-size: 52px; white-space: nowrap; } /* the title field inside handles long names (…) */
.board-actions { display: flex; gap: 10px; }
/* The board's header and edit bar: all buttons 40px tall */
.board-actions .btn, .edit-bar .btn { height: 40px; }

/* ---------- grid ---------- */
.grid { display: flex; gap: 16px; align-items: flex-start; }
.col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 16px; }

.pin {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: var(--tile-radius);
  overflow: hidden;
  background: var(--placeholder);
  cursor: pointer;
}
.pin img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.35s, filter 0.2s;
}
.pin.loaded img { opacity: 1; }
/* On hover the whole tile grows slightly (pointer devices only). */
.pin { transition: transform 0.25s ease; }
@media (hover: hover) {
  .pin:hover { transform: scale(1.02); z-index: 1; }
  .pin:hover::after { background: rgb(0 0 0 / 0.08); }
}
/* Hover effects only exist for mouse/trackpad (above). On iOS a tap that would change a :hover style is
   used to show the hover instead of clicking, which swallowed the first tap after closing an image. */
/* No grey flash over a tile when it's tapped (iOS's tap highlight on buttons and links) */
.pin, .activity-thumb { -webkit-tap-highlight-color: transparent; }
.pin::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0);
  transition: background 0.2s;
}
.pin.uploading { cursor: progress; }
.pin.uploading img { opacity: 0.45; }
.pin.uploading::before {
  content: "";
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  width: 28px;
  height: 28px;
  margin: -14px 0 0 -14px;
  border: 3px solid rgb(255 255 255 / 0.4);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
.pin.broken { background: repeating-linear-gradient(45deg, var(--placeholder) 0 10px, var(--surface-2) 10px 20px); }

.loading { display: grid; place-items: center; padding: 80px 0; }
.spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.empty { text-align: center; padding: 80px 16px; }
.empty p { margin: 0 0 8px; }
.empty p:first-child { font-size: 18px; font-weight: 600; }
.empty .btn { margin-top: 8px; }

/* ---------- add dialog ---------- */
.dialog {
  width: min(460px, calc(100vw - 32px));
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}
.dialog::backdrop { background: rgb(0 0 0 / 0.4); }
.dialog-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0px; }
.dialog-head h2 { font-size: 18px; }
.dialog-head { gap: 10px; }
.dialog-head .add-board { flex: 1; min-width: 0; margin-right: auto; }
.upload-zone {
  display: grid;
  justify-items: center;
  gap: 4px;
  padding: 28px 16px;
  border: 2px dashed var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s, background 0.15s;
}
@media (hover: hover) { .upload-zone:hover { border-color: var(--accent); background: var(--surface-2); } }
.upload-zone input { position: absolute; opacity: 0; pointer-events: none; width: 1px; }
.url-form { display: flex; gap: 8px; margin-top: 14px; }
.url-form input, .field select {
  flex: 1;
  min-width: 0;
  height: 38px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font: inherit;
}
.hint { margin: 14px 0 0; font-size: 13px; }

/* ---------- lightbox: the photo fills the window; details open from the title in the corner ---------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 50;
  touch-action: none; /* no scrolling or zooming the page through it; the gestures are the viewer's own */
  overscroll-behavior: contain;
}
.lightbox .lb-info { touch-action: pan-y; } /* the panel scrolls */
/* The viewer's veil over the page behind: it blurs (8px) and darkens it to black; only its opacity is
   animated, as an image opens and closes (see pageBehind) */
.lb-veil {
  position: absolute;
  inset: 0;
  background: #000;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  opacity: 0;
  pointer-events: none;
}
.pin.zooming { visibility: hidden; }
/* The image, centred and as large as fits. It doesn't move: images are swapped in place. */
.lb-stage {
  --pad-x: 0px;
  --pad-y: 0px;
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--pad-y) var(--pad-x);
  cursor: pointer; /* clicking beside the image goes back to the board */
}
/* Touch screens: a row of all the images, swiped through one at a time (each comes to rest in the middle,
   so the 40px gaps between them only show while swiping). It doesn't scroll while an image is pulled
   down or zoomed in. */
.lightbox.strip .lb-stage {
  display: flex;
  gap: 40px; /* STRIP_GAP in app.js */
  padding: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  touch-action: pan-x;
  scrollbar-width: none;
}
.lightbox.strip .lb-stage::-webkit-scrollbar { display: none; }
.lightbox.strip.zoomed .lb-stage { overflow-x: hidden; }
/* Pulling an image down: the row doesn't clip it either (see unclipForPull): it stops scrolling and is
   shifted to where it was scrolled to */
.lightbox.strip.pulling .lb-stage { overflow: visible; transform: translateX(var(--strip-x, 0px)); }
.lb-slide {
  flex: 0 0 100%;
  display: grid;
  place-items: center;
  padding: var(--pad-y) var(--pad-x);
  scroll-snap-align: center;
  scroll-snap-stop: always; /* one image per swipe */
}
/* As large as fits the window at the image's aspect ratio. The thumbnail shown while the original
   loads gets exactly the same box, so nothing jumps. */
.lb-stage img {
  --ratio: 1;
  width: min(100%, calc((100dvh - 2 * var(--pad-y)) * var(--ratio)));
  height: auto;
  aspect-ratio: var(--ratio);
  object-fit: contain;
  border-radius: 0;
  cursor: default;
  user-select: none;
  -webkit-user-select: none;
  will-change: transform;
}
.lb-nav {
  position: absolute;
  top: 50%;
  z-index: 1;
  width: 48px;
  height: 64px;
  margin-top: -32px;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  font-size: 44px;
  line-height: 1;
  text-shadow: 0 1px 6px rgb(0 0 0 / 0.6); /* stays visible on bright and dark photos */
  cursor: pointer;
}
.lb-nav:disabled { opacity: 0.3; cursor: default; }
.lb-prev { left: 12px; }
.lb-next { right: 12px; }
.detail-btn.lb-close { position: absolute; top: 14px; right: 14px; width: 36px; padding: 0; }
/* Detail action buttons: the buttons on the image viewer (back to the board, star, Info, Comments).
   Same height and corners, and the same translucent, blurred glass as the panel (--glass-*). They sit
   above the panel (z-index) so its shadow never falls on them. */
.detail-btn {
  z-index: 4;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 36px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius);
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow);
  color: var(--nav-text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s, background-color 0.15s;
}
.detail-btn.pressed { color: var(--nav-text-hover); }
@media (hover: hover) { .detail-btn:hover { color: var(--nav-text-hover); } }
.detail-btn svg { flex: none; }
.detail-btn[aria-pressed="true"] { color: var(--nav-text-current); background: var(--glass-bg-active); }
/* Star, Info and Comments in a row in the bottom right corner */
.lb-panel-btns { position: absolute; right: 16px; bottom: 16px; z-index: 4; display: flex; gap: 8px; }
.field { display: grid; gap: 6px; margin-top: 10px; font-size: 13px; font-weight: 600; color: var(--muted); }
.field select { flex: none; width: 100%; color: var(--text); font-weight: 500; }

/* Touch devices: no arrow buttons, swipe instead; the details panel is a bottom sheet. */
@media (hover: none) and (pointer: coarse) {
  .lb-nav { display: none; }
}
@media (max-width: 760px) {
  .detail-btn.lb-close { top: calc(10px + env(safe-area-inset-top)); right: 10px; }
  .lb-panel-btns { right: 12px; bottom: calc(12px + env(safe-area-inset-bottom)); }
  .lb-info { left: 12px; right: 12px; bottom: calc(12px + 36px + 10px + env(safe-area-inset-bottom)); width: auto; max-width: none; max-height: 65dvh; }
}

/* ---------- overlays ---------- */

.toasts {
  position: fixed;
  inset: auto auto 24px 50%; /* bottom centre (also undoes the popover's own placement) */
  z-index: 1000;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  overflow: visible;
  display: grid;
  gap: 8px;
  width: min(440px, calc(100vw - 32px));
  transform: translateX(-50%);
}
.toast {
  padding: 12px 16px;
  border-radius: var(--radius);
  background: var(--text);
  color: var(--bg);
  font-size: 14px;
  box-shadow: var(--shadow);
  animation: rise 0.2s ease-out;
}
.toast.error { background: var(--danger); color: #fff; }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }

/* ---------- small screens ---------- */
@media (max-width: 760px) {
  :root { --title-size: 22px; } /* the boards in the board list (the board's title: twice that) */
  .body { display: block; }
  /* Phones: a slim bar with the logo and a menu button at the top of the page, scrolling with it (nothing
     pinned to the screen's edges, which Mobile Safari would paint behind its own bars). The board list
     folds open under it, as part of the page, pushing the board down. */
  .mobile-bar {
    display: flex;
    align-items: center;
    justify-content: flex-start; /* the menu button right after the logo */
    gap: 4px;
    padding: calc(8px + env(safe-area-inset-top)) 8px 8px 16px;
  }
  .site-nav {
    position: static;
    display: none;
    height: auto;
    padding: 20px 16px 24px;
    border-right: 0;
    /* The page's black, like everything around it */
    background: var(--bg);
  }
  .nav-open .site-nav { display: flex; }
  /* While the list opens or closes, the board slides over it (see setNavOpen) */
  main.nav-sliding { position: relative; z-index: 1; background: var(--bg); }
  /* With the list open, a 1px line along the board's top edge (moving with it as it slides); it
     fades in and out over the slide (an opacity change: nothing else is painted again) */
  .nav-open main { position: relative; }
  .nav-open main::before {
    content: "";
    position: absolute;
    top: -1px;
    left: 0;
    right: 0;
    height: 1px;
    /* --nav-edge: the line's colour, clear at both ends and at 30% in the middle */
    background: linear-gradient(to right,
      color-mix(in srgb, var(--nav-edge) 0%, transparent),
      color-mix(in srgb, var(--nav-edge) 20%, transparent),
      color-mix(in srgb, var(--nav-edge) 0%, transparent));
    pointer-events: none;
    transition: opacity var(--nav-slide-ms, 280ms) ease-in-out;
  }
  .nav-open.nav-closing main::before { opacity: 0; }
  /* Once the list is open, the board is folded away (its width kept, so its columns aren't laid out
     again): only the list is left on the page */
  .nav-shown main { height: 0; padding-top: 0; padding-bottom: 0; overflow: hidden; }
  .site-nav .brand { display: none; } /* the logo is in the bar above */
  /* Not scrolling on its own here, so nothing clips the glow: no room needed around it (it would reach
     past the screen's edges and widen the page) */
  .site-nav .nav-scroll { flex: none; overflow: visible; padding: 0; margin: 0; }
  /* Signed out (a public board): Sign in at the top. Signed in, the account is at the bottom instead
     (.nav-account): About & Privacy as a row like the boards, then my avatar, full name and email,
     and a Sign out button. */
  .site-nav .nav-foot { order: -1; margin: 0; padding: 0; border-top: 0; }
  .site-nav .nav-foot .user { display: none; }
  .site-nav .public-only { margin: 12px 0; }
  .site-nav .nav-account { display: grid; margin-top: 28px; }
  .nav-signed-in { display: flex; align-items: center; gap: 12px; margin-top: 20px; padding: 28px 0 8px 8px; border-top: 1px solid #333;}
  .nav-signed-in .avatar-btn { width: 34px; height: 34px; font-size: 15px; }
  .nav-signed-in-text { display: grid; flex: 1; min-width: 0; color: #fff; font-size: 13px; line-height: 1.3; }
  .nav-signed-in-text > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .nav-signed-in-email { overflow: hidden; color: var(--muted); text-overflow: ellipsis; white-space: nowrap; }
  .nav-signed-in .btn { flex: none; height: 40px; } /* as the board's buttons */
  /* Boards as large white names straight on the background, each row a comfortable tap target; the board
     on screen has a gem to its left (all names leave room for it, so none moves) */
  .site-nav .nav-label { margin: 28px 0 6px 34px; }
  .site-nav .nav-group { gap: 0; }
  .site-nav .nav-item, .site-nav .nav-new, .site-nav .nav-new.nav-new-first {
    position: relative;
    min-height: 52px;
    padding: 8px 0 8px 34px;
    border-radius: 0;
    color: #fff;
    /* as the board's title */
    font-size: var(--title-size);
    font-weight: 700;
    letter-spacing: -0.01em;
  }
  .site-nav .nav-item[aria-current="page"]::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 50%;
    width: 25px;
    height: 25px;
    margin-top: -12.5px;
    background: url(board-list-gem.png) center / contain no-repeat;
  }
  .site-nav .nav-empty { padding: 0 0 0 34px; }
  /* The menu button's arrow points up while the list is open */
  .menu-btn svg { transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1); }
  .menu-btn[aria-expanded="true"] svg { transform: rotate(180deg); }
  main { padding: 16px 16px 60px; }
  .toolbar h1 { font-size: calc(2 * var(--title-size)); }
  /* Someone else's board: the owner under the title, the board's buttons (Add images, Add to shared
     boards) beside the two, centred, stacked if there are several. Hiding it is done from the board list
     here (.nav-hide), not on the board. */
  #forget-board { display: none; }
  .toolbar:has(.board-owner:not([hidden])) { flex-wrap: nowrap; gap: 16px; }
  .toolbar-title:has(.board-owner:not([hidden])) { flex-direction: column; align-items: flex-start; gap: 6px; }
  .toolbar:has(.board-owner:not([hidden])) .board-actions { flex: none; flex-direction: column; align-items: stretch; gap: 8px; }
  .toolbar-title .board-owner { margin-left: 0; }
  /* My own board (.mine, see renderNav), centred: a row above the title with Edit on the right (while
     editing Cancel and Confirm in its place), the title, and under it Add images and Share, or while
     editing the edit bar in their place. Each pair cross-fades in its row, whose height never changes. */
  .toolbar.mine { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .toolbar.mine > .edit-confirm { grid-row: 1; }
  .toolbar.mine > .toolbar-title { grid-row: 2; }
  .toolbar.mine > .board-actions, .toolbar.mine > .edit-bar { grid-row: 3; grid-column: 1; }
  .toolbar.mine .view-title-input { width: 100%; margin-left: 0; max-width: none; text-align: center; }
  .toolbar.mine .board-actions { justify-content: center; transition: opacity 0.2s ease; }
  .toolbar.mine.editing .board-actions { opacity: 0; pointer-events: none; }
  /* (the edit bar always at its full size here: only its opacity changes, as the buttons') */
  .toolbar.mine > .edit-bar { align-self: center; grid-template-rows: 1fr; transition: opacity 0.2s ease; }
  .toolbar.mine > .edit-bar .edit-bar-inner { justify-content: center; padding: 0; transition: none; }
  #add-images { order: -2; }
  #share-board { order: -1; }
  .toolbar.mine > .edit-confirm { display: block; }
  .edit-confirm-inner { display: grid; justify-items: end; } /* on the right */
  .edit-confirm-inner > span { display: flex; grid-area: 1 / 1; gap: 10px; transition: opacity 0.2s ease; } /* (on top of each other) */
  .edit-confirm-inner .btn { height: 40px; }
  .edit-confirm-done { justify-self: stretch; justify-content: space-between; } /* Cancel left, Confirm right */
  .edit-confirm-done #edit-save { margin-left: auto; } /* (also alone, while saving) */
  .edit-confirm-done, .toolbar.mine.edit-open .edit-confirm-edit { opacity: 0; pointer-events: none; }
  .toolbar.mine.edit-open .edit-confirm-done { opacity: 1; pointer-events: auto; }
  .toolbar:not(:has(#edit-board:not([hidden]), #edit-save:not([hidden]))) > .edit-bar { display: none; } /* not my board */
  .grid, .col { gap: 10px; }
  .grid { margin: 0 -16px; } /* the columns span the whole screen, edge to edge (main has 16px sides) */
  .pin { --tile-radius: 12px; }

  .lb-prev { left: 8px; }
  .lb-next { right: 8px; }
}

/* ---------- sharing ---------- */
.toolbar { flex-wrap: wrap; justify-content: space-between; }
/* The board title takes all the room the buttons beside it leave; only a name longer than that ends in … */
.toolbar-title { display: flex; flex: 1 1 0; align-items: center; min-width: 0; }
.toolbar-title h1 { flex: 1 1 0; min-width: 0; }
/* With an owner next to it, the title is only as wide as its text (still ending in … if too long) */
.toolbar-title:has(.board-owner:not([hidden])) h1 { flex: 0 1 auto; }
.toolbar-title:has(.board-owner:not([hidden])) .view-title-input[readonly] { field-sizing: content; width: auto; max-width: calc(100% + 11px); }
.toolbar-title p { margin: 2px 0 0; font-size: 14px; }
.toolbar-title p:empty { display: none; }
.board-actions { flex-wrap: wrap; }

.nav-item { display: flex; align-items: center; gap: 8px; }
.nav-item svg { flex: none; opacity: 0.6; }

.app:not(.public) .public-only { display: none; }
/* Someone else's board: the owner, right after the title */
.board-owner { display: inline-flex; flex: none; align-items: center; gap: 8px; color: var(--nav-text); font-size: 14px; white-space: nowrap; margin-left: 20px;}
.board-owner[hidden] { display: none; }
.board-owner .board-owner-avatar { width: 24px; height: 24px; font-size: 12px; }
/* Public (signed-out) board view: the sidebar only shows the logo and a Sign in button. */
.app.public .nav-scroll,
.app.public .user { display: none; }
.app.public .nav-foot { margin-top: auto; }

.note { margin: 8px 0 0; font-size: 13px; }
.note.warn { color: var(--danger); }
.splash-card .note { padding: 10px 14px; border-radius: var(--radius); background: var(--surface-2); color: var(--text); font-size: 14px; }

.dialog-wide { width: min(520px, calc(100vw - 32px)); }
.dialog h3 { margin: 22px 0 10px; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.dialog select, .dialog input:not([type="checkbox"]):not([type="file"]) {
  height: 38px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  min-width: 0;
}
.check { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 14px; cursor: pointer; }
.check input { accent-color: var(--accent); width: 16px; height: 16px; }

.people { display: grid; gap: 4px; min-height: 40px; }
.people .spinner { margin: 4px auto; width: 24px; height: 24px; }
.person { display: flex; align-items: center; gap: 12px; padding: 6px 0; }
.person-avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--surface-2);
  font-weight: 600;
  font-size: 14px;
}
.person-avatar img { width: 100%; height: 100%; object-fit: cover; }
.person-who { display: grid; flex: 1; min-width: 0; font-size: 14px; }
.person-who strong, .person-who span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
.person-who span { color: var(--muted); font-size: 13px; }
.dialog select.person-role { flex: none; height: 32px; padding: 0 10px; font-size: 13px; }
span.person-role { font-size: 13px; padding-right: 10px; }

/* The board link, as selectable text with a Copy button, right under the title */
.share-link { display: flex; align-items: center; gap: 10px; margin-top: 0px; }
.share-link-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 14px; user-select: all; }
#share-dialog .invite { margin-top: 0px; }

/* ---------- review dialog (details before upload) ---------- */
.dialog-review { width: min(680px, calc(100vw - 32px)); max-height: calc(100vh - 48px); padding: 0; }
.dialog-review form { display: flex; flex-direction: column; max-height: calc(100vh - 48px); }
.dialog-review .dialog-head { padding: 18px 20px 0; margin-bottom: 4px; }
.review-hint { margin: 0; padding: 0 20px 12px; border-bottom: 1px solid var(--line); }
.review-list { flex: 1; overflow-y: auto; padding: 4px 20px; }
.review-item { display: grid; grid-template-columns: 88px minmax(0, 1fr) auto; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.review-item:last-child { border-bottom: 0; }
.review-item img { width: 88px; height: 88px; object-fit: cover; border-radius: var(--radius); background: var(--placeholder); }
.review-fields { display: grid; gap: 6px; min-width: 0; }
.dialog .review-fields input:not([type="checkbox"]), .review-fields textarea {
  width: 100%;
  height: auto;
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  resize: vertical;
}
.dialog .review-fields .review-title { font-weight: 600; }
.review-file { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.review-actions { display: flex; justify-content: flex-end; gap: 8px; padding: 14px 20px; border-top: 1px solid var(--line); }
@media (max-width: 560px) {
  .review-item { grid-template-columns: 64px minmax(0, 1fr) auto; gap: 10px; }
  .review-item img { width: 64px; height: 64px; }
}

/* Section labels, styled like "Shared With Me" in the boards sidebar */
.lb-label {
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nav-label);
}
/* Move / Copy: an invisible native <select> over the button opens the system's list of boards */
.board-pick { position: relative; display: inline-flex; }
.board-pick[hidden] { display: none; }
.board-pick:has(.board-select:disabled) .btn { opacity: 0.5; }
.board-select:disabled { cursor: default; }
.board-select { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; font-size: 16px; /* 16px: no zoom on iOS */ }
@media (hover: hover) { .board-pick:has(.board-select:hover) .info-btn { background: rgb(255 255 255 / 0.28); } }
.board-pick:has(.board-select:focus-visible) .info-btn { outline: 2px solid var(--accent); outline-offset: 2px; }

/* A board that's still being created in Google Drive */
.nav-pending { color: var(--muted); cursor: progress; justify-content: space-between; }
@media (hover: hover) { .nav-pending:hover { background: none; } }
.spinner-small { flex: none; width: 14px; height: 14px; border-width: 2px; }

.splash-card > .spinner { margin-bottom: 4px; }

/* Owner name next to boards other people shared */
/* Board name, with the owner of shared boards on a second line */
.nav-text { display: grid; flex: 1; min-width: 0; }
.nav-text > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A board's name: long names end in "…" */
.nav-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nav-owner { color: var(--muted); font-size: 12px; font-weight: 400; line-height: 1.3; }

/* Image count per board, and the "+N new" badge */
.nav-count { flex: none; color: var(--muted); font-size: 12px; font-weight: 400; font-variant-numeric: tabular-nums; }
.nav-count-new { padding: 1px 7px; border-radius: var(--radius); background: var(--accent); color: var(--accent-text); font-weight: 600; }

.mobile-bar { display: none; }
.edit-confirm { display: none; } /* phones only (my board) */
.nav-account { display: none; } /* phones only */

/* Hiding a shared board, on phones: a button at the end of its row in the board list */
.nav-hide { display: none; }
@media (max-width: 760px) {
  .nav-hide {
    display: grid;
    flex: none;
    place-items: center;
    width: 36px;
    height: 36px;
    margin: -9px -6px -9px 0;
    padding: 0;
    border: 0;
    border-radius: var(--radius);
    background: transparent;
    color: var(--muted);
    cursor: pointer;
  }
  .nav-hide svg { opacity: 1; }
}
@media (max-width: 760px) { .mobile-bar { display: flex; } }
.menu-btn { width: 44px; height: 44px; border: 0; border-radius: var(--radius); background: none; color: var(--text); cursor: pointer; display: grid; place-items: center; }
.menu-btn.pressed { background: var(--surface-2); }
@media (hover: hover) { .menu-btn:hover { background: var(--surface-2); } }

/* CSV column matching in the review dialog */
.review-mapping { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 14px; padding: 12px 20px 14px; border-bottom: 1px solid var(--line); }
.mapping-field { display: grid; gap: 4px; font-size: 12px; font-weight: 600; color: var(--muted); }
.dialog .mapping-field select { width: 100%; height: 34px; padding: 0 10px; font-size: 14px; font-weight: 500; color: var(--text); }
.mapping-status { grid-column: 1 / -1; margin: 0; }
@media (max-width: 560px) { .review-mapping { grid-template-columns: 1fr; } }

.review-order { margin: 0 auto 0 0; font-size: 13px; color: var(--muted); }



/* Invite table in the share sheet: Email | View | Add | remove */
.invite { display: grid; gap: 10px; }
.invite-table { width: 100%; border-collapse: separate; border-spacing: 0; }
.invite-table th {
  padding: 0 5px 6px; /* 5px each side: 10px between columns */
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.invite-table th:first-child { text-align: left; padding-left: 0; }
.invite-table td { padding: 3px 5px; text-align: center; vertical-align: middle; } /* 10px between columns */
.invite-table td:first-child { width: 100%; padding-left: 0; }
.invite-table td:last-child { padding-right: 0; }
.dialog .invite-table input[type="email"] { width: 100%; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* People with access, as rows of the invite table */
.invite-table tr.member td { padding-top: 6px; padding-bottom: 6px; }
.member-who { display: flex; align-items: center; gap: 10px; min-width: 0; text-align: left; }

/* Share sheet: Close at the bottom; "Link copied" confirmation in green */
#share-copy.copied { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, var(--line)); }

/* Share sheet: roomier padding and its own corner radius */
#share-dialog { padding: 40px; border-radius: var(--share-radius); }
@media (max-width: 560px) { #share-dialog { padding: 24px; } }

/* Dropdowns: our own chevron instead of the browser's, which sits flush against the right edge and
   ignores padding. Inset 14px from the right, like the text on the left; grey works in both themes. */
select:not([multiple]) {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23888' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
}

/* "Anyone with the link" row: link icon in place of an avatar */
.member-anyone .person-avatar { color: var(--muted); }

/* Heading above the sharing table */
#share-dialog .share-table-title { margin: 30px 0 0 0; font-size: 14px; font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--text); }

/* A thin line between the entries of the sharing table */
.invite-table tbody tr td { padding-top: 8px; padding-bottom: 8px; border-top: 1px solid var(--line); }

/* Share sheet: the page behind it darkens more than for other dialogs, fading in */
#share-dialog::backdrop { background: rgb(0 0 0 / 0.65); animation: share-dim 0.2s ease-out; }
@keyframes share-dim { from { background: rgb(0 0 0 / 0); } }

/* Last row: "Add another collaborator", expanding into an invite row with Discard / Invite below it */
.invite-table tr.invite-add td { text-align: left; padding-left: 0; }
.invite-table tr.invite-row-actions td { border-top: 0; padding-top: 2px; text-align: right; }
.invite-row-actions .btn + .btn { margin-left: 8px; }
/* Close the table with a line under the "Add another collaborator" section (collapsed or expanded) */
.invite-table #invite-rows tr:last-child td { border-bottom: 1px solid var(--line); padding-bottom: 10px; }

/* Expanded "Add another collaborator": the email field and View / Add checkboxes look like one rounded
   field across the table (cells styled as a single box), with Discard / Invite underneath. */
.invite-table tr.invite-spacer td { height: 14px; padding: 0; }
.invite-table tr.invite-row td {
  padding: 4px;
  background: var(--bg);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.invite-table tr.invite-row td:first-child { border-left: 1px solid var(--line); border-radius: var(--radius) 0 0 var(--radius); padding-left: 0; }
.invite-table tr.invite-row td:last-child { border-right: 1px solid var(--line); border-radius: 0 var(--radius) var(--radius) 0; padding-right: 10px; }
.invite-table tr.invite-row:focus-within td { border-color: var(--accent); }
.dialog .invite-table tr.invite-row input[type="email"] { height: 42px; border: 0; background: transparent; outline: none; }
.invite-table tr.invite-row-actions td { padding-top: 12px; }
.invite-row-actions .btn-ghost { color: var(--text); }
.invite-row-actions .btn-primary { height: 42px; padding: 0 30px; }

/* The board link now sits below the sharing table */
#share-dialog .share-link { margin-top: 0px; }

/* "Add collaborator": styled like a member row, with a round + and the label in the accent colour */
.add-collab {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.add-collab .person-avatar { color: var(--text); font-size: 20px; font-weight: 500; line-height: 1; }
@media (hover: hover) { .add-collab:hover .person-avatar { background: color-mix(in srgb, var(--text) 12%, var(--surface-2)); } }

/* × at the end of a collaborator's row */
.member-remove { display: grid; place-items: center; width: 32px; height: 32px; }
@media (hover: hover) { .member-remove:hover { color: var(--danger); } }

/* Spinner in place of the sharing table while permissions load */
.share-loading { display: grid; place-items: center; min-height: 160px; margin-top: 30px; }

/* ---------- board edit mode ---------- */
.view-title-input {
  width: calc(100% + 11px); /* the whole title row (it sticks out 11px to the left, see margin-left) */
  height: 1.3em; /* the title's own line (the text centred in it) */
  padding: 0 10px;
  margin-left: -11px; /* text lines up with the content below; same size whether editing or not */
  max-width: 16em;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text);
  font: inherit;
  letter-spacing: -0.01em;
  text-overflow: ellipsis;
  transition: border-color 0.2s, background-color 0.2s, margin-left 0.2s;
}
.view-title-input[readonly] { pointer-events: none; }
/* In edit mode the field's edge lines up with the rest of the page */
.view-title-input:not([readonly]) { margin-left: 0; border-color: var(--line); background: var(--bg); }
.view-title-input:not([readonly]):focus { outline: none; border-color: #fff; }
/* Each tile's selection checkbox, bottom right, only in edit mode */
.pin-check {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
  display: none;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 2px solid #fff;
  border-radius: min(var(--radius), 7px);
  background: rgb(0 0 0 / 0.3);
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.4);
}
.grid.editing .pin { cursor: pointer; }
.grid.editing .pin-check { display: grid; }
/* Hovering a tile in edit mode dims it to 80% instead of growing it */
@media (hover: hover) {
  .grid.editing .pin:hover { transform: none; }
  .grid.editing .pin:hover::after { background: none; }
  .grid.editing .pin:not(.selected):hover img { filter: brightness(0.8); }
}
/* Selected tiles shrink to three quarters (hovered or not) */
.grid.editing .pin.selected, .grid.editing .pin.selected:hover { transform: scale(0.75); }
.pin.selected .pin-check { background: var(--accent); border-color: var(--accent); }
.pin.selected .pin-check::after {
  content: "";
  width: 10px;
  height: 5px;
  margin-top: -3px;
  border: solid #fff;
  border-width: 0 0 2px 2px;
  transform: rotate(-45deg);
}
/* The owner's View / Add ticks: locked (not clickable) but still in the accent colour */
.invite-table input[type="checkbox"].locked { pointer-events: none; cursor: default; opacity: 0.3; }

/* ---------- dragging images in ---------- */
/* Everything that can't take the drop is blurred; drop targets stay sharp and highlight under the cursor. */
body.dragging .mobile-bar,
body.dragging .site-nav .brand,
body.dragging .site-nav .nav-foot,
body.dragging .nav-label,
body.dragging .nav-empty,
body.dragging .nav-new,
body.dragging .nav-item,
body.dragging main:not(.drop-target) { filter: blur(3px); opacity: 0.45; transition: filter 0.15s, opacity 0.15s; }
main.drop-target.drop-hover {
  outline: 2px dashed var(--accent);
  outline-offset: -10px;
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}

/* "Add images" (mouse or trackpad): over the board, beside the sidebar, a place to drop, paste or choose
   them. It's part of the board (main), so a drop on it is a drop on the board. */
.add-overlay {
  position: fixed;
  inset: 0 0 0 220px;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 24px;
  background: color-mix(in srgb, var(--bg) 70%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
.add-zone {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 10px;
  width: min(520px, 100%);
  padding: 56px 32px 40px;
  border: 2px dashed var(--line);
  border-radius: var(--share-radius);
  background: var(--surface);
  text-align: center;
  transition: border-color 0.15s;
}
.add-zone strong { font-size: 20px; }
.add-zone .btn { margin-top: 10px; }
.add-zone-note { font-size: 13px; }
.add-zone-close { position: absolute; top: 10px; right: 10px; }
main.drop-hover .add-zone { border-color: var(--accent); }
@media (max-width: 760px) { .add-overlay { left: 0; } } /* no sidebar beside the board */
main.drop-hover:has(.add-overlay:not([hidden])) { outline: 0; background: none; }

/* Uploads in progress under a board's name in the sidebar: the item grows to show the line, and
   shrinks back when the upload is done */
.nav-upload {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 0.3s ease, opacity 0.3s ease;
}
.nav-upload.active { grid-template-rows: 1fr; opacity: 1; }
.nav-upload > div {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 0;
  overflow: hidden;
  color: var(--muted);
  font-size: 12px;
  font-weight: 400;
}
.nav-upload .spinner-small { width: 11px; height: 11px; margin: 3px 0; }
.nav-upload.done .spinner { display: none; }

/* A button waiting for Google Drive: its label makes way for a spinner (the button keeps its size) */
.btn.busy { position: relative; color: transparent !important; opacity: 1; }
.btn.busy::after {
  content: '';
  position: absolute;
  inset: 0;
  width: 14px;
  height: 14px;
  margin: auto;
  border: 2px solid rgb(255 255 255 / 0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* Share button: "Sharing" with an accent-coloured dot while the board is shared */
.share-dot { display: none; width: 7px; height: 7px; margin-left: 0px; border-radius: 50%; background: var(--sharing); }
#share-board.sharing .share-dot { display: inline-block; }

/* Star, on the image viewer next to the close button (moves left with the details sidebar) */
/* Star: a square button left of Info */
.detail-btn.lb-star { width: 36px; padding: 0; font-size: 17px; }
.lb-star[aria-pressed="true"] { color: var(--star); background: var(--glass-bg); }

/* Edit mode: the bar of board settings and actions under the title, folding open and shut */
.edit-bar { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows 0.25s ease, opacity 0.2s ease; }
.edit-bar.open { grid-template-rows: 1fr; opacity: 1; }
.edit-bar-inner { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-height: 0; overflow: hidden; }
.edit-bar.open .edit-bar-inner { padding-bottom: 20px; }
.edit-group { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.edit-group[hidden] { display: none; }
.edit-count { margin-right: 4px; color: var(--nav-text); font-size: 14px; font-variant-numeric: tabular-nums; white-space: nowrap; } /* "3 selected:", before what to do with them */
.edit-bar-inner { transition: padding 0.25s ease; }
/* A button with a checkbox in it (a label: a click anywhere on it ticks the box) */
.btn-check { cursor: pointer; user-select: none; }
.btn-check input { margin: 0; cursor: inherit; }
.btn-check:has(input:disabled) { opacity: 0.6; cursor: progress; }
/* Something that can't be undone: red text on a dark red ground */
.btn-warning { background: color-mix(in srgb, var(--danger) 14%, var(--bg)); color: var(--danger); }
.btn-warning.pressed { background: color-mix(in srgb, var(--danger) 30%, var(--bg)); }
@media (hover: hover) { .btn-warning:hover { background: color-mix(in srgb, var(--danger) 22%, var(--bg)); } }

/* Dragging images over a view they can't be added to: the reason, in the middle of the screen */
.drop-denied {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 70;
  max-width: min(420px, calc(100vw - 32px));
  padding: 16px 20px;
  border: 1px solid color-mix(in srgb, var(--danger) 45%, var(--line));
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  color: var(--text);
  font-size: 15px;
  line-height: 1.45;
  text-align: center;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* About & Privacy (#about): replaces the board view */
.about-page { display: none; max-width: 680px; padding: 4px 0 40px; color: var(--nav-text); font-size: 15px; line-height: 1.6; }
main.about-open > .about-page { display: block; }
main.about-open > :not(.about-page, .toolbar) { display: none !important; }
.about-page h2 {
  margin: 36px 0 12px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--nav-label);
}
.about-page section:first-of-type h2 { margin-top: 0; }
.about-page h3 { margin: 26px 0 6px; color: var(--text); font-size: 16px; }
.about-page p { margin: 0 0 12px; }
.about-page ul { margin: 0 0 12px; padding-left: 20px; }
.about-page li { margin-bottom: 8px; }
.about-page strong { color: var(--nav-text-hover); }
.about-page a { color: var(--nav-text-hover); }
@media (hover: hover) { .about-page a:hover { color: var(--text); } }

 

 


/* ---------- image viewer: the Info / Comments panel ----------
   One glass panel above the buttons, showing one .lb-panel at a time (data-tab). Both panels use the
   same parts: plain-text fields (.lb-field), quiet small text (.lb-meta) and 13px type throughout. */
.lb-info {
  position: absolute;
  right: 16px;
  bottom: calc(16px + 36px + 10px); /* just above the buttons */
  z-index: 3;
  display: flex;
  flex-direction: column;
  width: 400px;
  max-width: calc(100vw - 32px);
  max-height: min(70dvh, 640px);
  padding: 18px 22px 22px;
  border-radius: var(--share-radius);
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow);
  color: var(--nav-text);
  overflow: hidden auto;
  overscroll-behavior: contain;
}
.lb-info[data-open="false"],
.lb-info[data-tab="info"] .lb-panel-comments,
.lb-info[data-tab="comments"] .lb-panel-info { display: none; }
.lb-info * { font-size: 13px; }
/* All text in the panel is pure white (the id outranks every other colour rule); hints in empty fields
   are a dimmer white so they don't read as text */
#lb-info, #lb-info * { color: #fff; }
#lb-info ::placeholder { color: rgb(255 255 255 / 0.5); }
/* The "Added by … · date" line and the source links, half strength */
#lb-date, .lb-links { opacity: 0.5; }
#lb-date { margin-top: 10px; } /* a little further from the description */
.lb-info p { margin: 0; }
.lb-panel { display: flex; flex-direction: column; gap: 3px; min-height: 0; }

/* Text you can edit reads like text on a page: no box, only the caret */
.lb-field {
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: 1.45;
  resize: none;
  overflow: hidden;
  outline: none;
}
.lb-field[readonly] { cursor: text; }
.lb-title { color: var(--nav-text-current); font-weight: 600; font-size: 15px;}
.lb-meta { color: var(--nav-label); line-height: 1.4; }
.lb-meta:empty { display: none; }

/* Info: links to where the image came from, then Move / Copy / Delete */
.lb-links { display: grid; gap: 4px; }
.lb-links:not(:has(a:not([hidden]))) { display: none; }
.lb-link { color: var(--nav-text); text-decoration: none; word-break: break-all; transition: color 0.15s; }
@media (hover: hover) { .lb-link:hover { color: var(--nav-text-hover); } }
.lb-link::after { content: " ↗"; }
.lb-link-secondary { color: var(--nav-label); }
.lb-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 20px; } /* well clear of the link above */
.lb-actions .lb-status { margin-left: auto; } /* (".lb-info p" would otherwise reset the margin) */

/* Comments, like a messages app: past comments scroll (newest at the bottom), the composer and the
   note for public boards stay below them */
.lb-info[data-tab="comments"] { overflow: hidden; }
.comment-list {
  display: grid;
  gap: 16px;
  max-height: min(400px, 45dvh);
  margin: 0 -22px;
  padding: 4px 22px;
  overflow-y: auto;
  overscroll-behavior: contain;
  transition: opacity 0.15s;
}
.comment-list.stale { opacity: 0.35; } /* the previous image's, while this one's load (not "loading": the spinner's class) */
.comment-list:empty { display: none; }

/* A comment: picture, then a bubble with name and time on one line and the text below; replies indented */
.comment { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 8px; }
.comment.reply { grid-column: 2; }
.comment.resolved { opacity: 0.6; }
.comment-avatar { width: 28px; height: 28px; margin-top: 6px; font-size: 11px; }
.comment-bubble { padding: 8px 12px 9px; border-radius: 14px; background: color-mix(in srgb, var(--text) 6%, transparent); }
.comment-head { display: flex; align-items: baseline; gap: 8px; }
.comment-head strong { color: var(--nav-text-hover); font-weight: 600; }
/* When it was written ("5 minutes ago") */
.comment-date { margin-left: auto; color: #fff; opacity: 0.5; white-space: nowrap; }
.comment-badge { padding: 1px 6px; border-radius: var(--radius); background: var(--surface-2); color: var(--muted); }
.comment-body { margin: 2px 0 0; color: var(--nav-text-hover); white-space: pre-wrap; word-break: break-word; }

/* Writing a comment looks like a comment: my picture, a bubble to type in, Send below */
.comment-form { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 8px; }
/* My picture centred beside the one-line comment box: its 10px offset + (36px box - 28px picture) / 2 */
.comment-form .comment-avatar { margin-top: 14px; }
.comment-compose { display: grid; gap: 6px; justify-items: end; margin-top: 10px;}
.comment-compose .lb-field {
  min-height: 36px;
  padding: 8px 12px 9px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--text) 8%, transparent);
  color: var(--nav-text-hover);
}
/* Touch screens: 16px, below which Mobile Safari zooms the page in when the field is tapped */
@media (hover: none) { .comment-compose .lb-field { font-size: 16px; } }
/* Info action buttons: the panel's Move, Copy, Delete and Send */
.btn.info-btn { border: 0; background: rgb(255 255 255 / 0.1); color: #fff; }
.btn.info-btn.pressed { background: rgb(255 255 255 / 0.34); }
@media (hover: hover) { .btn.info-btn:hover { background: rgb(255 255 255 / 0.28); } }
/* (Delete: as other warning buttons, red on red, see-through like the others here) */
.btn.info-btn.btn-warning { background: color-mix(in srgb, var(--danger) 22%, transparent); color: var(--danger); }
.btn.info-btn.btn-warning.pressed { background: color-mix(in srgb, var(--danger) 40%, transparent); }
@media (hover: hover) { .btn.info-btn.btn-warning:hover { background: color-mix(in srgb, var(--danger) 32%, transparent); } }

/* Info and Comments buttons: white text and a chevron, up (opens) or down (closes); the comment count */
.lb-panel-btn, .lb-panel-btn:hover { color: #fff; }
.lb-panel-btn { gap: 6px; }
.panel-chevron { flex: none; transition: transform 0.2s; }
.lb-panel-btn[aria-pressed="true"] .panel-chevron { transform: rotate(180deg); }

/* Sidebar: new comments on a board (speech bubble and number) */
.nav-count-comments { display: inline-flex; align-items: center; gap: 4px; padding: 1px 7px; border-radius: var(--radius); background: color-mix(in srgb, var(--text) 14%, transparent); color: var(--text); font-weight: 600; }
.nav-count + .nav-count { margin-left: 4px; }

/* Activity (#activity): new pins and comments on all boards, replaces the board view */
.activity-page { display: none; max-width: 860px; padding: 4px 0 60px; }
main.activity-open > .activity-page { display: block; }
main.activity-open > :not(.activity-page, .toolbar) { display: none !important; }
.activity-feed { display: grid; gap: 36px; }
.activity-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; margin: 0 0 12px; color: var(--nav-text); font-size: 14px; }
.activity-head strong { color: var(--text); font-weight: 600; }
.activity-head a { color: var(--text); text-decoration: none; }
@media (hover: hover) { .activity-head a:hover { text-decoration: underline; } }
.activity-head time { margin-left: 4px; color: var(--comment-time); font-size: 12px; }
/* Pins at thumbnail size, in their own proportions */
.activity-thumbs { display: flex; flex-wrap: wrap; gap: 10px; }
.activity-thumb { display: block; flex: none; height: 160px; aspect-ratio: var(--ratio, 0.8); max-width: 100%; overflow: hidden; border-radius: var(--radius); background: var(--surface-2); }
.activity-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; transition: opacity 0.2s; }
.activity-thumb img:not([src]) { opacity: 0; }
@media (hover: hover) { .activity-thumb:hover img { opacity: 0.85; } }
.activity-thumb.zooming { visibility: hidden; } /* open in the viewer */
/* A pin with its new comments next to it */
/* A comment still loading (Activity page): an avatar and a bubble with two lines, pulsing */
.comment-placeholder .comment-avatar { background: var(--surface-2); }
.comment-placeholder .comment-bubble { display: grid; gap: 8px; width: min(320px, 100%); padding: 12px; }
.comment-placeholder .comment-bubble > span { display: block; width: 80%; height: 10px; border-radius: 5px; background: color-mix(in srgb, var(--text) 12%, transparent); }
.comment-placeholder .comment-bubble > span + span { width: 50%; }
.comment-placeholder { animation: placeholder-pulse 0.9s ease-in-out infinite alternate; }
@keyframes placeholder-pulse { from { opacity: 0.45; } to { opacity: 1; } }
.activity-pin { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 16px; }
.activity-pin .activity-thumb { height: auto; width: 180px; max-height: 320px; }
.activity-comments { gap: 10px; max-width: 520px; max-height: none; margin: 0; padding: 0; overflow: visible; }
@media (max-width: 600px) {
  .activity-pin { grid-template-columns: minmax(0, 1fr); }
  .activity-pin .activity-thumb { width: 100%; max-width: 260px; }
  .activity-thumb { height: 120px; }
}
.activity-loading { display: grid; place-items: center; padding: 30px 0; }
.activity-loading[hidden] { display: none; }
.activity-empty { margin: 0; color: var(--muted); font-size: 14px; }

/* Share table: icons for View (eye), Comment (speech bubble) and Add (+) */
.invite-table th svg { display: block; margin: 0 auto; }

/* ---------- Debug panel (debug mode only) ---------- */
.debug-toggle { position: fixed; left: 236px; bottom: 16px; z-index: 2000; height: 30px; padding: 0 12px; border: 1px solid var(--line); border-radius: 15px; background: var(--surface-2); color: var(--nav-text); font: inherit; font-size: 12px; font-weight: 600; cursor: pointer; }
.debug-toggle[aria-expanded="true"] { color: var(--text); border-color: var(--accent); }
.debug-panel { position: fixed; left: 236px; bottom: 56px; z-index: 2000; display: grid; gap: 16px; width: min(300px, calc(100vw - 32px)); max-height: calc(100dvh - 80px); overflow-y: auto; padding: 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: 0 12px 40px rgb(0 0 0 / 0.5); font-size: 13px; }
.debug-panel[hidden] { display: none; }
.debug-panel section { display: grid; gap: 6px; }
.debug-panel h3 { margin: 0 0 2px; color: var(--nav-label); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; }
.debug-panel h3 .debug-note { text-transform: none; letter-spacing: 0; font-weight: 400; }
.debug-panel label { display: flex; align-items: center; gap: 8px; color: var(--text); cursor: pointer; }
.debug-note { margin: 0; color: var(--muted); font-size: 12px; }
.debug-buttons { display: flex; flex-wrap: wrap; gap: 6px; }
.debug-buttons .btn:disabled { opacity: 0.4; cursor: default; }
/* Just right of the sidebar (free also while the viewer is open); on phones (no sidebar), in the corner */
@media (max-width: 760px) { .debug-toggle, .debug-panel { left: 16px; } }
.debug-taps { position: fixed; top: calc(8px + env(safe-area-inset-top)); left: 8px; right: 8px; z-index: 3000; padding: 8px 10px; border-radius: var(--radius); background: rgb(0 0 0 / 0.8); color: #9f9; font: 11px/1.4 ui-monospace, Menlo, monospace; white-space: pre-wrap; pointer-events: none; }
